Model Context Protocol
14 min read
What You’ll Learn
This chapter is all about the Model Context Protocol (MCP), the standard for connecting Claude Code to external tools, databases, and APIs. By the end, you’ll know how MCP servers work, which of the three transport modes to pick for your situation, how to add and configure servers at different scopes, how to share server configs with your team through .mcp.json, how elicitation lets servers request structured input from you mid-conversation, and how to troubleshoot connection issues when things go sideways.
What MCP Enables
Model Context Protocol (MCP) is the open standard that connects Claude Code to external tools, databases, APIs, ticketing systems, and documentation, beyond the local filesystem.
MCP lets Claude Code reach beyond your local filesystem. On its own, Claude Code can read files, run shell commands, and search your codebase. Add MCP into the mix, and it can also query a database, create tickets in your project management tool, search a knowledge base, interact with cloud services, or call pretty much any API you connect.
MCP servers expose tools that Claude Code calls just like its built-in ones. Connect a PostgreSQL MCP server and Claude Code gains a query tool for running SQL. Hook up a Jira MCP server and it picks up tools for creating and updating tickets. From Claude Code’s perspective, MCP tools work identically to its native file and shell tools. It decides when to use them based on what you’re asking for.
Claude Code’s Computer Use feature is itself implemented as a built-in MCP server, giving it access to screen capture and input tools through the same protocol. Plugins can also bundle MCP servers, making them available automatically when the plugin is enabled.
One important distinction: you don’t build MCP servers yourself. Instead, you install and connect existing servers that other developers and organizations have published. This chapter focuses on connecting and configuring servers, not developing them.
Architecture Overview
MCP follows a client-server architecture. Claude Code acts as the MCP client, connecting to one or more MCP servers that each provide a set of tools. These servers can run locally on your machine as child processes, or remotely on another host over the network.
The diagram above shows how everything fits together. Local servers connect via stdio (standard input/output) and run as child processes of Claude Code. Remote servers connect via HTTP over the network and can live anywhere: on a team server, in the cloud, or behind your corporate firewall. Each server exposes tools that show up in Claude Code’s tool palette right alongside its built-in capabilities.
You can connect multiple servers at the same time, and Claude Code handles the connections and routes tool calls to the right server automatically. A typical project might have a local database server (stdio), a remote documentation search server (HTTP), and a cloud API integration (HTTP) all running simultaneously.
Transport Modes
MCP supports three transport protocols, and each one determines how Claude Code talks to the server.
stdio (default for local servers)
With stdio, the server runs as a child process on your machine, and Claude Code communicates with it through stdin and stdout. It’s the simplest transport: no networking, no authentication, no port configuration. Most MCP servers you install locally use stdio by default.
# stdio transport (default, no --transport flag needed)claude mcp add my-tools -- npx @my-org/mcp-toolsThe server starts as a child process when Claude Code launches.
Use stdio when the server runs locally, you installed it via npm or downloaded a binary, and only you need access. The server process starts when Claude Code launches and stops when the session ends. No ports get opened and no network traffic leaves your machine.
HTTP (recommended for remote servers)
With HTTP, the server runs on a remote host and communicates via the Streamable HTTP protocol. It supports authentication headers, works across network boundaries, and handles reconnection gracefully. If the server isn’t running locally, HTTP is the way to go.
# HTTP transport for a remote serverclaude mcp add docs-server --transport http --url https://mcp.example.com/docsReach for HTTP when the server lives on another machine, runs in the cloud, or is shared across a team. It also supports OAuth authentication flows for servers that require user authorization.
# HTTP with custom headers for API key authclaude mcp add analytics --transport http --url https://mcp.example.com/analytics --header "X-API-Key: your-api-key-here"SSE (deprecated)
Server-Sent Events was the original remote transport for MCP. SSE is explicitly deprecated in favor of HTTP. It still works, but it’ll be removed in a future release. If you’ve got existing SSE server configurations, it’s time to migrate them to HTTP.
# DEPRECATED: use HTTP insteadclaude mcp add legacy-server --transport sse --url https://old-server.example.com/eventsMigrate existing SSE configurations to HTTP transport.
Don’t use SSE for new servers. If a server only supports SSE, check whether an updated version supports HTTP. If not, SSE will continue to work for now, but plan your migration sooner rather than later.
Adding MCP Servers
The claude mcp add command registers a new MCP server. The basic syntax is: server name, optional flags, a double dash separator, and then the command to start the server.
claude mcp add <name> [flags] -- <command> [args...]Here are some common variations.
# Basic local serverclaude mcp add postgres -- npx @mcp/postgres postgresql://localhost/mydb
# With environment variablesclaude mcp add github --env GITHUB_TOKEN=ghp_xxxxxxxxxxxx -- npx @mcp/github
# Scoped to project (saved in .mcp.json)claude mcp add project-db --scope project -- npx @mcp/postgres postgresql://localhost/projectdb
# Remote HTTP server with authenticationclaude mcp add company-api --transport http --url https://mcp.company.com/api --header "Authorization: Bearer TOKEN_HERE"
# Multiple environment variablesclaude mcp add analytics --env API_KEY=xxx --env REGION=us-east-1 -- npx @mcp/analyticsOnce you’ve added a server, Claude Code starts it automatically on the next session launch. You can verify the connection with /mcp from within an active session.
Server Scopes
MCP server configurations live at one of three scopes, and the scope determines who can see and use the server.
Local (default) stores the config in ~/.claude.json. The server is available only to you on this machine. Pick this scope for personal tools, local databases, or servers you’re experimenting with.
Project stores the config in .mcp.json at your project root. This file is meant to be committed to Git and shared with your team, so everyone who clones the repo gets the same MCP server configuration. It’s the right choice for team databases, shared documentation servers, or project-specific tools.
User stores the config in your user settings. The server is available to you across all projects on this machine. Use this for personal productivity tools you rely on everywhere.
When the same MCP server appears at multiple scopes, the most local configuration wins. Project scope overrides user scope, and local scope overrides project scope. This means you can always override a team-wide server configuration with your own local settings without affecting anyone else.
# Local scope (default)claude mcp add my-tool -- npx @my/tool
# Project scope (creates/updates .mcp.json)claude mcp add team-db --scope project -- npx @mcp/postgres $DB_URL
# User scopeclaude mcp add my-notes --scope user -- npx @mcp/notes.mcp.json Format
The .mcp.json file at your project root defines project-scoped MCP servers. It’s a JSON file with a mcpServers object where each key is a server name and each value contains that server’s configuration.
{ "mcpServers": { "database": { "command": "npx", "args": ["@mcp/postgres", "postgresql://localhost/mydb"], "env": { "DB_PASSWORD": "${DB_PASSWORD}" } }, "docs": { "command": "npx", "args": ["@mcp/docs-search", "--index", "./docs"] }, "cloud-api": { "type": "http", "url": "https://mcp.example.com/api", "headers": { "Authorization": "Bearer ${API_TOKEN}" } } }}Commit this file to Git for team-wide MCP server configuration.
Notice the ${DB_PASSWORD} and ${API_TOKEN} syntax. Environment variables referenced with ${VAR} get expanded at runtime from the developer’s local environment. This means you can safely commit the config file to Git without exposing secrets; each team member just sets the required environment variables locally.
For stdio servers, you’ll specify command and args. For HTTP servers, use type: "http" and url. Both support an env object for passing environment variables to the server process and a headers object for HTTP authentication.
When a team member clones the repo and fires up Claude Code, all project-scoped servers defined in .mcp.json start automatically. Each developer only needs to set the required environment variables (like DB_PASSWORD and API_TOKEN in the example above) in their local shell environment.
OAuth Authentication
Some remote MCP servers require OAuth authentication, and Claude Code handles the flow automatically.
/mcpShows connected servers, their status, and whether authentication is needed.
When you add a server that requires OAuth, Claude Code opens your browser for the authorization flow the first time you connect. After you authorize, tokens are stored locally and refreshed automatically. You don’t need to manage tokens yourself.
Claude Code follows RFC 9728 Protected Resource Metadata for automatic discovery of a server’s OAuth requirements. When connecting to an OAuth-protected server, Claude Code reads the server’s metadata document to determine the authorization endpoint, token endpoint, and supported scopes without any manual configuration. OAuth Client ID Metadata further streamlines this by letting servers publish their expected client identification, so Claude Code can present the right credentials during the authorization flow.
If a token expires and the automatic refresh fails, Claude Code will prompt you to reauthorize through the browser flow. This typically only happens if the server’s OAuth configuration changes or if the refresh token itself expires.
OAuth tokens are stored locally alongside your Claude Code configuration. They’re never committed to Git or shared with team members. Each developer goes through their own authorization flow the first time they connect to an OAuth-protected server.
Tool Search
When your MCP setup includes lots of servers with lots of tools, loading all of them into Claude Code’s context at once eats up a significant chunk of tokens. Tool search solves this by dynamically loading tools only when Claude Code actually needs them.
It kicks in automatically when context usage exceeds roughly 10% of the available window. At that point, Claude Code unloads MCP tools it isn’t actively using and maintains a search index instead. When a later prompt needs a tool that was unloaded, Claude Code searches the index and reloads the relevant tools transparently.
This is entirely automatic. You don’t need to configure or trigger tool search yourself. From your perspective, tools simply show up when Claude Code needs them.
If you want to control this behavior, the ENABLE_TOOL_SEARCH environment variable lets you toggle tool search on or off.
# Disable tool search (keep all tools loaded)ENABLE_TOOL_SEARCH=false claude
# Force tool search on (useful for debugging)ENABLE_TOOL_SEARCH=true claudeMost users never need to set this. The default auto-detection works well.
MCP Resources
Beyond tools, MCP servers can also expose resources. While tools are actions Claude Code can perform (run a query, create a ticket), resources are data sources it can reference (a database table, an API endpoint, a documentation page).
You reference MCP resources using @ mentions in your prompts.
Tell me about the schema of @database/usersThe @ syntax tells Claude Code to fetch data from the MCP resource.
Resources are read-only references. They give Claude Code additional context for its reasoning without triggering any tool calls. Not every MCP server exposes resources, as it depends on the server implementation. Check the server’s documentation to see what’s available.
The distinction between tools and resources matters because of what happens when you mention them. Referencing a resource with @ fetches data and adds it to context. Calling a tool executes an operation that may have side effects (inserting a database row, creating a ticket, sending a notification). Claude Code handles the distinction automatically. Just describe what you need and it’ll figure out the rest.
Elicitation
MCP servers can request structured input from you during tool execution through an interactive dialog. This capability, called elicitation, lets a server pause mid-operation, ask you a question, and use your response to continue. It’s the server’s way of gathering runtime information that shouldn’t be hardcoded in configuration.
When an MCP server sends an elicitation request, Claude Code presents it as an interactive form. You fill in the requested fields and submit. The server receives your response and continues its operation with that input. The whole exchange happens inline within the conversation flow.
Servers use elicitation when they need runtime decisions or context that varies between uses. Common scenarios include:
- Confirmation prompts before destructive operations (deleting records, overwriting files)
- Credential collection for services that require per-session authentication
- Configuration choices when a tool supports multiple modes or targets
- Disambiguation when a query matches multiple results and the server needs you to pick one
From the server author’s perspective, an elicitation request specifies a JSON Schema describing the expected input:
{ "method": "elicitation/create", "params": { "message": "Which database environment should this migration run against?", "requestedSchema": { "type": "object", "properties": { "environment": { "type": "string", "enum": ["development", "staging", "production"], "description": "Target database environment" }, "confirm": { "type": "boolean", "description": "Confirm you want to proceed" } }, "required": ["environment", "confirm"] } }}The server specifies a JSON Schema. Claude Code renders it as an interactive form.
There is nothing to configure on your end. Elicitation is automatic: if a connected MCP server sends an elicitation request, Claude Code handles the UI and routes your response back. The Elicitation and ElicitationResult hook events fire during this exchange, so you can add custom logic around elicitation requests through the hooks system if needed.
Managed MCP
If your organization needs to control which MCP servers developers can connect to, Claude Code supports managed MCP configuration. An administrator distributes a managed-mcp.json file that defines organizational servers and access policies.
{ "mcpServers": { "company-db": { "command": "npx", "args": ["@company/mcp-db"], "env": { "DB_HOST": "db.internal.company.com" } } }, "allowedMcpServers": [ "@company/*", "@mcp/postgres" ], "deniedMcpServers": [ "@mcp/shell-exec" ]}Distributed by administrators. Users cannot remove managed servers.
allowedMcpServers is a whitelist of server packages that developers are permitted to add. When it’s set, developers can only add servers matching these patterns.
deniedMcpServers is a blocklist of server packages that are explicitly forbidden, regardless of the allow list.
Managed servers (those defined in managed-mcp.json) can’t be removed or modified by individual users. They’re always available and always connected. This gives organizations control over which external integrations their developers use while still allowing approved additions.
Troubleshooting
When MCP servers aren’t behaving as expected, start with the /mcp status command inside an active Claude Code session.
/mcpThis shows each configured server with its current state: connected (running and responding), errored (started but hit a problem), or disconnected (not running). For errored servers, you’ll also see the error message.
Common Issues
Server not starting. Double-check that the command path is correct. If the server is an npm package, make sure it’s installed (npx will auto-install, but network issues can prevent this). Also verify that required environment variables are set.
# Verify the server command works outside Claude Codenpx @mcp/postgres postgresql://localhost/mydb
# Check environment variablesecho $DB_PASSWORDOutput too large. MCP tools have a maximum output size controlled by MAX_MCP_OUTPUT_TOKENS. If a tool returns more data than this limit allows, the output gets truncated. If you’re seeing incomplete results from an MCP tool, try bumping this limit up.
# Increase the maximum output size for MCP toolsMAX_MCP_OUTPUT_TOKENS=50000 claudeDefault is sufficient for most tools. Increase only if you see truncation.
Per-Tool Result-Size Caps
The global MAX_MCP_OUTPUT_TOKENS limit applies uniformly to every tool. But some tools legitimately return large results — a code search server returning full file contents, or a database tool exporting a large result set. MCP server authors can set a per-tool maximum result size using the _meta field in their tools/list response, overriding the global cap for specific tools.
The key is anthropic/maxResultSizeChars inside the tool’s _meta object. It accepts values up to 500,000 characters, giving server authors fine-grained control over which tools can return large payloads.
{ "tools": [ { "name": "search_codebase", "description": "Full-text search across the repository", "inputSchema": { "type": "object", "properties": { "query": { "type": "string" } } }, "_meta": { "anthropic/maxResultSizeChars": 200000 } } ]}Server authors set this in their tools/list response metadata. Users don't need to configure anything.
This is a server-side mechanism. As a user, you don’t need to configure per-tool caps. If you’re building or maintaining an MCP server and certain tools need larger output limits, set the _meta field in your tools/list response. Claude Code respects the per-tool cap automatically, falling back to the global MAX_MCP_OUTPUT_TOKENS for tools that don’t specify one.
Server timeout. If a server takes too long to respond, Claude Code times out the request. This usually points to a network issue (for HTTP servers) or a slow operation (for database queries). Check your network connectivity and consider whether the operation can be scoped more narrowly.
Authentication failures. For OAuth servers, try reauthenticating by running /mcp and following the auth flow again. For token-based auth, verify that the token is still valid and correctly set in your headers or environment variables.
Tool not appearing. If you added a server but its tools don’t show up, check that the server is connected via /mcp. If tool search is active (see the Tool Search section above), the tools may have been unloaded to save context. They’ll appear automatically when Claude Code determines they’re relevant to your prompt. You can also try explicitly mentioning the tool or server name in your prompt to nudge tool search into reloading it.
Configuration not loading. If you added a server via claude mcp add but it doesn’t show up in your next session, verify the scope matches your expectation. A server added with --scope project only appears when Claude Code runs from that project directory. Check ~/.claude.json for local servers and .mcp.json for project servers.
Environment Variables
Several environment variables give you additional control over MCP behavior.
| Variable | Purpose |
|---|---|
MAX_MCP_OUTPUT_TOKENS | Global maximum output size for all MCP tools. Increase if you see truncation. |
ENABLE_TOOL_SEARCH | Toggle automatic tool search on (true) or off (false). |
CLAUDE_CODE_MCP_SERVER_NAME | Override the display name of an MCP server. |
CLAUDE_CODE_MCP_SERVER_URL | Override the URL for an HTTP MCP server at runtime. |
MCP_CONNECTION_NONBLOCKING | Set to true for -p (print) mode so MCP connections don’t block the session. Useful in CI/CD pipelines where you don’t want a slow server to delay output. |
# Non-blocking MCP connections in print modeMCP_CONNECTION_NONBLOCKING=true claude -p "list all database tables"
# Override server URL at runtimeCLAUDE_CODE_MCP_SERVER_URL=https://staging.mcp.example.com claudeThese are most useful in CI/CD pipelines and scripted workflows.
Best Practices
-
Start with stdio for local development. It’s the simplest transport, requires no configuration, and works for the vast majority of use cases. Only move to HTTP when you need remote access or team sharing.
-
Use
.mcp.jsonfor team-shared servers. Commit the file to Git so every team member gets the same MCP configuration. Use${VAR}expansion for secrets to keep credentials out of version control. -
Use environment variable expansion for secrets. Never hardcode API keys, database passwords, or tokens in
.mcp.json. Stick with${VAR}syntax and document which environment variables each team member needs to set. -
Prefer HTTP over SSE for remote servers. SSE is deprecated and will be removed. All new remote server configurations should use HTTP transport.
-
Keep your MCP server count manageable. Each connected server and its tools eat into context window space. Only connect the servers you’re actively using for a project, and remove the ones you no longer need.
-
Verify connections with
/mcpbefore relying on tools. After adding or modifying server configurations, check that everything is connected before kicking off a task that depends on MCP tools. -
Scope servers appropriately. Use local scope for personal experimentation, project scope for team infrastructure, and user scope for personal tools you use across all projects.
Further Reading
- Model Context Protocol, official documentation on transports, scopes, OAuth, and managed MCP
- MCP Specification, the protocol specification and server registry
Next, learn how to create custom skills that extend Claude Code’s capabilities in Custom Skills.