Iterant is in early access. These docs describe the product as it works today.
Iterant Docs

MCP server

Connect Claude Code, Claude Desktop, Cursor, or VS Code to Iterant over a hosted, stateless Streamable HTTP MCP endpoint.

The Iterant MCP server gives an agent a small set of typed tools over your brands: what the site is doing, what the opportunity queue holds, how pages perform, how assistants answer about the brand, and how to put Terra to work.

It is a remote server. Nothing to install, nothing to run locally.

Eleven tools: nine reads and two writes. The writes are create_agent_task and get_agent_task, covered in Agent tasks.

Endpoint

https://mcp.iterant.ai/mcp

That single path is the whole server. The MCP hostname serves /mcp and the /.well-known/… documents and nothing else: the REST API is not reachable there, and /mcp is not reachable on api.iterant.ai. https://mcp.iterant.ai/mcp is the OAuth resource identity, and a token audienced for it must not be a token for the whole REST API.

Any other path on the MCP host returns a 404 in the standard error shape, indistinguishable from a path that does not exist anywhere.

Transport

Streamable HTTP, stateless, and dual-era: revision 2026-07-28 natively, with clients on 2025-03-26 through 2025-11-25 served through the initialize handshake they expect. The era is chosen per request, the way the revision specifies for a dual-era server: a request carrying per-request _meta (or the 2026-07-28 version header) gets the modern stateless surface, and a request carrying neither gets the 2025-era semantics. Today's Claude, Cursor, and VS Code builds connect either way.

For anyone writing a modern-era client:

  • POST only. GET and DELETE return 405 with Allow: POST. The revision removed the standalone SSE stream, session teardown, and Last-Event-ID resumability, so there is nothing behind either verb.
  • No sessions. No Mcp-Session-Id is minted or echoed, and one sent by an older client is ignored.
  • JSON responses. application/json, always. An Accept header that does not admit JSON is a 406; the endpoint never opens an event stream.
  • One message per request. An array body is an invalid request (batching left the protocol in 2025-06-18), unparseable JSON is a -32700 parse error under HTTP 400, and a JSON-RPC response POSTed at the server is refused: this server initiates nothing, so it has nothing to hear an answer to.
  • Three headers are required and validated against the body. MCP-Protocol-Version must equal the version in _meta, Mcp-Method must equal the body method, and Mcp-Name on tools/call must equal params.name (the =?base64?…?= sentinel encoding is decoded before comparing). A missing or contradicting header is -32020 under 400.
  • Every modern request carries _meta. params._meta must include io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities; sending the 2026-07-28 header without them is malformed, -32602 under 400.
  • server/discover is the front door. It returns the supported versions, the capabilities, and the instructions string, and it is the one method the revision requires of every server. It is answered in both eras, so a dual-era client can probe with it. An unknown modern-era method is a 404 whose JSON-RPC body is what tells you "wrong method" apart from "no MCP server here".
  • Origin is checked. A present-but-unlisted Origin is a 403; absent is fine, which is what every non-browser client sends.
  • Notifications get no reply. A message with no id returns 202 with an empty body.

Legacy-era requests keep their 2025-era rules: initialize negotiates the protocol version and returns the instructions, ping answers, the mirrored headers and _meta are not required, results keep their pre-2026-07-28 shapes, and an unknown method is a -32601 at HTTP 200. A version header naming a revision from neither era gets -32022 with every supported version in data.supported.

The server does not implement sessions, sampling, roots, logging, resources, or prompts. Nothing is lost by the last three: the revision deprecated them protocol-wide.

What your credential reaches

An itr_ API key reaches over MCP what it reaches over REST. A brand-pinned key gives the agent one brand, an org-scoped key gives it every brand in the organization. Revoke the key and both surfaces stop working on the next request.

An OAuth access token resolves a person. The organizations that user belongs to decide what the tools can see, and a user who belongs to several reaches the brands of all of them. A token whose subject has no Iterant account is a 401.

Authentication

OAuth 2.1

The default for interactive clients: add the server, the client opens a browser, you sign in to Iterant and consent, and the client holds a token that follows your account. No credential is pasted into a config file, and leaving the organization ends the access.

