Claude Code MCP Config: .mcp.json Format, Scopes and claude mcp add (2026)
Claude Code reads its MCP config from a different place than the rest of its settings, uses its own JSON shape, and applies its own scope rules. Most "my MCP server doesn't show up" problems come from one of those three things. This guide covers the config format, the three scopes, the claude mcp commands that write the config for you, and how to check what actually loaded.
If you only need to know which file sits where on disk, the companion article on Claude Code config file location lists every path. This one is about what goes inside the MCP config and how to get it right.
Claude Code MCP config at a glance
- Where it lives: not in
settings.json. Project-scoped servers go in.mcp.jsonat the repository root; local- and user-scoped servers are stored in~/.claude.json. - Top-level key:
mcpServers, an object whose keys are server names. - Two kinds of server: local processes Claude Code starts itself (stdio), and remote servers it connects to over HTTP.
- Easiest way to write it:
claude mcp addorclaude mcp add-json, which put the entry in the right file for the scope you choose. - How to check it:
claude mcp listfrom the shell, or/mcpinside a session.
The MCP config format
Every MCP config in Claude Code has the same outer shape: a mcpServers object, one entry per server. What goes inside an entry depends on the transport.
A local (stdio) server is a command Claude Code launches as a child process and talks to over standard input and output:
{
"mcpServers": {
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"],
"env": {
"LOG_LEVEL": "info"
}
}
}
}commandis the executable. It must be resolvable from the environment Claude Code runs in, which is not always the same as your interactive shell.argsis an array. Each argument is its own string; do not put the whole command line into one string.envsets environment variables for that server process only. Proxy variables, API tokens for the downstream service and log levels go here.typecan be omitted for stdio servers; an entry with acommandis treated as stdio.
A remote (HTTP) server is already running somewhere, and Claude Code connects to its URL:
{
"mcpServers": {
"issue-tracker": {
"type": "http",
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer ${TRACKER_TOKEN}"
}
}
}
}typeshould behttpfor streamable HTTP servers. Older servers may only offersse; that transport still works but is being phased out in favour of HTTP.headerscarries static auth such as bearer tokens or API keys. Servers that use OAuth instead do not need a header; you authenticate from/mcpinside a session and Claude Code stores the token for you.
The three scopes, and which file each one writes
Claude Code stores an MCP server in one of three scopes. The scope decides which file holds the entry and who sees the server.
|
Scope |
Stored in |
Who gets the server |
Typical use |
|---|---|---|---|
|
local (default) |
|
Only you, only in this project |
Personal or experimental servers, anything holding your own token |
|
project |
|
Everyone who clones the repo |
Shared team tooling, committed to version control |
|
user |
|
Only you, in every project |
Tools you want everywhere, such as a docs or search server |
When the same server name exists in more than one scope, local wins over project, and project wins over user. That precedence is the usual reason an edit to .mcp.json appears to do nothing: a local entry with the same name is shadowing it.
Two more rules matter for project scope:
- Project servers ask for approval. The first time Claude Code sees a server in a repository's
.mcp.json, it asks whether to trust it. If you declined once and want the prompt back,claude mcp reset-project-choicesclears those decisions. Settings keysenableAllProjectMcpServers,enabledMcpjsonServersanddisabledMcpjsonServerscontrol the same behaviour non-interactively. - Never commit a live secret.
.mcp.jsonis meant to be shared, so a token typed into it is a token published to everyone with repo access. Use environment variable expansion (next section) or keep credential-bearing servers in local or user scope.
Organisations can also deploy a managed MCP config next to managed-settings.json, and allow or deny specific servers through managed policy. Those entries cannot be overridden from the user side.
Environment variables inside .mcp.json
.mcp.json supports variable expansion, which is what makes a shared file safe to commit:
${VAR}is replaced with the value ofVARfrom the environment Claude Code was started in.${VAR:-default}usesdefaultwhenVARis not set.
Expansion works in command, args, env, url and headers. A team can commit:
{
"mcpServers": {
"internal-api": {
"type": "http",
"url": "${INTERNAL_MCP_URL:-https://mcp.internal.example.com/mcp}",
"headers": {
"Authorization": "Bearer ${INTERNAL_MCP_TOKEN}"
}
}
}
}Each developer then exports INTERNAL_MCP_TOKEN in their own shell profile. If a required variable is missing and has no default, the server fails to start, and /mcp shows it as failed rather than silently connecting without auth.
Adding servers with claude mcp add
You can edit the JSON by hand, but the CLI writes the entry into the correct file for the scope and avoids most syntax mistakes. The general form is claude mcp add [options] <name> -- <command> [args...] for stdio, and claude mcp add --transport http <name> <url> for remote servers.
# stdio server, local scope (the default)
claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /Users/me/projects
# stdio server with an environment variable, shared through .mcp.json
claude mcp add --scope project --env LOG_LEVEL=info filesystem -- npx -y @modelcontextprotocol/server-filesystem .
# remote HTTP server with a header, available in every project
claude mcp add --transport http --scope user --header "Authorization: Bearer $TRACKER_TOKEN" issue-tracker https://mcp.example.com/mcp
# paste a full JSON entry instead of flags
claude mcp add-json weather '{"type":"stdio","command":"node","args":["/opt/weather-mcp/index.js"]}'
# import servers you already configured in Claude Desktop (macOS and WSL)
claude mcp add-from-claude-desktopPoints that trip people up:
- The
--separator. Everything after--belongs to the server command. Without it, flags meant for the server (such as-y) are parsed as flags forclaudeand the add fails or stores the wrong command. - Options go before the name.
--scope,--env,--headerand--transportare options toclaude mcp add, so place them before the server name. - Quoting the header. A header value contains a space, so it needs quotes. In the example above, the shell expands
$TRACKER_TOKENat add time and stores the literal token; if you want the variable kept as a reference, write the entry withadd-jsonor edit.mcp.jsonand use${TRACKER_TOKEN}.
Managing what you added:
claude mcp list # every configured server and its connection status
claude mcp get filesystem # details for one server, including its scope
claude mcp remove filesystem --scope projectFor one-off runs or CI, claude --mcp-config ./ci-mcp.json loads servers from a specific file, and adding --strict-mcp-config ignores every other MCP config so the run sees only that file.
Windows: wrap npx with cmd /c
On native Windows (not WSL), npx is a batch script, and Claude Code cannot spawn it directly as a process. Servers added as plain npx ... fail with a "connection closed" style error. Wrap the command:
claude mcp add filesystem -- cmd /c npx -y @modelcontextprotocol/server-filesystem C:\Users\me\projectsIn JSON, that means "command": "cmd" and "args": ["/c", "npx", "-y", "..."]. Under WSL the Linux form works unchanged.
Verifying what actually loaded
Do not trust the file you just edited; ask Claude Code what it sees.
- From the shell:
claude mcp listshows each server with its status. A server you expected but that is missing from the list is a scope or file problem; a server that is listed but failing is a startup or auth problem. - Inside a session:
/mcplists connected servers, their tools, and any that failed. It is also where you complete OAuth for remote servers that need it. - Debug output: starting Claude Code with
--debug(or--mcp-debugon older versions) prints server startup errors, which is usually faster than guessing.
Common MCP config problems and fixes
- Server added to
settings.json. MCP servers insettings.jsonare ignored. Move the entry to.mcp.jsonor re-add it withclaude mcp add. - Edited
.mcp.json, nothing changed. A local- or user-scope server with the same name is taking precedence, or the project server was declined at the trust prompt. Checkclaude mcp get <name>for the scope that is actually in use. - Server times out at startup. Slow first runs (an
npxdownload, a container pull) can exceed the startup timeout. SetMCP_TIMEOUT(in milliseconds) before launching Claude Code, for exampleMCP_TIMEOUT=30000 claude. - Tool output truncated. Large tool results are capped.
MAX_MCP_OUTPUT_TOKENSraises the limit if a server legitimately returns big payloads. - Works in your terminal, fails in Claude Code. The server inherits Claude Code's environment, not your interactive shell's. Use an absolute path in
command, and put any variables the server needs in itsenvblock. - Server cannot reach the network behind a proxy. stdio servers are separate processes; give them
HTTP_PROXY/HTTPS_PROXYinenv. The same layering is explained for the desktop app in Claude Desktop HTTP proxy. - Invalid JSON. A trailing comma or an unquoted key makes the whole file unreadable. Validate the file with any JSON linter before restarting.
MCP config is independent of your API endpoint
The MCP config controls which tools Claude Code can call. The model endpoint, set through ANTHROPIC_BASE_URL and the credential variables in settings.json or the environment, controls where model requests go. The two do not interact: pointing Claude Code at a gateway or relay such as ROIBest AI changes nothing about how MCP servers are loaded, and adding an MCP server does not route model traffic anywhere new. If you are configuring both, the Claude Code configuration guide explains how settings layers merge, and Claude Code proxy covers the endpoint side.
FAQ
Where is the Claude Code MCP config file?
Project-scoped servers are in .mcp.json at the root of the repository. Local- and user-scoped servers are stored in ~/.claude.json in your home directory. MCP servers are not read from settings.json.
What is the difference between local, project and user scope?
Local scope (the default) applies only to you in the current project. Project scope writes to .mcp.json and is shared with everyone who uses the repository. User scope applies to you across every project. If the same name exists in several scopes, local overrides project, which overrides user.
Can I use environment variables in .mcp.json?
Yes. Use ${VAR} or ${VAR:-default} in command, args, env, url or headers. This is the recommended way to keep tokens out of a committed file.
Why does my MCP server show as failed in /mcp?
The most common causes are a command that is not on the path Claude Code sees, a missing environment variable, a startup that exceeds MCP_TIMEOUT, or, on native Windows, an npx command that is not wrapped in cmd /c. Run Claude Code with --debug to see the server's own error output.