MCP(模型上下文协议)
MCP 将 Claude Code 连接到外部工具和服务。实现跨越 src/services/mcp/ 中的 23 个文件,支持 4 种传输类型、2 种认证流程、6 种配置范围和完整的企业策略系统。
mcp__<server>__<tool>。
[a-zA-Z0-9_-] 之外的字符替换为 _,
最多 64 个字符。此前缀用于允许/拒绝权限规则。
架构
| 组件 | 文件 | 用途 |
|---|---|---|
| Client | client.ts (~3,400 lines) | 连接、传输创建、工具包装、工具调用 |
| Config | config.ts (~800 lines) | 从所有范围加载配置 |
| Auth | auth.ts (~1,200 lines) | OAuth + XAA 认证流程 |
| XAA | xaa.ts (512 lines) | 跨应用访问协议 (RFC 8693 + RFC 7523) |
| Normalization | normalization.ts | mcp__ 前缀的名称规范化 |
| Env Expansion | envExpansion.ts | 配置中的 ${VAR} 和 ${VAR:-default} 展开 |
| In-Process | InProcessTransport.ts | 进程内服务器的链接传输对(Chrome、Computer Use) |
| Elicitation | elicitationHandler.ts | MCP elicitation 请求处理器(基于 URL 的认证提示) |
| MCPTool | src/tools/MCPTool/ | 每个暴露给模型的 MCP 工具克隆的基础模板 |
| McpAuthTool | src/tools/McpAuthTool/ | 需要认证的服务器的伪工具 |
配置范围(优先级顺序)
服务器从 6 个源加载。当名称冲突时,更高优先级覆盖更低优先级。
企业范围是排他的:如果 managed-mcp.json 存在,
所有其他范围都被忽略。
| # | 范围 | 来源 | 说明 |
|---|---|---|---|
| 1 | claudeai | API fetch | Claude.ai 组织连接器(最低优先级) |
| 2 | plugin | dynamic | 来自已安装插件的服务器 |
| 3 | user | ~/.claude/settings.json | 全局用户配置 |
| 4 | project | .mcp.json | 向上遍历目录树到主目录 |
| 5 | local | .claude/settings.local.json | 私有项目配置(不提交) |
| 6 | enterprise | managed-mcp.json | 排他性:此文件存在时忽略所有其他范围 |
项目配置示例(.mcp.json)
{
"mcpServers": {
"github": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
},
"my-api": {
"type": "sse",
"url": "https://example.com/mcp/sse",
"headers": { "Authorization": "Bearer ${API_TOKEN}" }
}
}
}
All config fields support ${VAR} and
${VAR:-default} expansion.
Servers in .mcp.json require explicit user approval before connecting
(stored in enabledMcpjsonServers in settings).
传输类型
启动通过 stdin/stdout 通信的子进程。最常见的传输方式。type 字段可选以保持向后兼容性。
Stderr 用于调试(上限 64MB)。Chrome 和 Computer Use 服务器使用进程内优化以避免约 325MB 的子进程开销。
长连接 EventSource 连接。流无超时;单个 HTTP 请求有 60 秒超时。
支持基于浏览器的 OAuth 流程。支持 headersHelper 脚本用于动态认证头。
实现 MCP 2025-03-26 Streamable HTTP 协议。自动添加 Accept: application/json, text/event-stream。
通过 session ID 支持会话管理。支持 OAuth 认证。
WebSocket 传输。支持 Bun 和 Node.js 运行时。协议:["mcp"]。
支持代理和 TLS 选项。Headers 可配置。
连接生命周期
启动
Load configs from all scopes (enterprise takes exclusive control if present)
Deduplicate servers by signature (URL for remote, command for stdio)
Filter by enterprise allow/deny policies
Check project server approval status
Connect local servers (concurrency: 3) and remote servers (concurrency: 20) in parallel
On auth failure: cache 15 min, create McpAuthTool pseudo-tool
On success: fetch tools, commands, and resources in parallel
工具调用流程
Model outputs tool_use block with name "mcp__server__tool"
ensureConnectedClient() verifies or reconnects if cache was cleared
Permission check via standard permission system (passthrough by default)
callMCPTool() with timeout, checks isError flag in response
processMCPResult(): if output > 100,000 chars, saves to temp file and returns Read instructions
On URL elicitation error (-32042): retries up to 3 times
关闭
Stdio servers
SIGINT → 100ms → SIGTERM → 400ms → SIGKILL
Total failsafe: 600ms maximum
Remote servers
client.close() → closes transport, rejects pending requests
认证
Browser-based OAuth with automatic token storage in the OS keychain, keyed by server name and config hash. Auto-refreshes on 401. Supports step-up (403 with scope) and revocation (RFC 7009).
"oauth": {
"clientId": "my-app",
"callbackPort": 8080,
"authServerMetadataUrl": "https://auth.example.com/.well-known/..."
}
Enterprise SSO flow using RFC 8693 token exchange and RFC 7523 JWT Bearer grant.
Enabled with CLAUDE_CODE_ENABLE_XAA=1.
Key benefit: a single browser popup authenticates N MCP servers (cached id_token is reused).
Flow: PRM Discovery → AS Metadata → id_token → ID-JAG → access_token
When a server fails to connect due to auth, a pseudo-tool named
mcp__<server>__authenticate is created.
When the model calls it, the OAuth flow starts, and upon completion the real tools replace the pseudo-tool.
Always auto-approved (no user permission prompt). Auth failure is cached for 15 minutes.
工具暴露
命名示例
| Server name | Tool name | Exposed as |
|---|---|---|
| github | create_issue | mcp__github__create_issue |
| slack | search_public | mcp__slack__search_public |
| My Server! | do-thing | mcp__My_Server___do_thing |
工具注解(来自 MCP 规范)
| Annotation | Property | Effect |
|---|---|---|
| readOnlyHint | isConcurrencySafe, isReadOnly | 工具可并行运行,视为只读 |
| destructiveHint | isDestructive | 权限提示中的更高风险信号 |
| openWorldHint | isOpenWorld | 工具可访问外部系统 |
| _meta.anthropic/searchHint | searchHint | 工具被延迟(不加载到上下文直到搜索) |
| _meta.anthropic/alwaysLoad | alwaysLoad | 工具绕过延迟,始终在上下文中 |
Tool descriptions are capped at 2048 characters.
When output exceeds 100,000 characters, it is saved to a temp file
and the model receives instructions to use the Read tool.
权限系统
All MCP tools return checkPermissions() → passthrough.
This means in default mode the user is always prompted,
in bypassPermissions mode they are auto-approved,
and in auto mode the YOLO classifier decides.
用户权限规则
{
"permissions": {
"allow": [
"mcp__github__search_code",
"mcp__slack__*"
],
"deny": [
"mcp__untrusted_server__*"
]
}
} 企业服务器策略(managed-mcp.json)
{
"allowedMcpServers": [
{ "serverName": "github" },
{ "serverUrl": "https://*.company.com/*" },
{ "serverCommand": ["npx", "-y", "@company/mcp-*"] }
],
"deniedMcpServers": [
{ "serverName": "untrusted" }
]
} Denylist always takes precedence over allowlist.
CLI 命令
# Add a stdio server (default scope: local)
claude mcp add my-server npx -y @org/mcp-server
-s, --scope <scope> # local, user, or project
-e, --env KEY=VALUE # environment variables
# Add a remote server (transport auto-detected from URL)
claude mcp add my-api https://api.example.com/mcp
-t, --transport sse|http
-H, --header "Key: Value"
--client-id <id> # OAuth client ID
--xaa # Enable Cross-App Access
# Add with full JSON config
claude mcp add-json my-server '{"type":"http","url":"https://example.com/mcp"}'
# Other operations
claude mcp remove my-server [-s scope]
claude mcp list
claude mcp get my-server /mcp 斜杠命令
| Subcommand | Description |
|---|---|
| /mcp | 打开 MCP 设置 UI |
| /mcp enable [name|all] | 启用服务器 |
| /mcp disable [name|all] | 禁用服务器 |
| /mcp reconnect <name> | 重新连接特定服务器(清除缓存,新连接) |
高级功能
Headers helper script
Set headersHelper to a script path. The script receives the server name and URL as env vars and must output JSON headers. Runs with 10s timeout. Dynamic headers override static ones.
MCP resources
Servers can expose resources (files, data) via ListMcpResourcesTool and ReadMcpResourceTool. Both are deferred tools. Blob resources are base64-decoded and written to disk.
MCP prompts as commands
Server-exposed prompts become slash commands (mcp__server__prompt-name). Arguments are parsed from the prompt's argument schema and passed to client.getPrompt().
Agent-specific servers
Agents can reference existing servers by name (shared) or define inline servers (cleaned up when the agent finishes). Required servers are declared and must be configured.
Server instructions
Servers provide usage instructions during handshake (truncated at 2048 chars). Injected as a system prompt section each turn. Delta mode (feature-gated) avoids cache invalidation.
In-process transport
Chrome and Computer Use servers run in-process via InProcessTransport, avoiding ~325MB subprocess overhead. Uses linked transport pairs with queueMicrotask() delivery.
关键常量和超时
| Variable / Constant | Value | Purpose |
|---|---|---|
| MCP_TIMEOUT | 30,000ms | 每个服务器的连接超时 |
| MCP_TOOL_TIMEOUT | 100,000,000ms (~27.8h) | 工具调用超时(实际上无限) |
| MCP_REQUEST_TIMEOUT_MS | 60,000ms | 每个 HTTP 请求超时(SSE/HTTP) |
| MAX_MCP_OUTPUT_TOKENS | 25,000 | 工具输出中的最大 token |
| maxResultSizeChars | 100,000 chars | 保存到文件前的输出大小上限 |
| MAX_MCP_DESCRIPTION_LENGTH | 2048 chars | 工具描述上限 |
| MCP_AUTH_CACHE_TTL_MS | 15 min | needs-auth 缓存持续时间 |
| MCP_FETCH_CACHE_SIZE | 20 | 工具/资源/命令的 LRU 缓存大小 |
| local concurrency | 3 | 同时本地(stdio)服务器连接 |
| remote concurrency | 20 | 同时远程服务器连接 |
| MAX_ERRORS_BEFORE_RECONNECT | 3 | 重新连接前的终端错误 |
| MAX_URL_ELICITATION_RETRIES | 3 | URL elicitation (-32042) 重试 |
MCP_TIMEOUT, MCP_TOOL_TIMEOUT, and MAX_MCP_OUTPUT_TOKENS are in the SAFE_ENV_VARS set: they can be set via managed settings without triggering a security dialog.
错误处理
| Error type | Handling |
|---|---|
| 连接超时(30s) | 服务器标记为失败 |
| 认证错误(401) | 缓存为 needs-auth 15 分钟,创建 McpAuthTool |
| ECONNRESET / ETIMEDOUT / EPIPE | 计数:3 个连续错误关闭传输 |
| ECONNREFUSED / EHOSTUNREACH | 终端错误,立即关闭传输 |
| 会话过期(404 + -32001) | 清除缓存,自动重试一次 |
| URL elicitation (-32042) | 向用户显示 URL 对话框,最多重试 3 次 |
.mcp.json 中的服务器在连接前需要明确批准 — 在设置中使用
enableAllProjectMcpServers: true 批量批准。
第二:你可以使用通配符权限规则如 mcp__slack__* 来允许整个服务器而无需批准每个工具。
第三:MCP 工具超时实际上是无限的(约 27.8 小时)— 如果工具似乎卡住了,使用 /mcp reconnect server-name 强制重新连接。