MCP Servers

Connect to Model Context Protocol servers — setup, debug, transports

MCP (Model Context Protocol) connects Claude to external tool servers — databases, browsers, APIs, and custom internal services — without modifying the CLI itself. Servers expose tools, resources, and prompts that Claude discovers at session startup and uses on demand. This chapter covers transports, configuration, debugging, and the performance trade-offs that come with plugging in external capabilities.

MCP architecture: Claude CLI communicates with external services via stdio or SSE transportClaude CLIRequest →← ResponseTransportstdioSSEExternal Service

Three Transports

MCP servers communicate with Claude through one of three transport mechanisms. The right choice depends on where the server runs and how it is managed.

Transport Comparison

TransportConfig KeyBest ForTrade-off
stdiocommand + argsLocal tools, per-session isolation2-10s startup per session (server spawns as child process)
sseurl (path ending /sse)Remote servers already runningRequires a long-running process; older protocol
streamable-httpurl + type: “streamable-http”Modern remote servers, shared team toolsBetter connection handling than SSE; emerging standard

For most local development, stdio is the default and the right choice. The server process starts when the session begins and is torn down when it ends. Use SSE or streamable-http when the MCP server is a long-running remote service such as a shared database proxy or a team-wide tool server.

Inline Config

Pass MCP server definitions directly on the command line with --mcp-config and a JSON string. No config file needed.

Inline MCP Config
$

Claude starts the filesystem MCP server as a child process, discovers its tools via the MCP protocol handshake, uses them to fulfill the prompt, and tears down the server when the session ends. The inline JSON follows the same mcpServers schema as file-based config.

You can also point --mcp-config at a file path instead of raw JSON:

Terminal window
claude -p "Query the database" --mcp-config ./mcp-config.json

File-Based Config

For repeatable setups, define servers in a JSON config file. This is also the format used by .mcp.json in a project root (auto-discovered by Claude) and ~/.claude/settings.json for user-level tools.

{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@anthropic-ai/mcp-server-filesystem", "/home/user/projects"],
"env": {}
},
"database": {
"command": "python",
"args": ["-m", "mcp_server_postgres"],
"env": {
"DATABASE_URL": "postgresql://user:pass@localhost/mydb"
}
},
"remote-tools": {
"url": "http://internal-tools.company.com:3000/sse"
}
}
}

Each server specifies either a command (for stdio) or a url (for SSE / streamable-http). The optional env object passes environment variables to the server process — useful for secrets you do not want hardcoded in prompts.

MCP servers can be defined at five different scopes, and they merge at runtime. When the same server name appears in multiple scopes, the more specific scope wins.

Configuration Scopes

ScopeLocationShared?Use Case
CLI inline—mcp-config flagOne-shotScripts, CI/CD, experimentation
Local.claude/settings.local.jsonNOT committed (gitignored)Local-only tools with secrets
Project.claude/settings.jsonCommitted to repoTeam-shared tools (e.g., project database)
User~/.claude/settings.jsonAll projectsPersonal tools you always want available
Managedmanaged-mcp.jsonOrg-level, enterpriseAdmin-forced or admin-blocked servers

Precedence order: CLI > Local > Project > User > Managed.

Gotcha

MCP configs walk up the directory tree unconditionally. A .mcp.json at the repo root is visible to every subfolder session. Unlike skills, a .git boundary does not block MCP inheritance. An empty child .mcp.json does not shadow the parent. The only way to prevent parent MCP servers from loading is —strict-mcp-config or separate repositories.

Strict MCP Config

The --strict-mcp-config flag has two uses: fail-fast when a server fails to connect, and MCP isolation — ignoring all .mcp.json files in the directory tree.

Terminal window
# Isolation: only load servers from this specific config
claude -p "Run audit" \
--strict-mcp-config \
--mcp-config ./my-servers.json

When used without --mcp-config, it strips all MCP servers entirely. When used with --mcp-config, it loads only the explicitly specified config. This is essential for subfolder sessions in monorepos that need to avoid inheriting parent MCP servers.

It also serves as a fail-fast mechanism in CI/CD:

Strict Mode — Fail Fast
$

This flag is essential in CI/CD pipelines and automated workflows where silent degradation is unacceptable. Without it, a broken server means Claude simply says “I don’t have that capability” instead of raising an error your pipeline can catch.

Gotcha

By default, broken MCP servers are silently skipped. Claude proceeds without those tools and gives no warning. You will only discover the problem when Claude says “I don’t have that capability” for a tool you expected to be available. Always use —strict-mcp-config in automated pipelines.

ToolSearch: Deferred Loading

When many MCP servers are active, their tool descriptions can consume a significant chunk of the context window. Claude automatically activates ToolSearch when MCP tool descriptions exceed approximately 10% of the context window. This is not configurable — it is automatic.

