Where every MCP client keeps its config: the file, the shape and the reload rule
Fifteen clients, no shared file, no shared schema and no shared idea of when a change takes effect. One table, and the three mistakes that account for nearly every "the tools do not appear".
There is no standard config file for MCP and there is not going to be one. Each client owns its own, in its own format, in its own place, with its own rule for when an edit is noticed. The protocol standardised what travels over the wire; it said nothing about the file that starts the conversation, which is why the same server is a different three lines in every editor on the team.
One caveat before the table, because it is the honest one: paths and keys move when clients ship. Where this reference and a client’s own documentation disagree, the client wins, and the fastest way to find the current truth is to let the client write the entry itself — most now have an add command — and read what it wrote.
The clients that have a command
Five clients take a server from a command line, which is the least error-prone way in because the client writes its own file. The flags differ, and a remote server that takes a bearer key needs it as a header on every one of them.
# Claude Code — project scope by default; --scope user for everywhere
claude mcp add issues -- npx -y @you/issues-mcp
claude mcp add --transport http issues https://…/mcp --header "Authorization: Bearer $KEY"
# Codex — the key goes in ~/.codex/config.toml as bearer_token_env_var
codex mcp add issues -- npx -y @you/issues-mcp
codex mcp add issues --url https://…/mcp
# Gemini CLI — writes ~/.gemini/settings.json
gemini mcp add issues npx -y @you/issues-mcp
gemini mcp add --transport http issues https://…/mcp --header "Authorization: Bearer $KEY"
# Grok Build — ~/.grok/config.toml; --scope project keeps it with the repo
grok mcp add issues -- npx -y @you/issues-mcp
grok mcp add --transport http issues https://…/mcp --header "Authorization: Bearer $KEY"
# VS Code — the JSON has to survive the shell, so it is quoted
code --add-mcp '{"name":"issues","command":"npx","args":["-y","@you/issues-mcp"]}'The clients configured by file
The rest read a file you edit by hand, and the file is where the mistakes live. The shape is nearly the same everywhere — a map of names to entries — but the top-level key, the field names for a remote server and the header syntax differ enough that pasting one client’s entry into another’s file produces a config that parses and never connects.
| Client | File | Top-level key · remote fields | Picks it up |
|---|---|---|---|
| Claude Desktop | claude_desktop_config.json (Application Support / %APPDATA% under Claude) | mcpServers · type: "http", url, headers | On launch only — quit and reopen |
| Cursor | ~/.cursor/mcp.json, or .cursor/mcp.json in a project | mcpServers · type: "http", url, headers | Without a restart |
| VS Code | .vscode/mcp.json in a workspace, or the user-level file | servers · type: "http", url, headers; secrets via inputs | On window reload |
| Devin Desktop (formerly Windsurf) | ~/.config/devin/mcp_config.json, %APPDATA%\devin\mcp_config.json on Windows (legacy Cascade agent) | mcpServers · serverUrl (or url), headers | Not documented; save the file |
| Zed | settings.json | context_servers · url, headers | On save |
| Codex | ~/.codex/config.toml | [mcp_servers.name] · url, bearer_token_env_var | Next session |
| Gemini CLI | ~/.gemini/settings.json | mcpServers · httpUrl, headers | Next session |
| Grok Build | ~/.grok/config.toml; also reads .mcp.json and .cursor/mcp.json | TOML tables · url, headers | Next session |
| DeepSeek harness | The harness YAML, one entry per server | @deepseek-ai/dsh-mcp-client plugin · transport, url, headers | On restart |
On Windows, paths, npx and backslashes add failures of their own: MCP on Windows has them.
Two of the shapes, side by side, because they are the two most often pasted into the wrong file:
// Cursor and Claude Desktop — the same shape
{
"mcpServers": {
"issues": { "type": "http", "url": "https://…/mcp",
"headers": { "Authorization": "Bearer <your key>" } }
}
}
// VS Code — a different top-level key, and the secret behind a prompt
{
"inputs": [{ "id": "issues-key", "type": "promptString", "password": true }],
"servers": {
"issues": { "type": "http", "url": "https://…/mcp",
"headers": { "Authorization": "Bearer ${input:issues-key}" } }
}
}The clients with no file at all
- ChatGPT. Settings → Connectors for a remote server, or Settings → MCP servers in the desktop app for a local one. In the API, a remote server is a type: "mcp" tool on the request with the URL and an authorization string.
- Copilot Studio. Tools → Add a tool → Model Context Protocol, with the address. It runs in Microsoft’s cloud, cannot start a process on your machine, and speaks Streamable HTTP only — a server that offers SSE alone will not connect.
- Perplexity (macOS app). Settings → Connectors → Add Connector, and the launch command goes in the Command field. Local servers only, for now.
- OpenAI Agents SDK. No file: MCPServerStreamableHttp in code, with the URL and the header in params.
- Plain HTTP. Any HTTP client that can POST JSON with a bearer header is an MCP client for the purposes of a script.
The three mistakes
- The wrong file. Two levels — project and user — both exist, and the one you edited is not the one being read. Claude Code alone has three scopes. Check which file the client is reading before changing any of them.
- The wrong reload rule. Claude Desktop reads its config at launch and only then. Cursor watches the file. VS Code wants the window reloaded. A correct entry under the wrong assumption looks identical to a broken one.
- The key in the wrong place. A remote entry without its header parses cleanly and answers 401 on the first call. A local entry with the key in args rather than env puts the secret in the process list.
And the trailing comma, which is not a mistake about MCP at all: every one of these files is JSON or TOML, and a client that cannot parse its config almost always says nothing. When the tools do not appear and nothing is logged, validate the file before you doubt the server.