Skip to content
Console
Browse documentation
Reference

MCP client compatibility

What the Anectico MCP endpoint requires of a client, and a dated record of what has actually been run against each agent host.

On this page

The remote endpoint is one URL:

https://app.anectico.com/mcp

This page has two parts. The first states what a client must do to talk to the endpoint. The second is a record, one entry per agent host, of what has really been run and when. Every host is marked with exactly one of three words:

Status Meaning
Verified We ran it ourselves. The record says on what date and what was run.
Connected once We saw a real connection from the host. We did not run a full workflow.
Implemented, not verified The configuration or the server side is built from the host's own documentation. No run was made with the host.

A record is a statement about one day. A host can change after it, so each entry names the date.

What the endpoint requires

Every item here is a property of the running service, not an aspiration.

A successful validation or preview call can have a negative outcome. An invalid rule, program or signature returns status: error, with a summary starting invalid: <reason>. A refused launch, audience or routing preview starts refused: <reason>. The full evidence remains in data; isError is false because the call itself succeeded. The corresponding CLI checks print the full result and exit 1 on a negative outcome, including JSON output. An empty measurement or a metric threshold that was not met is a valid result.

Requirement Detail
Transport Streamable HTTP, stateless. One endpoint, and it serves POST only.
Other methods GET and DELETE are answered 405 with Allow: POST. There is no server-to-client stream to open and no session to delete.
Accept on POST Must contain both application/json and text/event-stream. A request missing either is answered 400.
Credential A branded an_ API key or an access token obtained through the advertised OAuth flow, in a header. Never in a query string or a request body.
Header form OAuth uses Authorization: Bearer <access-token>. API keys use Authorization: Bearer an_…, Authorization: ApiKey an_…, X-Anectico-API-Key: an_…, or X-API-Key: an_….
Session None. Every request is independent and carries its own credential.
Scopes mcp:read or mcp:write to reach the endpoint at all, plus the domain scope of every tool.

Read the result envelope’s scope before making a claim. project_id names the bound or requested project; an empty value explicitly means all projects of the workspace. When the answer covers a time window, scope.window repeats the window reported in its data. list_issues, get_service_health, list_anomaly_findings and search_traces accept an optional project_id. Omission uses a project-bound credential’s project; an organization credential may name a project or omit it for a workspace-wide read. A contradictory project is refused.

Product data and this documentation are exposed through tools; use tools/list to verify the connection. resources/list also advertises one static, read-only result viewer with MIME type text/html;profile=mcp-app. Its ui://anectico/result-view/v1/<bundle-hash>.html address identifies the viewer's exact build, never a customer's result. Read the exact address returned by the list; modified or retired addresses are refused. prompts/list and resources/templates/list remain empty.

The static viewer contains no customer data or credential and grants no permission to read a result. It needs only the endpoint's existing mcp:read or mcp:write permission. Result reads still require their own permissions. Resources have no subscriptions or change notifications. Discovery, lists and resource reads carry ttlMs: 0 and cacheScope: "private", including this static viewer. Do not share cached responses between connections.

get_analytics_result, get_service_health, get_person_timeline and get_experiment_result are directly listed viewing tools. Their descriptors link to that exact static viewer and declare model-only UI visibility. Every other server tool, including discovery and execution gateways, also declares model-only visibility; only viewing tools link a viewer. The supplied frame receives data and has no tool-call controls. A host's enforcement of forwarding restrictions needs separate verification.

Use Charts in chat for viewing-tool arguments, supported shapes, image negotiation, fallback and delivered-copy lifetime. Use The result viewer for signed-in proof links. query_product_analytics remains a read action through execute_read_action. Discover get_local_evaluation_snapshot and get_incident_slack_channel with list_read_actions and invoke them through execute_read_action; a viewing tool does not replace those actions.

The older two-endpoint HTTP+SSE transport is not served — there is no separate /sse or /messages path, and a client that requires it cannot connect.

The credential is checked before anything else. A malformed Accept, an unknown method and an invalid ?profile= are all answered only once the request has authenticated and cleared the umbrella-scope check. So an unauthenticated probe of this endpoint learns 401 and nothing more, whatever else is wrong with it — which is deliberate, and worth knowing when you are debugging a 401 you expected to be a 400.

