Claude Code MCP .mcp.json configuration developer tools

.mcp.json Configuration Reference: Complete Guide for Claude Code MCP Setup (2026)

The Prompt Shelf ·

Claude Code’s MCP setup has a reputation for being confusing. You add a server, it doesn’t show up. You copy a config from a README and it silently fails. You’re not sure whether to put it in .mcp.json or ~/.claude.json, and you find a dozen Stack Overflow posts pointing at claude_desktop_config.json which is something else entirely.

This article is a complete reference for every field in the MCP configuration schema, how the scope hierarchy actually works, and tested configurations for 15 popular MCP servers. No hand-waving. Every field matters.

The Two Config Files: .mcp.json vs claude_desktop_config.json

Before anything else, let’s clear up the most common source of confusion.

.mcp.json is Claude Code’s project-scoped configuration file. It lives in your project root directory, is checked into version control, and loads shared MCP servers for everyone on the team. This is the file you want in most development workflows.

claude_desktop_config.json is the configuration file for Claude Desktop, the standalone GUI application. It lives at ~/Library/Application Support/Claude/claude_desktop_config.json on macOS and %APPDATA%\Claude\claude_desktop_config.json on Windows. Claude Code does not read this file directly. If you’ve been copying configs from Claude Desktop documentation and wondering why they don’t work in Claude Code’s CLI, this is why.

That said, the JSON structures are nearly identical. A server entry that works in claude_desktop_config.json will work in .mcp.json with minimal or no modification. The schema is the same; the file location and loading mechanism differ.

Quick import: If you’ve already set up servers in Claude Desktop, you can import them to Claude Code with:

claude mcp add-from-claude-desktop

This works on macOS and WSL. It reads the Claude Desktop config from its standard location and lets you select which servers to import.

File Locations and Scope Hierarchy

MCP servers in Claude Code exist at three scopes, each stored differently:

ScopeStored InAvailability
Project.mcp.json in project rootCurrent project, shared with team
Local~/.claude.json (project entry)Current project, private to you
User~/.claude.json (global entry)All projects, private to you

Project scope is the main use case for .mcp.json. You commit the file, everyone who clones the repo gets the same servers. Claude Code shows a security prompt before loading project-scoped servers from .mcp.json for the first time, because the file could contain commands from someone else’s codebase.

Local scope is the default when you run claude mcp add without a --scope flag. It stores the server in ~/.claude.json under an entry for your current project path. Nobody else sees it.

User scope (--scope user) stores the server in ~/.claude.json globally, so it loads in every project you open.

When the same server name appears at multiple scopes, precedence goes: Local > Project > User > Plugin-provided > Claude.ai connectors. The highest-scope definition wins entirely — fields are not merged across scopes.

There is also a fourth level for organizations: managed-mcp.json, deployed by administrators to system paths (/Library/Application Support/ClaudeCode/managed-mcp.json on macOS, /etc/claude-code/managed-mcp.json on Linux). When this file exists, it takes exclusive control — users cannot add or modify any MCP server.

Full Schema Reference

Every .mcp.json file follows this top-level structure:

{
  "mcpServers": {
    "<server-name>": { ... }
  }
}

The mcpServers object is a map from server name to server configuration. The server name is a string you choose — it becomes the identifier in claude mcp list, the prefix in tool names (/mcp__servername__toolname), and the label in /mcp.

Reserved names: The name workspace is reserved by Claude Code for internal use. If your config defines a server with that name, Claude Code skips it at startup and logs a warning.

Common Fields (All Transport Types)

These fields apply regardless of transport:

{
  "mcpServers": {
    "my-server": {
      "type": "http",
      "timeout": 300000,
      "alwaysLoad": false
    }
  }
}
FieldTypeDescription
typestringTransport type: stdio, http, streamable-http, sse, ws
timeoutnumberPer-tool-call timeout in milliseconds. Overrides MCP_TOOL_TIMEOUT env var for this server only. Minimum effective value is 1000ms
alwaysLoadbooleanWhen true, loads all tools from this server upfront instead of deferring them. Default: false

