Add your servers at project scope so Claude Code writes them into a .mcp.json file at the
repository root, then commit that file. Every teammate who clones the repo gets
the same set of tools. One file, one shared toolset. Keep API keys and tokens out
of it by referencing environment variables instead of pasting the literal values.
If you have not connected a server yet, read MCP fundamentals and MCP configuration first. This guide is about the team part: one shared definition, no leaked secrets.
What are the MCP scopes, and which one is shared with the team?
When you run claude mcp add, Claude Code stores the server at one of three
scopes. The scope decides where the config lives and who else sees it.
| Scope | Loads in | Shared with team | Stored in |
|---|---|---|---|
| Local | Current project only | No | ~/.claude.json |
| Project | Current project only | Yes, via version control | .mcp.json in project root |
| User | All your projects | No | ~/.claude.json |
Local scope is the default. It stays private to you.Common gotchaBecause local is the default, running claude mcp add without --scope project writes the server to your private ~/.claude.json, so nothing lands in .mcp.json and teammates never see it.Run claude mcp list after adding to confirm it shows as project-scoped before you tell the team to pull. User scope follows you
across every project on your machine. Only project scope writes to a file inside
the repository, and that file is the one you commit. So pick project scope
whenever the whole team needs the same server.
How do I add a server at project scope?
Pass --scope project (or the short -s project) to claude mcp add. Claude
Code creates or updates .mcp.json at the repository root for you.
For a remote HTTP server:
claude mcp add --transport http --scope project linear https://mcp.linear.app/mcpFor a local stdio server, put the command after a -- separator. Everything
after the -- is the command Claude Code runs, untouched:
claude mcp add --scope project --transport stdio db -- npx @acme/db-mcp-serverThe -- matters. It tells the CLI where its own flags stop and the server
command begins. Drop it and the CLI tries to read the command as one of its own
options.
What goes into .mcp.json?
The command above writes a standardised shape. A project-scoped .mcp.json
holds an mcpServers object keyed by server name:
{
"mcpServers": {
"linear": {
"type": "http",
"url": "https://mcp.linear.app/mcp"
},
"db": {
"command": "npx",
"args": ["@acme/db-mcp-server"],
"env": {}
}
}
}You can edit this file by hand too. The type field accepts http (or
streamable-http as an alias), and stdio servers use command, args, and
env. Commit the file like any other config:
git add .mcp.json
git commit -m "Add Linear and database MCP servers for the team"Now a teammate runs git pull, opens Claude Code in the repo, and the servers
are already defined. No copying a command off a wiki. No guessing a URL.
Why does Claude Code ask teammates to approve shared servers?
Claude Code does not silently trust a .mcp.json that arrives from version
control. A committed file is something other people can change. So the first time
a teammate opens the project, Claude Code prompts them to approve the
project-scoped servers before it uses any of them.
Until they approve, the servers show as pending. You can see this state from the command line:
claude mcp listA server awaiting approval appears as ⏸ Pending approval. Running claude
interactively brings up the prompt to review and approve. If someone needs to
redo their decision later, this resets the stored choices for the project:
claude mcp reset-project-choicesThis is why project scope is safe to share. The config travels with the repo, but each person consents before the servers run on their machine.
How do I keep secrets out of the committed file?
The committed .mcp.json is readable by everyone with repo access, and it lives
in git history forever. Never put a literal API key, token, or password in it.
A pasted secret in a tracked file is a leaked secret.Common gotchaThe trap is fixing this too late: people paste a real key, commit, then swap in ${VAR} in a later commit and assume they are safe.The old value still sits in git history for anyone who runs git log -p .mcp.json, so a follow-up edit does not undo the leak. Treat any key that ever touched a commit as compromised, rotate it, and only then rewrite history if you must. For the wider question of
what to allow and what to block when you share
servers, read the MCP security basics.
Claude Code expands environment variables inside .mcp.json, so you commit a
reference and each person supplies the actual value from their own environment.
Two forms are supported:
${VAR}expands to the value of the environment variableVAR.${VAR:-default}expands toVARif it is set, otherwise usesdefault.
Expansion works in the command, args, env, url, and headers fields.
That covers both a bearer token on a remote server and a key passed to a local
server's environment:
{
"mcpServers": {
"api-server": {
"type": "http",
"url": "${API_BASE_URL:-https://api.example.com}/mcp",
"headers": {
"Authorization": "Bearer ${API_KEY}"
}
},
"db": {
"command": "npx",
"args": ["@acme/db-mcp-server"],
"env": {
"DATABASE_URL": "${DATABASE_URL}"
}
}
}
}The file names API_KEY and DATABASE_URL, but the values stay on each machine.
The ${API_BASE_URL:-...} default lets one teammate point at a staging host
without editing the shared file.
If a referenced variable has no value and no default, Claude Code fails to parse the config rather than connecting with a blank credential. That failure is the correct outcome. It tells the teammate to set the variable.
Where teammates set the values
The shared file declares which variables exist. Each person sets them once, locally, in whatever way suits their shell or secret store. A direct export works for a quick start:
export API_KEY="sk-the-real-value"
export DATABASE_URL="postgres://localhost:5432/app"For something durable, teams keep these in a .env file that is listed in
.gitignore, or in a secret manager that injects them into the shell. The rule
is the same either way. The value never enters a tracked file. Add the patterns
that hold secrets to .gitignore so they cannot be committed by accident:
echo ".env" >> .gitignore
echo ".env.local" >> .gitignoreA short note in your docs/onboarding.md listing the variables each server
needs saves every new hire from reverse-engineering the config.
Inspect and remove shared servers
These commands work the same for project-scoped servers as for any other:
claude mcp list
claude mcp get linear
claude mcp remove linearclaude mcp get linear prints the resolved config for one server, which is the
quick way to confirm a variable expanded the way you expected. claude mcp remove linear deletes it from .mcp.json, and you commit that removal so it
leaves everyone's setup at the same time.
Precedence when scopes collide
A teammate might already have a personal server with the same name as one in the committed file. Claude Code connects to each server once, using the definition from the highest-precedence source. It does not merge fields across scopes; the winning entry is used whole. The order is:
- Local scope
- Project scope
- User scope
So a personal local-scoped linear overrides the shared project-scoped linear
for that one person. This is useful when someone needs to point at a fork or a
local build while the team stays on the shared definition. It also explains a
common puzzle. When a teammate reports that their server behaves differently,
check whether they have a local or user entry shadowing the shared one.
A checklist for a clean shared setup
- Add team servers with
--scope projectso they land in.mcp.json. - Commit
.mcp.jsonto version control. - Reference every secret with
${VAR}, never a literal value. - Add
.envand similar secret files to.gitignore. - Document which environment variables each server needs.
- Confirm a fresh clone prompts for approval and connects after the variables are set.
Get these right and onboarding a teammate to your tools is one git pull, a few
exported variables, and one approval prompt. The next stop is wiring those
servers into repeatable workflows: see Claude Code workflows.