MCP server
Connect an AI agent — Claude, ChatGPT, Cursor, anything that speaks Model Context Protocol — to a Mutator workspace, so it can find automations, test them, read what happened and report what came out.
Endpoint: https://mutator.app/mcp
The one thing to know
No tool on this server can post anything.
That is not a scope you can widen or a permission you can grant. It is the shape of the server. An agent can build a run, watch it, read what came out and tell you about it; a person opens Mutator and decides whether any of it reaches a real account.
Nor can the public API, since approvals were removed on 20 September 2026: a run publishes nothing at all, and a post exists only once a person has put a particular file in a particular account's schedule, in Mutator, with their name on the decision. There is no key of any scope that reaches that. See what marketing may claim about this, and what the platform reviews were told.
Connecting
Authentication is a Mutator API key as a bearer token — the same keys the public API uses, created under Settings → API keys (workspace owner, any paid plan). See the public API documentation, which says what a key reaches on each plan.
A read key reaches every tool except mutator_start_run. Issue one of those unless the agent genuinely needs to start runs.
Claude Code
claude mcp add --transport http mutator https://mutator.app/mcp --header "Authorization: Bearer loop_sk_..."
Anything with a JSON config
{
"mcpServers": {
"mutator": {
"type": "http",
"url": "https://mutator.app/mcp",
"headers": { "Authorization": "Bearer loop_sk_..." }
}
}
}
Check it works by asking the agent to call mutator_whoami, or from a shell:
curl -s https://mutator.app/mcp -H "Authorization: Bearer loop_sk_..." -H "content-type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
GET https://mutator.app/mcp needs no key at all and returns a description of the server and its tools — useful for checking reachability, and for anything cataloguing MCP servers.
That same URL opens a page in a browser. One address serves both: a request asking for text/html gets the page, and everything else — a POST, or a GET sending */* or application/json — gets the protocol. Nothing about the endpoint changed for a client that was already using it.
Building an automation
An agent reads the vocabulary before it writes: mutator_list_brands for the brand the automation belongs to, mutator_list_step_types for the steps that exist, mutator_list_formats for the content formats, and mutator_list_connections for the account a publish step must name — there is no "post to TikTok" field, only "post to this connection, which happens to be TikTok".
Then mutator_create_automation with a graph of { key, type, position, config } nodes and { sourceKey, targetKey } edges. Most settings have defaults, so config: {} is usually enough. Two branches out of one step is how the same idea is produced two ways.
An invalid graph is saved anyway, with the problems returned as issues. That is deliberate: half-built is a normal state for a draft, and failing the whole call would lose the work. Two settings are refused outright at save time rather than at run time, because the executor refuses them hours later once somebody has activated and walked away — several versions of one video, and an image batch that is not 1 or exactly 4.
Tools
| Tool | Scope | What it does |
|---|---|---|
mutator_whoami | read | Which workspace this key reaches and what it may do |
mutator_list_automations | read | Every automation with id, name and status |
mutator_get_automation | read | One automation: status, schedule, spending limits |
mutator_list_runs | read | Recent runs of one automation |
mutator_get_run | read | One run, with per-step detail |
mutator_list_approvals | read | Always empty: approvals were removed |
mutator_get_analytics | read | How published content performed |
mutator_get_spend_limits | read | Daily and monthly ceilings, and what is left |
mutator_start_run | write | Start a run. Dry by default |
mutator_list_brands | read | The brands an automation can belong to |
mutator_list_connections | read | Connected accounts, and the id a publish step needs |
mutator_list_formats | read | The content formats, and the niches they suit |
mutator_list_step_types | read | Every step an automation can be built from |
mutator_create_automation | write | Create an automation. Draft only |
mutator_save_automation_graph | write | Replace its steps. Draft only |
mutator_set_schedule | write | Set when it would run. Saved switched off |
Dry by default
mutator_start_run runs dry unless the caller passes dryRun: false. A dry run skips publishing (and scheduling a repeat), not generation. It is not free: create and understand ignore dryRun, so a dry run makes the same paid generation calls a real run does, costs the same credits or provider charges, and is checked against the same spend caps (src/server/engine/runs.ts, the comment above assertSpendWithinCaps).
The public API leaves dryRun undefined and lets the engine decide, which is right for an integration somebody wrote on purpose. Here the caller is a model that may have inferred the entire call from one sentence, so the safe reading of silence is "test it": whatever it generates stops short of any social account. That limits what a mistaken call can publish, not what it can spend, which is why the tool description tells the model to start a run only when the user wants one.
idempotencyKey is required, 8–80 characters, and namespaced per key on the way through. Retrying with the same value returns the original run rather than starting a second one.
What this server is not
- Not an activator. An agent can build an automation and save it as a draft. It cannot switch one on. That is safe because a draft genuinely cannot run — it has no active version, the scheduler fires only active automations, and
createRunrefuses every trigger buttestunless the automation is active, which no API key can set. Activation is where a person reads what was built and takes responsibility for it, so it stays in Mutator. - Not a publisher. Above.
- Not a trend service. There is no virality, trending or discovery data in this product.
mutator_list_formatsreturns a hand-written catalogue, and a niche orders it rather than filtering it. An agent asked for "viral formats" can offer these; it cannot say any of them is trending. - Not stateful. No session id is issued, so any replica answers any request and a deploy loses nothing. Each call carries its own key.
Implementation notes
The server speaks JSON-RPC directly rather than using the official SDK. MCP is JSON-RPC 2.0 with four methods that matter to a tools-only server — initialize, tools/list, tools/call, ping — and the SDK's value is in transports that assume a long-lived process owning a socket. A Next route handler is neither.
Authentication, rate limiting and error shaping are shared with the public API, and the endpoint carries no scope of its own: reaching it needs only a valid key, and the one write tool checks the scope itself at call time. Requiring write at the door would lock read-only keys out of initialize.
No CORS headers, deliberately. Every MCP client that matters connects from a server or a desktop process, and authentication is a bearer token rather than a cookie, so there is nothing for a browser to be tricked into sending.
The protocol versions spoken are 2025-06-18, 2025-03-26 and 2024-11-05. An unknown version is answered with the newest rather than refused.