On alwaysLoad: Claude Code’s default behavior (tool search) defers MCP tool definitions and discovers them on demand. This keeps context usage low when you have many servers. Setting alwaysLoad: true puts all tools from that server into context at session start — useful for servers whose tools you use on nearly every task. Use it sparingly.

Stdio Server Fields

{
  "mcpServers": {
    "my-stdio-server": {
      "type": "stdio",
      "command": "/usr/local/bin/my-server",
      "args": ["--config", "/etc/my-server/config.json"],
      "env": {
        "API_KEY": "${MY_API_KEY}",
        "LOG_LEVEL": "info"
      }
    }
  }
}
FieldTypeRequiredDescription
commandstringYesThe executable to run. Can be a full path or a command on PATH
argsstring[]NoArguments passed to the command. Supports ${VAR} expansion
envobjectNoEnvironment variables passed to the spawned process. Merged with (not replacing) the inherited environment

CLAUDE_PROJECT_DIR: Claude Code automatically sets this environment variable in every spawned stdio server process. It points to the project root — the directory Claude Code was launched from. Your server can read it as process.env.CLAUDE_PROJECT_DIR (Node) or os.environ["CLAUDE_PROJECT_DIR"] (Python) to resolve project-relative paths without depending on the working directory.

If you reference ${CLAUDE_PROJECT_DIR} inside your .mcp.json config itself (in command or args), use the default form ${CLAUDE_PROJECT_DIR:-.} to avoid a parse error when the variable isn’t in your shell environment.

HTTP Server Fields

{
  "mcpServers": {
    "my-http-server": {
      "type": "http",
      "url": "https://mcp.example.com/mcp",
      "headers": {
        "Authorization": "Bearer ${API_TOKEN}",
        "X-Workspace-ID": "ws-123"
      },
      "headersHelper": "/path/to/auth-script.sh",
      "timeout": 600000,
      "alwaysLoad": false,
      "oauth": {
        "clientId": "your-client-id",
        "callbackPort": 8080,
        "scopes": "read write",
        "authServerMetadataUrl": "https://auth.example.com/.well-known/openid-configuration"
      }
    }
  }
}
FieldTypeRequiredDescription
urlstringYesThe MCP endpoint URL. Supports ${VAR} expansion
headersobjectNoStatic HTTP headers. Supports ${VAR} expansion. Use for Bearer tokens, API keys, workspace IDs
headersHelperstringNoShell command that outputs a JSON object of headers at connection time. Runs every time the server connects
oauthobjectNoOAuth configuration object (see below)

The type aliasing: The MCP specification uses the name streamable-http for the current HTTP transport. Claude Code accepts both http and streamable-http as equivalent values in the type field. Configs copied from server documentation that use streamable-http work without modification.

OAuth object fields:

FieldTypeDescription
clientIdstringOAuth client ID for servers that don’t support Dynamic Client Registration
callbackPortnumberFixed port for the OAuth callback URL (http://localhost:PORT/callback)
scopesstringSpace-separated OAuth scopes to request. Takes precedence over server-advertised scopes
authServerMetadataUrlstringOverride OAuth discovery URL. Must use https://. Requires Claude Code v2.1.64+

SSE Server Fields

The SSE transport is deprecated as of the MCP 2025-06 specification. Use HTTP servers instead where available.

{
  "mcpServers": {
    "legacy-sse-server": {
      "type": "sse",
      "url": "https://mcp.example.com/sse",
      "headers": {
        "Authorization": "Bearer ${API_TOKEN}"
      }
    }
  }
}

The field set is identical to HTTP servers. SSE servers support automatic reconnection with exponential backoff (up to 5 attempts, starting at 1 second, doubling each retry).

WebSocket Server Fields

{
  "mcpServers": {
    "events-server": {
      "type": "ws",
      "url": "wss://mcp.example.com/socket",
      "headers": {
        "Authorization": "Bearer ${WS_TOKEN}"
      }
    }
  }
}

WebSocket is appropriate for servers that push events to Claude without being polled — CI results, monitoring alerts, webhook events. Use HTTP instead if your server only responds to requests. WebSocket does not support the claude mcp add --transport CLI flag; use claude mcp add-json or edit .mcp.json directly.

Transport Types Configuration

stdio: Local Processes

Stdio is the original MCP transport. Claude Code spawns the server as a child process, writes JSON-RPC messages to its stdin, reads responses from its stdout. Logs from the server go to stderr (captured by Claude Code).

Use stdio for:

  • Servers that need direct filesystem access
  • Wrappers around local tools (databases, compilers, custom scripts)
  • Servers with credentials you don’t want sent over the network
  • Development and testing of your own MCP servers

The main limitation: stdio servers are local to the machine. You can’t share a running stdio server instance across team members. Each developer runs their own instance.

# CLI equivalent
claude mcp add --transport stdio --scope project \
  --env AIRTABLE_API_KEY=${AIRTABLE_API_KEY} \
  airtable -- npx -y airtable-mcp-server

HTTP (Streamable HTTP): Remote Services

HTTP is the current recommended transport for all remote MCP servers. The server runs independently and handles multiple client connections. Communication uses HTTP POST requests; the server can optionally stream responses using SSE.

Use HTTP for:

  • SaaS integrations (GitHub, Sentry, Notion, Slack)
  • Shared infrastructure servers your team runs
  • Any server that needs to be accessed from multiple machines
# CLI equivalent
claude mcp add --transport http notion https://mcp.notion.com/mcp

SSE: Server-Sent Events (Deprecated)

The HTTP+SSE transport from MCP protocol 2024-11-05 is deprecated. It used two separate endpoints: a GET endpoint that opened an SSE stream, and a POST endpoint that accepted JSON-RPC messages. Some servers still run it for backward compatibility.

If a server only exposes an SSE endpoint and hasn’t migrated to streamable HTTP yet, use type: "sse" in your config:

# CLI equivalent
claude mcp add --transport sse asana https://mcp.asana.com/sse

Streamable HTTP: 2025 Standard

streamable-http (or simply http in Claude Code) is the transport introduced in MCP protocol 2025-03-26 and refined in 2025-06-18. It uses a single endpoint that supports both POST requests and GET-initiated SSE streams.

The main improvements over SSE:

  • Single endpoint instead of two
  • Session management via Mcp-Session-Id headers
  • Resumable streams with event IDs
  • MCP-Protocol-Version header for version negotiation

From the .mcp.json perspective, http and streamable-http are identical — use either string as the type value.

Authentication Patterns

Static API Key (Header)

The most common pattern for SaaS integrations:

{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/",
      "headers": {
        "Authorization": "Bearer ${GITHUB_PAT}"
      }
    }
  }
}

The ${GITHUB_PAT} expands from your shell environment at load time. If the variable is unset and has no default, Claude Code fails to parse the config.

OAuth 2.0 (Remote Servers)

For servers that support OAuth, Claude Code handles the flow automatically. When the server responds with 401 or 403, Claude Code marks it as needing authentication and you complete the flow with /mcp:

{
  "mcpServers": {
    "sentry": {
      "type": "http",
      "url": "https://mcp.sentry.dev/mcp"
    }
  }
}

For servers requiring pre-configured credentials:

{
  "mcpServers": {
    "my-server": {
      "type": "http",
      "url": "https://mcp.example.com/mcp",
      "oauth": {
        "clientId": "your-client-id",
        "callbackPort": 8080
      }
    }
  }
}

The client secret is never stored in the config file — it goes in your system keychain (macOS) or credentials file. Pass it once with --client-secret when adding the server via CLI.

Dynamic Headers (headersHelper)

When your server uses short-lived tokens, Kerberos, or an internal SSO system, static headers don’t work. Use headersHelper to run a command that generates headers at connection time:

{
  "mcpServers": {
    "internal-api": {
      "type": "http",
      "url": "https://mcp.internal.example.com",
      "headersHelper": "/opt/bin/get-mcp-token.sh"
    }
  }
}

The script must output a JSON object of string key-value pairs to stdout. It runs with a 10-second timeout on each connection. Claude Code sets CLAUDE_CODE_MCP_SERVER_NAME and CLAUDE_CODE_MCP_SERVER_URL in the script’s environment, so one script can serve multiple servers:

#!/bin/bash
# get-mcp-token.sh
TOKEN=$(vault kv get -field=token secret/mcp/${CLAUDE_CODE_MCP_SERVER_NAME})
echo "{\"Authorization\": \"Bearer ${TOKEN}\"}"

Environment Variables for Stdio Servers

Stdio servers receive a merged environment: the process environment plus whatever you specify in env. Sensitive values go in the env map with shell variable expansion:

{
  "mcpServers": {
    "postgres": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@bytebase/dbhub"],
      "env": {
        "DATABASE_URL": "${DATABASE_URL}",
        "LOG_LEVEL": "warn"
      }
    }
  }
}

Never hardcode credentials in the env map values if the .mcp.json is committed to version control. Use shell variable expansion and document which variables need to be set.

15 Real-World MCP Server Configurations

1. GitHub

Official GitHub MCP server via remote HTTP. Requires a personal access token with permissions for the repositories you want Claude to access.

{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/",
      "headers": {
        "Authorization": "Bearer ${GITHUB_PAT}"
      }
    }
  }
}

Generate a fine-grained PAT at github.com/settings/personal-access-tokens with repository access scoped to the repos you need.

2. Filesystem

Local server for reading and writing files. The official @modelcontextprotocol/server-filesystem package exposes the directories you pass as arguments.

{
  "mcpServers": {
    "filesystem": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/you/Documents",
        "/Users/you/Projects"
      ]
    }
  }
}

Each argument after the package name is a directory to expose. The server won’t access paths outside these directories.

3. PostgreSQL

Database access via @bytebase/dbhub. Supports read and schema inspection. Use a read-only database user in production.

{
  "mcpServers": {
    "postgres": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "@bytebase/dbhub",
        "--dsn",
        "${DATABASE_URL}"
      ]
    }
  }
}

Set DATABASE_URL=postgresql://readonly:password@host:5432/dbname in your environment. For shared configs, keep the DSN in an env var rather than hardcoded in args.

4. SQLite

Lightweight local database access. Useful for local development databases and log analysis.

{
  "mcpServers": {
    "sqlite": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-sqlite",
        "--db-path",
        "${CLAUDE_PROJECT_DIR:-/tmp}/data.sqlite"
      ]
    }
  }
}

The ${CLAUDE_PROJECT_DIR:-/tmp} pattern uses the project directory if available, falling back to /tmp.

5. Slack

Slack integration via official MCP. Requires a Slack app with appropriate scopes.

{
  "mcpServers": {
    "slack": {
      "type": "http",
      "url": "https://mcp.slack.com/mcp",
      "oauth": {
        "scopes": "channels:read chat:write search:read files:read"
      }
    }
  }
}

Authenticate with /mcp after adding. The scopes field pins the OAuth request to the minimum permissions you need — useful if you want to limit what Claude can do in your Slack workspace.

6. Sentry

Error monitoring integration. OAuth-based, no token management required.

{
  "mcpServers": {
    "sentry": {
      "type": "http",
      "url": "https://mcp.sentry.dev/mcp"
    }
  }
}

Run /mcp to authenticate with your Sentry account. Once connected, Claude can pull error details, stack traces, and deployment history directly.

7. Linear

Issue tracking for engineering teams. Authenticate via the /mcp OAuth flow.

{
  "mcpServers": {
    "linear": {
      "type": "http",
      "url": "https://mcp.linear.app/mcp"
    }
  }
}

8. Notion

Workspace knowledge base. OAuth-based, requires Notion integration setup.

{
  "mcpServers": {
    "notion": {
      "type": "http",
      "url": "https://mcp.notion.com/mcp"
    }
  }
}

Authenticate with /mcp. You’ll be prompted to select which Notion workspaces to grant access to.

9. Google Drive

Document and spreadsheet access. OAuth-based via Google’s MCP server.

{
  "mcpServers": {
    "google-drive": {
      "type": "http",
      "url": "https://drive.googleapis.com/mcp",
      "oauth": {
        "scopes": "https://www.googleapis.com/auth/drive.readonly"
      }
    }
  }
}

