This is the protocol reference. If you just want to point Claude or ChatGPT at your engine and start talking to it, connecting your agent is the page you want — it covers the client side. This one covers what is happening underneath.

The endpoint

POST https://your-host/mcp

One URL, on the same origin as the dashboard and the REST API. Transport is streamable HTTP with JSON-RPC 2.0 over POST; there is no separate SSE endpoint to configure.

Protocol version2025-06-18
Server namefastsite
Capabilitiestools
Methodsinitialize, ping, tools/list, tools/call

Anything else returns -32601. Notifications answer 202 with no body. Batches are accepted up to 20 messages.

Tool failures are results, not protocol errors

When a tool fails — a missing site, a rejected shell file, a validation error — you get a normal result with isError: true and a human-readable message, not a JSON-RPC error. That is deliberate: a model can read the message and correct itself, which it cannot do with a transport-level failure.

Authentication

OAuth 2.1, public client, PKCE required. A client that has never seen your engine before can discover and complete the whole flow on its own — nothing is pre-registered by hand.

  1. The client POSTs /mcp with no token and gets 401 plus a WWW-Authenticate header naming the resource metadata URL.
  2. It fetches /.well-known/oauth-protected-resource, which points at the authorization server.
  3. It fetches /.well-known/oauth-authorization-server for the endpoints and the supported scopes.
  4. It registers itself at POST /oauth/register and receives a client_id. No secret is issued.
  5. It opens /oauth/authorize in a browser. You sign in with your normal engine account and approve the requested scopes.
  6. It exchanges the code at /oauth/token for an access token and a refresh token.
  7. It calls /mcp with Authorization: Bearer ….
Authorization code60 seconds, single use
Access token1 hour
Refresh token30 days, rotated on every use
PKCES256 only — plain is rejected

Refresh tokens rotate, and reuse of an already-rotated token is treated as theft: the whole token family is revoked and the client has to authorize again. Codes and tokens are stored hashed, never in plaintext.

Clients must request scopes explicitly

There is no default scope set. An authorization request that omits scope entirely is rejected with invalid_scope rather than being granted a safe minimum. If you are writing a client, ask for exactly what you need — the consent screen shows the user a plain-language description of each one.

What a token can reach

Scopes decide what kind of operation is allowed. Your account decides which sites it applies to.

A token carries the scopes you approved. Every site-scoped tool then checks the signed-in user's own access to that site — direct membership, membership of the site's team, or the admin role. An agent connected to your account can reach the sites you can reach, and nothing else. Granting content:write does not widen that; it only decides what the agent may do on sites you already have.

The scope vocabulary is shared with API keys, so a tool and an endpoint enforce the same thing. The full list is on the REST API page.

Tools

More than fifty, covering everything the dashboard does. tools/list is the authoritative catalogue for your version — this is the shape of it.

Content

list_posts, get_post, create_post, create_page, update_post, delete_content, restore_content, purge_content, list_trash, fact_check

Media

list_media, upload_media_from_url, delete_media, restore_media, purge_media

Shell and design

shell_list_files, shell_get_file, shell_put_file, shell_snapshot, shell_restore, list_components, upsert_component, delete_component

Localisation

add_language, remove_language, translate_site

Publishing

publish_site, preview_site, get_build_status, list_jobs

Sites and routing

list_sites, create_site, update_site, list_redirects, upsert_redirect, delete_redirect, list_scripts, upsert_script, delete_script

Webhooks and backups

list_webhooks, create_webhook, webhook_deliveries, backup_site, list_backups, restore_backup

Teams and credentials

list_teams, create_team, invite_member, accept_invite, and the GitHub credential tools used for publishing

Restoring the engine is deliberately absent. Disaster recovery is a command you run on the box with the workers stopped, not something an agent can trigger.

Start with the guide

get_authoring_guide is the tool to call first, before designing a shell or writing a body. Pass a site handle and it folds in that site's locales and embed syntax.

{
  "method": "tools/call",
  "params": {
    "name": "get_authoring_guide",
    "arguments": { "site": "blog" }
  }
}

It returns the rules the build audit actually enforces: body-only HTML, required image dimensions and alt text, the zero-JavaScript constraint, and the embed syntax for media and components. An agent that reads it first writes markup that publishes; one that guesses writes markup that gets rejected.

Creating content

{
  "method": "tools/call",
  "params": {
    "name": "create_post",
    "arguments": {
      "site": "blog",
      "title": "Hello, world",
      "body_html": "<p>Shipped by an agent.</p>",
      "status": "published"
    }
  }
}

Images are referenced by media id, never by external URL — upload_media_from_url imports one and returns the embed snippet to paste into the body. Alt text is required.

If a client will not connect

  • Discovery returns localhost. The engine advertises its own URL in the OAuth metadata. If APP_URL is still the default, a remote client is told to authorize against localhost and fails registration. Set APP_URL to the real public URL.
  • The endpoint must be reachable and HTTPS. Remote clients will not run an OAuth flow over plain HTTP to a non-loopback host.
  • Check the 401 first. A correct unauthenticated POST /mcp returns 401 with a WWW-Authenticate header. If it returns anything else, the problem is in front of the engine, not in the client.
  • Stdio-only clients need a bridge. Point them at npx mcp-remote https://your-host/mcp.

Prefer plain HTTP calls? The REST API covers the same operations with an API key instead of a token.