Pass tokens to .mcp.json from environment variables with ${VAR} expansion
Keep access tokens out of the .mcp.json you commit by referencing environment variables. The ${VAR} and ${VAR:-default} syntax, where expansion works, and team conventions.
.mcp.json is the file you commit so your team shares the same MCP servers. Write a GitHub access token into it directly and everyone with repository access has your token.
Claude Code expands ${VAR} references inside .mcp.json, so the token itself stays in your shell environment and only its name is committed.
KEY POINT
What you will learn
- The
${VAR}and${VAR:-default}syntax - Which fields the expansion works in
- Where to keep the variables, and what to agree on as a team
The syntax
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
}
},
"internal-api": {
"type": "http",
"url": "${INTERNAL_MCP_URL:-https://mcp.example.internal/mcp}",
"headers": {
"Authorization": "Bearer ${INTERNAL_MCP_TOKEN}"
}
}
}
}
| Form | Meaning |
|---|---|
${GITHUB_TOKEN} | Replaced with the value of GITHUB_TOKEN |
${VAR:-default} | Uses the default when VAR is unset |
Expansion is not limited to env: it works in command, args, url and headers too.
用語解説
When to use local scope instead: a server that only you authenticate to can be registered with claude mcp add at local scope, which stores it in ~/.claude.json rather than the shared file. The ${VAR} approach fits the other case — the whole team uses the same server, but each person authenticates as themselves. See claude mcp add --scope.
Where to keep the variables
# ~/.zshrc or ~/.bashrc
export GITHUB_TOKEN="ghp_xxxxxxxx"
Putting the export in your shell profile means it is there whenever you start claude from a terminal. For the VS Code extension, VS Code itself must carry the variable: put it in the shell profile and restart VS Code, or launch it from a terminal with code ..
If the project uses direnv, .envrc gives you per-directory values — and belongs in .gitignore.
When it isn't set
An unset variable usually means the server starts but fails to authenticate.
- Check the server's state with
/mcp. If it shows failed, continue - Run
echo $GITHUB_TOKENin your terminal to confirm there is a value - Confirm the shell you exported in is the shell that launched Claude Code
- Check the spelling of the variable name in
.mcp.json
Team conventions
.mcp.jsoncarries only${VAR}references — never a value- List the required variable names in the README (names only; each person issues their own value)
- Mirror the same names in
.env.example - Scope tokens minimally; on GitHub, start from read-only
If a token does get committed
Revoke and reissue the token before you worry about rewriting history. Removing it from the history does nothing about the copies already cloned by others.
For adding MCP servers and choosing a scope, see Adding MCP servers to Claude Code. For handling secrets across all three tools, see Stop AI coding tools from reading your API keys and secrets.
Summary
- Reference environment variables as
${GITHUB_TOKEN}in.mcp.json; never write the value ${VAR:-default}supplies a fallback, and expansion works inenv,args,urlandheaders- Keep the variables in your shell profile, and restart VS Code so the extension sees them
- If a token is committed, revoke it first — history rewriting comes second
FAQ
- What happens if the environment variable isn't set?
- The reference expands to an empty string, or to the default you supplied with ${VAR:-default}. The server then fails to authenticate, so check its state with /mcp.
- Are environment variables picked up when I launch from the VS Code extension?
- The environment of the shell that started VS Code is what counts. Exporting in a terminal after the fact may not reach it, so put the export in your shell profile, or launch VS Code from a terminal.
Primary sources
This article was drafted by AI from official documentation and reviewed by the site operator before publishing. Found a mistake? Let us know via the contact page.