Claude Code

MCP in Claude Code: local, project and user scopes plus .mcp.json for teams

TL;DR

Scope decides where an MCP server is stored and who sees it: local for you in one project, project for the team via .mcp.json, user for all your projects. Secrets always go through environment variables; read project servers before approving them.

You add an MCP server to Claude Code, then open another project and it's gone. A colleague clones the repo and gets asked "do you trust this server?". Or worse: an API key sits in a file committed to Git. All of this comes from not understanding MCP scopes in Claude Code: where a server is stored, who sees it, and which config wins on a name clash.

Adding servers: the two main kinds

# Remote server over HTTP (recommended)
claude mcp add --transport http github https://api.example.com/mcp \
  --header "Authorization: Bearer $TOKEN"

# Local stdio server: everything after -- is the server's command
claude mcp add --transport stdio airtable --env AIRTABLE_API_KEY=xxx \
  -- npx -y airtable-mcp-server

The -- matters: it stops Claude Code from treating the server's flags as its own. Short forms: -t (transport), -H (header), -s (scope), -e (env). The SSE transport is deprecated.

Three scopes

ScopeApplies toSharedStored in
local (default)Current project onlyNo~/.claude.json (under the project path)
projectCurrent projectYes, via Git.mcp.json at the repo root
userAll your projectsNo~/.claude.json

On a name clash, precedence is: organisation managed → local → project → user → plugin servers → claude.ai connectors. The entry from the highest source is used whole, with no field merging.

.mcp.json for the team, without leaking secrets

{
  "mcpServers": {
    "api-server": {
      "type": "http",
      "url": "${API_BASE_URL:-https://api.example.com}/mcp",
      "headers": { "Authorization": "Bearer ${API_KEY}" }
    }
  }
}
  • ${VAR} and ${VAR:-default} work in command, args, env, url and headers. Each person sets the variables in their own environment; the committed file holds no secrets.
  • An empty variable still counts as "set", so the default isn't used.
  • To prevent leaks, credential variables such as ANTHROPIC_API_KEY expand to empty inside a remote server's url/headers.

Approving project servers

In interactive sessions, Claude Code asks before using servers from .mcp.json; a cloned repo can't approve its own servers. Reset choices with claude mcp reset-project-choices. Note: in claude -p and the Agent SDK, project servers load without asking; to block them use --strict-mcp-config or disabledMcpjsonServers.

Handy management commands

claude mcp list            # list + health
claude mcp get github      # details for one server
claude mcp remove github   # remove (doesn't revoke tokens!)
claude mcp logout github   # revoke OAuth tokens
/mcp                       # in session: status, OAuth sign-in

Risks and caveats

  • Large outputs eat context: Claude Code warns when a tool result exceeds 10,000 tokens; the default limit is 25,000 (change it with MAX_MCP_OUTPUT_TOKENS).
  • remove doesn't revoke tokens: run logout first if you want issued tokens invalidated.
  • Project servers from unfamiliar repos: read .mcp.json before approving, especially stdio commands, since they run on your machine.
  • Same name in several scopes: a local entry silently beats the project one, a classic "why does my machine differ from yours".

How to apply it

  • Dev: Keep personal servers (notes, calendar) at user scope and experiments at local scope.
  • Tech Lead: Commit .mcp.json with environment variables for secrets and document which variables to set in the README.
  • PM/Admin: Use managed MCP to standardise the servers allowed across the organisation.

Sources & references

  1. Connect Claude Code to tools via MCP — Claude Code Docs