.mcp.json

MCP

Definition

The project-scoped MCP configuration file placed in the repository root. Defines which MCP servers are available for the project, their commands, arguments, and environment variable bindings. Checked into version control to share server configuration with the team. Supports ${ENV_VAR} expansion for credentials.

Example Usage

Check .mcp.json into your repo with GitHub MCP server config using ${GITHUB_TOKEN} so all team members get the same tools without manual setup.

Why It Matters for the CCA-F Exam

Exam questions about `.mcp.json` focus on two areas: (1) the correct location and scope (project root, version-controlled, project-scoped over global), and (2) credential safety via environment variable expansion. A question might show a `.mcp.json` snippet with a hardcoded API key and ask what is wrong — the answer is always "credentials should use ${ENV_VAR} substitution."

In Depth

.mcp.json is the project-scoped MCP configuration file that lives in the repository root. It defines which MCP servers are available when working inside that project, replacing the need for per-developer manual configuration. Because it is checked into version control, every team member who clones the repository automatically gets the same server definitions — no onboarding steps required.

File Structure

The file contains a single mcpServers object whose keys are logical server names. Each entry specifies the transport type and the parameters needed to connect:

{
  "mcpServers": {
    "github": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    },
    "internal-search": {
      "type": "http",
      "url": "https://mcp.internal.example.com/search",
      "headers": {
        "Authorization": "Bearer ${SEARCH_API_KEY}"
      }
    }
  }
}

${ENV_VAR} placeholders are expanded from the shell environment at runtime. This pattern means the config file is safe to commit — credentials never appear in plain text.

Scope and Override Hierarchy

.mcp.json is project-scoped. It is loaded when the MCP client starts inside the project directory. If a user also has a user-scoped MCP config (in ~/.claude/ settings), the project config takes precedence for servers defined in both places. This mirrors the CLAUDE.md hierarchy: more specific (project) overrides less specific (global).

Sharing vs Security

Checking in .mcp.json is the intended workflow for team environments. The ${ENV_VAR} expansion model means each developer must have the referenced variables set in their shell — typically via a .env.local file that is git-ignored. Never hardcode tokens or connection strings in .mcp.json itself.

For full configuration options and how scoping interacts with Claude Code settings, see MCP Server Configuration & Scoping.

Example

Minimal .mcp.json using stdio transport with environment variable substitution for the GitHub token

json
{
  "mcpServers": {
    "github": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}

Frequently Asked Questions

What is the difference between .mcp.json and .claude/settings.json?

.mcp.json is exclusively for MCP server definitions — it tells the client which servers to connect to and how. .claude/settings.json is Claude Code's broader configuration file covering permissions, hooks, default model, and other behaviors. MCP server config can also appear inside settings.json, but .mcp.json is the dedicated, portable, team-shareable location.

Does .mcp.json support both stdio and StreamableHTTP servers in the same file?

Yes. Each entry in mcpServers declares its own transport type. A project can have a local stdio server for a private script alongside a remote StreamableHTTP server for a shared internal tool — both defined in the same .mcp.json.

What happens if a referenced environment variable is not set when the client starts?

The client will either fail to launch the server (for stdio, where the env block is passed to the subprocess) or send a header with an empty or literal string (for HTTP headers). The resulting error surfaces as a connection failure or authentication error from the server. Best practice is to document required variables in the repository README and provide a .env.example file.