
Where Claude Code, Cursor and Codex keep MCP servers, the same server written for each, and the differences that break copy-paste.
Originally published on KitQuarry. Written by Eliran Kotzero for KitQuarry.
In short: all three tools speak MCP, but each keeps its servers in a different file. Claude Code uses .mcp.json at the repo root, Cursor uses .cursor/mcp.json, and Codex uses [mcp_servers.<name>] tables in .codex/config.toml. The JSON files look alike, but two details break copy-paste: Claude Code needs "type": "http" on remote servers, and every tool writes environment variables differently. Below is the same two-server setup written for each tool, the differences that matter, and how to check that each one loaded.
| Claude Code | Cursor | Codex | |
|---|---|---|---|
| Project file (commit it) | .mcp.json at the project root | .cursor/mcp.json | .codex/config.toml, trusted projects only |
| Personal file | ~/.claude.json (user scope, and local scope per project) | ~/.cursor/mcp.json | ~/.codex/config.toml |
| Format | JSON, mcpServers | JSON, mcpServers | TOML, [mcp_servers.<name>] |
| Env variable in a value | ${VAR} or ${VAR:-default} | ${env:VAR} | Name the variable in a field such as bearer_token_env_var |
| See what loaded | claude mcp list, /mcp | Customize, MCP Logs in the Output panel | codex mcp list, /mcp |
Sources: the Claude Code MCP docs, the Cursor MCP docs and the Codex MCP docs, all checked on 2026-10-29. Some third-party guides still say Codex has no project-level MCP config. The current Codex docs say it does: put the tables in .codex/config.toml in the repo, and Codex loads them once you trust the project.
The example has two servers: Context7, a local stdio server that the Codex docs use as their example (npx -y @upstash/context7-mcp), and team-docs, a stand-in for a remote HTTP server that needs a bearer token. mcp.example.com and TEAM_DOCS_TOKEN are placeholders; swap in your server's URL and auth. The token value never appears in a file. Each developer sets TEAM_DOCS_TOKEN in their own shell.
We checked that all three files parse (JSON and TOML). We didn't run them inside the three tools, so test them in yours before you rely on them.
.mcp.json{
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
},
"team-docs": {
"type": "http",
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer ${TEAM_DOCS_TOKEN}"
}
}
}
}
url needs a type ("http", "sse" or "ws"). Claude Code reads an entry without one as a stdio server, so it skips a url-only entry and reports has a "url" but no "type". The docs accept "streamable-http" as another name for "http".${VAR} and ${VAR:-default} expand in command, args, env, url and headers. If a variable is unset and has no default, the config still loads, claude mcp list shows a missing-variable warning, and the literal ${VAR} text is used.url and headers, some credential variables always read as empty, including ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN and NPM_TOKEN. That stops a repo's .mcp.json from sending your own credentials to a server it names. Use a variable name of your own, like TEAM_DOCS_TOKEN.CLAUDE_PROJECT_DIR inside a stdio server's environment. To use it in command or args of .mcp.json, write ${CLAUDE_PROJECT_DIR:-.}, because the variable isn't set in Claude Code's own environment..cursor/mcp.json{
"mcpServers": {
"context7": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
},
"team-docs": {
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer ${env:TEAM_DOCS_TOKEN}"
}
}
}
}
${env:NAME}. Cursor also offers ${userHome}, ${workspaceFolder} (the folder that contains .cursor/mcp.json), ${workspaceFolderBasename} and ${/}. They resolve in command, args, env, url and headers.url plus optional headers, as in Cursor's own examples. Cursor's stdio field table lists "type": "stdio" as required, so the example includes it.envFile (for example "${workspaceFolder}/.env"). Remote servers can't use envFile..codex/config.toml# .codex/config.toml (loaded only in a trusted project)
[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]
[mcp_servers.team-docs]
url = "https://mcp.example.com/mcp"
bearer_token_env_var = "TEAM_DOCS_TOKEN"
${...} placeholders in these fields. It takes the variable's name instead: bearer_token_env_var for an Authorization bearer token, env_http_headers for other headers read from the environment, and env_vars to forward named variables to a stdio server. env sets fixed values..codex/ layers only when you trust the project. In an untrusted project it skips them, including project config, hooks and rules. With several .codex/config.toml files, the one closest to your working directory wins (config basics).enabled_tools and disabled_tools, default_tools_approval_mode (auto, prompt, writes or approve), startup_timeout_sec (default 10) and tool_timeout_sec (default 60).# Claude Code: write the server into .mcp.json for the team
claude mcp add --transport http --scope project team-docs https://mcp.example.com/mcp
claude mcp add --transport stdio --scope project context7 -- npx -y @upstash/context7-mcp
# Codex: add a stdio server to your Codex config
codex mcp add context7 -- npx -y @upstash/context7-mcp
# Check what loaded
claude mcp list
codex mcp list
In claude mcp add, everything after -- is the server's own command, so its flags aren't read as Claude's. Without --scope, Claude Code uses local scope: the server goes into your entry for this project inside ~/.claude.json, not into .mcp.json, and your teammates won't see it. For a remote server in Codex, the docs show codex mcp add <name> --url <url>, and codex mcp login <name> starts an OAuth sign-in. Cursor adds servers through Customize or by editing mcp.json.
team-docs therefore hides the team's version completely..codex/config.toml files (closest first), then a selected profile, then ~/.codex/config.toml.A committed MCP config runs commands on every machine that opens the repo, so each tool puts a gate in front of it:
.mcp.json in an interactive session. Until then, claude mcp list shows them as pending approval. A repo can't approve its own servers: approval settings committed to .claude/settings.json are ignored until you trust the folder. claude mcp reset-project-choices resets your choices. In claude -p runs and Agent SDK sessions there's no prompt, and Claude Code loads project servers without asking, so add a server to disabledMcpjsonServers or use --strict-mcp-config if you don't want it there..codex/config.toml until you trust the project.Read a server's source before you approve it, and give it a narrowly scoped token. If you're also keeping agents away from secrets files, our .env guide covers the file-access side for all three tools.
There's no shared MCP file that all three tools read, so you maintain three. A few habits keep that manageable:
team-docs for internal API questions" in AGENTS.md or CLAUDE.md means the same thing in each tool..env.example or a short README table that lists the variables each developer needs.CLAUDE.md at AGENTS.md in one source of truth."type" on remote servers and the variable syntax..mcp.json, .cursor/mcp.json and .codex/config.toml with the same server names."type": "http" to every remote server in .mcp.json.${VAR}, ${env:VAR}, or a Codex *_env_var field.claude in the repo and approve the project servers, then check claude mcp list.codex mcp list or /mcp.Setting up instruction files too? The free sampler ships rules and skills in the formats Claude Code, Codex, Cursor, Windsurf and Copilot each expect. The AI Coding Rules Pack adds the full rule set and workflow skills.
Claude Code reads .mcp.json at the project root. Cursor reads .cursor/mcp.json in the project. Codex reads [mcp_servers.<name>] tables in .codex/config.toml, but only in a project you've trusted. The personal versions are ~/.claude.json, ~/.cursor/mcp.json and ~/.codex/config.toml.
Not as is. Both use an mcpServers object, but Claude Code treats an entry with no "type" as a stdio server, so a remote server with only a "url" is skipped with an error until you add "type": "http". Environment variables also differ: Cursor writes ${env:NAME}, Claude Code writes ${NAME} or ${NAME:-default}.
Yes. Current Codex docs let you add [mcp_servers.<name>] tables to .codex/config.toml in the repo. Codex loads project .codex/ layers only for trusted projects, and the config closest to your working directory wins. The ChatGPT desktop app, Codex CLI and IDE extension share this configuration.
Commit only variable references. In Claude Code use ${TOKEN} in .mcp.json, in Cursor use ${env:TOKEN}, and in Codex name the variable with bearer_token_env_var, env_http_headers or env_vars instead of writing the value. Each developer sets the variable in their own shell. Codex stores an OAuth client secret in config.toml, so keep that kind of setup in your personal ~/.codex/config.toml.
Claude Code asks you to approve project servers from .mcp.json in an interactive session. Until you do, claude mcp list shows the server as pending approval. Run claude in the folder and accept the trust dialog and the server prompt. To ask again later, run claude mcp reset-project-choices.
Official docs, checked 2026-10-29.
If you want a starting point, KitQuarry's free sampler is on GitHub: ai-coding-rules-sampler. It has a short CLAUDE.md/AGENTS.md, security rules and three skills (plan-feature, review-changes, record-decisions) for Claude Code, Cursor, Codex and Windsurf. MIT, free. (I made it.)
aiI like AI coding agents. I do not like when they rewrite a file that was already fine, hard-code a...
mcpConnecting 3 to 5 Model Context Protocol (MCP) servers (GitHub, Postgres, Linear, Slack, Notion) into...
aiHow Claude Code, Codex and Cursor load skills, what really costs context, and how to audit, prune and scope installed skills.
aiI use Cursor almost every day. The hard part is not generating code. It is giving the agent enough context, constraints, and a plan so the feature still makes sense after it reaches production.
aiLearn how the Model Context Protocol standardizes AI integrations, with a look at connecting Claude and Cursor to custom environments.
cursorCursor's November 6 changelog entry is short — "Voice Chat with Agents" — but it changes the shape of...
Workflows from the Neura Market marketplace related to this Cursor resource