Skip to main content

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:

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
SSE is being deprecated

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
Option order

All options (--transport, --env, --scope, --header) must come before the server name. The -- (double dash) separates the server name from the command to run.

Windows users

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โ€‹

ScopeStored inUse 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:

  1. Add the server:

    claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
  2. Run the /mcp command 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
Beware of third-party 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:

OSPath
macOS/Library/Application Support/ClaudeCode/managed-mcp.json
Linux/etc/claude-code/managed-mcp.json
WindowsC:\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). /clear resets 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โ€‹

Managing MCP server permissions
  • 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_TIMEOUT environment variable (default 60 seconds)