MCP 体系
Model Context Protocol 的完整实现——多传输层客户端、OAuth/XAA 认证、连接生命周期管理、资源发现与 Channel 通知推送
职责概述
解决的问题:CC 内置了 30 多个工具,但用户总会有新需求——连接公司的数据库、调用内部 API、操作特定格式的文件。不可能每次都改源码。MCP(Model Context Protocol)就是 CC 的"应用商店"机制,让第三方可以开发插件工具,CC 自动发现和调用。
应用场景:① 安装一个 MCP 插件后,CC 突然能查 PostgreSQL 了 ② 团队共享的内部工具(如部署脚本)打包成 MCP Server 给全组用 ③ 第三方开发者发布工具到市场,用户一键安装 ④ 企业内网服务通过 OAuth 认证安全接入。
一句话理解:就像手机的 App Store——手机出厂自带一些功能,但你想加新功能就装 App。MCP 就是 CC 的 App 安装协议。
架构设计
服务端架构
核心数据流
连接生命周期
认证决策流
关键类型与接口
服务器配置联合类型
// services/mcp/types.ts:23-26
export const TransportSchema = lazySchema(() =>
z.enum(['stdio', 'sse', 'sse-ide', 'http', 'ws', 'sdk']),
)
// services/mcp/types.ts:124-135 — 七种配置的联合类型
export const McpServerConfigSchema = lazySchema(() =>
z.union([
McpStdioServerConfigSchema(), // 本地进程
McpSSEServerConfigSchema(), // SSE 远程(支持 OAuth)
McpSSEIDEServerConfigSchema(), // IDE 内部 SSE
McpWebSocketIDEServerConfigSchema(), // IDE WebSocket
McpHTTPServerConfigSchema(), // HTTP 流式传输
McpWebSocketServerConfigSchema(), // 通用 WebSocket
McpSdkServerConfigSchema(), // SDK 进程内
McpClaudeAIProxyServerConfigSchema(), // claude.ai 代理
]),
)
连接状态联合类型
// services/mcp/types.ts:180-227
export type MCPServerConnection =
| ConnectedMCPServer // { type: 'connected', client, capabilities, tools... }
| FailedMCPServer // { type: 'failed', error? }
| NeedsAuthMCPServer // { type: 'needs-auth' }
| PendingMCPServer // { type: 'pending', reconnectAttempt? }
| DisabledMCPServer // { type: 'disabled' }
InProcessTransport(进程内传输)
// services/mcp/InProcessTransport.ts:11-49
class InProcessTransport implements Transport {
private peer: InProcessTransport | undefined
async send(message: JSONRPCMessage): Promise<void> {
if (this.closed) throw new Error('Transport is closed')
queueMicrotask(() => {
this.peer?.onmessage?.(message)
})
}
}
// 创建成对的传输通道
export function createLinkedTransportPair(): [Transport, Transport]
Channel 权限回调接口
// services/mcp/channelPermissions.ts:46-61
export type ChannelPermissionCallbacks = {
onResponse(requestId: string,
handler: (response: ChannelPermissionResponse) => void): () => void
resolve(requestId: string, behavior: 'allow' | 'deny',
fromServer: string): boolean
}
工具名称规范化
// services/mcp/mcpStringUtils.ts:39-41
export function getMcpPrefix(serverName: string): string {
return `mcp__${normalizeNameForMCP(serverName)}__`
}
// 例: "slack" 服务器的工具 "send_message" → "mcp__slack__send_message"
设计模式与亮点
多传输层抽象
connectToServer()(client.ts:595)是一个巨大的 memoize 函数,根据 serverRef.type 分发到六种传输实现。每种传输的认证逻辑统一通过 ClaudeAuthProvider 处理(SSE/HTTP),或通过专用通道(stdio 无需认证、SDK 通过控制消息桥接)。这种设计让添加新传输类型只需增加一个 else-if 分支。
批量状态更新 + 微任务合并
updateServer()(useManageMCPConnections.ts:297)将单个服务器的状态变更推入 pendingUpdatesRef,通过 16ms 的 setTimeout 窗口合并多个几乎同时到达的更新为一次 setAppState 调用。这避免了 N 个 MCP 服务器同时连接完成时触发 N 次 React 重渲染。
两阶段配置加载
MCP 配置分两阶段加载(useManageMCPConnections.ts:858-1024):Phase 1 先连接 Claude Code 本地配置的服务器(快速),Phase 2 再异步获取 claude.ai 组织配置的服务器(可能慢),两者并行执行不互相阻塞。还通过 dedupClaudeAiMcpServers() 按签名去重,避免重复连接。
XAA 企业免浏览器认证
xaa.ts 实现了三层 OAuth 链:PRM 发现(RFC 9728)→ Token Exchange(RFC 8693: id_token 换 ID-JAG)→ JWT Bearer Grant(RFC 7523: ID-JAG 换 access_token)。企业用户只需一次 IdP 浏览器登录,后续所有 MCP 服务器认证均为静默完成。
指数退避重连
远程传输(SSE/HTTP/WS)断开后,onclose 处理器(useManageMCPConnections.ts:333)启动最多 5 次的重连尝试,退避时间从 1s 到 30s 指数增长。重连前检查服务器是否被禁用,支持中途取消。
Channel 消息推送
通过 notifications/claude/channel 通知机制,MCP 服务器可以主动向 Claude 推送消息(如 Telegram/iMessage/Discord 入站消息)。五层门控(capability → runtime → auth → policy → allowlist)确保安全性。
mcpAuthCache 和 isMcpAuthCached() 缓存到磁盘。对于返回 401 的服务器有 15 分钟的 TTL,避免反复探测不可用的认证端点。ClaudeAuthProvider 将 token 持久化到系统 Keychain(macOS)或加密存储,跨 CLI 会话复用。
开发者实践指南
添加新的 MCP 传输类型
在 services/mcp/types.ts 中定义新的配置 Schema,在 client.ts 的 connectToServer() 函数中添加新的 else-if 分支创建传输实例。注意:
- 传输必须实现
@modelcontextprotocol/sdk的Transport接口 - 如需认证,在
auth.ts的ClaudeAuthProvider中处理 token 存储/刷新 - 参考
InProcessTransport.ts(63 行)作为最简传输实现
理解 MCP 工具调用链
MCP 工具调用流程:Tool.call() → ensureConnectedClient() → callMCPToolWithUrlElicitationRetry() → callMCPTool() → client.request()。如果遇到 McpSessionExpiredError,自动清除连接缓存并重试一次。
调试 MCP 连接问题
--debug 标志启动 Claude Code,所有 MCP 操作会通过 logMCPDebug() 输出详细日志。关注 "SSE transport initialized"、"Received tools/list_changed"、"reconnection attempt" 等关键消息。
架构师决策指南
连接管理的性能权衡
connectToServer 使用 memoize 缓存连接(client.ts:595),避免重复建立连接。代价是缓存失效策略复杂:服务器配置变更时需要通过 clearServerCache() 显式清除。当前通过 getServerCacheKey() 生成 name-jsonStringify(config) 作为缓存键,配置变更会导致新键值、旧连接泄漏直到进程退出。
本地 vs 远程并发度
服务器连接分为 local(stdio/sdk)和 remote(SSE/HTTP/WS)两组独立并发控制。本地受 getMcpServerConnectionBatchSize() 限制(进程创建开销),远程受 getRemoteMcpServerConnectionBatchSize() 限制。两组通过 Promise.all 并行执行,互不阻塞。
Channel 安全模型
Channel 推送是 MCP 体系中最复杂的安全边界。五层门控链在 gateChannelServer()(channelNotification.ts:191)中实现:
- capability — 服务器必须声明
experimental['claude/channel'] - runtime — GrowthBook 特性开关
tengu_harbor必须为 true - auth — 必须有 claude.ai OAuth token(API key 用户被阻断)
- policy — Teams/Enterprise 必须在 managed settings 中启用
channelsEnabled: true - allowlist — 插件必须在 GrowthBook
tengu_harbor_ledger白名单中
notifications/claude/channel/permission 事件伪造权限确认。这是可接受的风险——被攻陷的服务器本身已有无限对话注入能力,权限确认只是加速了攻击而非扩展了攻击面。
Elicitation 交互架构
Elicitation 是 MCP 协议的交互式确认机制,允许服务器向用户弹出表单或 URL 确认。通过 registerElicitationHandler()(elicitationHandler.ts:68)注册到 MCP Client。请求先经过 hook 链(可程序化响应),未处理的请求排队到 AppState.elicitation.queue 供 UI 渲染。URL 模式的 Elicitation 支持"等待完成"通知(ElicitationCompleteNotificationSchema),用于 OAuth 回调等异步场景。
◈ 可视化处理拓扑图
MCP 系统是一个从多源配置发现到运行时工具调用的完整生命周期管理管线。配置从 5 个作用域汇聚、经过策略过滤后并发连接,每条连接根据 Transport 类型走不同的创建路径,最终将远程工具统一封装为 Claude Code 内部的 Tool 对象。
Phase 2 — 并发连接与 Transport 创建
processBatched(items, localBatch)
processBatched(items, remoteBatch)
auth.ts — token 获取/刷新
Phase 3 — 工具发现与运行时调用
Phase 4 — 健康监控与自动重连
① 连接断开 → 错误计数 +1
② 连续错误 > 3 → closeTransportAndRejectPending()
③ clearServerCache() → 清空 memoize 缓存条目
④ 下次工具调用 → connectToServer() 自动重建
⑤ Session 过期 (404 + -32001) → isMcpSessionExpiredError() 检测 → 自动重连
缓存即状态,清缓存即重连——无需显式连接池状态机
connectToServer 被 memoize 包装,缓存存在即已连接,clearServerCache() 即重连。Transport 类型通过工厂分支创建(stdio/sse/http),但上层代码统一通过 ConnectedMCPServer 接口操作,完全屏蔽底层差异。16ms React 批量更新机制确保多服务器并发连接不会造成 UI 抖动。⇉ 核心处理流程详解
MCP(Model Context Protocol)系统是从配置发现到工具调用的完整生命周期管理。其核心链路横跨配置加载(config.ts)、连接管理(client.ts)、React 编排(useManageMCPConnections.ts)和运行时工具调用四大模块。以下是从应用启动到工具执行的完整处理链路:
getClaudeCodeMcpConfigs()(config.ts:1071)从 5 个作用域读取配置:project(.mcp.json)、local(项目本地覆盖)、user(~/.claude/mcp.json)、enterprise(托管策略)和 plugin(插件提供的 MCP 服务器)。通过 addScopeToServers()(config.ts:69)标记每个服务器的来源作用域,再用 dedupPluginMcpServers()(config.ts:223)基于 URL 签名去重,防止同一服务器重复连接 — config.ts:1071-1251filterMcpServersByPolicy()(config.ts:536)过滤。企业策略通过白名单(allowedMcpServers)或黑名单(deniedMcpServers)控制。环境变量通过 expandEnvVars()(config.ts:556)展开。禁用的服务器不生成网络连接,仅标记为 type: 'disabled' — config.ts:536-551getMcpToolsCommandsAndResources()(client.ts:2226)将服务器分为本地(stdio/sdk,低并发)和远程(sse/http,高并发)两组。对每个服务器调用 connectToServer()(client.ts:595,memoized)。根据类型创建不同 Transport:stdio 使用 StdioClientTransport,SSE 使用 SSEClientTransport,HTTP 使用 StreamableHTTPClientTransport,IDE 通过特殊管道通信 — client.ts:2226-2403ClaudeAuthProvider(auth.ts)实现 OAuthClientProvider 接口,管理 token 的获取、刷新和撤销。认证失败时 handleRemoteAuthFailure()(client.ts:340)返回 failed 状态连接。认证缓存通过 setMcpAuthCacheEntry()(client.ts:293)持久化到磁盘,避免重复认证流程 — client.ts:340-361, auth.tsclient.listTools() 发现可用工具。每个 MCP 工具被封装为 Claude Code 的 Tool 对象(client.ts:1786-1832),注入 call()、checkPermissions()、isReadOnly() 等方法。isIncludedMcpTool()(client.ts:569)基于 include/exclude 配置过滤工具 — client.ts:1786-1832useManageMCPConnections(useManageMCPConnections.ts:143)通过 16ms 时间窗口的批量更新机制(MCP_BATCH_FLUSH_MS = 16),将多个服务器的连接结果合并为单次 setAppState() 调用。每个服务器的连接回调(onConnectionAttempt)进入 pending 队列,通过 setTimeout(flush, 16) 延迟刷入状态 — useManageMCPConnections.ts:207-270call()(client.ts:1833)。先通过 ensureConnectedClient()(client.ts:1688)确认连接活跃,再调用 callMCPToolWithUrlElicitationRetry()(client.ts:2813)处理 URL 认证重试。结果通过 processMCPResult()(client.ts:2720)和 transformResultContent()(client.ts:2478)将 MCP 格式转换为 Claude API 的 ContentBlock 格式 — client.ts:1833-1971onerror 和 onclose 处理器(client.ts:1266-1570)。连续错误超过 3 次触发 closeTransportAndRejectPending(),清空 memoize 缓存使下次调用自动重连。HTTP 传输层的 session 过期(404 + JSON-RPC -32001)由 isMcpSessionExpiredError()(client.ts:193)检测,自动清除缓存重建连接 — client.ts:1240-1570connectToServer 被 memoize 包装(client.ts:595),相同参数返回同一个 Promise。当连接断开时,onclose 处理器调用 clearServerCache()(client.ts:1648)清空特定服务器的缓存条目,使下一次工具调用自动触发重连。这种设计避免了维护复杂的连接池状态机——缓存即状态,清缓存即重连。
★ 设计精华
1. Memoize-as-Connection-Pool 模式
不维护显式的连接池,而是利用 memoize 的缓存特性作为隐式连接池。key 由服务器名和配置对象计算(getServerCacheKey(),client.ts:581),值是连接 Promise。连接断开时只需 cache.delete(key),下次调用自然重建。这消除了连接状态机(connecting/connected/disconnected/reconnecting)的复杂性——缓存存在即已连接,不存在即需连接。
export const connectToServer = memoize(
async (name: string, serverRef: ScopedMcpServerConfig, ...): Promise<MCPServerConnection> => {
// 创建 transport、执行 OAuth、发现工具...
// 返回 ConnectedMCPServer 或 FailedMCPServerConnection
}
)
// 断开时清空缓存 → 下次调用自动重连
clearServerCache(name, serverRef)
staleTime 思想——用缓存策略替代状态管理。全局 clearPluginCache()(pluginLoader.ts:3225)也使用了相同模式管理插件加载。2. 分层去重:签名 + URL 双重保障
MCP 配置来自 5 个不同作用域,同一个服务器可能被多处配置。getMcpServerSignature()(config.ts:202)为每个配置计算签名(基于 URL 或 command 数组)。在插件层,dedupPluginMcpServers()(config.ts:223)阻止插件注册已存在的 MCP 服务器;在 claude.ai 层,dedupClaudeAiMcpServers()(config.ts:281)阻止 claude.ai connector 与手动配置冲突。两层去重确保同一后端服务只有一个活跃连接。
.mcp.json 中把 GitHub MCP 命名为 gh,在 claude.ai 中命名为 GitHub,但只要 URL 相同就会被识别为重复。这种内容语义去重比名称去重更健壮。3. SSE 长连接的超时分离策略
SSE 传输层有两个 fetch:EventSource 的长连接 fetch 和普通 API 请求的 fetch。wrapFetchWithTimeout()(client.ts:492)仅包装 API 请求 fetch(60 秒超时),EventSource 的 fetch 保持无超时。如果错误地给 EventSource 也加了超时,SSE 流会在 60 秒后断开,导致推送通知丢失。这个分离通过 transportOptions.eventSourceInit 和 transportOptions.fetch 分别配置实现 — client.ts:630-671
// API 请求:带超时
transportOptions.fetch = wrapFetchWithTimeout(
wrapFetchWithStepUpDetection(createFetchWithInit(), authProvider),
)
// EventSource 长连接:不设超时
transportOptions.eventSourceInit = {
fetch: async (url, init) => fetch(url, { ...init, ...proxyOptions })
}
4. 批量更新的时间窗口合并
React 的状态更新是同步的——每个 setAppState 触发一次渲染。当 10 个 MCP 服务器同时连接完成时,不加控制会产生 10 次渲染。useManageMCPConnections 用 MCP_BATCH_FLUSH_MS = 16(一帧时间)的时间窗口收集所有更新,在单次 setAppState 中批量应用(useManageMCPConnections.ts:216-270)。16ms 足够收集同一"事件循环 tick"中的多个回调,又短到用户感知不到延迟。
if (newState === prevState) return prevState)跳过无变化的更新。◈ Agent 实践借鉴 — 客服 Agent 外部系统集成设计
场景映射:客服 agent 在外部系统集成上的真实问题
客服 agent 需要连接 6+ 外部系统,每个系统协议不同、稳定性不同、接入方式也不同。典型痛点包括:
- 多系统多协议:CRM(REST API 客户信息)、ERP(gRPC 订单/库存)、支付网关(REST 退款)、物流系统(消息队列查件)、知识库(REST FAQ)、短信平台(REST 通知)。甚至还有老系统走 SOAP 协议。
- 第三方系统不稳定:物流系统每周二凌晨维护、CRM 偶尔超时、支付网关在月底高峰期限流。断线后客服 agent 不能直接挂掉,需要自动重连或降级处理。
- 新系统接入怕影响老系统:新增一个短信平台连接,不能因为短信平台的 bug 导致已有的 CRM 查询和订单查询挂掉。连接之间必须隔离。
- 配置分散难管理:6 个系统的连接配置散落在不同地方,改一个配置要改三个文件,还容易改漏。
借鉴 CC + 客服改造
1. Memoize 连接池(CC 的核心模式,客服场景最该抄的)
CC 的 connectToServer 用 memoize 包装,缓存存在=已连接,缓存清除=重连。这个模式在客服场景非常合适——连接 6 个外部系统不需要维护 6 个状态机:
// 借鉴 CC 的 Memoize-as-Connection-Pool → 客服系统连接池
// 核心思想:不维护显式连接池,用缓存特性管理连接
interface ExternalSystem {
name: string // 'crm' | 'erp' | 'payment' | 'logistics' | 'kb' | 'sms'
protocol: 'rest' | 'grpc' | 'mq' | 'soap'
config: SystemConfig
}
// 用 memoize 实现隐式连接池——缓存存在=已连接
const connectToExternalSystem = memoize(
async (systemName: string, config: SystemConfig): Promise<SystemConnection> => {
const adapter = createTransportAdapter(config) // 工厂分支
const connection = await adapter.connect(config)
const health = await connection.healthCheck()
if (!health.ok) throw new Error(`${systemName} 健康检查失败`)
return { status: 'connected', connection, adapter }
}
)
// 连接断开时:清缓存 = 重连(无需显式状态机)
function onSystemConnectionLost(systemName: string, config: SystemConfig) {
clearConnectionCache(systemName, config)
// 下次工具调用 connectToExternalSystem() 自动重建
// 借鉴 CC 的 onclose 处理器:连续错误超限则降级
logWarning(`外部系统 ${systemName} 断开,下次调用自动重连`)
}
// 降级策略:连接失败不影响其他系统
async function callWithFallback(
systemName: string,
operation: string,
params: any,
fallbackValue?: any
): Promise<any> {
try {
const conn = await connectToExternalSystem(systemName, getConfig(systemName))
return await conn.connection.call(operation, params)
} catch (error) {
logError(`${systemName}.${operation} 调用失败`, error)
if (fallbackValue !== undefined) return fallbackValue
throw new ServiceUnavailableError(systemName, operation)
}
}
2. 统一 Transport 适配器(CC 6 种 → 客服 2-3 种)
CC 的 6 种 Transport(stdio/SSE/HTTP/WS/SDK/InProcess)统一为 Transport 接口。客服场景只需要 REST/gRPC/MQ 三种,但同样需要统一接口:
// 借鉴 CC 的 Transport 接口 → 客服场景的统一适配器
interface ServiceTransport {
connect(config: SystemConfig): Promise<Connection>
send(request: ServiceRequest): Promise<ServiceResponse>
close(): Promise<void>
healthCheck(): Promise<HealthStatus>
}
// REST 适配器——大多数客服系统走 REST
class RestTransport implements ServiceTransport {
private client: HttpClient | undefined
async connect(config: SystemConfig): Promise<Connection> {
this.client = createHttpClient(config.baseUrl, {
timeout: config.timeout || 5000,
retries: config.retries || 2,
headers: { 'Authorization': `Bearer ${config.apiKey}` },
})
return { type: 'rest', client: this.client }
}
async send(request: ServiceRequest): Promise<ServiceResponse> {
return this.client!.request({
method: request.method,
path: request.path,
body: request.params,
})
}
async healthCheck(): Promise<HealthStatus> {
try {
await this.client!.get('/health')
return { ok: true }
} catch { return { ok: false } }
}
close() { this.client = undefined }
}
// MQ 适配器——物流系统走消息队列
class MessageQueueTransport implements ServiceTransport {
private consumer: MQConsumer | undefined
async connect(config: SystemConfig): Promise<Connection> {
this.consumer = await createConsumer(config.queueUrl, config.queueName)
return { type: 'mq', consumer: this.consumer }
}
async send(request: ServiceRequest): Promise<ServiceResponse> {
// 发送查询消息 → 等待响应消息(带超时)
const correlationId = generateId()
return waitForResponse(this.consumer!, correlationId, config.responseTimeout)
}
// ... healthCheck, close
}
3. 外部 API → 内部 Tool 封装
CC 把每个 MCP 工具封装为 Tool 对象。客服场景把每个外部系统 API 封装为统一的 Tool:
// 借鉴 CC 的 wrapMcpTool → 客服场景的外部 API → Tool 封装
interface CustomerServiceTool {
name: string // 如 "query_order"
description: string // 如 "查询订单状态"
requiredSystem: string // 如 "erp"
requiredPermission: string // 如 "order:read"
inputSchema: object // 参数 schema
execute(params: any): Promise<ToolResult>
}
// 封装 CRM 的"查客户"接口为统一 Tool
function createQueryCustomerTool(crmSystem: string): CustomerServiceTool {
return {
name: 'query_customer',
description: '查询客户信息(CRM系统)',
requiredSystem: crmSystem,
requiredPermission: 'customer:read',
inputSchema: {
type: 'object',
properties: {
phone: { type: 'string', description: '客户手机号' },
customerId: { type: 'string', description: '客户ID' },
},
},
async execute(params) {
// 连接 + 调用 + 结果转换
const conn = await connectToExternalSystem(
crmSystem, getConfig(crmSystem)
)
const raw = await conn.connection.call('getCustomer', {
phone: params.phone,
customerId: params.customerId,
})
// 原始 API 返回 → 统一 ToolResult 格式
return {
success: true,
data: {
name: raw.customer_name,
phone: raw.phone_number,
vipLevel: raw.vip_level,
tags: raw.tags,
},
summary: `客户 ${raw.customer_name},${raw.vip_level}会员`,
}
},
}
}
// agent 调用时无感知底层是 REST 还是 gRPC
// const result = await toolRegistry.get('query_customer').execute({ phone: '138xxxx' })
4. 连接健康检查 + 自动重连
// 借鉴 CC 的 onclose/onerror + reconnectWithBackoff
// 健康检查循环——每 30 秒检查所有外部系统连接
async function startHealthMonitor(systems: ExternalSystem[]): Promise<void> {
setInterval(async () => {
for (const system of systems) {
const cacheKey = getCacheKey(system.name, system.config)
const cached = connectionCache.get(cacheKey)
if (!cached) continue // 未连接,跳过
const health = await cached.adapter.healthCheck().catch(() => ({ ok: false }))
if (!health.ok) {
// 借鉴 CC:清缓存 → 下次调用自动重建
connectionCache.delete(cacheKey)
logWarning(`${system.name} 健康检查失败,已清除缓存,下次调用自动重连`)
// 通知 agent 该系统暂时不可用
notifySystemStatus(system.name, 'degraded')
}
}
}, 30_000)
}
// 指数退避重连——借鉴 CC 的 reconnectWithBackoff
async function reconnectWithBackoff(
systemName: string,
config: SystemConfig,
maxAttempts: number = 5,
): Promise<SystemConnection> {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
clearConnectionCache(systemName, config)
const conn = await connectToExternalSystem(systemName, config)
notifySystemStatus(systemName, 'healthy')
return conn
} catch (error) {
const delay = Math.min(1000 * Math.pow(2, attempt), 30_000)
logWarning(`${systemName} 重连失败(第${attempt}次),${delay}ms后重试`)
await sleep(delay)
}
}
throw new Error(`${systemName} 重连${maxAttempts}次后仍然失败`)
}
落地清单
1. Memoize 连接池——这个太实用了,不维护状态机,用缓存特性管理连接。连接 6 个外部系统完全够用。
2. 统一 Transport 接口——REST/gRPC/MQ 统一为
ServiceTransport 接口,新增协议只需加适配器。3. Tool 封装——外部 API 封装为
CustomerServiceTool,agent 调用时不感知底层协议差异。4. 连接隔离——单个系统连接失败不影响其他系统,降级而非报错。
1. OAuth PKCE 认证——客服系统用内部认证(API Key / 内网 Token),不需要 OAuth 浏览器授权流程。
2. 6 种传输方式——客服场景 REST + gRPC + MQ 三种覆盖 95% 场景,不需要 SSE/WebSocket/InProcess。
3. Elicitation 交互确认——不需要外部系统弹确认框,客服操作确认走内部审批流程。
4. Channel 消息推送——客服场景不需要外部系统主动推送消息到 agent。
代码索引
| 文件 | 行数 | 说明 |
|---|---|---|
services/mcp/client.ts | ~3349 | MCP 客户端核心:connectToServer、callMCPTool、工具封装、连接缓存 |
services/mcp/auth.ts | ~2466 | OAuth 2.0 认证:ClaudeAuthProvider、Token 持久化/刷新/撤销 |
services/mcp/config.ts | ~1579 | 配置加载:多作用域读取、策略过滤、签名去重、启停管理 |
services/mcp/useManageMCPConnections.ts | ~1142 | React Hook:连接生命周期、批量更新、重连、Channel 注册 |
services/mcp/MCPConnectionManager.tsx | ~73 | React Context:提供 reconnectMcpServer / toggleMcpServer 给子组件 |
services/mcp/types.ts | ~258 | 所有 MCP 类型定义:配置 Schema、连接状态、CLI 状态 |
services/mcp/InProcessTransport.ts | ~64 | 进程内传输对:linked pair,用于无子进程的 MCP 通信 |
services/mcp/SdkControlTransport.ts | ~137 | SDK 传输桥:CLI ↔ SDK 进程的控制消息转发 |
services/mcp/channelNotification.ts | ~317 | Channel 通知:五层门控、消息包装、会话匹配 |
services/mcp/channelPermissions.ts | ~241 | Channel 权限:短 ID 生成、远程确认回调、allowlist 过滤 |
services/mcp/elicitationHandler.ts | ~314 | Elicitation 处理:表单/URL 模式、hook 集成、完成通知 |
services/mcp/claudeai.ts | ~165 | claude.ai 代理:从组织 API 获取 MCP 服务器配置 |
services/mcp/xaa.ts | ~512 | XAA 认证:PRM 发现、Token Exchange、JWT Bearer Grant |
services/mcp/xaaIdpLogin.ts | ~488 | XAA IdP 登录:OIDC 授权码 + PKCE、id_token 缓存 |
services/mcp/oauthPort.ts | ~79 | OAuth 回调端口:动态端口分配、redirect URI 构建 |
services/mcp/headersHelper.ts | ~139 | 动态 Header:通过外部脚本获取认证 Header |
services/mcp/officialRegistry.ts | ~73 | 官方 MCP 注册表:预取白名单 URL |
services/mcp/vscodeSdkMcp.ts | ~113 | VSCode MCP 双向通信:文件变更通知、实验门控同步 |
services/mcp/normalization.ts | ~23 | 名称规范化:MCP 工具名 ↔ API 兼容格式 |
services/mcp/mcpStringUtils.ts | ~107 | 字符串工具:工具名解析、前缀生成、权限匹配 |
services/mcp/envExpansion.ts | ~39 | 环境变量展开:${VAR} 和 ${VAR:-default} 语法 |
services/mcp/channelAllowlist.ts | ~77 | Channel 白名单:GrowthBook 驱动的插件许可列表 |
services/mcp/utils.ts | ~575 | 工具函数:过期客户端检测、Agent frontmatter 提取 |
server/types.ts | ~58 | 服务端类型:ServerConfig、SessionState、SessionIndex |
server/directConnectManager.ts | ~214 | WebSocket 会话管理:消息收发、权限请求/响应、中断 |
server/createDirectConnectSession.ts | ~89 | 创建 Direct Connect 会话:POST /sessions、响应验证 |