Connecting MCP Servers
MCP (Model Context Protocol) is an open-source protocol that lets Claude Code communicate with external tools, databases, and APIs in a standardized way. Connecting MCP servers greatly extends Claude Code's built-in capabilities.
What Is MCP?โ
Out of the box, Claude Code can only work with the file system, the terminal, and web search. Connect MCP servers and you get:
- Databases โ query PostgreSQL, MySQL, SQLite directly
- External services โ integrate GitHub, Slack, Sentry, Notion, Jira
- Local tools โ browser automation, image processing, file conversion
- Custom tools โ connect your own internal systems
All of it happens through natural-language conversation with Claude.
Installing MCP Serversโ
MCP servers support three transport types:
HTTP Remote Servers (Recommended)โ
Recommended for connecting to cloud-based services:
# Basic syntax
claude mcp add --transport http <server-name> <URL>
# Example: connect Notion
claude mcp add --transport http notion https://mcp.notion.com/mcp
# Bearer token authentication
claude mcp add --transport http secure-api https://api.example.com/mcp \
--header "Authorization: Bearer your-token"
SSE Remote Serversโ
claude mcp add --transport sse asana https://mcp.asana.com/sse
The SSE transport is deprecated. Use HTTP servers where possible.
stdio Local Serversโ
Servers that run as a local process:
# Basic syntax
claude mcp add [options] <server-name> -- <command> [args...]
# Example: Airtable server
claude mcp add --transport stdio --env AIRTABLE_API_KEY=YOUR_KEY airtable \
-- npx -y airtable-mcp-server
All options (--transport, --env, --scope, --header) must come before the server name. The -- (double dash) separates the server name from the command to run.
On native Windows (not WSL), stdio servers that use npx need a cmd /c wrapper:
claude mcp add --transport stdio my-server -- cmd /c npx -y @some/package
Installation Scopeโ
| Scope | Stored in | Use case |
|---|---|---|
local (default) | ~/.claude.json (per project) | Personal servers, sensitive credentials |
project | .mcp.json (can be committed to git) | Team-shared servers |
user | ~/.claude.json (global) | Servers used across all projects |
# Add at project scope (team sharing)
claude mcp add --transport http paypal --scope project https://mcp.paypal.com/mcp
# Add at user scope (global)
claude mcp add --transport http hubspot --scope user https://mcp.hubspot.com/anthropic
Project-scoped servers are stored in .mcp.json and shared with your team. For security, an approval prompt appears on first use.
Environment Variable Expansion in .mcp.jsonโ
.mcp.json supports environment variables, so you can separate team-shared configuration from personal credentials:
{
"mcpServers": {
"api-server": {
"type": "http",
"url": "${API_BASE_URL:-https://api.example.com}/mcp",
"headers": {
"Authorization": "Bearer ${API_KEY}"
}
}
}
}
You can also specify defaults with ${VAR:-default}.
Managing Serversโ
# List registered servers
claude mcp list
# Details for a specific server
claude mcp get <server-name>
# Remove a server
claude mcp remove <server-name>
# Import from Claude Desktop (macOS/WSL)
claude mcp add-from-claude-desktop
# Add directly with JSON configuration
claude mcp add-json weather '{"type":"http","url":"https://api.weather.com/mcp"}'
# Check server status inside a session
/mcp
Dynamic Tool Updates (list_changed)โ
Claude Code supports the MCP list_changed notification. When an MCP server dynamically updates its available tools, prompts, or resources, Claude Code picks up the new capabilities automatically without reconnecting to the server.
claude.ai MCP Server Integrationโ
If you sign in to Claude Code with a claude.ai account, MCP servers added at claude.ai/settings/connectors are automatically available in Claude Code too. On Team/Enterprise plans, only administrators can add servers.
# Disable claude.ai MCP servers
ENABLE_CLAUDEAI_MCP_SERVERS=false claude
OAuth 2.0 Authenticationโ
Many cloud MCP servers require OAuth authentication:
-
Add the server:
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp -
Run the
/mcpcommand in a Claude Code session and complete the browser login.
Authentication tokens are stored securely and refreshed automatically. You can revoke access with "Clear authentication" in the /mcp menu.
Authenticating from the CLI โ claude mcp login / logoutโ
Starting with v2.1.186, you can authenticate MCP servers directly from the CLI without opening the interactive /mcp menu:
# Log in to a server (browser OAuth)
claude mcp login <server-name>
# Log out
claude mcp logout <server-name>
# Environments that can't open a browser (SSH, etc.) โ complete via stdin redirect
claude mcp login <server-name> --no-browser
--no-browser is especially useful when you cannot launch a browser, such as in SSH sessions or headless environments.
Pre-Configured OAuth Credentialsโ
Servers that don't support automatic OAuth provide credentials after you register an app in their developer portal. Pin the OAuth callback port with --callback-port so it matches the pre-registered redirect URI (http://localhost:PORT/callback):
# Pre-configured credentials + fixed callback port
claude mcp add --transport http \
--client-id your-client-id --client-secret --callback-port 8080 \
my-server https://mcp.example.com/mcp
# Dynamic client registration + fixed callback port only
claude mcp add --transport http \
--callback-port 8080 \
my-server https://mcp.example.com/mcp
Popular MCP Serversโ
Anthropic has not verified the security of every server. Only install servers you trust. Servers that fetch external content in particular carry prompt injection risk.
GitHubโ
claude mcp add --transport http github https://api.githubcopilot.com/mcp/
> Review PR #456 and suggest improvements
> Pull the issue list for this sprint and analyze priorities
Sentry (Error Monitoring)โ
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
# Authenticate via /mcp
> What are the most common errors in the last 24 hours?
> Show me the stack trace for error ID abc123
PostgreSQLโ
claude mcp add --transport stdio db -- npx -y @bytebase/dbhub \
--dsn "postgresql://readonly:pass@prod.db.com:5432/analytics"
> What is total revenue this month?
> Find customers who haven't purchased in 90 days
Filesystemโ
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"@modelcontextprotocol/server-filesystem",
"/Users/username/projects"
]
}
}
}
MCP Resources (@-mentions)โ
When an MCP server exposes resources, you can reference them with @ mentions:
> Analyze @github:issue://123 and suggest a fix
> Compare @postgres:schema://users with @docs:file://database/user-model
Typing @ in your prompt shows available resources in the autocomplete menu.
MCP Prompts (Commands)โ
When an MCP server exposes prompts, you can run them as slash commands:
> /mcp__github__list_prs
> /mcp__github__pr_review 456
> /mcp__jira__create_issue "Login bug" high
Typing / shows available MCP prompts alongside your other commands.
Tool Search (Managing Tools at Scale)โ
When you connect an MCP server, each server's tool definitions (names, descriptions, parameter schemas) are included in the context on every request. A single server can consume thousands of tokens, so connecting multiple servers leaves less context for your actual work.
Tool Search solves this. Instead of preloading every tool, Claude searches for tools dynamically only when it needs them.
It activates automatically when MCP tool descriptions exceed 10% of the context:
# Custom threshold (5%)
ENABLE_TOOL_SEARCH=auto:5 claude
# Always on
ENABLE_TOOL_SEARCH=true claude
# Disabled
ENABLE_TOOL_SEARCH=false claude
Using Claude Code as an MCP Serverโ
Claude Code itself can serve as an MCP server for other applications:
claude mcp serve
Add it to Claude Desktop's claude_desktop_config.json:
{
"mcpServers": {
"claude-code": {
"type": "stdio",
"command": "claude",
"args": ["mcp", "serve"]
}
}
}
Plugin-Provided MCP Serversโ
Plugins can bundle MCP servers, so tools become available automatically when the plugin is enabled. Define them in .mcp.json or plugin.json at the plugin root:
{
"mcpServers": {
"plugin-api": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/api-server",
"args": ["--port", "8080"]
}
}
}
Building a Custom MCP Serverโ
You can turn internal systems or custom tools into MCP servers.
Node.jsโ
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
const server = new Server(
{ name: 'my-custom-server', version: '1.0.0' },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'get_product_info',
description: 'Look up product info in the internal DB by product ID',
inputSchema: {
type: 'object',
properties: {
product_id: { type: 'string', description: 'Product ID' }
},
required: ['product_id']
}
}
]
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === 'get_product_info') {
const { product_id } = request.params.arguments;
const product = await fetchProductFromDB(product_id);
return {
content: [{ type: 'text', text: JSON.stringify(product) }]
};
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
Pythonโ
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
server = Server("my-python-server")
@server.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="query_analytics",
description="Query data from the internal analytics system",
inputSchema={
"type": "object",
"properties": {
"metric": {"type": "string"},
"date_range": {"type": "string"}
},
"required": ["metric"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
if name == "query_analytics":
result = await query_analytics_system(arguments)
return [TextContent(type="text", text=str(result))]
async def main():
async with stdio_server() as streams:
await server.run(
streams[0], streams[1],
server.create_initialization_options()
)
if __name__ == "__main__":
import asyncio
asyncio.run(main())
Managed MCP Configuration (Enterprise)โ
Organizations can centrally control MCP servers:
Method 1: managed-mcp.json (Exclusive Control)โ
Deploy it to the system path and users can only use the servers it defines:
| OS | Path |
|---|---|
| macOS | /Library/Application Support/ClaudeCode/managed-mcp.json |
| Linux | /etc/claude-code/managed-mcp.json |
| Windows | C:\Program Files\ClaudeCode\managed-mcp.json |
Method 2: Allow/Deny Lists (Policy-Based)โ
Control servers with allowedMcpServers and deniedMcpServers in managed settings:
{
"allowedMcpServers": [
{ "serverName": "github" },
{ "serverUrl": "https://mcp.company.com/*" }
],
"deniedMcpServers": [
{ "serverUrl": "https://*.untrusted.com/*" }
]
}
Restrictions can target server name (serverName), command (serverCommand), or URL pattern (serverUrl), and the deny list always takes precedence.
MCP vs. Skills: Division of Laborโ
MCP servers are best for connecting external systems, while Skills are best for automating repetitive workflows. The biggest difference between the two is context cost:
- MCP: just being connected puts tool definitions into the context on every request
- Skill: only the description is in context; the full content loads only when invoked
Prototype your external API integration quickly with MCP, then convert frequently used workflows into Skills to use your context more efficiently.
Session Guards (v2.1.212)โ
Safeguards were added to prevent one slow MCP server from holding the whole session hostage, or a tool call from spinning into an infinite loop.
Automatic backgrounding of long MCP calls
When an MCP tool call exceeds 2 minutes, it automatically moves to the background so you can keep using the session while waiting for the response. Adjust the threshold or disable it with the CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS environment variable.
# Raise the threshold to 5 minutes
CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS=300000 claude
Runaway caps
- WebSearch: 200 per session by default (adjust with
CLAUDE_CODE_MAX_WEB_SEARCHES_PER_SESSION) - Subagent creation: 200 per session by default (adjust with
CLAUDE_CODE_MAX_SUBAGENTS_PER_SESSION)./clearresets the budget
These exist to stop search loops or delegation loops from running out of control, so before raising a limit it's better to find the cause of the loop first.
Security Considerationsโ
- Use read-only accounts or apply the principle of least privilege
- Manage API tokens with environment variables (use the
${VAR}syntax in.mcp.json) - Add sensitive configuration files to
.gitignore - Output size limit: 25,000 tokens by default (adjust with
MAX_MCP_OUTPUT_TOKENS) - Startup timeout: adjust with the
MCP_TIMEOUTenvironment variable (default 60 seconds)