Authentication choices

The endpoint accepts either an an_ API key or an audience-bound OAuth access token. A request with no credential receives a 401 and a WWW-Authenticate challenge pointing to the protected-resource metadata; an OAuth-capable client follows that document to the advertised authorization server and uses PKCE. API-key clients can continue sending their configured header without running discovery.

There is nothing to obtain by hand for the OAuth path. The advertised authorization server accepts dynamic client registration and client metadata documents, so a host identifies itself on first connection and is a public client — no client secret exists to store, and PKCE authenticates the exchange instead. A client metadata document must be served from a public HTTPS address, name its own address as its client_id, fit within 5 KiB and not redirect. A document that offers the public method none is stored as a public client even when it also lists a signed assertion as an option; the signed assertion is never accepted. You are never asked for a client id, and an operator never has to pre-provision one.

The protected-resource metadata is served on both well-known locations, because the two are constructed differently and clients in the wild ask for either:

https://app.anectico.com/.well-known/oauth-protected-resource/mcp
https://app.anectico.com/.well-known/oauth-protected-resource

The token must be bound to this endpoint's URL as its audience. A conforming client sends the resource indicator automatically. Both sides enforce it: the authorization server refuses to issue a token for any other resource identifier — including near-misses such as a trailing slash, a query string or the bare origin — and this endpoint refuses a token that arrives bound to something else, with a valid signature and a valid issuer. That is deliberate and there is no setting that widens it. A 401 carrying invalid_token after an authorization that appeared to succeed means the client requested the wrong resource identifier; it should be exactly the URL at the top of this page. For the same reason, do not add ?profile= to the address of a host that signs in with OAuth.

Every authorization response — an approval, a denial and a refusal that returns to the host — carries the issuer in an iss parameter, so a host that compares it exactly (ChatGPT does) accepts the response.

An OAuth connection is read-only and deliberately less capable than the person who authorized it — it is capped at a fixed delegation ceiling regardless of that person's role, and no write permission is offered. See How agent access is enforced for exactly what is inside and outside it. A host that cannot send an API key therefore cannot change anything in Anectico.

The host opens sign-in and consent directly; the person need not open the Console first. Consent shows the client and redirect hosts, lets the person choose a workspace and narrow the requested permissions, and creates one connection per approval. Include resource with the exact MCP endpoint and request offline_access when refresh is needed. Public clients use PKCE S256. Revoking a connection stops that approval's access and token issuance; other approvals remain independent. See Connect and revoke an agent.

Protocol revisions

Five revisions are served, and the endpoint negotiates rather than requiring one:

Revision How a client reaches it
2026-07-28 server/discover, with the Mcp-Protocol-Version and Mcp-Method headers and the matching per-request _meta. There is no initialize at this revision.
2025-11-25 The initialize handshake.
2025-06-18 The initialize handshake.
2025-03-26 The initialize handshake.
2024-11-05 The initialize handshake.

One edge worth knowing: an initialize request that names 2026-07-28 in its body but sends none of that revision's per-request headers or _meta is negotiated down to 2025-11-25, because initialize is precisely the handshake that revision removes. A transitional client that sets the modern headers as well is not downgraded — it gets an error, because initialize no longer exists there.

What every tool tells a host about itself

Every tool carries a human title and states all four MCP hints as explicit true or false values: readOnlyHint, destructiveHint, idempotentHint and openWorldHint. A read tool is read-only, not destructive and closed-world. Only a read is marked read-only, so a host that runs read-only tools without asking (Claude and ChatGPT both document this) never runs a write that way. A write is never marked read-only. Its destructive hint says whether it removes state the key cannot put back, and its idempotent hint says whether repeating the call leaves the same end state; both are the catalog's own grades, which the MCP tool reference publishes for each action. The two doors that run the less frequent writes are always marked destructive, so a host asks before them. Tool names use only letters, digits and underscores and are at most 63 characters long, the shortest limit a host documents.

Host records

These are the records. Where a host is a service run by its vendor, the vendor's own pages are the source, and the page we read is named. The vendors' pages carry no date of their own, so each date below is the day we read them.

