Claude Code 通过 MCPTool 实现了对 Model Context Protocol(MCP)的深度集成,使其能够连接外部 MCP 服务器并动态获取工具、资源和命令。这种架构将 Claude Code 从一个封闭的工具系统转变为一个开放的、可扩展的代理平台,允许用户通过配置文件集成任意第三方服务和能力,同时保持统一的权限模型和错误处理机制。
Sources: MCPTool.ts, client.ts
核心架构:从协议到工具的映射
MCPTool 采用动态适配器模式:基础 MCPTool 类只是一个模板,实际运行时会被 MCP 服务器的具体工具定义覆盖。这种设计允许 Claude Code 在启动时从连接的 MCP 服务器动态发现工具,并将它们转换为内部 Tool 接口,无需硬编码任何服务器特定的逻辑。
整个 MCP 集成系统分为三个核心层:连接管理层(负责建立和维护与 MCP 服务器的通信)、协议适配层(将 MCP 协议的对象模型转换为 Claude Code 的 Tool/Command/Resource 模型)、执行层(处理工具调用、资源读取和用户交互)。每一层都通过依赖注入和回调机制解耦,使得添加新的传输协议或认证方式无需修改核心逻辑。
Sources: MCPTool.ts, client.ts
架构层次与数据流
graph TB
subgraph "应用层"
A[QueryEngine] --> B[Tool Registry]
B --> C{Tool Type?}
end
subgraph "MCP 适配层"
C -->|MCP Tool| D[fetchToolsForClient]
C -->|MCP Resource| E[fetchResourcesForClient]
C -->|MCP Command| F[fetchCommandsForClient]
D --> G[Tool Discovery]
E --> H[Resource Discovery]
F --> I[Prompt Discovery]
end
subgraph "连接管理层"
G --> J[connectToServer]
H --> J
I --> J
J --> K{Transport Type?}
K -->|stdio| L[StdioClientTransport]
K -->|sse| M[SSEClientTransport]
K -->|http| N[StreamableHTTPClientTransport]
K -->|ws| O[WebSocketTransport]
K -->|sdk| P[SdkControlClientTransport]
end
subgraph "协议层"
L --> Q[MCP SDK Client]
M --> Q
N --> Q
O --> Q
P --> Q
Q --> R[tools/list]
Q --> S[resources/list]
Q --> T[prompts/list]
end
subgraph "外部服务"
R --> U[MCP Server 1]
S --> V[MCP Server 2]
T --> W[MCP Server N]
end
style A fill:#e1f5ff
style D fill:#fff4e6
style J fill:#f3e5f5
style Q fill:#e8f5e9
协议适配过程发生在 fetchToolsForClient 函数中:当 MCP 服务器通过 tools/list 请求返回工具列表时,每个工具定义(包含 name、description、inputSchema、annotations)被转换为一个完整的 Tool 对象。这个转换过程会保留 MCP 服务器的元数据(如 readOnlyHint、destructiveHint),同时注入 Claude Code 特定的功能(如权限检查、进度报告、结果截断)。关键的是,call 方法被覆盖为通过 MCP 客户端发送 tools/call 请求,并将结果转换回 Claude Code 的格式。
连接管理:多传输协议支持
Claude Code 支持五种传输协议连接 MCP 服务器,每种协议针对不同的部署场景优化:stdio 用于本地进程通信(最常见,适合命令行工具封装)、SSE 用于服务器推送事件(适合 Web 服务)、HTTP 用于可流式传输的 HTTP(适合 REST API)、WebSocket 用于双向实时通信(适合 IDE 集成)、SDK 用于进程内直接调用(适合插件系统)。所有传输层都实现了 MCP SDK 的 Transport 接口,确保协议层的统一性。
连接生命周期通过 connectToServer 函数管理,该函数使用记忆化缓存避免重复连接同一服务器。缓存键由服务器名称和配置对象生成,当配置变更时缓存自动失效。连接建立后会注册清理回调,确保进程退出时正确关闭所有 MCP 服务器(特别是 stdio 传输需要终止子进程)。连接超时默认 60 秒,可通过环境变量 MCP_CONNECTION_TIMEOUT_MS 调整。
传输协议对比
| 协议类型 | 配置字段 | 适用场景 | 认证方式 | 性能特征 |
|---|---|---|---|---|
| stdio | command, args, env | 本地 CLI 工具、脚本封装 | 进程继承 | 低延迟、高吞吐 |
| SSE | url, headers, oauth | Web 服务、远程 API | OAuth 2.0、Bearer Token | 服务器推送、长连接 |
| HTTP | url, headers, oauth | REST API、微服务 | OAuth 2.0、自定义头部 | 请求-响应、可流式 |
| WebSocket | url, headers | IDE 集成、实时协作 | Token、mTLS | 全双工、低延迟 |
| SDK | name | 进程内插件、扩展 | 无需认证 | 零网络开销 |
连接失败处理采用分层策略:首先捕获 MCP SDK 抛出的协议错误(如 McpError),然后将其转换为 TelemetrySafeError 以避免敏感信息泄露到遥测系统。对于 stdio 传输,还会捕获子进程的 stderr 输出并记录到调试日志,帮助诊断启动失败。连接成功后,会立即预取工具、资源和命令列表并缓存,减少后续调用的延迟。
工具发现与动态注册
工具发现是 MCP 集成的核心功能,通过 fetchToolsForClient 函数实现。该函数首先检查服务器的 capabilities.tools 能力声明,如果支持则发送 tools/list 请求获取工具列表。每个 MCP 工具定义包含:name(工具标识符)、description(人类可读描述)、inputSchema(JSON Schema 格式的参数定义)、annotations(可选的元数据,如 readOnlyHint、destructiveHint、openWorldHint)。
转换过程会深度定制基础 MCPTool 的每个方法:name 字段使用 mcp__<server>__<tool> 格式避免冲突(可通过环境变量 CLAUDE_AGENT_SDK_MCP_NO_PREFIX 禁用前缀),description 和 prompt 直接使用 MCP 服务器的定义(超过 2000 字符会被截断),inputJSONSchema 直接传递 MCP 的 JSON Schema,checkPermissions 返回带有自动规则建议的 passthrough 行为。最关键的是 call 方法的覆盖:它通过 MCP 客户端发送 tools/call 请求,支持进度回调和 elicitation 重试。
Sources: client.ts, MCPTool.ts
工具调用流程
sequenceDiagram
participant QE as QueryEngine
participant Tool as MCPTool Instance
participant Client as MCP Client
participant Server as MCP Server
QE->>Tool: call(args, context)
Tool->>Tool: extractToolUseId(parentMessage)
Tool->>Tool: emit progress(started)
loop Session Retry (max 1)
Tool->>Client: ensureConnectedClient()
Client->>Client: check cache
alt Cache miss/expired
Client->>Server: reconnect via Transport
Server-->>Client: connection ack
end
Tool->>Client: callMCPToolWithUrlElicitationRetry()
Client->>Server: tools/call request
alt Elicitation needed
Server-->>Client: elicitation request
Client->>QE: handleElicitation()
QE->>QE: show dialog to user
QE-->>Client: user response
Client->>Server: elicitation response
end
Server-->>Client: tool result
Client-->>Tool: mcpResult
alt Session expired
Tool->>Tool: clear cache, retry
else Success
Tool->>Tool: emit progress(completed)
Tool-->>QE: {data, mcpMeta}
end
end
工具过滤机制通过 isIncludedMcpTool 函数实现,允许用户通过配置文件排除特定的 MCP 工具。过滤发生在工具注册阶段,不会影响 MCP 服务器本身。工具的 searchHint 字段从 MCP 工具的 _meta.anthropic/searchHint 元数据中提取,用于改进工具搜索的相关性排序。alwaysLoad 标记(来自 _meta.anthropic/alwaysLoad)会强制工具始终加载到上下文中,即使自动分类器认为它不相关。
资源管理:暴露外部数据源
MCP 资源允许服务器暴露可读的数据源(如文件系统、数据库、API 端点),Claude Code 通过 ListMcpResourcesTool 和 ReadMcpResourceTool 两个内置工具访问它们。资源发现通过 fetchResourcesForClient 函数实现,该函数发送 resources/list 请求获取资源列表,每个资源包含 uri(唯一标识符)、name(显示名称)、description(可选描述)、mimeType(可选 MIME 类型)。
ListMcpResourcesTool 接受可选的 server 参数过滤特定服务器的资源,返回所有匹配资源的元数据数组。ReadMcpResourceTool 则通过 server 和 uri 参数读取具体资源内容,支持文本和二进制数据。对于二进制资源(如图片、PDF),内容会被保存到临时文件,工具结果中返回文件路径而非原始数据,避免在上下文中占用大量 token。
Sources: ListMcpResourcesTool.ts, ReadMcpResourceTool.ts
资源读取与二进制处理
flowchart TD
A[ReadMcpResourceTool.call] --> B{Resource Type?}
B -->|Text| C[Return text content]
C --> D[Direct inclusion in context]
B -->|Binary| E[Read blob data]
E --> F[Determine MIME type]
F --> G{Size check}
G -->|< 10MB| H[Save to tool-results directory]
G -->|>= 10MB| I[Reject with error]
H --> J[Generate file path]
J --> K[Return path + metadata]
K --> L[Claude uses FileReadTool]
style A fill:#e1f5ff
style E fill:#fff4e6
style H fill:#e8f5e9
资源缓存策略使用 LRU 缓存(最多 20 个服务器),缓存键为服务器名称。当服务器断开连接时(触发 onclose 回调),缓存会被清除以确保重新连接后获取最新资源列表。资源工具本身也会被动态添加:如果没有任何 MCP 服务器提供资源工具,Claude Code 会自动添加 ListMcpResourcesTool 和 ReadMcpResourceTool 到工具注册表中。
Sources: client.ts, mcpOutputStorage.ts
命令集成:MCP Prompts 作为斜杠命令
MCP 服务器的 prompts 能力允许服务器提供预定义的提示模板,Claude Code 将它们转换为斜杠命令。转换过程在 fetchCommandsForClient 函数中实现:发送 prompts/list 请求获取提示列表,每个提示包含 name(命令标识符)、description(命令描述)、arguments(可选参数列表)。
转换后的命令名称格式为 /mcp__<server>__<prompt>,参数通过空格分隔传递。当用户执行命令时,getPromptForCommand 方法会被调用,它发送 prompts/get 请求到 MCP 服务器,传递提示名称和参数。服务器返回的 messages 数组(包含角色和内容)会被转换为 Claude Code 的消息格式并注入到对话上下文中。
Sources: client.ts, useManageMCPConnections.ts
命令生命周期
stateDiagram-v2
[*] --> Discovery: prompts/list request
Discovery --> Registration: Convert to Command
Registration --> Registry: Add to command registry
Registry --> Invocation: User types /mcp__server__prompt
Invocation --> ParameterParsing: Parse arguments
ParameterParsing --> ServerRequest: prompts/get request
ServerRequest --> ResponseTransform: Receive messages
ResponseTransform --> ContextInjection: Convert to MessageParam
ContextInjection --> [*]: Messages in conversation
note right of Discovery
Cached by server name
LRU size: 20 servers
end note
note right of ServerRequest
Supports dynamic content
Server can generate based on args
end note
动态命令更新通过 MCP 的 notifications/prompts/list_changed 通知实现。当服务器提示列表变更时,Claude Code 会收到通知并重新获取命令列表,更新命令注册表。这种机制允许 MCP 服务器根据上下文动态调整可用命令,例如基于用户权限或当前项目状态显示不同的命令集。
Sources: useManageMCPConnections.ts, client.ts
认证与安全:OAuth 2.0 和跨应用访问
MCP 集成支持多种认证机制,最复杂的是 OAuth 2.0 授权码流程,通过 ClaudeAuthProvider 类实现。该类实现了 MCP SDK 的 OAuthClientProvider 接口,负责发现授权服务器元数据、启动浏览器授权流程、接收回调、交换令牌和自动刷新。令牌存储在 macOS Keychain 或加密的文件存储中,确保安全性。
跨应用访问 是一个高级特性,允许 MCP 服务器通过用户的企业身份提供商(IdP)访问其他应用程序。配置非常简单:只需在 MCP 服务器配置中设置 oauth.xaa: true,Claude Code 会自动处理 OIDC 登录、ID Token 获取和令牌交换。XAA 配置(IdP issuer、clientId)是全局的,存储在 settings 中,避免为每个服务器重复配置。
OAuth 流程与令牌管理
sequenceDiagram
participant Client as MCP Client
participant Auth as ClaudeAuthProvider
participant Storage as Secure Storage
participant Browser as User Browser
participant AS as Authorization Server
Client->>Auth: tokens() - get cached tokens
Auth->>Storage: read tokens
Storage-->>Auth: null (first time)
Auth-->>Client: null
Client->>Auth: clientInformation() - discover
Auth->>AS: GET /.well-known/oauth-authorization-server
AS-->>Auth: {authorization_endpoint, token_endpoint}
Auth-->>Client: client metadata
Client->>Auth: authorize() - start flow
Auth->>Auth: generate PKCE challenge
Auth->>Browser: open authorization URL
Browser->>AS: user login & consent
AS-->>Browser: redirect to localhost
Browser->>Auth: callback with auth code
Auth->>AS: exchange code for tokens
AS-->>Auth: {access_token, refresh_token}
Auth->>Storage: save tokens
Auth-->>Client: authorization complete
Note over Client,AS: Later - token refresh
Client->>Auth: tokens() - expired
Auth->>Storage: read refresh_token
Auth->>AS: refresh token request
AS-->>Auth: new access_token
Auth->>Storage: update tokens
Auth-->>Client: fresh tokens
令牌刷新策略采用指数退避重试机制:当收到 401 错误时,AuthProvider 会尝试刷新令牌,最多重试 3 次,每次间隔加倍(1s、2s、4s)。刷新失败会触发 needs-auth 状态,提示用户重新授权。所有 OAuth 参数(state、code_verifier)都会被安全地清理,避免日志泄露敏感信息。
Sources: auth.ts, xaaIdpLogin.ts
Elicitation:服务器发起的用户交互
Elicitation 是 MCP 的一个独特能力,允许服务器在工具执行过程中请求用户输入或确认。这通过 ElicitRequestSchema 请求处理器实现,支持两种模式:表单模式(服务器定义输入字段,Claude Code 渲染表单)和 URL 模式(服务器提供 URL,用户在浏览器中完成操作后通知服务器)。
URL 模式的 elicitation 特别适合 OAuth 授权或外部服务集成:服务器返回一个 URL 和 elicitationId,Claude Code 显示该 URL 并等待用户完成操作。用户可以在浏览器中登录第三方服务,完成后服务器会发送 ElicitationCompleteNotification,触发 Claude Code 继续工具执行。这种机制避免了在 CLI 中处理复杂的 Web 流程。
Sources: elicitationHandler.ts, client.ts
Elicitation 交互模式
flowchart LR
A[Tool Call] --> B{Elicitation Type?}
B -->|Form| C[Server defines fields]
C --> D[Claude renders form]
D --> E[User fills inputs]
E --> F[Submit to server]
F --> G[Continue execution]
B -->|URL| H[Server provides URL]
H --> I[Display URL to user]
I --> J[User opens in browser]
J --> K[Complete external action]
K --> L[Server sends completion]
L --> M[Resume tool call]
style A fill:#e1f5ff
style D fill:#fff4e6
style I fill:#e8f5e9
Elicitation 超时和重试由客户端控制:URL 模式默认等待 5 分钟,用户可以通过界面取消或重试。表单模式支持验证,服务器可以在用户提交后返回错误消息,要求重新输入。所有 elicitation 请求都通过 handleElicitation 回调传递给上层,允许 Claude Code 在不同环境(CLI、IDE、Desktop)中以最适合的方式渲染交互界面。
Sources: elicitationHandler.ts, client.ts
输出处理:验证、截断与持久化
MCP 工具的输出可能非常大(如数据库查询结果、文件列表),因此需要智能的截断和持久化策略。输出处理分为三个阶段:首先通过 getContentSizeEstimate 估算 token 数量(文本使用快速估计算法,图片固定 1600 tokens),然后检查是否超过 MAX_MCP_OUTPUT_TOKENS 限制(默认 25000,可通过环境变量或 GrowthBook 特性标志调整),最后根据内容类型选择截断或持久化。
对于文本输出,直接截断到字符限制(token 数 × 4),并附加截断消息提示用户使用分页工具。对于结构化内容(ContentBlock 数组),逐块累积直到达到限制,图片块会被压缩(通过 compressImageBlock)以减少 token 占用。对于二进制数据(如 PDF、图片),内容会保存到 ~/.claude/tool-results/ 目录,工具结果中只返回文件路径和元数据。
Sources: mcpValidation.ts, mcpOutputStorage.ts
输出处理决策树
| 输出类型 | Token 估算 | 超限处理 | 存储位置 | 后续操作 |
|---|---|---|---|---|
| 纯文本 | 字符数 / 4 | 截断 + 提示 | 内存中 | 使用分页工具重试 |
| 结构化内容 | 逐块累积 | 截断 + 图片压缩 | 内存中 | 检查 structuredContent |
| 二进制数据 | MIME 类型推断 | 持久化到文件 | tool-results 目录 | 使用 FileReadTool 读取 |
| 图片 | 固定 1600 | 压缩或持久化 | 内存或文件 | 直接显示或读取 |
持久化文件命名使用模式 {server}_{tool}_{timestamp}.{ext},扩展名根据 MIME 类型推断(如 application/pdf → .pdf)。文件保存后会生成使用说明,指导 Claude 使用 offset 和 limit 参数分块读取,避免一次性加载大文件。所有持久化文件会在会话结束时自动清理。
Sources: mcpValidation.ts, mcpOutputStorage.ts
错误处理与重连机制
MCP 集成的错误处理采用多层防御策略:协议层捕获 MCP SDK 的 McpError(包含 JSON-RPC 错误码如 -32000 ConnectionClosed),适配层将其转换为 TelemetrySafeError 以避免敏感信息泄露,应用层提供用户友好的错误消息和重试选项。错误分类通过构造函数名称和错误码实现,确保遥测数据的隐私安全性。
会话过期重试是关键机制:某些 MCP 服务器(如基于会话的 Web 服务)会在长时间不活动后使会话失效,返回特定的错误码。Claude Code 检测到这类错误后会清除连接缓存,重新建立连接,并自动重试工具调用(最多 1 次)。这种机制对用户透明,避免了手动重连的繁琐。
Sources: client.ts, MCPTool.ts
错误处理流程
flowchart TD
A[Tool Call Error] --> B{Error Type?}
B -->|McpError| C{Error Code?}
C -->|-32042 Session Expired| D[Clear connection cache]
D --> E[Retry once]
E --> F{Retry succeeded?}
F -->|Yes| G[Return result]
F -->|No| H[Throw TelemetrySafeError]
C -->|Other codes| I[Extract error message]
I --> J[Sanitize for telemetry]
J --> H
B -->|Network Error| K[Log to debug]
K --> L[Show connection hint]
L --> H
B -->|Auth Error| M[Update server status]
M --> N[Show auth prompt]
N --> O[User re-authorizes]
O --> E
style A fill:#ffebee
style H fill:#e1f5ff
style G fill:#e8f5e9
连接状态监控通过 Transport 的 onclose 回调实现:当底层连接断开时(如 stdio 子进程退出、WebSocket 连接丢失),缓存会被清除,下次工具调用时会自动重连。UI 层通过 MCPConnectionManager React Context 提供重连和切换服务器的功能,用户可以手动触发重连或禁用故障服务器。
Sources: client.ts, useManageMCPConnections.ts
性能优化:缓存与批处理
MCP 集成的性能优化集中在三个关键点:连接缓存(避免重复建立连接)、资源预取(启动时并行获取所有服务器的工具/资源/命令)、批处理启动(并发连接多个服务器,避免顺序等待)。这些优化使得即使配置了 10+ MCP 服务器,启动时间也能保持在可接受范围内。
connectToServer 函数使用 memoize 高阶函数缓存连接结果,缓存键由服务器名称和配置对象序列化生成。当配置变更时(如环境变量更新、OAuth 令牌刷新),缓存会自动失效。fetchToolsForClient、fetchResourcesForClient、fetchCommandsForClient 三个函数使用 LRU 缓存(大小 20),确保频繁访问的服务器数据在内存中,减少重复请求。
启动性能优化策略
graph LR
A[App Startup] --> B[Load MCP Configs]
B --> C[Partition servers]
C --> D[Disabled servers]
C --> E[Active servers]
E --> F[Batch connect - concurrency 20]
F --> G1[Server 1: connect]
F --> G2[Server 2: connect]
F --> G3[Server N: connect]
G1 --> H1[Prefetch: tools+resources+commands]
G2 --> H2[Prefetch: tools+resources+commands]
G3 --> H3[Prefetch: tools+resources+commands]
H1 --> I[Merge to registry]
H2 --> I
H3 --> I
I --> J[App ready]
style F fill:#fff4e6
style I fill:#e8f5e9
并发连接控制通过 pMap 库实现,默认并发度为 20。这比传统的固定批次处理更高效:每个连接完成后立即释放槽位,避免慢速服务器阻塞整个批次。连接超时(60 秒)确保即使某个服务器无响应,也不会无限期阻塞启动。所有连接和预取操作都并行执行,最大化利用网络和 CPU 资源。
Sources: client.ts, useManageMCPConnections.ts
配置管理:多层级配置合并
MCP 配置支持六个作用域,按优先级从低到高:managed(企业强制配置)、enterprise(企业管理配置)、user(全局用户配置)、project(项目级配置)、dynamic(运行时动态配置)、local(.mcp.json 文件)。配置合并时,高优先级配置会覆盖低优先级的同名服务器,但不同名服务器会合并。
配置来源包括:~/.config/claude-code/settings.json 的 mcpServers 字段(user 作用域)、项目根目录的 .claude/settings.json(project 作用域)、项目根目录的 .mcp.json(local 作用域)、企业管理的 managed-mcp.json(managed 作用域)、Claude.ai 的远程配置(claudeai 作用域)、插件提供的 MCP 服务器(pluginSource 字段标记来源)。
配置作用域与合并规则
| 作用域 | 存储位置 | 优先级 | 可修改性 | 适用场景 |
|---|---|---|---|---|
| managed | ~/.claude/managed/managed-mcp.json | 最低(1) | 只读 | 企业强制策略 |
| enterprise | 企业配置服务器 | 2 | 管理员 | 组织级共享 |
| user | ~/.config/claude-code/settings.json | 3 | 用户 | 个人偏好 |
| project | .claude/settings.json | 4 | 项目成员 | 项目特定 |
| local | .mcp.json | 5 | 开发者 | 本地开发 |
| dynamic | 运行时 API | 最高(6) | 程序 | 动态发现 |
环境变量展开在配置加载时自动执行:配置字符串中的 ${VAR_NAME} 和 $VAR_NAME 会被替换为对应的环境变量值。这允许敏感信息(如 API 密钥)通过环境变量传递,避免硬编码在配置文件中。展开逻辑支持默认值语法 ${VAR:-default},当变量未定义时使用默认值。
Sources: config.ts, envExpansion.ts
实际应用场景
场景 1:数据库查询工具 — 通过 MCP 封装 PostgreSQL 客户端,提供 query 工具执行 SQL 查询,list_tables 工具浏览架构。服务器通过 resources 能力暴露数据库元数据(表结构、索引信息),Claude 可以先读取资源了解数据库结构,再构造精确的查询。
场景 2:云服务集成 — 使用 SSE 传输连接 AWS/Azure/GCP 的 MCP 服务器,通过 OAuth 认证访问用户资源。服务器提供 list_instances、deploy_function、read_logs 等工具,Claude 可以执行完整的云资源管理流程。XAA 功能允许服务器以用户的身份访问其他 SaaS 服务。
场景 3:IDE 深度集成 — 通过 WebSocket 传输连接 VS Code 或 JetBrains 的 MCP 服务器,提供 goto_definition、find_references、rename_symbol 等语言感知工具。服务器通过 elicitation 请求用户确认重构操作,确保安全性。这种集成使 Claude Code 成为一个强大的代码智能助手。
Sources: client.ts, elicitationHandler.ts
延伸阅读
- MCP 服务:服务器连接、资源管理与协议实现 — 深入了解 MCP 服务层的实现细节
- 工具架构:Tool 接口与权限模型 — 理解 Claude Code 的通用工具系统
- 权限服务:PermissionMode 与动态权限验证 — 学习 MCP 工具的权限检查机制
- Bridge 系统:IDE 双向通信与远程控制 — 探索 IDE 集成的另一种方式