Claude Code MCP Configuration File: Scope, JSON, and Safety

Put Claude Code MCP servers in the right configuration scope, write a reviewable .mcp.json file, validate it before a session starts, and keep credentials out of the repository.

14 min readClaude Code, MCP, and JSON

The short answer

Use a project-root .mcp.json file when a team can safely share an MCP server definition. Use ~/.claude.json for private local or user-scoped servers. In both places, treat configuration as code: validate the JSON, state the transport explicitly, and pass secrets by environment variable rather than committing them.

In this guide

  1. Choose the right scope
  2. Write .mcp.json
  3. Configure remote HTTP servers
  4. Configure local stdio servers
  5. Validate before opening a session
  6. Review and troubleshoot safely
  7. FAQ

Choose the scope before you write JSON

The most common Claude Code MCP configuration mistake is choosing a file because it is convenient, then discovering that a colleague cannot see the server or that a token has been committed. Claude Code separates local, project, and user scopes. The official MCP documentation describes project scope as a version-controlled .mcp.json file, while local and user scopes live in your home-level configuration.

ScopeWho loads itStorageGood use
LocalOne project, private to you~/.claude.jsonExperiments and personal servers
ProjectOne repository, shared in Git.mcp.json at the repository rootSafe team-wide server definitions
UserAll your projects, private to you~/.claude.jsonPersonal utilities used everywhere

A project file is a contract with the team. It should answer which server is connected, which transport it uses, and how someone supplies their own credential. It should not contain a credential, a private filesystem path, or a one-off command that other developers cannot run. Keep those in a user or local configuration and document the required environment variable instead.

Write a team-safe .mcp.json file

Start with the smallest useful server entry. This example is intentionally incomplete as a production integration: it shows a shared remote endpoint and an environment-variable placeholder, but it does not put a real token in source control. Replace the URL with a server your team has reviewed.

{
  "mcpServers": {
    "team-catalog": {
      "type": "http",
      "url": "${CATALOG_MCP_URL:-https://mcp.example.com}",
      "headers": {
        "Authorization": "Bearer ${CATALOG_MCP_TOKEN}"
      }
    }
  }
}

The top-level key is mcpServers. Each server name becomes the identifier that teammates see in Claude Code. Prefer names that describe the system and access boundary, such as team-catalog-readonly, not vague names such as tools or prod.

Do not copy secrets into JSON examples

A committed bearer token is not a configuration shortcut. Rotate it, remove it from Git history, and move it to your team's approved secret-delivery path. A checked-in file should refer to an environment variable, then fail visibly when that variable is missing.

Remote MCP servers need an explicit transport

For a remote server, type and url work together. Claude Code's reference notes that an entry with a URL but no type is interpreted as a stdio entry and skipped. Use http for the current remote HTTP transport; use sse only for an existing server that still requires it, and use ws only when the server genuinely needs a persistent WebSocket connection.

{
  "mcpServers": {
    "issue-tracker": {
      "type": "http",
      "url": "https://mcp.example.com/issues",
      "headers": {
        "X-Workspace": "${WORKSPACE_ID}",
        "Authorization": "Bearer ${ISSUES_MCP_TOKEN}"
      }
    }
  }
}

Before adding a remote server, decide what data it can read and which actions it can take. A server that sees issue text, database rows, or deployment controls can introduce prompt-injection and authorization risk. The correct configuration scope does not make an untrusted server safe; it only controls who loads it.

Local stdio servers are processes, not just JSON

A stdio MCP server runs as a local process. The configuration must make the process auditable: name the executable, show arguments separately, and keep any environment variables narrow. The double dash in the equivalent claude mcp add command separates Claude Code options from the server command. In JSON, that separation appears as distinct command and args fields.

{
  "mcpServers": {
    "local-notes": {
      "command": "node",
      "args": ["./scripts/mcp-notes-server.mjs"],
      "env": {
        "NOTES_ROOT": "${NOTES_ROOT:-./notes}"
      }
    }
  }
}