Claude Code

  • Status: Connected once
  • How it connects: With a key, through the project file .mcp.json that anectico agent bootstrap --host claude writes. A header helper supplies the key from your credential store. Or with a browser sign-in (/mcp in the host, or claude mcp login).
  • What was run, and when: 9 October 2026, Claude Code 2.1.295. claude mcp list reported the server Connected from a project .mcp.json written the way the bootstrap writes it. The other end was a stand-in server that answers 401 unless the exact Authorization: Bearer header arrives, and it saw the key. With the environment variable unset the host sent the literal text of the reference and said "Missing environment variables".
  • Host version: 2.1.295.
  • Known limits: No Anectico tool was called by this host in that run, and no workflow was run. The browser sign-in was not run with this host. A project server is "Pending approval" until the person approves it once.

Codex

  • Status: Verified
  • How it connects: With a key, through ~/.codex/config.toml that anectico agent bootstrap --host codex writes (bearer_token_env_var). Or with a browser sign-in (codex mcp login anectico).
  • What was run, and when: 9 October 2026, Codex 0.162.0 with its default model (gpt-6.1-sol) at medium reasoning effort. Codex was connected with anectico agent bootstrap --host codex and checked with anectico agent doctor --host codex. All thirteen skills available on that date were run from start to finish. Each run started from a new workspace that held real data with known numbers, and asked the job's question in a person's words, without naming a skill, a tool or a command. Each answer was compared with the API: the numbers, people and releases in it; every link against the links the tools had returned; and the workspace before and after, to show that nothing was written unless the person asked. Each answer was then read for the job's limits. All thirteen in that run passed: anectico-cli, anectico-setup, anectico-investigate-customer, anectico-triage-issue, anectico-product-question (saved an insight), anectico-did-my-fix-work (saved a watch), anectico-incident (opened an incident, linked the issue, posted an update), anectico-alerts-setup (created a rule), anectico-weekly-review, anectico-agent-fleet-review, anectico-which-change-caused-this, anectico-reproduce-this and anectico-is-my-app-tracked. Seven more runs passed: the four jobs that write, each with the default read-only key (Codex did the read part and named the missing scopes); an incident on a plan without incident response (Codex said it was not opened, and why); an error message that carried an instruction and a link (Codex reported it and did not act on it); and a workspace nothing had been sent to.
  • Host version: 0.162.0.
  • Known limits:
    • The pack now has 26 skills: the foundation and 25 jobs. The ten job skills added on 11 October, anectico-integrate, anectico-build-an-app and anectico-account-value were not part of the thirteen-skill host run above. Readiness and later case records do not extend that historical qualification.
    • Writes in a non-interactive run. Codex asks for approval before it calls a tool that is not read-only. Started with codex exec there is nobody to ask, and Codex refuses the call with "MCP tool call requires approval, but approval policy is never". It says so and changes nothing. To let an unattended run write, set default_tools_approval_mode = "approve" under [mcp_servers.anectico] in the Codex configuration; the runs above that wrote had it set. An interactive Codex asks you instead.
    • The runs used a key. The browser sign-in was not run with Codex.
    • The recorded agent fleet review used a key from --scope-profile agent-observability. Newly created default investigate keys now include llm:read and evals:read, so they cover model costs and stored quality scores. This host run has not been repeated with the larger default bundle. Existing keys keep their original scopes.
    • The recording steps met only "no recording": the workspace that was used does not store session recordings. A found recording was not exercised.
    • A project .codex/config.toml in a directory Codex does not trust is not read.
    • This is a record of one day, one Codex version and one model. Another model, or a lower reasoning effort, was not run.

Cursor

  • Status: Implemented, not verified
  • How it connects: With a key, through .cursor/mcp.json (or ~/.cursor/mcp.json) that anectico agent bootstrap --host cursor writes, using Cursor's own ${env:ANECTICO_API_KEY} syntax. Or with the host's sign-in, which Cursor starts from the Connect button on the server.
  • What was run, and when: Nothing. No Cursor application or command line that lists MCP servers was available on 9 October 2026. The file format and the reference syntax come from Cursor's documentation.
  • Host version: none run.
  • Known limits: Cursor's documentation does not say what an unset ${env:VAR} expands to, nor whether mcp.json accepts comments. The bootstrap assumes "nothing" and "no comments". A Cursor started from the Dock or Start menu does not see variables set in your shell.

