API and MCP
Write access to your CMS, from the assistant you already use
One remote MCP server and one REST contract over Ghost, WordPress, Shopify and Webflow.
Install
-
1Create a workspace API key
Create API keyWhy
The key begins with
sk_specter_, is shown once, and is scoped to that one workspace. It authenticates MCP and REST alike, and is revocable from the screen that made it. -
2Paste the config into your assistant
Run it in a terminal.
claude mcp add --transport http spectersync https://app.spectersync.com/api/mcp \ --header "Authorization: Bearer sk_specter_YOUR_KEY"Why
Registers the server for the current project. Add
--scope userto register it for every project instead.Edit the config file, then restart the app.
{ "mcpServers": { "spectersync": { "command": "npx", "args": [ "-y", "mcp-remote", "https://app.spectersync.com/api/mcp", "--header", "Authorization:${SPECTERSYNC_KEY}" ], "env": { "SPECTERSYNC_KEY": "Bearer sk_specter_YOUR_KEY" } } } }Why
The file is at
~/Library/Application Support/Claude/on macOS and%APPDATA%\Claude\on Windows. It takes local commands rather than URLs, so the hosted endpoint is reached through themcp-remotebridge — which needs Node 18 or later, because that is what suppliesnpx.Put it in
~/.cursor/mcp.json.{ "mcpServers": { "spectersync": { "url": "https://app.spectersync.com/api/mcp", "headers": { "Authorization": "Bearer sk_specter_YOUR_KEY" } } } }Why
That covers every project. For one project only, use
.cursor/mcp.jsonin the repo root instead.Open Cascade's MCP panel and edit the file it points at.
{ "mcpServers": { "spectersync": { "serverUrl": "https://app.spectersync.com/api/mcp", "headers": { "Authorization": "Bearer sk_specter_YOUR_KEY" } } } }Why
The file is
~/.codeium/windsurf/mcp_config.json; refresh the panel afterwards so Cascade reconnects. Windsurf's docs takeserverUrlorurl, and their own remote example usesserverUrl.Put it in
~/.gemini/settings.json.{ "mcpServers": { "spectersync": { "httpUrl": "https://app.spectersync.com/api/mcp", "headers": { "Authorization": "Bearer sk_specter_YOUR_KEY" } } } }Why
Or
.gemini/settings.jsonin a repo root for that project only. Restart the CLI and run/mcpto see the tools it picked up. The streamable-HTTP key ishttpUrl—urlis the SSE one.Put it in
~/.gemini/config/mcp_config.json.{ "mcpServers": { "spectersync": { "serverUrl": "https://app.spectersync.com/api/mcp", "headers": { "Authorization": "Bearer sk_specter_YOUR_KEY" } } } }Why
Or
.agents/mcp_config.jsonfor one workspace. Antigravity readsserverUrlonly — its docs sayurlandhttpUrlare not supported, so a config copied from another editor will fail here.Settings → Connections → MCP servers → Add a custom MCP.
Server URL https://app.spectersync.com/api/mcp Header key Authorization Header value Bearer sk_specter_YOUR_KEYWhy
Devin takes a remote server through a form rather than a file. Set the transport type to HTTP (the docs call it Streamable HTTP in prose), paste the three values below, and set Authentication method to Auth Header. Adding a custom server needs the Manage MCP Servers permission; without it the button is not there, and an org admin has to grant it — or you can use Suggest MCP Integration to ask.
Put it in
.vscode/mcp.json.{ "servers": { "spectersync": { "type": "http", "url": "https://app.spectersync.com/api/mcp", "headers": { "Authorization": "Bearer ${input:spectersync-key}" } } }, "inputs": [ { "type": "promptString", "id": "spectersync-key", "description": "Spectersync API key (sk_specter_…)", "password": true } ] }Why
Or run MCP: Open User Configuration from the command palette to apply it everywhere. The
inputsblock makes VS Code prompt for the key once and store it securely, so a config you commit never carries the key itself.Export the key, then run it in a terminal.
codex mcp add spectersync \ --url https://app.spectersync.com/api/mcp \ --bearer-token-env-var SPECTERSYNC_KEYWhy
export SPECTERSYNC_KEY=sk_specter_YOUR_KEYfirst. The command writes an[mcp_servers.spectersync]block into~/.codex/config.tomlwithurlandbearer_token_env_var, and Codex builds theAuthorization: Bearer …header from that variable at connect time, so the key never lands in the file. Codex's MCP docs cover the same server underconfig.toml; the flags come from the CLI's help.ChatGPT cannot reach Spectersync today. No config
Why
ChatGPT speaks MCP through a custom connector, and a connector will not take a bearer key: it authenticates over OAuth, over no authentication, or a mix of the two, per OpenAI's developer-mode guide. A key is what Spectersync issues, so there is no configuration here that would work if you pasted it. The route that needs no OAuth is a Custom GPT with an Action over the REST surface, and that surface is not live either. Both are being built.
-
3Ask it something read-only
List my connected sites in Spectersync. Do not change anything.Why
Restart the client first so it picks the server up. The prompt should call
list_connectionsand come back with the CMSes on your workspace. A key that is wrong or revoked returns401instead, which tells you the same thing faster than a failed write would.When you ask it to change something, it drafts into a working copy and then calls
create_review, which hands you one link with a card per change: before, after, and accept, reject or skip. Nothing reaches your CMS until you accept, and the link expires within a day. That is the whole publish path on the free plan —publishwithconfirm: true, publishing without the round trip through you, is part of Pro.
What it costs
Reading, previews and reverts are free — a rollback you have to pay for is a rollback people postpone. A refused write publishes nothing and returns the reserved credit.
| Read a document | Free |
|---|---|
| Preview a publish | Free |
| Revert to a snapshot | Free |
| Send changes for review | Free |
| Publish a document | 1 credit |
| Recipe, per document | 1 credit |
| Analysis recipe, per document | 2 credits |
| Granted at signup | 400 credits, once |
| Credit pack | $29 for 400 credits, good for twelve months |
| Pro | $99 a month — unlimited credits, fair use 5,000 documents a month |
| Additional user on Pro | $49 a month each, same workspace |
| Plan detail | Pricing page |
The safety contract
Four rules stand between an assistant and a live page.
| The publish has to be the preview | PUT defaults to dryRun: true and returns the field-level before and after plus a dryRunId. The id is bound to the whole document that would go live, and works once. |
|---|---|
| The write carries the revision you read | Every publish sends back the baseVersion that came with the document. If the page moved in the CMS meanwhile, the write is refused with 409 and nothing changes. |
| On the free plan, a person clicks it | The assistant calls create_review. Everything it staged becomes one page of before/after cards at a link you open — accept, reject with a note, or skip each one. Only an accept publishes, and it runs the same write path. Doing nothing publishes nothing, and the link expires. Publishing straight from the assistant is the Pro path. |
| Every publish is snapshotted first | The response carries a snapshotId, and one POST puts the page back. If the snapshot cannot be saved, the publish does not happen. |
Why it is built this way
Anything writing to a CMS on someone's behalf is occasionally going to be wrong, and the person who finds out is the site owner. So a preview reaches nothing on your CMS, and an edit made through any other route in between voids the id rather than riding along on your approval. The optimistic lock holds on Shopify and Webflow too, whose APIs have no such lock: Spectersync re-reads the live item and compares before writing, and a document with no recorded revision at all is refused rather than written blind. A rollback is itself snapshotted, so an unwanted rollback is recoverable as well.
The hosted MCP server carries the same guarantee. publish is the only
tool that writes to a live CMS, and it needs confirm: true, the
base_version the agent read, and a dry_run_id from its own
prior preview of that exact document. An agent cannot reach your site on one tool
call, and it cannot reach it with a document other than the one you were shown.
Limits and errors
v1 reads and updates content that already exists; the rest stays in the web app.
| Create, delete, upload media | Web app only — not over API or MCP |
|---|---|
| Webflow SEO meta | Written when the collection carries a conventionally slugged field (meta-title / seo-title, meta-description / seo-description) or one is mapped in config. Webflow has no reserved SEO surface on CMS items, so a collection without such a field has nowhere to put them |
| Review link | One to twenty-four hours, twenty-four by default. At expiry the link, the batch and the staged edits it froze are all deleted; snapshots of anything published are kept |
| Request budget | 60 a minute per key, counted per server instance |
| Snapshot retention | 7 days on free and credit packs, 90 on Pro. The most recent snapshot of a document is never deleted, so a revert is always available |
| Per-platform detail | Capability matrix |
401 | Missing, unknown or revoked key |
|---|---|
402 | Out of credits, past the fair-use ceiling, a tool your plan does not include, or use_review_url — this plan publishes through a review link. Nothing written, the CMS was never contacted |
404 | No such site, post or snapshot |
409 | Refused, nothing written — details.reason says which |
422 | Body off contract, or a publish with no baseVersion or dryRunId |
429 | Over the request budget |
502 | The CMS refused the write |
REST and OpenAPI Not live yet
Every /v1 path below returns 404 today. Read it as the contract
to build against — the same code path as MCP, so the same guarantees.
Authorization: Bearer sk_specter_…
Base URL https://app.spectersync.com/api POST /v1/reviews | Turn the staged edits into one link a person approves on |
|---|---|
GET /v1/reviews/{id} | What they accepted, what they rejected, and the comment on each |
GET /v1/sites | Connected CMSes, with what each one's write lock guarantees |
GET /v1/sites/{site}/posts | Documents on a site — filter by kind, status or title |
GET /v1/sites/{site}/posts/{post} | Markdown, frontmatter, what is live, and the baseVersion |
PUT /v1/sites/{site}/posts/{post} | Preview by default; publishes on dryRun: false |
POST …/snapshots/{snapshot}/revert | Put the CMS back to a snapshot |
The body is markdown and the frontmatter has the same nine fields on every platform, so
you build against one contract instead of four APIs. Full detail is in
/api/v1/openapi.json
— OpenAPI 3.1, generated from the schemas the endpoints validate against.
Questions before you connect
Which clients work today?
How does publishing work on the free plan?
create_review. That returns one
link — no login — with a card per changed page: the before and after, the checks we ran, and
accept, reject or skip. Accepting runs the same publish path as the paid route, snapshot and
revision lock included. A rejection can carry a note, which the assistant reads back through
review_status so it can redo the edit. The link is a capability: anyone holding
it can approve those changes, so treat it like a password. It expires within a day, and at
expiry the staged edits go with it. confirm: true — publishing without the
round trip through a human — is part of Pro.Where do my CMS credentials go?
What can the assistant actually change?
How do I undo something?
snapshotId.
POST …/snapshots/{id}/revert republishes the state from before, and returns an
undoSnapshotId for the state that rollback replaced.