Avoid a project configuration that starts a general shell wrapper, points to an arbitrary absolute path, or gives a tool unbounded access to files. If the server writes files or calls an API, apply the same validate-before-execute discipline used for an MCP tool JSON Schema.

Validate the file before Claude Code loads it

First, check syntax with the JSON Validator. That catches trailing commas, unquoted keys, and malformed nesting. Then validate the shape your team expects. A JSON file can be valid and still be a broken MCP configuration, for example when a remote entry has a URL without a transport type.

import { z } from "zod";

const RemoteServer = z.object({
  type: z.enum(["http", "sse", "ws"]),
  url: z.string().url(),
  headers: z.record(z.string()).optional(),
});

const StdioServer = z.object({
  command: z.string().min(1),
  args: z.array(z.string()).default([]),
  env: z.record(z.string()).optional(),
});

const McpConfig = z.object({
  mcpServers: z.record(z.union([RemoteServer, StdioServer])),
});

export function validateMcpConfig(raw: unknown) {
  return McpConfig.safeParse(raw);
}

This is a starting point, not a universal schema. Add an allowlist for server names, limit which domains are acceptable, and require HTTPS for remote endpoints in a production team. Use the JSON Schema Generator or JSON to Zod to accelerate a first draft, then review every generated constraint.

Validation does not grant trust

A schema tells you that a file has the expected shape. It does not prove the endpoint is safe, the server is authorized, or its tools should be approved. Review the server owner, scopes, and side effects separately, then confirm its state with claude mcp list or /mcp.

Review checklist and common failures

The official settings guide distinguishes shared project settings from a local settings file. Treat that distinction as a code-review question: would every developer need this exact server definition, and can it run without a secret baked into the repository? If either answer is no, it belongs outside the committed project configuration.

Configuration kindMinimum fieldsReview question
Remote servertype plus urlA URL without a type is skipped as an invalid stdio entry.
Local stdio servercommand and optional argsKeep executable paths and arguments reviewable.
Authenticationenvironment variable referenceDo not commit bearer tokens or API keys.
Project filemcpServers objectEvery shared server should have a clear owner and purpose.
  • Server is not found: check the chosen scope and run the session from the expected repository root.
  • A remote entry is skipped: add an explicit type that matches the endpoint transport.
  • A project server is pending: review it interactively; project scope does not silently approve a server for every clone.
  • A variable is literal text: check the environment variable name and provide a safe default only where one makes sense.
  • A config change seems ignored: inspect /status for loaded sources, then confirm the JSON is valid.

A safe handoff sequence

  1. 1. Decide whether the server is local, project, or user scoped.
  2. 2. Write the smallest server entry with an explicit transport or command.
  3. 3. Keep secrets in environment variables, never in a committed JSON file.
  4. 4. Validate JSON syntax and the expected server shape before opening a session.
  5. 5. Review and approve the server in Claude Code, then verify its status.

Frequently asked questions

Where should a team put a shared Claude Code MCP server?

Put a shareable, secret-free definition in .mcp.json at the repository root. Use project scope only when every collaborator should see the server and the server configuration is safe to review in Git.

Does .mcp.json replace Claude Code settings.json?

No. Settings files configure Claude Code behavior such as permissions and hooks. .mcp.json is for project-scoped MCP server definitions. Both can exist in the same repository, but they solve different configuration problems.

Can an MCP configuration include an API token?

It can technically include a header, but a shared configuration should reference an environment variable rather than contain the token. This limits accidental exposure in Git history, review tools, logs, and copied examples.

Why use a JSON validator when Claude Code parses the file?

A validator gives fast, line-level feedback before a Claude Code session starts. It also separates JSON syntax failures from configuration-shape failures, which makes a broken file faster to diagnose in a team review.

What is the difference between HTTP and stdio MCP servers?

An HTTP server is a remote endpoint Claude Code connects to over the network. A stdio server is a local process Claude Code starts and communicates with through standard input and output. The security and deployment review for each is different.

Related tutorials

Back to TutorialsWritten by Zhisan, July 2026