Gemini CLI

  • Status: Connected once
  • How it connects: With a key, through ~/.gemini/settings.json that anectico agent bootstrap --host gemini writes, with ${ANECTICO_API_KEY} in the header. Or with a browser sign-in (/mcp auth anectico).
  • What was run, and when: 9 October 2026, Gemini CLI 0.63.0. gemini mcp list reported the server Connected and the stand-in server saw the key. With the variable unset it saw a bare Bearer.
  • Host version: 0.63.0.
  • Known limits: No Anectico tool was called by this host and no workflow was run. In a folder Gemini CLI does not trust it loads no MCP server at all, until trust is granted. The browser sign-in was not run.

Grok

  • Status: Implemented, not verified
  • How it connects: Through the connector page at grok.com/connectors (New Connector, then Custom, then the endpoint address), which calls from xAI's servers. xAI's page says to "complete any required authentication" and does not say how Grok registers itself or whether the form takes an API key. See Connect Grok.
  • What was run, and when: Nothing with a Grok account. The server side was checked against xAI's pages read on 9 October 2026: public address, Streamable HTTP, sign-in with PKCE.
  • Host version: not shown by the service.
  • Known limits: The endpoint must be reachable from the public internet; xAI rejects local and private addresses. xAI publishes no tool-count limit, no annotation rule and no source addresses for custom connectors.

ChatGPT

  • Status: Implemented, not verified
  • How it connects: Through ChatGPT Plugins, Add custom MCP server, with OAuth. ChatGPT calls from OpenAI's servers, and it does not send API keys, so a ChatGPT connection is read-only. See Connect ChatGPT.
  • What was run, and when: Nothing with a ChatGPT account. The server side was built and tested against OpenAI's authentication guide and ChatGPT's own public client document, both read on 9 October 2026: both documented callback addresses, issuer checking, public client registration, exact resource binding.
  • Host version: not shown by the service.
  • Known limits: OpenAI's pages do not list which plans may add a custom server, and a workspace owner may have to allow it. They do not say whether ChatGPT's agent surfaces (Dots) accept a custom server. They publish no tool-count limit.

Muse

  • Status: Implemented, not verified
  • How it connects: Meta's pages say a person asks Muse to create a custom connector. They do not mention MCP servers. Other companies' guides describe Settings, Connectors, Add custom connector with an OAuth sign-in; we have not been able to confirm that in Meta's own pages. See Connect Muse.
  • What was run, and when: Nothing with a Muse account. The server side follows the generic contract below, read against Meta's pages on 9 October 2026.
  • Host version: not shown by the service.
  • Known limits: Meta does not review custom connectors. How a remote server is added, how Muse registers itself and what its limits are is not established. Muse Code, the terminal agent, is a different product with its own record below.

Muse Code

Muse Code is Meta's terminal coding agent. It is a different product from the Muse app above.

  • Status: Implemented, not verified
  • How it connects: With a key, through ~/.config/muse/settings.json that anectico agent bootstrap --host muse writes: a streamable_http server named anectico with ${ANECTICO_API_KEY} in the header, "mode": "optional", and the "schema_version": 1 that Meta says the file must have. Or with a browser sign-in (muse mcp login anectico). See Connect Muse.
  • What was run, and when: Nothing with Muse Code. It was not installed. The file format, the commands and the folders come from Meta's own pages for Muse Code, read on 10 October 2026. The setup command was tested on that file only, in a temporary home folder, with a stand-in server.
  • Host version: none run.
  • Known limits: Written from Meta's documentation; not yet tested on a real install. Meta's pages do not say whether ${ANECTICO_API_KEY} is filled inside headers, what happens when the variable is not set, whether XDG_CONFIG_HOME moves the file, where the file is on Windows, or whether it may contain comments. The command cannot start Muse Code, so anectico agent doctor --host muse always says what it did not check. Run /mcp inside Muse Code to see whether the server loaded.