Use drive.readonly scope to prevent accidental writes. Upgrade to drive scope only if your workflow requires creating or modifying files.

10. Browser / Playwright

Browser automation for testing and web interaction. Runs headlessly by default.

{
  "mcpServers": {
    "playwright": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@playwright/mcp@latest"]
    }
  }
}

For headed mode (visible browser window):

{
  "mcpServers": {
    "playwright": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@playwright/mcp@latest", "--headed"]
    }
  }
}

11. Memory

Persistent memory that survives sessions. Uses a local file to store key-value facts Claude learns across conversations.

{
  "mcpServers": {
    "memory": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-memory"],
      "env": {
        "MEMORY_FILE_PATH": "${HOME}/.claude-memory.json"
      }
    }
  }
}

12. Time

Gives Claude accurate current time and timezone conversion. Surprisingly useful when building features that depend on dates.

{
  "mcpServers": {
    "time": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-time"],
      "alwaysLoad": true
    }
  }
}

The alwaysLoad: true here makes sense — time lookups are needed immediately and the tool footprint is minimal.

13. EverArt

AI image generation within Claude sessions.

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

Web search via Brave’s API. Useful for giving Claude access to current information without browser automation.

{
  "mcpServers": {
    "brave-search": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-brave-search"],
      "env": {
        "BRAVE_API_KEY": "${BRAVE_API_KEY}"
      }
    }
  }
}

Get an API key at brave.com/search/api. The free tier includes 2,000 queries/month.

15. Puppeteer

Alternative to Playwright for browser automation. Better compatibility with certain legacy web apps.

{
  "mcpServers": {
    "puppeteer": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-puppeteer"]
    }
  }
}

Environment Variable Patterns

Basic Expansion

{
  "mcpServers": {
    "api-server": {
      "type": "http",
      "url": "${API_BASE_URL}/mcp",
      "headers": {
        "Authorization": "Bearer ${API_TOKEN}"
      }
    }
  }
}

${VAR} expands to the value of the environment variable. If unset with no default, Claude Code fails to parse the config and logs an error.

Expansion with Defaults

{
  "mcpServers": {
    "api-server": {
      "type": "http",
      "url": "${API_BASE_URL:-https://api.example.com}/mcp"
    }
  }
}

${VAR:-default} uses default when VAR is unset or empty. Good for servers where the URL is configurable but has a sensible default for most users.

Where Expansion Works

Environment variable expansion is supported in:

  • command — the server executable path
  • args — command-line arguments (each element separately)
  • env values — not keys
  • url — the full URL string
  • headers values — not keys

It does not expand in: field names (keys in JSON objects), type values, or nested OAuth configuration fields.

Common Patterns

Per-user API keys in a shared config:

{
  "mcpServers": {
    "stripe": {
      "type": "http",
      "url": "https://mcp.stripe.com/mcp",
      "headers": {
        "Authorization": "Bearer ${STRIPE_API_KEY}"
      }
    }
  }
}

Team members set STRIPE_API_KEY in their shell profile or .env.local. The shared .mcp.json never contains credentials.

Environment-specific URLs:

{
  "mcpServers": {
    "internal-api": {
      "type": "http",
      "url": "${INTERNAL_API_URL:-https://api.staging.example.com}/mcp"
    }
  }
}

Production sets INTERNAL_API_URL=https://api.example.com. Everyone else gets the staging URL as default.

Security Best Practices

allowedTools and deniedMcpServers

Claude Code exposes MCP tool permissions through the settings system. You can restrict which tools from an MCP server are usable in a project:

In .claude/settings.json:

{
  "permissions": {
    "allow": ["mcp__filesystem__read_file", "mcp__filesystem__list_directory"],
    "deny": ["mcp__filesystem__write_file", "mcp__filesystem__delete_file"]
  }
}

Permission entries use glob patterns. mcp__filesystem__* allows or denies all tools from the filesystem server.

For organizations, deniedMcpServers in managed settings blocks specific servers from loading at all:

{
  "deniedMcpServers": [
    { "serverUrl": "https://untrusted-server.example.com/*" },
    { "serverCommand": ["npx", "-y", "suspicious-package"] }
  ]
}

Denylist entries match by URL pattern (with * wildcard support), exact command array, or server name.

Environment Variable Scoping

Never put credentials directly in .mcp.json values. Even if the file is in .gitignore, you risk accidentally committing it. Always use ${VAR} expansion:

// Bad — credential in config
{
  "env": {
    "API_KEY": "sk-live-abc123xyz"
  }
}

// Good — credential from environment
{
  "env": {
    "API_KEY": "${STRIPE_API_KEY}"
  }
}

For team configs, document required environment variables in your README or a .env.example file:

# .env.example
STRIPE_API_KEY=sk-...
GITHUB_PAT=github_pat_...
DATABASE_URL=postgresql://...

Server Trust and Prompt Injection Risk

Every MCP server can potentially expose Claude to prompt injection — a connected server that fetches external content (issues, emails, documents) could embed instructions in that content. The Anthropic documentation is explicit about this risk.

Before connecting a server, verify:

  1. It comes from a known, trusted source
  2. You understand what external content it fetches
  3. You’ve reviewed what permissions it requests

For project-scoped servers in .mcp.json, Claude Code prompts for approval before loading them the first time. This prompt exists for a reason. When you approve a project server, you’re trusting the commands defined in that file will run on your machine.

If you need to reset approval choices: claude mcp reset-project-choices.

managed-mcp.json for Teams

For organizations that need to control which servers run, deploy managed-mcp.json to the system path. When this file exists, it takes exclusive control — users cannot add additional servers:

// /Library/Application Support/ClaudeCode/managed-mcp.json (macOS)
{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/"
    },
    "sentry": {
      "type": "http",
      "url": "https://mcp.sentry.dev/mcp"
    }
  }
}

Don’t store API keys in managed-mcp.json — the file is readable by all users on the machine. Use ${VAR} expansion with per-user environment variables, or OAuth flows.

Debugging Configuration Issues

Server Doesn’t Appear

Check the status with:

claude mcp list
# Look for ⏸ Pending approval or ✗ Rejected

If the server shows as pending approval, start an interactive Claude Code session and accept the trust prompt for project-scoped servers.

If the server isn’t listed at all, the config may have a parse error. Check for:

  • Unset environment variables without defaults: ${UNSET_VAR} will cause a parse failure
  • Missing required fields (command for stdio, url for http)
  • The reserved name workspace

Server Loads but Tools Don’t Work

Inside a Claude Code session:

/mcp

This shows each server’s connection status and tool count. A server that shows as connected but with 0 tools usually means it connected but advertises no tools — check the server’s documentation for initialization requirements.

Authentication Failures

For HTTP servers, Claude Code does not fall back to OAuth if you’ve set headers.Authorization and the server rejects it. It marks the connection as failed. Verify your token is valid for the MCP endpoint specifically (not just the REST API), or remove the headers.Authorization to use the OAuth flow instead.

Timeout Issues

Default MCP tool timeout is set by the MCP_TOOL_TIMEOUT environment variable. For servers that run long operations (large database queries, browser automation), set a per-server timeout:

{
  "mcpServers": {
    "browser": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@playwright/mcp@latest"],
      "timeout": 120000
    }
  }
}

The timeout value is per-tool-call in milliseconds. Note that for HTTP servers, the first-byte budget has a 60-second minimum regardless of this value.

Exponential Backoff on Connection Failures

HTTP and SSE servers reconnect automatically on disconnect. Claude Code retries up to 5 times with exponential backoff (1s, 2s, 4s, 8s, 16s). For initial connection failures, it retries up to 3 times on transient errors (5xx, connection refused, timeout). Authentication errors and 404s are not retried — they require a config fix.

During reconnection, the server shows as pending in /mcp. After 5 failed attempts, it’s marked as failed. You can retry manually from /mcp.

Large Tool Output Warnings

When a tool returns more than 10,000 tokens, Claude Code displays a warning. The default ceiling is 25,000 tokens. Raise it with the MAX_MCP_OUTPUT_TOKENS environment variable:

