Claude Code MCP configuration: .mcp.json and local, project, user scopes
Go deeper on this topic
SaaS integrations
Give AI the context to continue the work: source conversations, open tasks, and unresolved details, from adoption decisions to integration code.
Article 3 of 8 in this series.
Next reads
Dub conversion tracking: lead and sale APIs with Stripe customer mapping
Connect Dub clicks to signups and sales. Check Business requirements, lead and sale fields, USD/JPY amounts, invoiceId, and Stripe metadata with official sources and a credential-free JSON planner.
Dub webhook signature verification: raw bodies and replays in Node.js
Verify Dub-Signature with raw-body HMAC-SHA256 and extract a minimal lead.created work record. An offline Node.js/Bun example checks tampering, JSON reserialization, and replay limits without credentials.
Record Slack huddles and feed AI at 22:00: six Circleback settings
A Circleback workflow for giving AI usable work context: Slack huddles, a 22:00 sync, source statements, open tasks, and adoption criteria. Separates workflow experience, documented features, and local test evidence.
Use the topic hub as a map, then continue to the next article in the series. New here? Start at the home hub →
Your team updates .mcp.json, yet your machine still uses an older MCP endpoint. Before changing the shared URL again, check whether another scope defines the same server name. A work handoff can include the intended configuration source alongside the conversation history.
This guide covers local, project, and user in the Claude Code CLI. We checked the official documentation on October 24, 2026, and implemented a small explanation model using synthetic inputs. We did not run Claude Code, authenticate, connect a server, or change any real configuration.
Where Claude Code stores MCP configuration
| Scope | Applies to | Stored in |
|---|---|---|
| local, the default | Your current project | Project-specific entries in ~/.claude.json |
| project | The current project, shared with the team | .mcp.json at the project root |
| user | All your projects | ~/.claude.json |
For a duplicate server name, local takes precedence over project, then user. The winning entry replaces the whole server definition; fields are not merged. See the official scope reference.
This comparison excludes managed settings, plugins, and claude.ai connectors. The documentation also describes an exception for duplicate stdio servers in the Desktop Code tab; do not apply this CLI model there unchanged.
An offline experiment with three servers called notes
We gave notes three synthetic URLs. The .invalid endpoints are example data; the code sends no requests. Only the project entry contains an X-Demo header, making it possible to see whether a lower-priority field survives.
Download mcp-scope.mjs and mcp-scope-demo.mjs into one folder. Run the demo with Node.js 22+ or Bun:
node mcp-scope-demo.mjs
# or
bun mcp-scope-demo.mjsThe input is our own JSON shape containing three server maps, rather than an actual Claude Code configuration file:
{
"local": { "notes": { "type": "http", "url": "https://local.example.invalid/mcp" } },
"project": {
"notes": {
"type": "http",
"url": "https://project.example.invalid/mcp",
"headers": { "X-Demo": "project-only" }
}
},
"user": { "notes": { "type": "http", "url": "https://user.example.invalid/mcp" } }
}In the output, localWins has scope local and server URL https://local.example.invalid/mcp. Its server has no headers. With an empty local map, projectWins selects project and keeps X-Demo. Emptying the project map as well makes userWins select user.
absent returns not-found, while malformed JSON in invalid returns invalid-input. These are names from our function, not Claude Code error messages. On October 24, 2026, Node.js v26.12.1 and Bun 1.3.11 produced identical JSON.
When a shared configuration appears to be ignored
Start with the intended server name and the revision of the shared .mcp.json. A personal local entry with that name may take precedence. Compare the complete entry, including headers, instead of assuming only the URL changes.
Then confirm the endpoint, required permissions, and who owns the configuration. Our suggested workflow is to inspect a difference that contains no credentials before trying to fix the shared file by adding secrets. Treat approval and authentication as separate checks. A matching name does not demonstrate a successful connection.
For the next person or AI session, record the project, server name, intended scope, shared-file revision, and whether the connection has actually been verified. Continue with Circleback MCP setup and read-only checks for meeting context, or the Claude Code context handoff guide for records across sessions.
What the model cannot tell you
The function reads only the supplied JSON. It does not read home configuration or environment variables, write files, or execute command strings. It rejects malformed JSON and invalid scope-map types, but is not a full MCP schema validator. It accepts an empty server object as data, so selected does not mean the configuration is usable.
This experiment implements the documented three-scope rule for explanation. It does not reproduce every CLI configuration source, authentication, approval, organization policy, or environment-variable expansion. Endpoint correctness and whether AI uses a tool as intended require separate verification.
FAQ
- Q. Where is the Claude Code MCP configuration file?
- In the CLI, project scope uses .mcp.json at the project root. Local and user scopes use ~/.claude.json. Local applies to the current project; user applies across your projects. Local is the default.
- Q. Are duplicate server definitions merged?
- Across the three CLI scopes, local wins over project, then user. The entire entry is selected; lower-priority headers are not merged. See the article and official documentation for exceptions such as managed settings and the Desktop Code tab.
- Q. Does selected in the experiment mean a server will connect?
- It only means our explanation model selected an entry. Full configuration validity, authentication, approval, and actual connections are untested. The model does not read real configuration files.