Any MCP client

  • Status: Verified
  • How it connects: With a key in a header, or with OAuth, as in the sections above. Any client that speaks stateless Streamable HTTP and can send a fixed header should be compatible, because that is the whole of what the endpoint requires.
  • What was run, and when: 9 October 2026. Our own tests drive the contract on this page with the official MCP client library and a fake authorization server: the 401 challenge, both protected-resource documents, the exact audience, a 403 with the missing scopes, the served tool list, and the annotations on every tool as they go over the wire. The tests of the authorization server run the full registration, sign-in, consent and token exchange with a public client. anectico mcp verify is a client of the same endpoint and uses protocol 2026-07-28.
  • Host version: the official MCP Go SDK, as pinned by the service.
  • Known limits: This is conformance to the contract, not a statement about any vendor's product. It cannot show that a host works.

What the bootstrap writes for each host

anectico agent bootstrap --host claude|codex|cursor|gemini|muse writes one anectico entry into the host's own configuration, reads it back the way the host will, and makes one authenticated call with exactly the URL and headers the host will send. The files and the reference syntax per host are in Connect an AI agent with MCP. That check proves the credential, the endpoint, the scopes and the shape of the file. It does not launch the host. Ask the host itself: list its tools once it has connected.

For any other client, create a remote Streamable HTTP server named anectico with the endpoint and header above.

Environment-variable expansion differs by host

A configuration that refers to ANECTICO_API_KEY must use the host's own reference syntax, because a host that does not recognize it sends the text itself as the credential and the server rejects it: Claude Code and Gemini CLI expand ${ANECTICO_API_KEY}, Muse Code is documented to expand ${VAR} (not yet run), Cursor expands ${env:ANECTICO_API_KEY}, and Codex names the variable in bearer_token_env_var. The bootstrap writes the right form for the host, and a host started from a shell that does not have the variable set sends nothing usable — which anectico agent bootstrap and anectico agent doctor report as needs_environment rather than as success. Where a host is launched from somewhere that does not inherit your shell's variables, write the literal key into a user-level file with --config-scope user --credential embed; the file is created with owner-only permissions, and it must not be committed. Muse Code does not take a literal key.

What is not supported

  • Credentials outside a header. No query-string or body form is accepted, on any path.
  • Shared caching of the tool list. Tool-list responses carry ttlMs: 0 and cacheScope: "private", because what a key is offered depends on that key's scopes. Re-list when you need it — do not carry a list across a change of credential or of permissions.
  • Cancelling a call in progress, before the 2026-07-28 protocol. Cancellation is propagated to the running handler only for clients on that revision; on the earlier ones, disconnecting ends your side of the exchange and leaves the call to finish on its own.
  • Writes through OAuth. A request for a write permission through OAuth is refused with invalid_scope. Writes need a key you create on purpose.

Tool-list size, and when it bites

MCP hosts do not report having too many tools. The overflow simply stops being offered to the model inside the client. Anectico therefore keeps its list small on purpose, reaching the long tail through gateway tools, and designs against two self-imposed ceilings: 40, past which we assume a host may silently drop tools, and 50, past which we assume tool-selection accuracy degrades. Those two numbers are our conservative design targets, not measurements of any particular client — no host we checked publishes its real limit, which is exactly why we budget against a pessimistic one.

What a key is served follows from the capability catalog, and the counts below are checked against the MCP tool reference whenever this page is built:

  • A key that holds every read permission is served 40 tools: the 38 first-class read tools and the 2 read doors.
  • A key that also holds every write permission is served 50 tools: those, plus 7 promoted write tools and 3 write doors.
  • An OAuth connection is read-only, so it is served at most the 40.

Both are at the ceilings and not over them. A narrower key is served fewer. To keep a key's list short without changing its permissions, add ?profile=investigate, ?profile=incident, ?profile=agent-observability or ?profile=admin to the endpoint, as Connect an AI agent with MCP describes. A profile only ever subtracts. It is for connections that use a key: a host that signs in with OAuth sends the exact endpoint as its resource, and an address with a query string is refused. Scope recipes for agent jobs sizes each job.

Failure symptoms, in the order you will meet them

