1454 字
7 分钟
MCP 传输机制
2025-04-30

总览#

MCP 使用 JSON-RPC 对消息进行编码,所有消息必须使用 UTF-8 编码;协议当前定义了两种标准传输机制:

  1. stdio(标准输入/输出),通过子进程的 stdin/stdout 进行通信
  2. Streamable HTTP(可流式 HTTP),基于 HTTP POST/GET 与可选的 Server-Sent Events(SSE)实现流式交互

客户端应优先支持 stdio;同时,MCP 也允许通过插件化方式实现自定义传输(custom transports)以满足特殊需求。

stdio 传输#

在 stdio 传输中:

  • 客户端以子进程(subprocess)方式启动 MCP 服务器,服务器从其标准输入(stdin)读取 JSON-RPC 消息,并将消息写入标准输出(stdout)。
  • 可以发送单条请求/响应/通知,也可以发送 JSON-RPC 批量消息(batch),批量中可包含多条请求和/或通知;所有消息以换行分隔,不得包含嵌入换行。
  • 服务器可将 UTF-8 编码的日志写入标准错误(stderr),客户端可选择捕获、转发或忽略这些日志;但服务器不得向 stdout 输出非 MCP 消息,客户端亦不得向 stdin 写入非 MCP 消息。

Streamable HTTP 传输#

Streamable HTTP 取代了 2024-11-05 版本中的 HTTP+SSE 传输,支持服务器作为独立进程处理多个客户端连接。其核心特点包括:

  • 使用 HTTP POST 发送客户端→服务器 的 JSON-RPC 消息,服务器可通过 SSE(Server-Sent Events)对客户端进行流式推送,实现服务器→客户端 的通知与请求。
  • 服务器必须提供单一 MCP 端点(endpoint),同时支持 POST 和 GET 方法,例如 https://example.com/mcp

安全警告#

实现 Streamable HTTP 时,必须注意以下安全措施:

  1. 验证所有连接请求的 Origin 头,以防 DNS rebinding 攻击;
  2. 在本地运行时,应仅绑定到 localhost(127.0.0.1),避免对外网接口(0.0.0.0)开放;
  3. 应对所有连接实施适当的认证机制。

没有这些防护,攻击者可能借助 DNS rebinding 从远程网页访问本地 MCP 服务器。

发送消息(Client → Server)#

  1. 客户端必须使用 HTTP POST 将每个 JSON-RPC 消息发送到 MCP 端点;
  2. 请求头 Accept 中应同时列出 application/json 和 text/event-stream;
  3. POST 请求体可以是:
    • 单个 JSON-RPC 请求/通知/响应
    • 包含多条请求和/或通知的 JSON 数组(批量)
    • 包含多条响应的 JSON 数组(批量)
  4. 如果 POST 内容仅包含响应或通知:
    • 若服务器接受,应返回 HTTP 202 Accepted,无响应体;
    • 若无法接受,应返回 HTTP 错误码(如 400 Bad Request),响应体可包含无 id 的 JSON-RPC 错误响应。
  5. 若 POST 内容包含请求:
    • 服务器必须返回 Content-Type: text/event-stream(开启 SSE 流)或 Content-Type: application/json(返回单个 JSON 对象);客户端需同时支持两种情况;
    • 若使用 SSE,服务器应最终为每个请求发送一条响应(可批量),期间可在响应前发送与该请求相关的服务器发起的请求/通知;发送完毕后,应关闭 SSE 流(除会话过期外);
    • 断线时,不应视为请求取消;取消应由客户端显式发送 CancelledNotification;为防止丢包,服务器可实现可恢复(resumable)SSE。

监听消息(Server → Client)#

  1. 客户端可使用 HTTP GET 打开 SSE 流,以便在未先发送 POST 的情况下接收服务器消息;
  2. GET 请求头 Accept 中应包含 text/event-stream;
  3. 服务器要么返回 Content-Type: text/event-stream 并开启 SSE,要么返回 405 Method Not Allowed;
  4. 在 SSE 流中,服务器可发送批量或单条 JSON-RPC 请求/通知,但不得在流中发送响应(除恢复关联请求的流外);客户端也可随时关闭流。

多连接#

  • 客户端可同时保持多个 SSE 连接;
  • 服务器每条 JSON-RPC 消息只能发送到其中一个连接,不得跨连接广播同一消息;
  • 可结合可恢复性机制降低丢包风险。 

可恢复性与重发#

  • 服务器可为 SSE 事件附加全局唯一的 id,作为该流的游标;
  • 客户端在断线后可通过 HTTP GET 并加上 Last-Event-ID 头请求重连,服务器可在该 id 之后继续重放该流的消息,但不得重放属于其他流的消息。

会话管理#

  • MCP “会话” 从初始化阶段开始,可选地分配 Mcp-Session-Id,放在初始化响应的头中;
  • 客户端在后续所有请求中必须带上该 Mcp-Session-Id 头;缺失该头的请求,服务器可返回 400 Bad Request;
  • 服务器随时可通过让包含该会话 ID 的请求返回 404 Not Found 来终止会话;客户端收到 404 后应重新发送初始化请求,开始新会话;
  • 客户端也可通过 HTTP DELETE 并附带 Mcp-Session-Id 头主动终止会话,服务器可返回 405 表示不支持此操作。

向后兼容(Backwards Compatibility)#

为了兼容旧版 2024-11-05 的 HTTP+SSE 传输:

  • 服务器端可同时托管旧 SSE 和新 MCP 端点(或将旧 POST 与新端点合并);
  • 客户端在接到服务器 URL 后,先尝试 POST InitializeRequest;
  • 若返回成功,则使用新 Streamable HTTP;
  • 若返回 4xx(如 405/404),再发 GET 以期打开 SSE 并接收首条 endpoint 事件,即判定为旧传输,切换到 HTTP+SSE。

自定义传输#

MCP 传输层是无感知于底层通道的,客户端与服务器可按需通过插件实现额外的自定义传输机制。但任何自定义实现都必须遵循 JSON-RPC 消息格式及生命周期要求,并在文档中说明其连接建立与消息交换方式,以便互操作性。

参考#

MCP 传输机制
https://blog.lpkt.cn/posts/mcp-transport-20250326/
作者
lollipopkit
发布于
2025-04-30
许可协议
CC BY-NC-SA 4.0