传输层
协议版本: 2025-11-25
MCP 使用 JSON-RPC 来编码消息。JSON-RPC 消息必须使用 UTF-8 编码。
协议当前定义了两种标准传输机制用于客户端-服务器通信:
- stdio,通过标准输入和标准输出进行通信
- Streamable HTTP,可流式 HTTP 传输
客户端应该尽可能支持 stdio。
客户端和服务器也可以以可插拔的方式实现自定义传输。
1 stdio 传输
在 stdio 传输模式中:
- 客户端将 MCP 服务器作为子进程启动。
- 服务器从其标准输入(
stdin)读取 JSON-RPC 消息,并将消息发送到其标准输出(stdout)。 - 消息是单独的 JSON-RPC 请求、通知或响应。
- 消息以换行符分隔,禁止包含嵌入的换行符。
- 服务器可以向其标准错误(
stderr)写入 UTF-8 字符串用于任何日志目的,包括信息性、调试和错误消息。 - 客户端可以捕获、转发或忽略服务器的
stderr输出,不应该假设stderr输出表示错误条件。 - 服务器禁止向其
stdout写入任何非有效 MCP 消息的内容。 - 客户端禁止向服务器的
stdin写入任何非有效 MCP 消息的内容。
2 Streamable HTTP 传输
此传输方式取代了协议版本 2024-11-05 中的 HTTP+SSE 传输。请参阅下方的向后兼容性指南。
在 Streamable HTTP 传输模式中,服务器作为独立进程运行,可以处理多个客户端连接。此传输使用 HTTP POST 和 GET 请求。服务器可以选择使用服务器发送事件(SSE)来流式传输多个服务器消息。这允许构建基本的 MCP 服务器,以及支持流式传输和服务器到客户端通知和请求的更丰富功能的服务器。
服务器必须提供一个 HTTP 端点路径(以下称为 MCP 端点),支持 POST 和 GET 方法。例如,这可以是一个类似 https://example.com/mcp 的 URL。
2.1 安全警告
在实现 Streamable HTTP 传输时:
- 服务器必须验证所有传入连接的
Origin头以防止 DNS 重绑定攻击 - 如果
Origin头无效或不被允许,服务器必须响应 HTTP 403 Forbidden - 在本地运行时,服务器应该仅绑定到 localhost(127.0.0.1)而不是所有网络接口(0.0.0.0)
- 服务器应该为所有连接实现适当的身份验证
如果没有这些保护措施,攻击者可以使用 DNS 重绑定从远程网站与本地 MCP 服务器交互。
2.2 向服务器发送消息
从客户端发送的每个 JSON-RPC 消息必须是到 MCP 端点的新 HTTP POST 请求。
- 客户端必须使用 HTTP POST 向 MCP 端点发送 JSON-RPC 消息。
- 客户端必须包含
Accept头,列出application/json和text/event-stream作为支持的内容类型。 - POST 请求的正文必须是单个 JSON-RPC 请求、通知或响应。
- 如果输入是 JSON-RPC 响应或通知:
- 如果服务器接受输入,服务器必须返回 HTTP 状态码 202 Accepted,无正文。
- 如果服务器无法接受输入,必须返回 HTTP 错误状态码(例如 400 Bad Request)。HTTP 响应正文可以包含一个没有
id的 JSON-RPC 错误响应。
- 如果输入是 JSON-RPC 请求,服务器必须返回
Content-Type: text/event-stream以启动 SSE 流,或返回Content-Type: application/json以返回一个 JSON 对象。客户端必须支持这两种情况。 - 如果服务器启动 SSE 流:
- 服务器应该立即发送一个包含事件 ID 和空
data字段的 SSE 事件,以便客户端准备重新连接(使用该事件 ID 作为Last-Event-ID)。 - 服务器向客户端发送带有事件 ID 的 SSE 事件后,服务器可以随时关闭连接(而不终止 SSE 流)以避免持有长时间连接。客户端应该按照可恢复性和重新传递中描述的方式重新连接。
- 服务器必须最终返回与客户端的 JSON-RPC 请求匹配的 JSON-RPC 响应,然后应该关闭 SSE 流。
- 如果对请求的响应可能需要很长时间来计算,服务器应该发送 JSON-RPC 请求通知以指示进度。服务器应该将此通知设置为
notifications/progress端点。 - 服务器可以在与客户端请求相关的 JSON-RPC 响应之前发送 JSON-RPC 请求或通知(例如,调用客户端托管的工具)。
- 服务器可以发送与客户端请求无关的 JSON-RPC 请求或通知。这可以包括来自服务器的不同并发 HTTP 请求的请求。
- 客户端应该通过向 MCP 端点发送新的 HTTP POST 来发送对任何服务器请求的响应。
- 服务器应该立即发送一个包含事件 ID 和空
- 如果服务器返回 JSON 对象:
- 正文必须是与客户端的 JSON-RPC 请求对应的 JSON-RPC 响应。服务器禁止在此响应中返回 JSON-RPC 请求或通知。
2.3 监听来自服务器的消息
- 客户端可以向 MCP 端点发出 HTTP GET。这可用于打开 SSE 流,允许服务器与客户端通信,而无需客户端首先通过 HTTP POST 发送数据。
- 客户端必须包含
Accept头,列出text/event-stream作为支持的内容类型。 - 服务器必须在响应此 HTTP GET 时返回
Content-Type: text/event-stream,或者返回 HTTP 405 Method Not Allowed,表示服务器在此端点不提供 SSE 流。 - 如果服务器启动 SSE 流:
- 服务器可以在流上发送 JSON-RPC 请求和通知。
- 这些消息应该与来自客户端的任何并发运行的 JSON-RPC 请求无关。
- 客户端应该通过向 MCP 端点发送新的 HTTP POST 来发送对任何服务器请求的响应。
2.4 多连接
- MCP 客户端可以向 MCP 服务器打开多个并发 SSE 连接,服务器必须支持多个同时连接。
- 这可能是避免队头阻塞所必需的:由于单个连接上的消息必须按顺序传递,客户端和服务器可能希望为可以独立处理的消息使用单独的连接。
- 服务器可以限制客户端可以打开的连接数,如果超过限制则响应 HTTP 429 Too Many Requests。
- 服务器可以随时关闭 SSE 连接,如果客户端希望继续接收来自服务器的消息,应该重新连接。
2.5 可恢复性和重新传递
为支持恢复断开的连接和重新传递可能丢失的消息:
- 服务器可以按照 SSE 标准中的描述向其 SSE 事件附加
id字段。- 如果存在,ID 必须在该会话内的所有流中全局唯一——如果未使用会话管理,则在该特定客户端的所有流中全局唯一。
- 事件 ID 应该编码足够的信息以识别源流,使服务器能够将
Last-Event-ID关联到正确的流。
- 如果客户端希望在断开连接后恢复(无论是由于网络故障还是服务器发起的关闭),应该向 MCP 端点发出 HTTP GET,并包含
Last-Event-ID头以指定其收到的最后一个事件 ID。 - 服务器可以重放客户端自给定事件 ID 以来错过的任何事件。重放的事件可以与后续事件一起批量处理到单个 SSE 数据事件中。
- 如果服务器无法重放错过的事件(例如,如果其历史记录有限),应该发送 JSON-RPC 通知通知客户端。在这种情况下,如果客户端想要从消息丢失中恢复,应该使用自己的重试逻辑。
2.6 会话管理
Streamable HTTP 中的会话管理通过 MCP-Session-Id 头进行操作。
- 服务器可以通过在其对客户端 HTTP 请求(通常是第一个请求)的响应中包含
MCP-Session-Id头来为客户端分配会话 ID。会话 ID 必须是全局唯一的字符串,不超过 4096 个字符。 - 如果服务器使用会话,必须在其对客户端第一个请求的响应中包含
MCP-Session-Id头。 - 客户端必须在所有后续对服务器的 HTTP 请求中包含
MCP-Session-Id头。值必须是从服务器接收的会话 ID。 - 如果服务器收到带有无效或过期会话 ID 的请求,必须响应 HTTP 404 Not Found,除非该请求是
InitializeRequest。响应正文可以包含描述错误的 JSON-RPC 错误响应。- 当客户端收到 HTTP 404 以响应包含其认为有效的会话 ID 的请求时,这意味着其会话不再有效。如果想要继续,客户端必须通过发送不带会话 ID 的新
InitializeRequest来启动新会话。
- 当客户端收到 HTTP 404 以响应包含其认为有效的会话 ID 的请求时,这意味着其会话不再有效。如果想要继续,客户端必须通过发送不带会话 ID 的新
- 客户端可以向 MCP 端点发送带有
MCP-Session-Id头的 HTTP DELETE 以显式终止会话。- 服务器可以对此请求响应 HTTP 405 Method Not Allowed,表示服务器不允许客户端终止会话。
2.7 序列图
2.8 协议版本头
在 Streamable HTTP 传输中,客户端必须在所有 HTTP 请求中包含 MCP-Protocol-Version 头,其值设置为它们正在使用的协议版本。例如,MCP-Protocol-Version: 2025-11-25。
2.9 向后兼容性
客户端和服务器可以按以下方式保持与已弃用的 HTTP+SSE 传输(来自协议版本 2024-11-05)的向后兼容性:
服务器如果想要支持旧客户端,应该:
- 继续托管旧传输的 SSE 和 POST 端点,以及为 Streamable HTTP 传输定义的新"MCP 端点"。
- 也可以将旧的 POST 端点和新的 MCP 端点合并,但这可能会引入不必要的复杂性。
客户端如果想要支持旧服务器,应该:
- 从用户接受 MCP 服务器 URL,该 URL 可能指向使用旧传输或新传输的服务器。
- 尝试向服务器 URL POST 一个
InitializeRequest,带有如上定义的Accept头:- 如果成功,客户端可以假设这是一个支持新 Streamable HTTP 传输的服务器。
- 如果失败并出现以下 HTTP 状态码"400 Bad Request"、"404 Not Found"或"405 Method Not Allowed":
- 向服务器 URL 发出 GET 请求,期望这将打开 SSE 流并返回
endpoint事件作为第一个事件。 - 当
endpoint事件到达时,客户端可以假设这是一个运行旧 HTTP+SSE 传输的服务器,并应该为所有后续通信使用该传输。
- 向服务器 URL 发出 GET 请求,期望这将打开 SSE 流并返回
3 自定义传输
客户端和服务器可以实现额外的自定义传输机制以满足其特定需求。协议与传输无关,可以在任何支持双向消息交换的通信通道上实现。
选择支持自定义传输的实现者必须确保它们保留 MCP 定义的 JSON-RPC 消息格式和生命周期要求。自定义传输应该记录其特定的连接建立和消息交换模式以帮助互操作性。