可流式 HTTP
社区译文;来源: MCP 80041ab0
在可流式 HTTP 传输中,服务器作为独立进程运行,可以处理多个客户端连接。概括而言:
- 服务器公开一个接受 POST 的 HTTP 端点(即 MCP 端点)。
- 客户端将每个 JSON-RPC 请求或通知作为独立的 HTTP POST 发送。
- 服务器以单个 JSON 对象或限定于该请求的服务器发送事件(英文)(SSE)流响应每个请求; 流中先承载请求相关通知,最后承载最终响应。
- 服务器到客户端的交互(采样、信息征询、根目录)按照 多轮往返请求(MRTR)(SEP-2322(英文))作为输入请求嵌入结果。
- 长期变更通知(例如列表变更和资源更新)在
subscriptions/listen请求的响应流上传递。
这些交互的时序图参见消息流。
服务器 MUST 提供一个支持 POST 的 HTTP 端点路径(下文称为 MCP 端点)。
例如,该端点可以是类似 https://example.com/mcp 的 URL。
安全与端点
实现可流式 HTTP 传输时:
- 服务器 MUST 验证所有传入连接的
OriginHeader,以防止 DNS 重绑定攻击。- 如果存在
OriginHeader 且值无效,服务器 MUST 以 HTTP 403 Forbidden 响应。 HTTP 响应正文 MAY 包含一个没有id的 JSON-RPC 错误响应。
- 如果存在
- 在本地运行时,服务器 SHOULD 仅绑定到 localhost(127.0.0.1),而不是所有网络接口(0.0.0.0)。
- 服务器 SHOULD 为所有连接实现适当的身份认证。
如果缺少这些保护,攻击者可能利用 DNS 重绑定从远程网站与本地 MCP 服务器交互。
发送消息
客户端发送的每条 JSON-RPC 消息 MUST 是一个发往 MCP 端点的新 HTTP POST 请求。
- 客户端 MUST 使用 HTTP POST 发送 JSON-RPC 消息。
- 客户端 MUST 包含一个
AcceptHeader,同时列出application/json和text/event-stream两种受支持的内容类型。 - 客户端 MUST 在每个 POST 请求中包含请求元数据 Header。
- HTTP POST 的正文 MUST 是单个 JSON-RPC 请求_或_通知。客户端 MUST NOT 发送 JSON-RPC 响应。
- 如果正文是 JSON-RPC 通知:
- 如果服务器接受该通知,服务器 MUST 返回 HTTP 状态码
202 Accepted,且不包含正文。 - 如果服务器无法接受该通知,则 MUST 返回 HTTP 错误状态码(例如
400 Bad Request)。 HTTP 响应正文 MAY 包含一个没有id的 JSON-RPC 错误响应。
- 如果服务器接受该通知,服务器 MUST 返回 HTTP 状态码
- 如果正文是 JSON-RPC 请求,服务器 MUST 返回
Content-Type: application/json(单个 JSON 对象)或Content-Type: text/event-stream(SSE 响应流)。客户端 MUST 同时支持两者。
notifications/cancelled 仅用于 stdio 传输;
在可流式 HTTP 上,关闭 SSE 响应流本身就是取消信号,不应再发送 notifications/cancelled 消息
(参见[取消][cancellation])。上述通知规则描述了通知 POST 的传输机制;本修订版未定义通知 POST 的 Header 要求。接收消息
当服务器返回 SSE 响应流(Content-Type: text/event-stream)时:
- 服务器 MAY 在最终响应之前发送 JSON-RPC 通知,例如
notifications/progress或notifications/message。这些通知 MUST 与发起它们的客户端请求相关。 - 服务器 MUST NOT 在此流上发送独立的 JSON-RPC 请求。服务器到客户端的交互
(采样、信息征询、列出根目录)按照 MRTR(SEP-2322(英文))嵌入
InputRequiredResult内的输入请求,而不是在此流或任何其他流上作为独立请求传递。 这与协议版本2025-03-26到2025-11-25的可流式 HTTP 不同;在那些版本中, 服务器可以在 SSE 流上发送此类请求。 - 最终 JSON-RPC 响应 SHOULD 终止该流。
长期通知流通过发送 subscriptions/listen 请求获得。服务器响应本身是保持打开的 SSE 流,
用于传递客户端订阅的变更通知(例如 notifications/tools/list_changed 或
notifications/resources/updated)。notifications/progress 和 notifications/message
等限定于请求的通知不会在监听流上传递,而只会在与其相关的请求响应流上传递。
启动 SSE 流时,服务器 SHOULD 在 HTTP 响应中包含 X-Accel-Buffering: no Header。
这会指示反向代理(例如 nginx)禁用响应缓冲,确保 SSE 事件立即传递给客户端,而不是滞留在缓冲区中。
缺少此 Header 时,代理可能先累积消息再发送给客户端,从而引入不必要的延迟,并可能破坏 SSE 通信的实时特性。
subscriptions/listen][subscriptions-listen] 响应流,
建议服务器定期发出 SSE 注释行(以冒号开头的行,例如 :\r\n)作为 keep-alive。
这样可以避免在没有通知流动的静默期内,由中间组件或客户端空闲超时关闭连接。根据
[SSE 规范(英文)][sse],任何以冒号开头的行都是不携带事件数据的注释;客户端必须忽略此类行,
且不得将其视为格式错误的输入。不支持通过 Last-Event-ID 恢复 SSE 流。
消息流
以下时序图展示单个 MCP 端点上的消息流。
请求与响应。 每个请求都是独立的 POST;服务器逐个请求选择以单个 JSON 对象或 SSE 流响应:
sequenceDiagram
participant Client
participant Server
note over Client,Server: Simple response
Client->>Server: POST tools/call (JSON-RPC request)
Server-->>Client: 200 OK, application/json<br/>JSON-RPC response
note over Client,Server: Streaming response
Client->>Server: POST tools/call (JSON-RPC request)
note over Server: Opens SSE stream<br/>scoped to this request
Server-->>Client: SSE: notifications/progress
Server-->>Client: SSE: notifications/progress
Server-->>Client: SSE: JSON-RPC response
note over Client,Server: Stream closes
note over Client,Server: Notification
Client->>Server: POST (JSON-RPC notification)
Server-->>Client: 202 Accepted
服务器到客户端的交互(MRTR)。 当服务器需要客户端输入(采样、信息征询或根目录)时,
它不会发送自己的 JSON-RPC 请求,而是返回包含 inputRequests 的
InputRequiredResult;客户端随后携带匹配的 inputResponses
重试原始请求(参见多轮往返请求):
sequenceDiagram
participant Client
participant Server
Client->>Server: POST tools/call (id: 1)
note over Server: Needs user input or<br/>an LLM completion
Server-->>Client: InputRequiredResult<br/>(inputRequests: elicitation/create)
note over Client: Gathers the requested input
Client->>Server: POST tools/call (id: 2)<br/>(original params + inputResponses)
Server-->>Client: Final result
变更通知。 希望接收服务器主动变更通知的客户端使用 subscriptions/listen
打开长期流;该响应流保持打开,并且只承载客户端订阅的通知类型:
sequenceDiagram
participant Client
participant Server
Client->>Server: POST subscriptions/listen<br/>(notification filter)
Server-->>Client: SSE: notifications/subscriptions/acknowledged
note over Client,Server: Stream stays open
Server-->>Client: SSE: notifications/tools/list_changed
Server-->>Client: SSE: notifications/resources/updated
note over Client,Server: Until the client or server closes the stream
取消
服务器 MUST 将 SSE 响应流关闭视为对该请求的取消。由于每个请求都有自己的响应流, 传输层断开不会产生歧义。服务器 SHOULD 尽快停止已取消请求的工作,并且 MUST NOT 再为其发送任何消息。完整规则参见取消。
请求元数据
可流式 HTTP 传输将选定的 JSON-RPC 正文字段镜像到 HTTP Header,使中间组件 (负载均衡器、网关、可观测性工具)无需解析正文即可路由和检查请求。
协议版本 Header
每个发往 MCP 端点的 POST 请求 MUST 包含 MCP-Protocol-Version Header。
例如:MCP-Protocol-Version: 2026-07-28
Header 值 MUST 与请求正文 _meta 中的 io.modelcontextprotocol/protocolVersion 字段匹配。
如果值不匹配,服务器 MUST 以 400 Bad Request 和 HeaderMismatch JSON-RPC 错误拒绝请求
(参见服务器验证)。
如果服务器未实现请求的协议版本(无论该版本对服务器未知,还是服务器选择不支持某个已知版本),
则 MUST 以 400 Bad Request 和列出其支持版本的
UnsupportedProtocolVersionError 响应。
协商流程参见版本控制:协议版本协商。
如果服务器未实现请求的 RPC 方法,则 MUST 以 404 Not Found 和错误代码为 -32601
(Method not found)的 JSON-RPC 错误响应。JSON-RPC 错误正文可将此情况与旧版
HTTP+SSE 服务器因未托管现代 MCP 端点而返回的 404 区分开
(参见向后兼容)。
支持早于 2025-06-18 的协议版本(这些版本未定义 MCP-Protocol-Version Header)的服务器
MAY 将省略该 Header 的请求视为协议版本 2025-03-26。不支持此类客户端的服务器
MUST 按服务器验证拒绝缺少该 Header 的请求。
标准请求 Header
| Header Name | Source Field | Required For |
|---|---|---|
Mcp-Method | method | All requests |
Mcp-Name | params.name or params.uri | tools/call, resources/read, prompts/get requests |
这些 Header 是符合规范的 REQUIRED 条件。
如果 Mcp-Name 源值无法安全表示为纯 ASCII Header 值,客户端 MUST 使用
值编码中描述的 Base64 哨兵格式进行编码。
tools/call 请求:
POST /mcp HTTP/1.1
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"location": "Seattle, WA"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "ExampleClient",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}resources/read 请求:
POST /mcp HTTP/1.1
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: resources/read
Mcp-Name: file:///projects/myapp/config.json
{
"jsonrpc": "2.0",
"id": 2,
"method": "resources/read",
"params": {
"uri": "file:///projects/myapp/config.json",
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "ExampleClient",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}来自工具参数的自定义 Header
MCP 服务器 MAY 在工具 inputSchema 内的参数 schema 中使用 x-mcp-header 扩展属性,
指定要镜像到 HTTP Header 的特定工具参数。如何标注工具参数的详细信息参见
工具定义。
服务器可选择是否使用 x-mcp-header,但客户端 MUST 支持此功能。当服务器的工具定义包含
x-mcp-header 标注时,符合规范的客户端 MUST 将指定参数值镜像到 HTTP Header。
Schema 扩展
x-mcp-header 属性指定用于构造 Header 名称 Mcp-Param-{name} 的名称部分。
对 x-mcp-header 值的约束:
- MUST NOT 为空
- MUST 匹配 HTTP field-name token 语法(
1*tchar,参见 RFC 9110 第 5.1 节(英文)) - MUST NOT 包含控制字符,包括回车(CR,
\r)或换行(LF,\n) - 在
inputSchema的所有x-mcp-header值中,按大小写不敏感比较时 MUST 唯一 - MUST 仅应用于基本类型(integer、string、boolean)的参数。不得应用于
number类型参数。 Integer 值 MUST 位于 JavaScript 的安全范围内(−253+1 到 253−1) - MUST 仅应用于从 schema 根_静态可达_的属性:可达路径只能由
properties键组成。 路径 MUST NOT 经过items(或任何其他数组关键字)、组合关键字(oneOf、anyOf、allOf、not)、条件关键字(if/then/else)或$ref。只要路径中的每一步都是properties键,就允许嵌套对象属性。出现在任何其他位置的x-mcp-header标注会使该标注 以及整个工具定义无效。
Header 提取定义为:读取被标注属性精确属性路径(通向该属性的 properties 键链)上的实例值。
如果调用参数中该路径没有值,则省略该 Header。
使用可流式 HTTP 传输的客户端 MUST 拒绝任何 x-mcp-header 值违反这些约束的工具定义。
拒绝意味着客户端 MUST 从 tools/list 结果中排除无效工具。客户端 SHOULD 在拒绝工具定义时
记录警告,其中包括工具名称和拒绝原因。这样,单个格式错误的工具定义不会妨碍其他有效工具使用。
使用其他传输(例如 stdio)的客户端 MAY 完全忽略 x-mcp-header 标注。
工具定义示例:
{
"name": "execute_sql",
"description": "Execute SQL on Google Cloud Spanner",
"inputSchema": {
"type": "object",
"properties": {
"region": {
"type": "string",
"description": "The region to execute the query in",
"x-mcp-header": "Region"
},
"query": {
"type": "string",
"description": "The SQL query to execute"
}
},
"required": ["region", "query"]
}
}生成的 HTTP 请求:
POST /mcp HTTP/1.1
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: execute_sql
Mcp-Param-Region: us-west1
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "ExampleClient",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
},
"name": "execute_sql",
"arguments": {
"region": "us-west1",
"query": "SELECT * FROM users"
}
}
}值编码
客户端将参数值放入 HTTP Header 前 MUST 对其编码,以确保安全传输并防止注入攻击。
类型转换:将参数值转换为其字符串表示:
string:原样使用该值integer:转换为十进制字符串表示(例如42、-7)boolean:转换为小写的"true"或"false"
根据 RFC 9110(英文),HTTP Header 字段值必须由可见 ASCII 字符 (0x21-0x7E)、空格(0x20)和水平制表符(0x09)组成。当值无法安全表示为纯 ASCII Header 值时 (例如包含非 ASCII 字符、控制字符或首尾空白),客户端 MUST 使用以下格式对 UTF-8 表示进行 Base64 编码:
Mcp-Param-{Name}: =?base64?{Base64EncodedValue}?=同一编码规则适用于 Mcp-Name Header 值。工具和提示词名称仅被 SHOULD 约束为 Header 安全字符,
因此安全集合之外的名称(或资源 URI)按以下方式承载:
Mcp-Name: =?base64?{Base64EncodedValue}?=前缀 =?base64? 和后缀 ?= 表示该值经过 Base64 编码。这些标记区分大小写,并且 MUST
完全按所示形式(小写)出现。需要检查这些值的服务器和中间组件 MUST 相应地解码。
特别是,服务器在服务器验证期间将编码的 Mcp-Name 或
Mcp-Param-{Name} 值与相应的请求正文值比较前 MUST 对其解码。
为避免歧义,客户端对于匹配哨兵模式(即以 =?base64? 开头并以 ?= 结尾)的任何纯 ASCII 值,
也 MUST 使用 Base64 编码。
编码示例:
| Original Value | Reason | Encoded Header Value |
|---|---|---|
"us-west1" | Plain ASCII | Mcp-Param-Region: us-west1 |
"Hello, 世界" | Contains non-ASCII | Mcp-Param-Greeting: =?base64?SGVsbG8sIOS4lueVjA==?= |
" padded " | Leading/trailing spaces | Mcp-Param-Text: =?base64?IHBhZGRlZCA=?= |
"line1\nline2" | Contains newline | Mcp-Param-Text: =?base64?bGluZTEKbGluZTI=?= |
"=?base64?literal?=" | Matches sentinel pattern | Mcp-Param-Val: =?base64?PT9iYXNlNjQ/bGl0ZXJhbD89?= |
客户端行为
通过 HTTP 传输构造 tools/call 请求时,客户端 MUST:
- 从请求正文中提取所有标准 Header 的值(例如
method、params.name、params.uri)。 - 向请求附加
Mcp-MethodHeader,并在适用时附加Mcp-NameHeader。 - 检查工具的
inputSchema,查找标有x-mcp-header的属性,并从每个被标注属性的精确属性路径提取值; 如果没有值,则省略 Header(参见 Schema 扩展)。 - 按值编码规则编码这些值。
- 向请求附加一个
Mcp-Param-{Name}: {Value}Header。
如果服务器因必要的 Mcp-Param-* Header 缺失或与正文不匹配,而以
HeaderMismatch 错误拒绝请求,客户端 SHOULD 调用 tools/list
检查工具 inputSchema 是否发生变化,然后使用适当 Header 重试原始请求。
服务器对自定义 Header 的行为
无法识别某个 Mcp-Param-{Name} Header 的中间服务器 MUST 按
HTTP 语义 RFC(英文)要求转发该 Header,并在其他方面忽略它。
服务器 MUST 拒绝包含无效字符的、已识别的 Mcp-Param-{Name} Header
(参见值编码)。
任何处理消息正文的服务器 MUST 验证编码后的 Header 值(如果采用 Base64 编码,则先解码)
与请求正文中的相应值匹配。如果任何验证失败,服务器 MUST 以 400 Bad Request HTTP 状态和
JSON-RPC 错误代码 -32020(HeaderMismatch)拒绝请求。
| Scenario | Client Behavior | Server Behavior |
|---|---|---|
| Parameter value provided | Client MUST include the header | Server MUST validate header matches body |
Parameter value is null | Client MUST omit the header | Server MUST NOT expect the header |
| Parameter not in arguments | Client MUST omit the header | Server MUST NOT expect the header |
| Client omits header but value is in body | Non-conforming client | Server MUST reject the request |
大小写敏感性
Header 名称(在 RFC 9110(英文)中称为“字段名称”)不区分大小写。 客户端和服务器 MUST 对 Header 名称使用不区分大小写的比较。Header 值(例如方法名称)区分大小写。
服务器验证
处理请求正文的服务器 MUST 拒绝 Header 指定值与请求正文相应值不匹配的请求。 这可防止网络中的不同组件依赖不同真相源时产生潜在安全漏洞(例如,负载均衡器依据 Header 值路由, 而 MCP 服务器依据正文值执行)。
42.0 和 42 视为相等)。因 Header 验证失败而拒绝请求时,服务器 MUST 返回 HTTP 状态 400 Bad Request,并且 MUST
使用以下错误代码包含 JSON-RPC 错误响应:
| Code | Name | Description |
|---|---|---|
-32020 | HeaderMismatch | The HTTP headers do not match the corresponding values in the request body, or required headers are missing/malformed. |
此错误代码分配自 MCP 规范为协议定义错误预留的子范围。参见 错误代码。
错误响应示例:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32020,
"message": "Header mismatch: Mcp-Name header value 'foo' does not match body value 'bar'"
}
}验证失败条件包括:
- 缺少必要的标准 Header(
MCP-Protocol-Version、Mcp-Method、Mcp-Name)。 - Header 值与相应请求正文值不匹配。对于允许 Base64 哨兵编码的 Header(
Mcp-Name和Mcp-Param-{Name}),服务器在与正文值比较前 MUST 解码已编码值 (参见值编码)。 - Header 值包含无效字符。
400 Bad Request),
但不要求返回 JSON-RPC 错误响应。MCP-Protocol-Version Header 指示的版本要求进行 Header 与正文验证。如果版本较旧或缺少该 Header,
中间组件 SHOULD 拒绝请求,而不是信任未经验证的 Header 值。向后兼容
同时支持现代(逐请求元数据)MCP 版本和需要 initialize 握手的旧版本的客户端,
MAY 通过先尝试现代请求来检测服务器实现的是哪个协议时代。收到 400 Bad Request 时,
客户端在回退前 SHOULD 检查响应正文:现代服务器也会对
UnsupportedProtocolVersionError、
MissingRequiredClientCapabilityError 和 Header 验证失败使用 400。
- 如果正文包含已识别的现代 JSON-RPC 错误,则服务器使用现代 MCP 版本:应使用公布的
supported版本重试或修正请求,而不是回退。 - 如果正文为空或不是已识别的现代 JSON-RPC 错误,则回退到
initialize,并在后续请求中继续使用旧版本。
有关协议时代模型和面向实现者的兼容性矩阵,请参见版本控制:向后兼容。
早期可流式 HTTP 修订版
协议版本 2025-03-26 到 2025-11-25
也使用可流式 HTTP 传输,但形态不同:服务器可以通过 Mcp-Session-Id Header 分配会话
(通过 HTTP DELETE 终止);客户端可以使用 HTTP GET 打开独立 SSE 流,以接收服务器主动发起的消息;
服务器可以在 SSE 流上发送 JSON-RPC 请求;流还可通过 Last-Event-ID 恢复。
这些机制均不属于本修订版。
仅支持本修订版的服务器从旧版客户端收到此类流量时 SHOULD 按以下方式响应:
- 对 MCP 端点的 HTTP GET 或 DELETE:以
405 Method Not Allowed响应。 - 请求中的
Mcp-Session-IdHeader:忽略它,并且不生成或回显会话 ID。 Last-Event-IDHeader:忽略它;流不可恢复。
需要与使用这些协议版本的对端互操作的服务器和客户端,除实现上述版本协商回退外, 还需实现相应修订版中描述的行为(例如 2025-11-25:可流式 HTTP(英文))。
HTTP+SSE 传输(2024-11-05)
2025-03-26 起已弃用,并根据功能生命周期策略
被归类为弃用(SEP-2596(英文))。
新实现 SHOULD NOT 采用它;现有实现 SHOULD 迁移到
可流式 HTTP。
它可能在未来修订版中被移除;参见弃用功能注册表。客户端和服务器可以按以下方式保持与已弃用的 HTTP+SSE 传输(英文) (来自协议版本 2024-11-05)的向后兼容:
希望支持旧版客户端的服务器应当:
- 在为可流式 HTTP 传输定义的新“MCP 端点”之外,继续托管旧传输的 SSE 和 POST 端点。
- 也可以合并旧 POST 端点和新 MCP 端点,但这可能引入不必要的复杂性。
希望支持旧版服务器的客户端应当:
- 接受用户提供的 MCP 服务器 URL,该 URL 可能指向使用旧传输或新传输的服务器。
- 尝试使用上述定义的
AcceptHeader 向服务器 URL POST 请求:- 如果成功,客户端可以假定该服务器支持新的可流式 HTTP 传输。
- 如果请求以 HTTP 状态码
400 Bad Request、404 Not Found或405 Method Not Allowed失败, 并且响应正文不是已识别的现代 JSON-RPC 错误(现代服务器会为不支持的版本、未知方法或 Header 验证失败返回此类错误):- 向服务器 URL 发出 GET 请求,预期该请求会打开 SSE 流,并以
endpoint事件作为第一个事件返回。 - 当
endpoint事件到达时,客户端可以假定该服务器运行旧版 HTTP+SSE 传输, 并应在所有后续通信中使用该传输。
- 向服务器 URL 发出 GET 请求,预期该请求会打开 SSE 流,并以