export MAX_MCP_OUTPUT_TOKENS=50000
claude

If you’re authoring an MCP server and a specific tool legitimately returns large results (a full database schema, a file tree), annotate the tool in your tools/list response:

{
  "name": "get_full_schema",
  "description": "Returns the complete database schema",
  "_meta": {
    "anthropic/maxResultSizeChars": 200000
  }
}

This raises the threshold for that tool specifically, up to a hard ceiling of 500,000 characters, without requiring users to bump the global environment variable.

Checking Server Details

To inspect exactly how Claude Code has stored a server — including which OAuth credentials are configured — use:

claude mcp get <server-name>

This shows the transport type, URL or command, configured headers (redacted), and OAuth status. If a server appears to be loading incorrectly, compare claude mcp get output against your .mcp.json entry to confirm which scope’s definition is winning.

Migration: From claude_desktop_config.json to .mcp.json

The two files use nearly identical JSON structures. Migration is mostly about moving entries and updating file location.

Claude Desktop format (~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/Documents"],
      "env": {}
    }
  }
}

Claude Code .mcp.json format:

{
  "mcpServers": {
    "filesystem": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/Documents"]
    }
  }
}

The main differences:

  1. type field: Claude Code requires an explicit type field. Claude Desktop infers stdio when command is present. Add "type": "stdio" to all your stdio server entries.

  2. Empty env object: Omit "env": {} if you have no environment variables to set. It’s valid either way but cleaner to omit.

  3. HTTP servers: Claude Desktop may store remote servers differently depending on version. In Claude Code, all remote servers need an explicit type: "http" or type: "sse".

Automated migration: Instead of manual conversion, use:

claude mcp add-from-claude-desktop

This handles the format differences automatically and lets you select which servers to import.

Scope consideration: Imported servers go to local scope by default. To share them with your team, copy the resulting entries to .mcp.json in your project root and add --scope project to future claude mcp add commands.

FAQ

Can I use .mcp.json with Claude Desktop?

No. Claude Desktop reads claude_desktop_config.json from its own application support directory. The two applications maintain separate configuration files. Use claude mcp add-from-claude-desktop to copy servers from Claude Desktop to Claude Code.

What happens when .mcp.json has a server name that matches my user-scope server?

The local-scope or user-scope definition wins. Claude Code connects to one instance of each server name, using the highest-precedence definition. The entire entry from that scope is used — fields aren’t merged. Use claude mcp list to see which entry is active.

Can I commit .mcp.json with API keys in env values?

You can, but you shouldn’t. Anyone with access to the repo can read the file. Use ${ENV_VAR} expansion and require team members to set their own credentials in shell profiles or .env.local (which should be in .gitignore).

How do I add a server for just one project without checking it in?

Use local scope (the default): claude mcp add --transport http myserver https://.... This stores the server in ~/.claude.json under your current project path. Nobody else sees it, and it doesn’t appear in .mcp.json.

The server connected in Claude Desktop but fails in Claude Code. Why?

The most common cause is a missing or incorrect type field, or a command that’s not on PATH in the environment where Claude Code runs. Claude Desktop and the Claude Code CLI may run with different PATH values. Try using full paths for command values, or verify with which npx / which python3 in the terminal where you run claude.

What’s the difference between timeout in the server config and MCP_TOOL_TIMEOUT?

MCP_TOOL_TIMEOUT is a global environment variable that sets the default timeout for all MCP tool calls. The timeout field in a server’s .mcp.json entry overrides MCP_TOOL_TIMEOUT for that specific server only. If you need a long-running operation for one server and fast timeouts elsewhere, set timeout per-server.

Can I disable MCP entirely for a project?

For individual users, you can remove all MCP server entries from the relevant config files. For organizations, deploy a managed-mcp.json with an empty mcpServers object — this prevents any MCP server from loading and blocks claude mcp add.


For related configuration guides:

Related Articles

Explore the collection

Browse all AI coding rules — CLAUDE.md, .cursorrules, AGENTS.md, and more.

Browse Rules