MCP 使用 JSON-RPC 来编码消息。JSON-RPC 消息**必须**使用 UTF-8 编码。 该协议目前定义了两种标准的客户端-服务器通信传输机制:
- stdio,通过标准输入和标准输出进行通信
- 可流式 HTTP
客户端在可能的情况下**应当**支持 stdio。 客户端和服务器也可以以可插拔的方式实现自定义传输。stdio
在 stdio 传输中
- 客户端将 MCP 服务器作为子进程启动。
- 服务器从其标准输入 (
stdin
) 读取 JSON-RPC 消息,并向其标准输出 (stdout
) 发送消息。
- 消息是单个的 JSON-RPC 请求、通知或响应。
- 消息以换行符分隔,并且**不得**包含内嵌的换行符。
- 服务器**可以**向其标准错误 (
stderr
) 写入 UTF-8 字符串用于日志记录。客户端**可以**捕获、转发或忽略此日志记录。
- 服务器**不得**向其
stdout
写入任何不是有效 MCP 消息的内容。
- 客户端**不得**向服务器的
stdin
写入任何不是有效 MCP 消息的内容。
可流式 HTTP
在**可流式 HTTP** 传输中,服务器作为一个独立的进程运行,可以处理多个客户端连接。此传输使用 HTTP POST 和 GET 请求。服务器可以选择性地使用服务器发送事件(SSE)来流式传输多个服务器消息。这允许基本的 MCP 服务器,也允许支持流式传输和服务器到客户端通知和请求的更功能丰富的服务器。 服务器**必须**提供一个支持 POST 和 GET 方法的单一 HTTP 端点路径(以下称为**MCP 端点**)。例如,这可以是一个像 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 *请求*、*通知*或*响应*。
- 如果输入是 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 流
- 服务器**可以**在流上发送 JSON-RPC *请求*和*通知*。
- 这些消息**应当**与任何并发运行的来自客户端的 JSON-RPC *请求*无关。
- 服务器**不得**在流上发送 JSON-RPC *响应*,**除非**是恢复与先前客户端请求关联的流。
- 服务器**可以**随时关闭 SSE 流。
- 客户端**可以**随时关闭 SSE 流。
多个连接
- 客户端**可以**同时连接到多个 SSE 流。
- 服务器**必须**只在其中一个连接的流上发送其每个 JSON-RPC 消息;也就是说,它**不得**在多个流上广播相同的消息。
可恢复性与重新投递
为了支持恢复断开的连接,并重新投递可能丢失的消息
- 服务器**可以**在其 SSE 事件上附加一个
id
字段,如 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 的服务器**应当**对没有
Mcp-Session-Id
头的请求(初始化除外)响应 HTTP 400 Bad Request。
- 服务器**可以**随时终止会话,之后它**必须**对包含该会话 ID 的请求响应 HTTP 404 Not Found。
- 当客户端在包含
Mcp-Session-Id
的请求中收到 HTTP 404 响应时,它**必须**通过发送一个新的不带会话 ID 的 InitializeRequest
来开始一个新会话。
- 不再需要特定会话的客户端(例如,因为用户正在离开客户端应用程序)**应当**向 MCP 端点发送一个带有
Mcp-Session-Id
头的 HTTP DELETE 请求,以明确终止会话。
- 服务器**可以**对此请求响应 HTTP 405 Method Not Allowed,表示服务器不允许客户端终止会话。
时序图
如果使用 HTTP,客户端**必须**在所有后续向 MCP 服务器发出的请求中包含 MCP-Protocol-Version: <protocol-version>
HTTP 头,允许 MCP 服务器根据 MCP 协议版本进行响应。 例如:MCP-Protocol-Version: 2025-06-18
客户端发送的协议版本**应当**是在初始化期间协商的版本。 为实现向后兼容性,如果服务器*没有*收到 MCP-Protocol-Version
头,并且没有其他方式来识别版本——例如,依赖于初始化期间协商的协议版本——服务器**应当**假定协议版本为 2025-03-26
。 如果服务器收到一个带有无效或不受支持的 MCP-Protocol-Version
的请求,它**必须**以 400 Bad Request
响应。向后兼容性
客户端和服务器可以与已弃用的 HTTP+SSE 传输(来自协议版本 2024-11-05)保持向后兼容性,方法如下: 希望支持旧客户端的**服务器**应:
- 继续托管旧传输的 SSE 和 POST 端点,同时托管为可流式 HTTP 传输定义的新“MCP 端点”。
- 也可以将旧的 POST 端点和新的 MCP 端点结合起来,但这可能会引入不必要的复杂性。
希望支持旧服务器的**客户端**应
- 接受用户提供的 MCP 服务器 URL,该 URL 可能指向使用旧传输或新传输的服务器。
- 尝试向服务器 URL 发送一个带有如上定义的
Accept
头的 InitializeRequest
POST 请求
- 如果成功,客户端可以假定这是一个支持新可流式 HTTP 传输的服务器。
- 如果它以 HTTP 4xx 状态码失败(例如,405 Method Not Allowed 或 404 Not Found)
- 向服务器 URL 发出 GET 请求,期望这将打开一个 SSE 流,并返回一个
endpoint
事件作为第一个事件。
- 当
endpoint
事件到达时,客户端可以假定这是一个运行旧 HTTP+SSE 传输的服务器,并应在所有后续通信中使用该传输。
自定义传输
客户端和服务器**可以**实现额外的自定义传输机制以满足其特定需求。该协议是传输无关的,可以在任何支持双向消息交换的通信通道上实现。 选择支持自定义传输的实现者**必须**确保它们保留 MCP 定义的 JSON-RPC 消息格式和生命周期要求。自定义传输**应当**记录其特定的连接建立和消息交换模式,以帮助互操作性。