Skip to main content
Preview. The pages beside this one exist because those clients are the ones people ask about first — not because they are the ones that work.

The list is not a whitelist

There is no per-client code in this server. Nothing checks a clientInfo name, nothing branches on a user agent, and no client is registered with us before it connects. POST /mcp is a standard Model Context Protocol server over Streamable HTTP, and anything that speaks the protocol connects — a named editor, a chat platform, an automation node, a shell script, or forty lines you wrote against an MCP SDK this afternoon.
The one thing that is client-shaped is a pair of tools, search and fetch, which carry the fixed schemas ChatGPT’s connector surface requires. They are listed to every client identically and are ordinary tools everywhere else. That is the whole of the special-casing.

The four facts

Give a client these and you are done. Three more things save an afternoon:
  • No Mcp-Session-Id is ever issued. If your client is waiting for one, it will not arrive and it does not need one.
  • GET /mcp and DELETE /mcp return 405. There is no stream to open and no session to tear down. A test client reporting 405 is reporting a working server.
  • Neither an older client nor a newer one is locked out. This server is dual-era: 2026-07-28 has no handshake and every request declares its own revision, while initialize still works and still negotiates for everything before it. The MCP-Protocol-Version header alone decides which you get, so the value in the table is what a client sends today and nothing about that has changed. What earns a 400 is a client asserting a revision we do not speak — and that 400 lists what we do, so it is one retry, not a guess. Protocol revisions has the detail.

Editors and coding agents

Verified against each project’s own documentation on 2026-09-07. Where a client has changed its format recently, this is the current one.
Each of those has one thing that catches people:
The remote form takes serverUrl (or url); a command key is what makes a server local, and there is no separate transport flag. ${env:VAR} and ${file:/path} both expand, so the key need not sit in the file. Note that Windsurf’s MCP documentation now lives under Devin Desktop and is labelled as applying to the legacy Cascade agent — if your Windsurf is newer than that, check its own current docs before trusting this block.
Zed’s own documentation says that when a remote server has no configured Authorization header, it prompts you through the standard MCP OAuth flow. Since Zed documents no environment-variable expansion in context_servers, that is the better option here: omit headers entirely and let Zed authenticate, rather than writing a workspace key into settings.json. Project-scoped context_servers in .zed/settings.json are not documented — treat this as user-level config.
Omitting type falls back to the legacy sse transport for backward compatibility, and we serve no SSE stream, so the connection simply fails. Set "type": "streamableHttp" — camelCase, which matches no other client on this page. Cline’s own docs disagree with each other about where the settings file lives, so open it from the MCP Servers → Configure button rather than typing a path.
Not an object, unlike almost everywhere else. ${{ secrets.NAME }} resolves from .env at the workspace root, then .continue/.env, then ~/.continue/.env. It does not read your shell environment: Continue’s own FAQ says the IDE extensions cannot, so exporting the variable in your profile and expecting it to arrive will not work.
The config key is uri (the deeplink form uses url, which is a good way to lose ten minutes). streamable_http uses underscores. Goose has removed SSE support entirely, which for this server changes nothing. A token referenced as ${IMPELLABS_API_KEY} must also be named in env_keys, or the substitution has nothing to substitute from.
These are two different products with two different answers, and the distinction matters. Junie documents url plus a headers map, with Authorization: Bearer token as its own worked example — so the block above is the documented shape. AI Assistant is configured only through Settings | Tools | AI Assistant | Model Context Protocol, documents a url-only remote server, and documents no way to set a header at all. See below.

Chat platforms and automation

LibreChat: set requiresOAuth: false explicitly. LibreChat auto-detects OAuth by probing the server without your configured headers. Ours answers that probe with 401 and a WWW-Authenticate: Bearer header — correctly, because that is how an OAuth client is meant to discover the flow — and LibreChat reads it as “this server is OAuth-protected” and never uses your bearer key. The flag is the fix. Also note type is not optional: an http(s):// URL with no type defaults to sse, which we do not serve.
Warp has no transport field at all — it infers it from the URL. It also documents ${VAR} expansion only for a CLI server’s args, not for a URL server’s headers, so expect to paste the key literally and prefer a narrowly scoped one accordingly.

n8n

n8n is not a config file; it is a node. Add the MCP Client Tool node and set:
Node version 1.2 and later default to HTTP Streamable; version 1 predates it and speaks SSE only, which we do not serve. n8n’s documentation page for this node still describes only the old SSE Endpoint field — if that is what you see, the node on your canvas is an old version, and adding a fresh one gives you the transport selector.

Where we could not verify a config

A wrong config block costs more than a missing one, so these are named rather than guessed at. If your client is not on this page at all, it is very likely fine. Give it the four facts at the top.

Anything built on an MCP SDK

Forty lines is a client. Both official SDKs connect to this server with no adapter, no bridge and nothing registered on our side.
Both SDKs shipped a v2 that renamed exactly these things, so most tutorials you will find describe the older shape and will not run. If you are on the v1 line, translate: Python’s transport was streamablehttp_client, yielded a three-tuple and took a headers= kwarg; TypeScript’s package was the monolithic @modelcontextprotocol/sdk with deep .js import paths. The snippets above are the current form.
Two details that cost time rather than failing loudly. In Python, a bare httpx2.AsyncClient() defaults to a 5-second total timeout — pass one explicitly, as above. And Client("https://…") accepts a bare URL string but builds its own transport with no HTTP client, so it cannot carry an Authorization header; pass the transport object.

Whichever era your SDK is on

The snippets above are handshake-era clients, which is what both SDKs do by default and what every shipping client sends today. They keep working exactly as written. But this server is dual-era — it also answers the current 2026-07-28, in which there is no handshake at all — so an SDK on either side of that line connects:
  • An SDK that speaks 2025-06-18 runs initialize, which is answered in the newest handshake revision we speak rather than refused over an unrecognised version string. Nothing about that path changed when the modern era was added, and nothing about it is going to.
  • An SDK that probes for a modern server first finds one. server/discover is answered here — in either era, so even a probe that forgot the MCP-Protocol-Version header gets told what we speak — and an unsupported revision comes back as -32022, the code a dual-era client reads to decide it is talking to a modern server rather than falling back to initialize.
  • A client that goes modern must then send the header, two required _meta keys and the mirrored Mcp-Method / Mcp-Name headers on every request. Protocol revisions is the page for that.

Rate limits and transport constraints

What a client gets refused for, and which refusals are worth retrying.

What is the same in every client

None of the above changes what a model may do. The client decides how the connection is spelled; the credential decides what it can reach, and that is checked inside the dispatcher on every single call.
mcp:connect lists the tools and calls none of them. Every tool demands its own scope on top, and scopes never imply one another — a key that may read agents cannot run one. Mint a key per client, holding only what you want that client reaching unattended. See Authentication.

Tools

What is callable, and how to get the authoritative list for your own key.

Credits

What a tool call costs, and what an empty wallet returns.