MusePi

MCP 协议与传输机制

English | 中文 本文档说明 coding-agent 如何实现 MCP JSON-RPC 消息传递,以及协议关注点如何与传输关注点分离。

范围

涵盖:

不涵盖扩展作者体验或命令 UI。

实现文件

层次边界

协议层(JSON-RPC + MCP 方法)

传输层(MCPTransport

MCPTransport 抽象投递与生命周期:

传输实现拥有帧格式与 I/O 细节:

Manager/Client 接线

connectToServer() 始终为标准的服务端到客户端请求安装 onRequest handler。MCPManager 安装通知 handler、HTTP-like OAuth server 的 OAuth 刷新钩子,以及受管连接的 onClose 重连处理。

传输选择

client.ts:createTransport() 根据配置选择传输:

"sse" 使用遗留 HTTP+SSE 传输:用 GET 打开配置的 URL,读取 endpoint 事件的纯文本 URL/path,将 JSON-RPC 请求 POST 到该 endpoint,并从 stream 接收 JSON-RPC 响应。

JSON-RPC 消息流与关联

Request IDs

每个传输使用 Snowflake.next() 生成每请求 ID。ID 是传输本地关联令牌。

Stdio 关联路径

未知响应 ID 被忽略(不 reject,不 error callback)。

HTTP 关联路径

如果 SSE stream 在匹配响应前结束,请求以 No response received for request ID ... 失败。在捕获到匹配响应后,传输在后台清空剩余的 SSE 消息。

Notifications

客户端通过 transport.notify(...) 发出 JSON-RPC 通知。

服务端发起通知通过 transport onNotification 暴露;MCPManager 消费已知的 MCP list/update 通知,并可通过自身回调转发所有通知。

Stdio transport 内部

生命周期与状态转换

如果 read loop 异常退出,finally 触发 #handleClose(),执行同样的 pending-request rejection 与 close callback。

超时与取消

每个请求:

取消仅本地生效:transport 不会向服务端发送协议级取消通知。

畸形载荷处理

在读循环中:

如果底层 stream parser 抛出,onError 被调用(当仍 connected 时),然后连接关闭。

断开/失败行为

进程退出或 stream 关闭时:

反压/流式说明

Streamable HTTP transport 内部

生命周期与连接语义

HTTP transport 有逻辑连接状态,但请求路径按 HTTP 调用无状态:

因此 connected 表示“transport 可用”,不是“已建立持久 stream”。

Session header 行为

超时、取消和认证刷新

对于 request()

对于 notify()

对于 MCPManager 管理的 HTTP-like OAuth 配置,出站请求和尽力而为的服务端请求响应在 HTTP 401/403 时,若 token refresh 返回替换 headers,则重试一次。

HTTP 错误传播

在非 OK 响应上:

在 JSON-RPC error 对象上:

畸形 JSON body(response.json() 失败)作为 parse exception 传播。

SSE 行为与模式

存在两条 SSE 路径:

  1. 按请求的 SSE 响应#parseSSEResponse
    • 当 POST 响应 content type 为 text/event-stream 时使用
    • 消费 stream 直到找到匹配 response id
    • 可在同一 stream 中处理交错的通知
  2. 背景 SSE listenerstartSSEListener()
    • 可选的 GET listener,用于服务端发起的通知和服务端到客户端请求
    • connectToServer() 在 Streamable HTTP transports 上,在 initialize 之后、notifications/initialized 之前启动它
    • listener 启动最多等待一秒;非常小的 request timeout 下等待时间更短;timeout: 0 / OMP_MCP_TIMEOUT_MS=0 禁用该启动截止时间
    • 如果 GET 返回 405、另一个非 OK 状态、无 body 或超时,listener 静默禁用自身

畸形载荷与断开处理

SSE JSON 解析错误从 readSseJson 冒出并 reject request/listener。

Legacy HTTP+SSE transport 内部

LegacySseTransport 实现 MCP 协议修订版 2024-11-05:

json-rpc.ts 工具与 transport 抽象的差异

src/mcp/json-rpc.ts 提供 callMCP()parseSSE() helper,用于直接 HTTP MCP 调用(被 Exa integration 使用),而不是 MCPClient/MCPManager 使用的 MCPTransport 抽象。

HttpTransport 的显著差异:

该路径更轻量,但不如完整 transport 实现稳健。

重试/重连责任

Transport-level

当前 transport 实现不会

它们快速失败并传播错误。

Manager/tool-bridge level

MCPManager 为受管连接接线 transport.onClose,并在 transport 意外关闭时运行 reconnectServer(name)。重连会拆毁陈旧连接、重新解析 auth/config 值、使用 backoff(500100020004000 ms)重试、重新加载工具,并在重连期间保留陈旧工具。

MCPToolDeferredMCPTool 也会在 tool call 中对可重试连接错误尝试一次 reconnect + retry。这是 tool availability recovery,不是 transport-level retry。

失败场景总结

实用边界规则

如果关注点是消息形状、id 关联或 MCP 方法顺序,它属于 protocol/client logic。

如果关注点是帧格式(JSONL vs HTTP/SSE)、stream parsing、fetch/spawn lifecycle、timeout clocks 或连接清理,它属于 transport implementation。