How deferred loading works:

  1. Tool names are listed in the init event, but full schemas are NOT loaded upfront
  2. Claude sees the names and knows the tools exist
  3. When Claude needs a specific tool, it calls ToolSearch to fetch the full schema
  4. Only then is the schema loaded into context

Without deferred loading, 80 MCP tools with detailed schemas could consume roughly 40K tokens of context. With ToolSearch, the overhead drops to approximately 2K tokens until a tool is actually needed. The trade-off is one extra round-trip per unique MCP tool used during the session.

You can see deferred tools in a session — they appear in the <available-deferred-tools> block, listed by name only with no parameters or descriptions:

{
"name": "mcp__chrome-devtools__take_screenshot",
"deferred": true
}

When Claude needs the tool, it fetches the full schema first:

{
"type": "tool_use",
"name": "ToolSearch",
"input": {
"query": "select:mcp__chrome-devtools__take_screenshot",
"max_results": 1
}
}
Gotcha

MCP tool descriptions persist in context even when unused. With 20+ servers and detailed schemas, effective context can shrink from 200K to ~70K tokens. Monitor usage.input_tokens in response payloads to detect context bloat. ToolSearch mitigates this automatically when descriptions exceed ~10% of the window, but the only real fix is keeping active servers under 10 and total tools under 80.

Init Event: MCP Server Status

When using --output-format stream-json, the init event reports the connection status of every MCP server. Parse this in automation to verify all expected servers are healthy.

Init Event — MCP Server Statusartifacts/09/mcp_config_load.json
1{
2 "type": "system",
3 "subtype": "init",
4 "session_id": "a3b1c4d2-9e8f-4a7b-b6c5-1d2e3f4a5b6c",
5 "mcp_servers": [A
6 {
7 "name": "filesystem",
8 "status": "connected",B
9 "tools": [
10 "mcp__filesystem__read_file",
11 "mcp__filesystem__write_file",
12 "mcp__filesystem__list_directory"
13 ]
14 },
15 {
16 "name": "database",C
17 "status": "error",
18 "error": "Connection refused: postgresql://localhost: 5432/mydb"
19 }
20 ],D
21 "tools": [
22 {
23 "name": "Read"
24 },
25 {
26 "name": "Write"
27 },
28 {
29 "name": "mcp__filesystem__read_file"
30 },
31 {
32 "name": "mcp__filesystem__write_file"
33 },
34 {
35 "name": "mcp__filesystem__list_directory"
36 }
37 ]
38}
AArray of all configured MCP servers and their connection state
BConnected servers list their discovered tools
CFailed servers report the error — only visible with stream-json
Dtools array merges built-in tools with MCP tools from healthy servers

Each server shows "status": "connected" or "status": "error". In automation, check this init event to confirm all expected servers started successfully before proceeding:

Terminal window
claude -p "List tools" \
--output-format stream-json \
--verbose \
--mcp-config ./mcp.json | head -1 | jq '.mcp_servers'

Debugging MCP Connections

When an MCP server fails to connect, work through these steps:

Test the server binary directly:

Terminal window
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{}}}' \
| npx -y @anthropic-ai/mcp-server-filesystem /tmp

If this hangs or errors, the server itself is broken — the problem is not with Claude.

Common failure causes:

  • Server binary not installed (npx downloads on first run — slow, may timeout)
  • Missing environment variables (check the env object in your config)
  • Port conflict for SSE/streamable-http servers
  • disabledMcpServers in ~/.claude.json overriding your config

MCP Tool Naming and Filtering

MCP tools follow a strict naming pattern: mcp__<server-name>__<tool-name>. This convention is important for tool filtering with --disallowedTools:

Terminal window
# Block a single MCP tool
claude -p "..." --disallowedTools "mcp__chrome-devtools__click"
# Block an entire MCP server's tools (glob pattern)
claude -p "..." --disallowedTools "mcp__chrome-devtools__*"

Performance Limits

MCP servers are powerful but have real costs. Keep these constraints in mind.

MCP Performance Constraints

ConstraintLimitRecommendation
Simultaneous serversNo hard capKeep under 10 enabled at once
Total active toolsNo hard capKeep under 80 active tools
Output warning10K tokensWarning when any MCP tool output exceeds this
Output hard cap25K tokens (default)Override with MAX_MCP_OUTPUT_TOKENS env var
Context impact~200K effectiveToo many tool descriptions can shrink effective context to ~70K

To raise the output cap for data-heavy MCP tools:

Terminal window
MAX_MCP_OUTPUT_TOKENS=50000 claude -p "Fetch large dataset" --mcp-config ./mcp.json
Tip

When MAX_MCP_OUTPUT_TOKENS is exceeded, the output is truncated silently — no warning appears in the final result. If MCP tool responses seem incomplete, check whether you are hitting this cap.