There is no tool that calls any endpoint
Every tool is explicit and typed, on purpose. A catch-all wrapper is rejected by both major client directories, and it hands a model a surface nobody has read.
MCP server and HTTP API
One server stands in front of every channel the account has connected, with 31 typed tools behind it. Your client reads the channels, reads what each network will actually accept, writes the post and sends it.
Self serve One key opens the MCP server and the HTTP API. You make it yourself, in Settings, and nothing goes out until you or your agent says so.
Connect
Every one of these talks to the same endpoint and signs in the same way. Choose one for its own three steps, or take the terminal instead.
Speaks MCP over HTTP
01
Add it as a custom connector
Customize, Connectors, Add custom connector, and paste this as the remote MCP server URL, exactly as written and without a trailing slash. Leave authentication on: Claude reads two documents from this server, registers itself, and sends you to sign in and approve.
https://api.postauto.io/api/mcp
02
Or open Claude with it filled in
This link opens the same form with the name and the address already typed. What you approve is scoped, and the consent screen says so in plain words. publish_post and retry_target are marked destructive, so Claude asks before either reaches a timeline.
Open the form in Claude03
Or paste a key, if the form cannot sign in
Some organisations' connector form has no sign-in for a custom server. Paste this as the server URL instead: it carries an API key in the path, authenticates exactly as a header does, and is a secret from then on. Make the key in Settings, API keys. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
https://api.postauto.io/api/mcp/pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MCP over HTTP, or from a terminal
01
Add the server
One command, no key. Claude Code registers itself with the server and works out where to sign in on its own.
claude mcp add --transport http postauto https://api.postauto.io/api/mcp
02
Sign in
Run /mcp inside Claude Code and follow the browser. It stores the token and refreshes it when it expires, so this is the last time you think about it. From a shell instead, claude mcp login postauto does the same.
See what you are approving03
Or use a key, for a script with no browser
A cron job cannot follow a browser, so it wants a key instead. Make one in Settings, API keys and pass it as a header. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
claude mcp add --transport http postauto \ https://api.postauto.io/api/mcp \ --header "Authorization: Bearer pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Speaks MCP over HTTP
01
Turn on developer mode, then add it
Settings, Security and login, Developer mode. Then chatgpt.com/plugins, the plus button, a name and a description, and this as the MCP server URL. Choose OAuth: ChatGPT registers itself with this server and sends you to sign in. A workspace admin does the same under Workspace settings, Apps, Create, and publishes it from Drafts.
https://api.postauto.io/api/mcp
02
Write actions ask first
ChatGPT confirms write actions by default; keep that on. Everything that reads runs without a question, and the two tools that reach a timeline are marked so a client can see it.
Every tool, and what each one can reach03
Or a key, where you choose no authentication
Choose No Authentication and use this address instead: it carries an API key in the path and authenticates exactly as a header does. A published plugin cannot present a key, so this is for your own connector only. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
https://api.postauto.io/api/mcp/pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Speaks MCP over HTTP
01
Write it into mcp.json
~/.cursor/mcp.json gives every project the server, .cursor/mcp.json in a repository gives one project it. No key: Cursor speaks OAuth, opens a browser, and holds its own token. This file is safe to commit.
{
"mcpServers": {
"postauto": {
"url": "https://api.postauto.io/api/mcp"
}
}
} 02
Or add it in one click
Cursor's own install link, carrying exactly the entry above. It opens Cursor, shows you the server, and asks before adding it.
Add to Cursor03
Or a key in the file
The same entry with the key as a header, for a machine with no browser. A committed .cursor/mcp.json with a key in it is a published key, so ignore the file or keep this in the user scoped one. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
{
"mcpServers": {
"postauto": {
"url": "https://api.postauto.io/api/mcp",
"headers": {
"Authorization": "Bearer pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}
} MCP over HTTP, or from a terminal
01
Add it to the CLI's settings
~/.gemini/settings.json for every project, .gemini/settings.json for one. httpUrl is the streamable HTTP form, which is what this endpoint speaks. With oauth enabled the CLI registers itself and /mcp auth postauto signs you in.
{
"mcpServers": {
"postauto": {
"httpUrl": "https://api.postauto.io/api/mcp",
"oauth": {
"enabled": true
}
}
}
} 02
One line does the same, and the app takes it too
This command writes the entry above. The Gemini app takes the same address under Settings & help, Connected Apps, Custom apps for Spark, Add a custom app, for personal accounts in the US for now.
gemini mcp add --transport http postauto https://api.postauto.io/api/mcp
03
Or a key in settings.json
The same entry with the key as a header, for a machine with no browser. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
{
"mcpServers": {
"postauto": {
"httpUrl": "https://api.postauto.io/api/mcp",
"headers": {
"Authorization": "Bearer pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}
} Speaks MCP over HTTP
01
Add a workspace server
.vscode/mcp.json, type http and the address, nothing to paste. VS Code handles the sign-in itself: a browser opens on the first connection, and the token is stored and refreshed for you.
{
"servers": {
"postauto": {
"type": "http",
"url": "https://api.postauto.io/api/mcp"
}
}
} 02
Or install it in one click
VS Code's own install link, carrying exactly the entry above. The server then appears in the MCP view and its tools in the chat's tool picker.
Install in VS Code03
Or a key, prompted for and kept by VS Code
The keyed form uses an input rather than the key itself: VS Code asks for it the first time and stores it, so this file is safe to commit too. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
{
"inputs": [
{
"type": "promptString",
"id": "postauto-key",
"description": "Postauto API key (pau_live_...)",
"password": true
}
],
"servers": {
"postauto": {
"type": "http",
"url": "https://api.postauto.io/api/mcp",
"headers": {
"Authorization": "Bearer ${input:postauto-key}"
}
}
}
} Speaks MCP over HTTP
01
Add it to settings.json
Under context_servers, with url. Settings, AI, MCP Servers does the same from a screen. A remote server is native in Zed: with no Authorization header set, it prompts you to sign in through the standard flow the first time it connects.
{
"context_servers": {
"postauto": {
"url": "https://api.postauto.io/api/mcp"
}
}
} 02
Nothing to bridge
An extension is only for a server that runs as a program on your machine. A remote one is added exactly as above, and that is the whole of it.
The server, in full03
Or a key in the same entry
With an Authorization header set, Zed sends it and never asks you to sign in. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
{
"context_servers": {
"postauto": {
"url": "https://api.postauto.io/api/mcp",
"headers": {
"Authorization": "Bearer pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}
} Speaks MCP over HTTP
01
Write it into mcp_config.json
~/.codeium/windsurf/mcp_config.json, still the path the product reads under its new name. serverUrl is its word for the endpoint. Leave the headers out and Devin Desktop sends you to sign in.
{
"mcpServers": {
"postauto": {
"serverUrl": "https://api.postauto.io/api/mcp"
}
}
} 02
Or from the panel
MCPs in the Cascade panel, or Devin Settings, Cascade, MCP Servers, takes the same address and offers the same sign-in.
https://api.postauto.io/api/mcp
03
Or a key in the same entry
Add Authorization with Bearer and your key under headers on the same entry, for a machine with no browser. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
{
"mcpServers": {
"postauto": {
"serverUrl": "https://api.postauto.io/api/mcp",
"headers": {
"Authorization": "Bearer pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}
} MCP over HTTP, or from a terminal
01
Add it, then sign in
The first command writes the entry into ~/.codex/config.toml; the second opens a browser. Codex registers itself with this server and holds its own token.
codex mcp add postauto --url https://api.postauto.io/api/mcp codex mcp login postauto
02
Or write config.toml yourself
The same entry by hand, in ~/.codex/config.toml or a project's .codex/config.toml. auth is oauth unless you say otherwise. The Codex desktop app takes the same address under Settings, MCP servers, Add server, Streamable HTTP.
[mcp_servers.postauto] url = "https://api.postauto.io/api/mcp"
03
Or a key, for a script with no browser
Export POSTAUTO_API_KEY first; Codex reads the key from that variable rather than writing it into the file. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
codex mcp add postauto --url https://api.postauto.io/api/mcp --bearer-token-env-var POSTAUTO_API_KEY
Speaks MCP over HTTP
01
Install it from Raycast
The Install MCP Server command, or Manage MCP Servers, Install New Server. Paste this as the URL, leave OAuth Type on Dynamic, press Sign In. Raycast registers itself with PKCE and stores the token encrypted. MCP is a Pro feature there.
https://api.postauto.io/api/mcp
02
Ending it is one action on either side
Logout Server in Raycast drops its token. Settings, Connected apps in Postauto ends the connection from this side, and the token stops working on the next request.
The server, in full03
Or a key in the address
The form has an HTTP Headers field for a key; this address carries one in the path instead and needs no field at all. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
https://api.postauto.io/api/mcp/pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MCP over HTTP, or from a terminal
01
Add it as a custom connector in Grok
grok.com/connectors, New Connector, Custom, and paste this as the MCP server URL. Grok discovers the tools and completes the sign-in this server asks for. The same connector works on iOS and Android.
https://api.postauto.io/api/mcp
02
From Grok Build, one command
Writes the entry into ~/.grok/config.toml. A server that signs in opens a browser on first use, and the token lives under ~/.grok. The xAI API's remote MCP tools take the same address with a key as the authorization value.
grok mcp add --transport http postauto https://api.postauto.io/api/mcp
03
Or a key, for a script with no browser
The same command with the key as a header. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
grok mcp add --transport http postauto https://api.postauto.io/api/mcp --header "Authorization: Bearer pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
MCP over HTTP, or from a terminal
01
Add it, name the auth, sign in
Three commands: the add writes the server, the configure says it signs in, the login opens a browser. openclaw mcp doctor postauto --probe afterwards says whether the tools are reachable.
openclaw mcp add postauto --url https://api.postauto.io/api/mcp --transport streamable-http openclaw mcp configure postauto --auth oauth openclaw mcp login postauto
02
Or in the Control UI
Settings, MCP, Add server takes the same address with transport Streamable HTTP and auth OAuth. Either way it lands in ~/.openclaw/openclaw.json under mcp.servers.
https://api.postauto.io/api/mcp
03
Or a key, for a machine with no browser
The same add with the key as a header, and no configure or login afterwards. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
openclaw mcp add postauto --url https://api.postauto.io/api/mcp --transport streamable-http --header "Authorization: Bearer pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
MCP over HTTP, or from a terminal
01
Add it to config.yaml
~/.hermes/config.yaml, under mcp_servers. Hermes connects to a remote endpoint directly and runs the sign-in on first use; the token is cached under ~/.hermes/mcp-tokens.
mcp_servers:
postauto:
url: "https://api.postauto.io/api/mcp"
auth: oauth 02
Leave the confirmation on
Two tools reach real timelines and nothing can take a post back: publish_post and retry_target. Both are marked so a client can see it and ask you first. Everything else reads, or writes a draft that waits for you.
Every tool, and what each one can reach03
Or a key in the same entry
The same entry with the key as a header, for a machine with no browser. A key can publish to every channel on the account and it does not expire, so give an agent its own and revoke it in Settings, API keys when you are done.
mcp_servers:
postauto:
url: "https://api.postauto.io/api/mcp"
headers:
Authorization: "Bearer pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" The postauto CLI, or plain HTTP
01
Install the CLI and sign in
One package, no dependencies. auth login opens the browser, you approve, and the token stays in a file only you can read. postauto mcp is also the bridge for a client that only launches programs: it speaks stdio to the client and HTTP to us.
npm i -g postauto postauto auth login
02
Then write a post
Every command is one tool call, so what the CLI can do is exactly what an agent can do: accounts, networks, posts, draft, publish, inbox, and call for any of the rest. Answers are JSON.
postauto draft --to <channelId> --text "Doors open at seven." --next-gate
03
Or plain HTTP, on a key
This is the shape of every MCP call, and both headers are required by the transport. It answers with the whole tool list. The REST API is the same service layer behind a different door, on the same key.
curl -sS -X POST https://api.postauto.io/api/mcp \
-H "Authorization: Bearer $POSTAUTO_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' Nothing on that list is the one you use? Anything that speaks MCP over HTTP works, and anything that does not can still call the plain HTTP API on the same key.
The short version
A client you already use, a chat app or an editor or a terminal agent, asks a server what it can do. The server answers with a list of tools, each one with a name, a description and a typed set of arguments. From then on the model can call them, and the client shows you what it called and what came back.
Postauto is one of those servers. It registers 31 tools in front of 16 networks, so the model never learns 16 network APIs, never holds 16 sets of tokens, and never guesses at 16 sets of media rules.
Transport is streamable HTTP in stateless mode. There is no session to open and none to close, which is why the whole setup is a URL and a header rather than a process to supervise. GET and DELETE answer 405, because there is nothing for them to do.
Authentication is a bearer token on every call. The same token authenticates the HTTP API, so a caller with no MCP in it is not a second integration, it is the same one through a different door.
MCP server and HTTP API
One MCP server and one HTTP API stand in front of every channel the account has connected. Your agent reads the channels, reads what each network will actually accept, writes the post and sends it. It never learns 16 network APIs, holds 16 sets of tokens, or handles 16 sets of media rules.
claude mcp add --transport http postauto \
https://api.postauto.io/api/mcp \
--header "Authorization: Bearer pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" One command, and the tools below are in the session. The same key opens the HTTP API.
The post, where it landed
Step zero
Keys are self serve. There is no waitlist, no form and nobody to email. The same key authenticates the MCP server and the HTTP API, and it is the only thing either of them needs.
One
Sign in and go to Settings, API keys. An account may hold up to 3 active keys, so an agent can have its own and you can revoke it without breaking anything else.
Two
A key is pau_live_ followed by 32 characters, and it is shown exactly
once. Postauto stores only a SHA-256 hash of it, so it cannot be shown again. Lose one
and you revoke it and make another.
Three
Authorization: Bearer pau_live_... on every call. Treat it like a
password: it can publish to every channel on the account. It cannot mint another key,
and it cannot reach anybody else's account.
The header is the one to use. It keeps the key out of URLs, which means out of proxy logs, browser history and shell history.
Some MCP clients still cannot attach a custom header. For those, and only for those, the key goes in the path instead. It authenticates identically. If that address ends up somewhere shared, revoke the key.
https://api.postauto.io/api/mcp/pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx The address
The endpoint is https://api.postauto.io/api/mcp. Transport is streamable HTTP in stateless
mode: one POST, one answer, no session to open and none to close. Anything that speaks MCP
over HTTP works, and GET and DELETE answer 405 because there is nothing for them to do.
{
"mcpServers": {
"postauto": {
"type": "http",
"url": "https://api.postauto.io/api/mcp",
"headers": {
"Authorization": "Bearer pau_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}
} A file like this next to your code gives everyone on the project the same tools in their session, which is usually what you want.
A file with a key in it does not belong in version control. Add it to
.gitignore, or keep the server in your own user scoped configuration and
leave the repository clean.
This is also the shape of every call the server takes. Both headers are required by the transport: without the Accept line a compliant client would not be compliant, and the server answers 406.
It answers with the 31 tools below. A missing or revoked key answers 401 with a JSON-RPC error explaining how to send one.
curl -sS -X POST https://api.postauto.io/api/mcp \
-H "Authorization: Bearer $POSTAUTO_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' The surface
Every tool is explicit and typed. There is no wrapper that will call any endpoint you name, on purpose: it hands a model a surface nobody has read, and the client directories reject it anyway. The natural order for an agent is account_status for the ceilings, then list_accounts, then get_network_rules for each target, then create_post.
What this key can reach, filed the way the customer files it, and how much of the plan is left. An agent that reads its ceilings first does not discover them on the tenth post.
list_accounts Reads list_clients Reads resolve_client Reads account_status Reads list_tags Reads list_media Reads Read the network's real rules, cut the text to fit them, then create the post. With no departure time it is saved as a draft for a person to approve, which is usually the right default for an agent.
get_network_rules Reads split_into_thread Reads next_slot Reads upload_from_url Writes create_post Publishes update_post Writes The half that reaches an audience. Both of the first two take an idempotencyKey, and this is the pair worth using it on: a retry after a timeout is what a well written client does with a network error, and without a key it is also how a post publishes twice.
publish_post Publishes retry_target Publishes delete_post Writes The questions an agent asks afterwards: did it land, which channel refused it and in whose words, what performed, and what needs a person.
list_posts Reads search_posts Reads get_post Reads get_post_metrics Reads top_posts Reads list_notifications Reads acknowledge_notifications Writes Two standing instructions: turn a feed into posts, and send a post that did well a second time. Both create posts on their own schedule, which is why both are set up deliberately and neither can be triggered on demand.
list_feeds Reads preview_feed Reads watch_feed Writes update_feed Writes unwatch_feed Writes list_repost_rules Reads create_repost_rule Writes update_repost_rule Writes delete_repost_rule Writes create_post takes content and targets, plus optional media, overrides, parts, tags and per-network settings, and at most one of scheduledAt, nextSlot or publishNow. With none of those three the post is saved as a draft for a person to approve, which is usually the right default for an agent running on its own.
idempotencyKey is what makes a retry after a timeout safe. Send the same key again and you get the first call's answer back rather than a second post. Keys are honoured for 24 hours.
{
"content":
"Six bags of the Ethiopia Guji left, then it is gone until March.",
"targets": [
"0a9c2f1e-6b7c-4a1e-9d3f-2b5c8e7a1d40",
"7d1b4c30-11aa-4f52-8a90-3c6d5e2f1b88",
"c4f8a5b2-90d7-4e63-b1a8-5f2c6d3e9a11"
],
"idempotencyKey": "guji-restock-2026-09-01"
} Before you wire it into a loop
The refusals are the interesting part of an API an agent drives unattended. Each of these is something the server actually refuses, and the message it returns says which channel, which limit or which id was the problem.
Every tool is explicit and typed, on purpose. A catch-all wrapper is rejected by both major client directories, and it hands a model a surface nobody has read.
Not by this API, not by the app, and on several networks not by the network. publish_post and retry_target are annotated so a client can see it and ask a person first. On a post nobody has read, ask.
draft, scheduled and failed can be revised. publishing, published and partial are refused with the reason, and the check happens inside the write, so a scheduled post that departs while your call is in flight is refused rather than edited on its way out.
Every network counts differently. X weighs a whole emoji family as 2, Bluesky counts it as 1, and Threads counts the string in UTF-8 bytes, where one curly apostrophe is worth 3. get_network_rules returns the unit, and split_into_thread does the arithmetic.
If a publish was interrupted after it started and before the network answered, nobody knows whether it went out. That channel is refused, by name, and takes confirmMayAlreadyBeLive on the next call once you have opened the channel and looked.
There is deliberately no tool for it. Both create posts, and an agent with a loop is the caller most likely to call one in one. The schedule reaches the same result within the half hour, and create_post is there when a post is wanted now.
The other front door
The REST API is the same service layer under a different door, on the same key, at
https://api.postauto.io/api/v1. It lists channels and networks, splits a thread, finds
the next gate, creates, reads, revises and deletes posts, reads their numbers, and manages
feeds and repost rules.
curl -X POST https://api.postauto.io/api/v1/posts \
-H "Authorization: Bearer $POSTAUTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Six bags of the Ethiopia Guji left.",
"targets": ["0a9c2f1e-6b7c-4a1e-9d3f-2b5c8e7a1d40"],
"nextSlot": true
}' Two things are MCP only today, and both are the finishing half of publishing: publish_post, which sends a post that is already written, and retry_target, which flies one channel again after it failed. Over HTTP a post goes out by being scheduled, or by passing publishNow when you create it.
Reading a customer's own client names, searching posts by their words and reading notifications are MCP only as well. Everything else is on both.
120 a minute
Reads, per key
Every GET on /api/v1.
30 a minute
Writes, per key
POST, PATCH, PUT and DELETE on /api/v1, and every MCP call including the tool list, because every MCP call is a POST.
20 a minute
Per address, before the key
Charged on every request that reaches the API, so a bad key cannot be guessed at in a loop.
Anything else that comes back as a message rather than as data is the answer: it names the network that refused the post, the limit that was passed, or the id that does not exist.
Make a key
Connect one channel, add the server to your client, and ask it to draft something. The draft waits for you, and nothing goes out until you say so.