MCP 使用 JSON-RPC 编码消息。JSON-RPC 消息 必须 采用 UTF-8 编码。 该协议目前定义了两种用于客户端 - 服务器通信的标准传输机制:Documentation Index
Fetch the complete documentation index at: https://mcp.zhcndoc.com/llms.txt
Use this file to discover all available pages before exploring further.
- stdio,通过标准输入和标准输出进行通信
- Streamable HTTP
stdio
在 stdio 传输中,客户端将 MCP 服务器作为子进程启动。 两端通过子进程的标准流进行通信:- 服务器从
stdin读取 JSON-RPC 消息,并向stdout写入 JSON-RPC 消息。 - 消息是单独的 JSON-RPC 请求、通知或响应。
- 消息以换行符分隔,且 MUST NOT 包含嵌入的换行符。
- 服务器 MAY 为任何日志目的向
stderr写入 UTF-8 字符串, 包括信息、调试和错误消息。 - 客户端 MAY 捕获、转发或忽略服务器的
stderr输出,并且 SHOULD NOT 假定stderr输出表示错误条件。 - 服务器 MUST NOT 向其
stdout写入任何不是有效 MCP 消息的内容。 - 客户端 MUST NOT 向服务器的
stdin写入任何不是有效 MCP 消息的内容。
发送消息
客户端通过向服务器的stdin 写入 JSON-RPC 请求、通知或
响应来发送消息,每行一条消息。
接收消息
所有服务器到客户端的消息——对客户端请求的响应、进行中的 通知(notifications/progress、notifications/message),以及
subscriptions/listen
流上的投递——都会到达 stdout,每行一条消息,多路复用到单个
共享通道上。
为了区分属于不同并发订阅的通知,客户端 MUST 使用
_meta 中携带的 io.modelcontextprotocol/subscriptionId 字段来关联通知。详情请参见
SubscriptionsListenRequest
的 schema。
请求元数据
stdio 传输的所有请求元数据都以内联方式携带在 JSON-RPC 消息体中。协议版本、客户端标识以及 每个请求的能力信息位于_meta.io.modelcontextprotocol/*;
方法名和参数则位于 JSON-RPC 所规定的位置。没有
头部层。
取消
要取消正在进行的请求,客户端 MUST 发送一条notifications/cancelled 通知,引用该请求的 ID。由于
stdio 是单一共享的双向通道,因此没有可关闭的按请求流。
服务器 SHOULD 尽快停止已取消请求的工作,并且
MUST NOT 为其发送任何后续消息。完整规则请参见
Cancellation。
关闭
客户端 SHOULD 通过以下方式发起关闭:- 关闭子进程(服务器)的输入流。
- 等待服务器退出。
- 如果服务器未在合理时间内退出,则使用适合该操作系统的机制强制终止 进程。
SIGTERM
升级到 SIGKILL。在没有 POSIX 信号的 Windows 上,客户端可以
使用 TerminateProcess
或 Job Objects。
当服务器的标准输入被关闭或读取
返回文件结束符时,服务器 SHOULD 立即退出。这是主要的优雅关闭信号,也是唯一可移植的信号,因此遵守它可以减少强制终止的需要。
服务器 MAY 通过关闭其到客户端的输出流并退出来发起关闭。
意外终止
如果服务器进程意外退出,客户端 SHOULD 重新启动它。 由于协议是无状态的,任何正在进行中的请求都会丢失,客户端可以 用新进程重试这些请求。活动的subscriptions/listen 流也必须在重启后
重新建立。
向后兼容性
支持现代(按请求元数据)MCP 版本和需要initialize 握手的旧版的客户端 SHOULD 在发送任何其他请求之前先通过
server/discover 进行探测。如果服务器返回 Method not found(-32601),
客户端则回退到旧版 initialize 握手。如果服务器返回
UnsupportedProtocolVersionError,则表示其使用的是不含
initialize 的 MCP 版本——客户端 SHOULD 改用所宣传的 supported
列表中的某个版本重试,而不是回退到 initialize。参见
Lifecycle: Backward Compatibility。
仅支持现代版本的客户端不需要探测。
Streamable HTTP
这替代了协议版本 2024-11-05 中的 HTTP+SSE 传输。
见下文 向后兼容性。
https://example.com/mcp 的 URL。
安全与端点
在实现 Streamable HTTP 传输时:- Servers MUST validate the
Originheader on all incoming connections to prevent DNS rebinding attacks.- If the
Originheader is present and invalid, servers MUST respond with HTTP 403 Forbidden. The HTTP response body MAY comprise a JSON-RPC error response that has noid.
- If the
- When running locally, servers SHOULD bind only to localhost (127.0.0.1) rather than all network interfaces (0.0.0.0).
- Servers SHOULD implement proper authentication for all connections.
发送消息
客户端发送的每条 JSON-RPC 消息 MUST 都是到 MCP endpoint 的一个新的 HTTP POST 请求。- 客户端 MUST 使用 HTTP POST 发送 JSON-RPC 消息。
- 客户端 MUST 在
Accept头中同时列出application/json和text/event-stream作为受支持的内容类型。 - 客户端 MUST 在每个 POST 请求中包含 请求元数据头 。
- HTTP POST 的正文 MUST 是一个单独的 JSON-RPC request、 notification,或对服务器发起的输入请求的 response(见 接收消息)。
- 如果正文是 JSON-RPC notification 或对服务器发起的输入请求的
response:
- 如果服务器接受它,服务器 MUST 返回 HTTP 状态码
202 Accepted,且没有正文。 - 如果服务器无法接受它,服务器 MUST 返回 HTTP 错误状态码
(例如
400 Bad Request)。HTTP 响应正文 MAY 包含一个没有id的 JSON-RPC error response。
- 如果服务器接受它,服务器 MUST 返回 HTTP 状态码
- 如果正文是 JSON-RPC request,服务器 MUST 返回
Content-Type: application/json(单个 JSON 对象)或Content-Type: text/event-stream(SSE 响应流)之一。 客户端 MUST 同时支持两者。
接收消息
当服务器返回 SSE 响应流 (Content-Type: text/event-stream)时:
- 服务器 MAY 发送 JSON-RPC notifications——例如
notifications/progress或notifications/message— 在最终响应之前发送。这些通知 MUST 与 发起该请求的客户端请求相关联。 - 服务器 MUST NOT 在此流上发送独立的 JSON-RPC requests。
服务器到客户端的交互(sampling、elicitation、list-roots)被嵌入为
InputRequiredResult中的输入请求,遵循 SEP-2322 (MRTR),而不是作为单独的请求在此或其他任何流上 传递。 - 最终的 JSON-RPC response SHOULD 终止该流。
subscriptions/listen
request。服务器的响应本身是一个保持打开的 SSE 流,并
投递客户端选择订阅的变更通知(例如
notifications/tools/list_changed 或 notifications/resources/updated)。
诸如 notifications/progress 和
notifications/message 之类按请求作用域的通知 不会 在 listen 流上投递——它们
只会在其所关联请求的响应流中传输。
在启动 SSE 流时,服务器 SHOULD 在 HTTP 响应中包含
X-Accel-Buffering: no 头。这会指示反向代理(例如 nginx)禁用响应缓冲,确保 SSE 事件能够立即传递给客户端,而不是被保留在缓冲区中。没有该头时,代理可能会在发送给客户端之前累积消息,从而引入不必要的延迟,并可能破坏 SSE 通信的实时特性。
不支持通过 Last-Event-ID 进行可恢复的 SSE 流。
取消
关闭 SSE 响应流 MUST 被服务器视为该请求的取消。由于 每个请求都有自己的响应流,因此传输级断开是明确无歧义的。服务器 SHOULD 尽快停止已取消请求的工作,并且 MUST NOT 为其发送任何后续消息。完整规则请参见 Cancellation。请求元数据
Streamable HTTP 传输会将选定的 JSON-RPC 正文字段镜像到 HTTP 头中,以便中介层(负载均衡器、网关、可观测性 工具)无需解析正文即可路由和检查请求。协议版本头
发送到 MCP endpoint 的每个 POST 请求 MUST 包含一个MCP-Protocol-Version 头。
例如:MCP-Protocol-Version: DRAFT-2026-v1
该头值 MUST 与请求正文的
_meta 中携带的 io.modelcontextprotocol/protocolVersion 字段匹配。
如果这些值不匹配,服务器 MUST 拒绝该请求,
返回 400 Bad Request 和一个 HeaderMismatch JSON-RPC 错误
(见 Server Validation)。
如果服务器不实现所请求的协议版本(无论该版本对服务器来说是未知版本,还是服务器已知但选择不支持的版本),它 MUST 响应
400 Bad Request 和一个
UnsupportedProtocolVersionError,列出其支持的版本。详见
Lifecycle: Protocol Version Negotiation
的协商流程。
如果服务器不实现所请求的 RPC 方法,它 MUST 响应
404 Not Found 和 JSON-RPC 错误码 -32601
(Method not found)。JSON-RPC 错误正文可将此情况与由未托管现代 MCP endpoint 的旧版 HTTP+SSE 服务器返回的 404 区分开来(见 Backward Compatibility)。
支持早于 2025-06-18 的协议版本客户端(该版本未定义 MCP-Protocol-Version 头)的服务器 MAY 将缺少该头的请求视为协议版本 2025-03-26。不支持此类客户端的服务器 MUST 按照 Server Validation 拒绝缺少该头的请求。
标准请求头
| 头名称 | 来源字段 | 适用范围 |
|---|---|---|
Mcp-Method | method | 所有请求和通知 |
Mcp-Name | params.name or params.uri | tools/call、resources/read、prompts/get 请求 |
tools/call request:
resources/read 请求:
来自工具参数的自定义头
MCP 服务器 MAY 使用参数的 schema 中的inputSchema 内的
x-mcp-header 扩展属性,将特定工具参数映射到
HTTP 头中。详见
Tool Definitions
,了解如何为工具参数添加注解。
虽然服务器使用 x-mcp-header 是可选的,但客户端 MUST
支持此功能。当服务器的工具定义包含
x-mcp-header 注解时,符合规范的客户端 MUST 将指定的参数值映射到 HTTP 头中。
Schema 扩展
x-mcp-header 属性指定用于构造
头名称 Mcp-Param-{name} 的名称部分。
x-mcp-header 值的约束:
- MUST NOT 为空
- MUST 仅包含 ASCII 字符(不包括空格和
:) - 在
inputSchema中所有x-mcp-header值之间 MUST 具有不区分大小写的唯一性 - MUST 仅应用于原始类型参数(number、string、boolean)
x-mcp-header 值
违反这些约束的工具定义。拒绝的含义是客户端 MUST 将无效工具从
tools/list 的结果中排除。客户端 SHOULD 在拒绝工具定义时记录一条
警告,其中包括工具名称和拒绝原因。
工具定义示例:
值编码
客户端 MUST 在将参数值包含到 HTTP 头之前对其进行编码,以确保安全传输并防止注入攻击。 类型转换:将参数值转换为其字符串表示形式:string:按原值使用number:转换为十进制字符串表示形式(例如,42、3.14)boolean:转换为小写的"true"或"false"
=?base64? 和后缀 ?= 表示该值已进行
Base64 编码。需要检查这些值的服务器和中介层 MUST 相应地对其进行解码。
编码示例:
| 原始值 | 原因 | 编码后的头值 |
|---|---|---|
"us-west1" | 纯 ASCII | Mcp-Param-Region: us-west1 |
"Hello, 世界" | 包含非 ASCII | Mcp-Param-Greeting: =?base64?SGVsbG8sIOS4lueVjA==?= |
" padded " | 前导/尾随空格 | Mcp-Param-Text: =?base64?IHBhZGRlZCA=?= |
"line1\nline2" | 包含换行符 | Mcp-Param-Text: =?base64?bGluZTEKbGluZTI=?= |
客户端行为
当通过 HTTP 传输构造tools/call 请求时,客户端
MUST:
- 从请求正文中提取任何标准头的值(例如,
method、params.name、params.uri)。 - 将
Mcp-Method头以及(如适用)Mcp-Name头附加到 请求中。 - 检查工具的
inputSchema中标记了x-mcp-header的属性,并提取每个参数的值。 - 按照 值编码 规则对这些值进行编码。
- 将
Mcp-Param-{Name}: {Value}头附加到请求中。
自定义头的服务器行为
不识别Mcp-Param-{Name} 头的中间服务器
MUST 转发它,并在其他方面忽略它,正如
HTTP Semantics RFC 所要求的那样。
服务器 MUST 拒绝包含无效字符的、被识别的 Mcp-Param-{Name} 头
(见 值编码)。
任何处理消息正文的服务器 MUST 验证已编码的
头值(若为 Base64 编码,则在解码后)是否与请求正文中的相应
值匹配。若任何验证失败,服务器 MUST 以
400 Bad Request HTTP 状态和 JSON-RPC 错误码
-32001(HeaderMismatch)拒绝请求。
| 场景 | 客户端行为 | 服务器行为 |
|---|---|---|
| 提供了参数值 | 客户端必须包含该头 | 服务器必须验证头与正文匹配 |
参数值为 null | 客户端必须省略该头 | 服务器不得期望该头 |
| 参数未出现在参数中 | 客户端必须省略该头 | 服务器不得期望该头 |
| 客户端省略头但正文中有值 | 不符合规范的客户端 | 服务器必须拒绝该请求 |
大小写敏感性
头名称(在 RFC 9110 中称为“字段名”) 是不区分大小写的。客户端和服务器 MUST 对头名称使用不区分大小写的 比较。头_值_(例如方法名)是 区分大小写的。服务器验证
处理请求正文的服务器 MUST 拒绝那些其 头中指定的值与请求正文中的相应值不匹配的请求。这可防止在 网络中不同组件依赖不同事实来源时出现潜在安全漏洞 (例如,负载均衡器根据头值进行路由,而 MCP 服务器 根据正文值执行)。 当因头验证失败而拒绝请求时,服务器 MUST 返回 HTTP 状态400 Bad Request,并且 SHOULD 使用以下错误码包含一个 JSON-RPC 错误
响应:
| Code | Name | Description |
|---|---|---|
-32001 | HeaderMismatch | HTTP 头与请求正文中的相应值不匹配,或者必需的头缺失/格式错误。 |
-32000 到 -32099)内。
错误响应示例:
- 缺少必需的标准头(
MCP-Protocol-Version、Mcp-Method、Mcp-Name)。 - 头值与对应的请求正文值不匹配。
- 头值包含无效字符。
中介层 MUST 在验证失败时返回适当的 HTTP 错误状态(例如,
400 Bad Request),但不要求返回
JSON-RPC 错误响应。向后兼容性
支持现代(按请求元数据)MCP 版本和需要initialize 握手的旧版的客户端 MAY 通过先尝试现代请求来检测服务器实现的是哪个时代。在
400 Bad Request 时,客户端 SHOULD 在回退前检查响应正文:
现代服务器也会对
UnsupportedProtocolVersionError、
MissingRequiredClientCapabilityError 和头验证失败使用 400。
- 如果正文包含可识别的现代 JSON-RPC 错误,则表示服务器支持
现代版本的 MCP——应改用宣传的
supported版本重试 或修正请求,而不是回退。 - 如果正文为空或不是可识别的现代 JSON-RPC 错误,则
回退到
initialize,并在后续请求中继续使用旧版。
- 继续同时托管旧传输的 SSE 和 POST 端点,
以及为 Streamable HTTP 传输定义的新 “MCP endpoint”。
- 也可以将旧的 POST 端点与新的 MCP endpoint 合并,但这可能会引入不必要的复杂性。
- 接受来自用户的 MCP 服务器 URL,该 URL 可能指向使用旧传输或新传输的服务器。
- 尝试向该服务器 URL 发送 POST 请求,并使用如上所定义的
Accept头:- 如果成功,客户端可以假定这是支持 新 Streamable HTTP 传输的服务器。
- 如果失败并返回 HTTP 状态码
400 Bad Request、404 Not Found或405 Method Not Allowed,且响应正文不是 可识别的现代 JSON-RPC 错误(现代服务器会为不支持的版本、未知方法或头验证失败返回此类错误):- 向服务器 URL 发起 GET 请求,期望这会打开
一个 SSE 流,并将
endpoint事件作为第一个事件返回。 - 当收到
endpoint事件时,客户端可以假定这是 运行旧 HTTP+SSE 传输的服务器,并应在后续所有通信中使用该 传输。
- 向服务器 URL 发起 GET 请求,期望这会打开
一个 SSE 流,并将