Iterant advertises its authorization server through RFC 9728 protected-resource metadata, served unauthenticated and CORS-open at both:

https://mcp.iterant.ai/.well-known/oauth-protected-resource/mcp
https://mcp.iterant.ai/.well-known/oauth-protected-resource

Both return the same document, and the path-suffixed form is the one RFC 9728 specifies for a resource that lives at …/mcp:

{
  "resource": "https://mcp.iterant.ai/mcp",
  "authorization_servers": ["https://…"],
  "bearer_methods_supported": ["header"],
  "scopes_supported": ["openid", "offline_access"]
}

A 401 from the endpoint carries the same pointer on its WWW-Authenticate challenge, so a client that has never seen Iterant can discover where to authenticate.

Connectors register themselves through OAuth dynamic client registration, so the flow starts without anyone filing a ticket. (Revision 2026-07-28 deprecates DCR in favor of Client ID Metadata Documents but keeps it for authorization servers that have not adopted CIMD yet, and that compatibility path is the one this flow rides today.)

API key

For headless callers: n8n, CI runners, container jobs, anything that cannot complete a browser redirect. Mint a key at Settings → Developers (see API keys) and send it as the bearer:

Authorization: Bearer itr_…

The per-client install steps below show where the header goes.

Scopes

Iterant defines no scopes. There is no iterant:read, no iterant:write, and no scope name is reserved for a future one.

Authorization is decided on every call from the credential itself: which organization it belongs to, which brand it is pinned to, and what that organization can see. The scopes_supported values in the metadata document are the standard OIDC ones and say nothing about Iterant's objects.

One consequence: tools/list returns all eleven tools to every authenticated caller. A credential that cannot do something still sees the tool in the list and gets a refusal when it calls it. Today every credential that can read a brand can also start a task for it, so the only refusal a tool raises is a tenancy one.

Install

One command, no credential:

claude mcp add --transport http iterant https://mcp.iterant.ai/mcp

Run /mcp inside Claude Code, pick iterant, and choose Authenticate. A browser opens; sign in to Iterant and consent. The server shows as connected, with eleven tools.

Headless or shared environments use a key instead:

claude mcp add --transport http iterant https://mcp.iterant.ai/mcp \
  --header "Authorization: Bearer ${ITERANT_API_KEY}"

--scope project commits the server to the repository's .mcp.json. That is fine for the OAuth form, which stores no credential, but keep key-authenticated servers in user scope (the default) or behind an environment reference like the one above.

Choosing a brand

Tools take a brand_slug such as acme, the same slug you see in your dashboard URLs. A UUID is not accepted.

brand_slug is required on all ten brand-scoped tools. It never defaults, even when your credential is pinned to a single brand and even when your organization has one brand in it. An agent that does not know the slug calls list_brands first, and the server validates whatever it passes against what the credential can reach.

Tools only

The server publishes tools only. There are no MCP prompts, so no Iterant slash commands appear in your client, and no MCP resources, so closed vocabularies are named inline in the tool descriptions. Both hold for this phase, see MCP tools.

server/discover returns an instructions string: a short orientation telling the agent to start at list_brands and get_brand_overview, how identifiers work, that one tool spends money and takes five minutes, and how to read metric states and estimates. In a client that runs tool search, that string plus the tool names is all the model sees at session start.

Verifying a connection

The MCP Inspector lists the tools your credential can see, the fastest way to confirm auth:

npx @modelcontextprotocol/inspector --cli https://mcp.iterant.ai/mcp \
  --transport http --method tools/list \
  --header "Authorization: Bearer itr_YOUR_KEY_HERE"

Eleven tools is a healthy answer. A 401 means the key was not accepted: mistyped, truncated, or revoked. The WWW-Authenticate header points at the protected-resource metadata, which is what an OAuth client needs from it.

Any Inspector build works: an older one opens with initialize and is served as a legacy-era client.

Next

MCP tools. Every tool, what it takes, and what it returns.

Agent tasks. What create_agent_task starts, and how it settles.

Last updated on

On this page