传输
协议版本:2025-03-26
MCP 使用 JSON-RPC 编码消息。JSON-RPC 消息必须使用 UTF-8 编码。
该协议目前定义了两种标准的客户端-服务器通信传输机制:
客户端应该尽可能支持 stdio。
客户端和服务器也可以以可插拔方式实现自定义传输。
stdio
在 stdio 传输中:
- 客户端将 MCP 服务器作为子进程启动。
- 服务器从其标准输入 (
stdin) 读取 JSON-RPC 消息,并向其标准输出 (stdout) 发送消息。 - 消息可以是 JSON-RPC 请求、通知、响应——或包含一个或多个请求和/或通知的 JSON-RPC 批处理。
- 消息由换行符分隔,并且绝不能包含嵌入的换行符。
- 服务器可以向其标准错误 (
stderr) 写入 UTF-8 字符串以进行日志记录。客户端可以捕获、转发或忽略此日志记录。 - 服务器绝不能向其
stdout写入任何不是有效 MCP 消息的内容。 - 客户端绝不能向服务器的
stdin写入任何不是有效 MCP 消息的内容。
sequenceDiagram
participant Client
participant Server Process
Client->>+Server Process: 启动子进程
loop 消息交换
Client->>Server Process: 写入 stdin
Server Process->>Client: 写入 stdout
Server Process--)Client: stderr 上的可选日志
end
Client->>Server Process: 关闭 stdin,终止子进程
deactivate Server Process
可流式 HTTP
这取代了协议版本 2024-11-05 的 HTTP+SSE 传输。请参阅下面的向后兼容性指南。
在 可流式 HTTP 传输中,服务器作为独立进程运行,可以处理多个客户端连接。此传输使用 HTTP POST 和 GET 请求。服务器可以选择使用 服务器发送事件 (SSE) 来流式传输多个服务器消息。这允许基本的 MCP 服务器以及支持流式传输和服务器到客户端通知和请求的功能更丰富的服务器。
服务器必须提供单个 HTTP 端点路径(此后称为 MCP 端点),该端点同时支持 POST 和 GET 方法。例如,这可能是像 https://example.com/mcp 这样的 URL。
安全警告
实现可流式 HTTP 传输时:
- 服务器必须验证所有传入连接上的
Origin头以防止 DNS 重绑定攻击 - 在本地运行时,服务器应该仅绑定到 localhost (127.0.0.1) 而不是所有网络接口 (0.0.0.0)
- 服务器应该为所有连接实施适当的身份验证
如果没有这些保护,攻击者可以使用 DNS 重绑定从远程网站与本地 MCP 服务器交互。
向服务器发送消息
从客户端发送的每个 JSON-RPC 消息必须是对 MCP 端点的新 HTTP POST 请求。
- 客户端必须使用 HTTP POST 向 MCP 端点发送 JSON-RPC 消息。
- 客户端必须包含
Accept头,列出application/json和text/event-stream作为支持的内容类型。 - POST 请求的主体必须是以下之一:
- 如果输入仅包含(任意数量的)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 流:
- SSE 流应该最终为 POST 正文中发送的每个 JSON-RPC _请求_包含一个 JSON-RPC 响应。这些 响应 可以 批处理。
- 服务器可以在发送 JSON-RPC _响应_之前发送 JSON-RPC 请求_和_通知。这些消息应该与原始客户端 _请求_相关。这些 请求_和_通知 可以 批处理。
- 服务器不应该在为每个接收的 JSON-RPC _请求_发送 JSON-RPC _响应_之前关闭 SSE 流,除非会话过期。
- 在发送所有 JSON-RPC _响应_后,服务器应该关闭 SSE 流。
- 断开连接可能随时发生(例如,由于网络条件)。
- 因此:
- 断开连接不应该被解释为客户端取消其请求。
- 要取消,客户端应该显式发送 MCP
CancelledNotification。 - 为避免由于断开连接而导致的消息丢失,服务器可以使流可恢复。
- 因此:
监听来自服务器的消息
- 客户端可以向 MCP 端点发出 HTTP GET。这可用于打开 SSE 流,允许服务器与客户端通信,而客户端首先不通过 HTTP POST 发送数据。
- 客户端必须包含
Accept头,列出text/event-stream作为支持的内容类型。 - 服务器必须响应此 HTTP GET 返回
Content-Type: text/event-stream,或返回 HTTP 405 Method Not Allowed,指示服务器不在此端点提供 SSE 流。 - 如果服务器启动 SSE 流:
多个连接
- 客户端可以保持同时连接到多个 SSE 流。
- 服务器必须仅在连接的流之一上发送其每个 JSON-RPC 消息;也就是说,它绝不能在多个流上广播相同的消息。
- 消息丢失的风险可以通过使流可恢复来缓解。
可恢复性和重新传递
为了支持恢复断开的连接并重新传递可能丢失的消息:
- 服务器可以将
id字段附加到其 SSE 事件,如 SSE 标准中所述。- 如果存在,ID 必须在该会话中的所有流中全局唯一——或者如果未使用会话管理,则在所有具有该特定客户端的流中全局唯一。
- 如果客户端希望在断开连接后恢复,它应该向 MCP 端点发出 HTTP GET,并包含
Last-Event-ID头以指示它收到的最后一个事件 ID。- 服务器可以使用此头来重放将在最后一个事件 ID 之后发送的消息,在已断开的流上,并从该点恢复流。
- 服务器绝不能重放将在不同流上传递的消息。
换句话说,这些事件 ID 应该由服务器基于_每个流_分配,以充当该特定流中的游标。
会话管理
MCP “会话"由客户端和服务器之间逻辑相关的交互组成,从初始化阶段开始。为了支持希望建立有状态会话的服务器:
- 使用可流式 HTTP 传输的服务器可以在初始化时分配会话 ID,方法是在包含
InitializeResult的 HTTP 响应中包含Mcp-Session-Id头。- 会话 ID 应该是全局唯一且加密安全的(例如,安全生成的 UUID、JWT 或加密哈希)。
- 会话 ID 必须仅包含可见 ASCII 字符(范围从 0x21 到 0x7E)。
- 如果服务器在初始化期间返回
Mcp-Session-Id,则使用可流式 HTTP 传输的客户端必须在其所有后续 HTTP 请求的Mcp-Session-Id头中包含它。- 需要会话 ID 的服务器应该使用 HTTP 400 Bad Request 响应没有
Mcp-Session-Id头的请求(初始化除外)。
- 需要会话 ID 的服务器应该使用 HTTP 400 Bad Request 响应没有
- 服务器可以随时终止会话,之后必须使用 HTTP 404 Not Found 响应包含该会话 ID 的请求。
- 当客户端收到 HTTP 404 响应包含
Mcp-Session-Id的请求时,它必须通过发送没有附加会话 ID 的新InitializeRequest来启动新会话。 - 不再需要特定会话的客户端(例如,因为用户正在离开客户端应用程序)应该向带有
Mcp-Session-Id头的 MCP 端点发送 HTTP DELETE,以显式终止会话。- 服务器可以使用 HTTP 405 Method Not Allowed 响应此请求,指示服务器不允许客户端终止会话。
序列图
sequenceDiagram
participant Client
participant Server
note over Client, Server: 初始化
Client->>+Server: POST InitializeRequest
Server->>-Client: InitializeResponse<br/>Mcp-Session-Id: 1868a90c...
Client->>+Server: POST InitializedNotification<br/>Mcp-Session-Id: 1868a90c...
Server->>-Client: 202 Accepted
note over Client, Server: 客户端请求
Client->>+Server: POST ... 请求 ...<br/>Mcp-Session-Id: 1868a90c...
alt 单个 HTTP 响应
Server->>Client: ... 响应 ...
else 服务器打开 SSE 流
loop 连接保持打开时
Server-)Client: ... 来自服务器的 SSE 消息 ...
end
Server-)Client: SSE 事件:... 响应 ...
end
deactivate Server
note over Client, Server: 客户端通知/响应
Client->>+Server: POST ... 通知/响应 ...<br/>Mcp-Session-Id: 1868a90c...
Server->>-Client: 202 Accepted
note over Client, Server: 服务器请求
Client->>+Server: GET<br/>Mcp-Session-Id: 1868a90c...
loop 连接保持打开时
Server-)Client: ... 来自服务器的 SSE 消息 ...
end
deactivate Server
向后兼容性
客户端和服务器可以与已弃用的 HTTP+SSE 传输(来自协议版本 2024-11-05)保持向后兼容,如下所示:
希望支持旧客户端的服务器应该:
- 继续托管旧传输的 SSE 和 POST 端点,以及为可流式 HTTP 传输定义的新 “MCP 端点”。
- 也可以组合旧的 POST 端点和新的 MCP 端点,但这可能会引入不必要的复杂性。
希望支持旧服务器的客户端应该:
- 从用户接受 MCP 服务器 URL,该 URL 可能指向使用旧传输或新传输的服务器。
- 尝试向服务器 URL POST
InitializeRequest,包含如上定义的Accept头:- 如果成功,客户端可以假设这是支持新可流式 HTTP 传输的服务器。
- 如果失败并出现 HTTP 4xx 状态代码(例如,405 Method Not Allowed 或 404 Not Found):
- 向服务器 URL 发出 GET 请求,期望这将打开 SSE 流并将
endpoint事件作为第一个事件返回。 - 当
endpoint事件到达时,客户端可以假设这是运行旧 HTTP+SSE 传输的服务器,并且应该对所有后续通信使用该传输。
- 向服务器 URL 发出 GET 请求,期望这将打开 SSE 流并将
自定义传输
客户端和服务器可以实现其他自定义传输机制以满足其特定需求。该协议是传输不可知的,可以在支持双向消息交换的任何通信通道上实现。
选择支持自定义传输的实现者必须确保他们保留 MCP 定义的 JSON-RPC 消息格式和生命周期要求。自定义传输应该记录其特定的连接建立和消息交换模式以帮助互操作性。