Pass tokens to .mcp.json from environment variables with ${VAR} expansion

Claude Code Published: Updated:

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.

Verified on Sep 25, 2026 These tools change quickly. Please also check the latest official documentation.
Contents
  1. The syntax
  2. Where to keep the variables
  3. When it isn't set
  4. Team conventions
  5. Summary

.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}"
      }
    }
  }
}
FormMeaning
${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.

  1. Check the server's state with /mcp. If it shows failed, continue
  2. Run echo $GITHUB_TOKEN in your terminal to confirm there is a value
  3. Confirm the shell you exported in is the shell that launched Claude Code
  4. Check the spelling of the variable name in .mcp.json

Team conventions

  • .mcp.json carries 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 in env, args, url and headers
  • 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.