MCP 集成
五种传输协议
MCP 将外部服务统一抽象为工具/资源/命令三种原语,实现无限扩展
学习
概念讲解与核心设计分析
12.1 五种传输协议
Claude Code 的 MCP(Model Context Protocol)集成支持 5 种传输协议,覆盖从本地进程到远程服务的全场景通信需求:
- StdioClientTransport — 通过子进程的 stdin/stdout 通信,最常用的本地 MCP 服务器连接方式。启动一个子进程并通过标准输入输出交换 JSON-RPC 消息
- SSEClientTransport — 基于 Server-Sent Events 的 HTTP 长连接,适合远程 MCP 服务器。客户端通过 GET 请求建立 SSE 连接接收消息,通过 POST 发送请求
- StreamableHTTPClientTransport — 基于可流式 HTTP 的传输,支持双向流通信,是 SSE 的升级版本
- WebSocketTransport — 基于 WebSocket 的全双工通信,适合需要低延迟双向交互的场景
- SdkControlClientTransport — SDK 控制传输,用于 Claude Code SDK 内部进程间通信
12.2 客户端核心逻辑
client.ts 是 MCP 集成的核心模块,提供三个关键函数:
connectToServer()— 根据配置选择传输协议,建立与 MCP 服务器的连接。处理连接超时、重连和错误恢复fetchToolsForClient()— 从已连接的 MCP 服务器获取工具列表,并将 MCP 工具定义转换为 Claude Code 内部的 Tool 对象格式。这个转换过程包括参数映射、权限标记和描述本地化prefetchAllMcpResources()— 预加载所有 MCP 服务器的资源(工具列表、资源模板等),减少运行时的延迟
12.3 配置管理与聚合
config.ts 负责 MCP 配置的解析和聚合:
parseMcpConfig()— 解析单个 MCP 服务器配置,验证必要字段getClaudeCodeMcpConfigs()— 从多个来源聚合 MCP 配置:项目.mcp.json、用户全局配置、企业管理员配置、Skill 定义的 MCP 服务器filterMcpServersByPolicy()— 根据组织策略过滤 MCP 服务器,企业管理员可以设置允许列表和黑名单
12.4 OAuth 认证与错误处理
auth.ts 实现了完整的 OAuth 认证流程,支持 XAA IDP 登录。当 MCP 服务器需要认证时,系统会自动引导用户完成 OAuth 授权流程,获取并缓存访问令牌。
MCP 集成定义了自定义错误层次结构:
- McpAuthError — 认证失败,需要用户重新授权
- McpSessionExpiredError — 会话过期,需要重新建立连接
- McpToolCallError — 工具调用失败,包含错误详情和重试建议
12.5 MCPTool 包装器与权限控制
MCPTool 包装器将 MCP 服务器暴露的工具封装为 Claude Code 标准工具接口。MCPConnectionManager.tsx 是 React 组件,提供连接状态可视化和管理界面。通道权限系统通过 allowlists 控制哪些 MCP 工具可以被使用。
架构
模块关系与设计决策
MCP 集成架构图
配置聚合层
getClaudeCodeMcpConfigs() → filterMcpServersByPolicy()
传输协议层
client.ts 核心连接
MCPTool 包装器
MCP Tool → Claude Code Tool 对象 → 权限检查 → 工具调用
源码
共 3 个关键代码示例
// connectToServer: 根据配置选择传输协议并连接
async function connectToServer(
config: McpServerConfig
): Promise<McpClient> {
let transport: Transport;
switch (config.transport) {
case 'stdio':
transport = new StdioClientTransport({
command: config.command,
args: config.args || [],
env: config.env
});
break;
case 'sse':
transport = new SSEClientTransport(
new URL(config.url),
{ headers: config.headers }
);
break;
case 'streamable-http':
transport = new StreamableHTTPClientTransport(
new URL(config.url)
);
break;
case 'websocket':
transport = new WebSocketTransport(config.url);
break;
default:
throw new Error(
'Unsupported transport: ' + config.transport
);
}
const client = new McpClient();
await client.connect(transport);
return client;
}
// fetchToolsForClient: MCP 工具转换为内部格式
async function fetchToolsForClient(
client: McpClient,
serverName: string
): Promise<Tool[]> {
const mcpTools = await client.listTools();
return mcpTools.map(tool => ({
name: serverName + ':' + tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
// MCPTool 包装器处理实际调用
execute: async (input) => {
return client.callTool(tool.name, input);
}
}));
}// parseMcpConfig: 解析单个 MCP 配置
function parseMcpConfig(
raw: Record<string, unknown>
): McpServerConfig {
return {
name: String(raw.name),
transport: raw.transport as TransportType || 'stdio',
command: raw.command as string,
args: (raw.args as string[]) || [],
env: raw.env as Record<string, string>,
url: raw.url as string,
headers: raw.headers as Record<string, string>,
authType: raw.authType as string
};
}
// getClaudeCodeMcpConfigs: 聚合所有来源的配置
async function getClaudeCodeMcpConfigs(): Promise<
McpServerConfig[]
> {
const configs: McpServerConfig[] = [];
// 1. 项目级 .mcp.json
const projectConfig = await loadJsonFile(
'.mcp.json'
);
if (projectConfig?.mcpServers) {
for (const [name, cfg] of
Object.entries(projectConfig.mcpServers)
) {
configs.push(parseMcpConfig({ name, ...cfg }));
}
}
// 2. 用户全局配置
const userConfig = await loadUserMcpConfig();
configs.push(...userConfig);
// 3. 企业管理员配置
const enterpriseConfig = await loadEnterpriseMcpConfig();
configs.push(...enterpriseConfig);
// 4. 策略过滤
return filterMcpServersByPolicy(configs);
}
// filterMcpServersByPolicy: 企业策略过滤
function filterMcpServersByPolicy(
configs: McpServerConfig[]
): McpServerConfig[] {
const policy = getOrganizationPolicy();
if (!policy?.mcpAllowlist) return configs;
return configs.filter(c =>
policy.mcpAllowlist.includes(c.name) ||
policy.mcpAllowlist.includes('*')
);
}// OAuth 认证流程
async function handleMcpAuth(
serverConfig: McpServerConfig
): Promise<string> {
if (serverConfig.authType !== 'oauth') {
return '';
}
// 检查缓存的 token
const cached = await getTokenCache(serverConfig.name);
if (cached && !isTokenExpired(cached)) {
return cached.accessToken;
}
// 发起 OAuth 流程
const authUrl = buildAuthUrl({
clientId: serverConfig.oauth?.clientId,
redirectUri: 'http://localhost:' + getRandomPort(),
scope: serverConfig.oauth?.scope || 'read'
});
// 启动本地服务器接收回调
const code = await waitForAuthCallback(authUrl);
// 交换 access token
const token = await exchangeCodeForToken(
code, serverConfig
);
await setTokenCache(serverConfig.name, token);
return token.accessToken;
}
// 自定义错误层次结构
class McpAuthError extends Error {
constructor(serverName: string, detail: string) {
super('MCP Auth Error [' + serverName + ']: ' + detail);
this.name = 'McpAuthError';
}
}
class McpSessionExpiredError extends Error {
constructor(serverName: string) {
super('MCP session expired: ' + serverName);
this.name = 'McpSessionExpiredError';
}
}
class McpToolCallError extends Error {
public readonly toolName: string;
public readonly retryable: boolean;
constructor(
toolName: string,
message: string,
retryable: boolean = false
) {
super('MCP tool call failed [' + toolName + ']: '
+ message);
this.name = 'McpToolCallError';
this.toolName = toolName;
this.retryable = retryable;
}
}互动
步进式流程演示
MCP 连接交互式演练
Step 1: 配置发现与聚合
系统启动时,getClaudeCodeMcpConfigs() 从四个来源收集 MCP 配置:项目 .mcp.json、用户全局配置、企业配置和 Skill 定义。所有配置经过去重和策略过滤后合并。
// .mcp.json 示例
{
"mcpServers": {
"github": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"]
}
}
}
Step 2: 传输协议选择与连接
connectToServer() 根据配置中的 transport 字段选择对应的传输实现。Stdio 模式会启动一个子进程;SSE 模式会建立 HTTP 长连接;WebSocket 模式会建立全双工连接。
Step 3: 工具发现与注册
fetchToolsForClient() 调用 MCP 服务器的 tools/list 方法获取工具定义,然后将每个 MCP 工具转换为 Claude Code 的 Tool 接口。工具名称会加上服务器名前缀避免冲突。
// MCP 工具名转换
"read_file" → "github:read_file"
"search" → "github:search"
Step 4: 认证与错误恢复
如果 MCP 服务器需要 OAuth 认证,系统会自动启动认证流程。连接断开时,MCPConnectionManager 会根据错误类型决定是重试连接还是提示用户重新授权。