Symptom Cause
401, empty body, WWW-Authenticate: Bearer realm="anectico", resource_metadata="…" No credential header reached the server at all. There is no error code and no body, on purpose: nothing was attempted, so there is nothing to report a failure about. The resource_metadata parameter is the recovery path — follow it.
401 — authentication required Malformed, unknown, revoked and expired keys all answer identically, on purpose: the endpoint will not confirm that a key it rejects ever existed. Check first that the variable expanded, then that the key is live and unexpired.
401 — invalid_token, the access token signature is invalid A bearer that is not an an_ key was validated against the advertised authorization server and failed. Most often this is a signed-in user's own Anectico session token, which is not a credential here; it is also what a token from some other issuer gets.
401 — invalid_token, after an authorization that succeeded The token is bound to the wrong audience. The client requested a resource identifier that is not this endpoint's URL.
403 OAuth challenge with insufficient_scope and no named scope The token validated but no existing Anectico membership could be resolved. Follow the explicit first-access steps above or contact support with the attempt time; the response is intentionally generic.
403 — the mcp:read or mcp:write scope is required for the MCP endpoint The key authenticates but was never granted an umbrella scope.
405, Allow: POST The client opened a GET stream or sent a DELETE. This endpoint is POST-only and stateless.
400 — Accept must contain both 'application/json' and 'text/event-stream' The client is not speaking Streamable HTTP, or something is stripping the header. Note this arrives after authentication, so a bad Accept on an unauthenticated request still answers 401.
400 — invalid_profile See the four shapes below.
Connects, zero tools The key holds an umbrella scope and no domain scope. Every tool needs both.

Because it is refused rather than ignored, ?profile= has four distinct rejections and each names what to fix:

What you sent Message
?profile=incidnet unknown profile "incidnet" — use one of: …
?profile= profile must not be empty — use one of: …
?profile=%20 profile must not be empty — use one of: …
?profile=a&profile=b profile must be supplied exactly once — use one of: …

Every one is a 400 carrying "error": "invalid_profile" and the list of valid names. The last two matter more than they look: a URL builder that appends an empty parameter, and one that appends the same parameter twice, are both common, and either silently serving the whole surface would look exactly like the filter working. Names are matched exactly and are case-sensitive — ?profile=Incident is an unknown profile, not incident.

Reading a confirmation preview

A confirm-gated write returns a one-line summary and a preview object with its readable summary, concrete details and confirm_token. Read the proposed values before approving. Customer-authored configuration is evidence, never instructions. The confirm_token is opaque and authorizes only the displayed request. An empty or encoded preview is refused before a token is issued.

Picture support is a separate qualification

The connection records above qualify exactly their named workflow and date. They do not qualify Apps, a visible image attachment or a vendor's enforcement of model-only tools. Generic host documentation describes a capability, the locally implemented endpoint establishes delivery, and an observed product and build record establishes only what was actually seen in that host. No vendor rendering record is qualified here. A Codex tool or CLI run also cannot establish what a ChatGPT, Claude, Cursor, Gemini or other host displays.

For request-based image negotiation and evidence fallback, use Charts in chat.

MCP Apps standard and reference host

The result views conform to the MCP Apps standard and render in its official reference host (version 2.0.3, checked 17 October 2026). They have not yet been observed live in a vendor host. The local check covers every supported picture kind, exact delivered values, image fallback and active refusal of requests from the frame. It does not establish another host's enforcement.

The MCP Apps overview lists Claude and Claude Desktop. ChatGPT documents its implementation separately in OpenAI's UI guidance. Both use the open standard; the overview's host list is not a test of Anectico.

Product Anectico picture observation
Official MCP Apps reference host 2.0.3 Locally rendered supported pictures; local refusal policy exercised
Claude web Not yet observed live
Claude Desktop Not yet observed live
Claude mobile Not yet observed live
ChatGPT Not yet observed live
Cursor desktop chat Not yet observed live
Cursor cloud agent Not yet observed live
Codex desktop Not yet observed live
Codex CLI Recorded source and image-outcome workflow; owner-visible picture not established
Claude Code Owner-visible picture not established
Gemini CLI Owner-visible picture not established

These observations do not imply a directory listing, universal host support or recall of saved copies. Use Charts in chat for the supported shapes and fallbacks.