1454 字
7 分钟
MCP 传输机制
总览
MCP 使用 JSON-RPC 对消息进行编码,所有消息必须使用 UTF-8 编码;协议当前定义了两种标准传输机制:
- stdio(标准输入/输出),通过子进程的 stdin/stdout 进行通信
- 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 时,必须注意以下安全措施:
- 验证所有连接请求的 Origin 头,以防 DNS rebinding 攻击;
- 在本地运行时,应仅绑定到 localhost(127.0.0.1),避免对外网接口(0.0.0.0)开放;
- 应对所有连接实施适当的认证机制。
没有这些防护,攻击者可能借助 DNS rebinding 从远程网页访问本地 MCP 服务器。
发送消息(Client → Server)
- 客户端必须使用 HTTP POST 将每个 JSON-RPC 消息发送到 MCP 端点;
- 请求头 Accept 中应同时列出 application/json 和 text/event-stream;
- POST 请求体可以是:
- 单个 JSON-RPC 请求/通知/响应
- 包含多条请求和/或通知的 JSON 数组(批量)
- 包含多条响应的 JSON 数组(批量)
- 如果 POST 内容仅包含响应或通知:
- 若服务器接受,应返回 HTTP 202 Accepted,无响应体;
- 若无法接受,应返回 HTTP 错误码(如 400 Bad Request),响应体可包含无 id 的 JSON-RPC 错误响应。
- 若 POST 内容包含请求:
- 服务器必须返回 Content-Type: text/event-stream(开启 SSE 流)或 Content-Type: application/json(返回单个 JSON 对象);客户端需同时支持两种情况;
- 若使用 SSE,服务器应最终为每个请求发送一条响应(可批量),期间可在响应前发送与该请求相关的服务器发起的请求/通知;发送完毕后,应关闭 SSE 流(除会话过期外);
- 断线时,不应视为请求取消;取消应由客户端显式发送 CancelledNotification;为防止丢包,服务器可实现可恢复(resumable)SSE。
监听消息(Server → Client)
- 客户端可使用 HTTP GET 打开 SSE 流,以便在未先发送 POST 的情况下接收服务器消息;
- GET 请求头 Accept 中应包含 text/event-stream;
- 服务器要么返回 Content-Type: text/event-stream 并开启 SSE,要么返回 405 Method Not Allowed;
- 在 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 消息格式及生命周期要求,并在文档中说明其连接建立与消息交换方式,以便互操作性。
参考
- Model Context Protocol v2025-03-26: https://modelcontextprotocol.io/specification/2025-03-26/basic/transports
- JSON-RPC 2.0 规范(JSON-RPC 2.0 Specification): https://www.jsonrpc.org/specification
- Server-Sent Events (SSE)(MDN 文档): https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
- DNS 重绑定攻击(DNS Rebinding Attack)解析: https://owasp.org/www-community/attacks/DNS_Rebinding
- HTTP/1.1 协议(RFC 7230-7235): https://datatracker.ietf.org/doc/html/rfc7230 https://datatracker.ietf.org/doc/html/rfc7231
- CORS 与 Origin 安全策略(MDN 文档): https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#access_control_allow_origin