可流式 HTTP

社区译文;来源: MCP 80041ab0

可流式 HTTP 在协议版本 2025-03-26 中引入,用以替代协议版本 2024-11-05 中的 [HTTP+SSE 传输(英文)][http-sse]。

修订版 2026-07-28 更改了可流式 HTTP 的行为。客户端必须确保正确处理向后兼容。变更包括:

  • 移除 GET 流端点。
  • 移除协议层会话。

参见变更日志和下文的向后兼容。

在可流式 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 传输时:

  1. 服务器 MUST 验证所有传入连接的 Origin Header,以防止 DNS 重绑定攻击。
    • 如果存在 Origin Header 且值无效,服务器 MUST 以 HTTP 403 Forbidden 响应。 HTTP 响应正文 MAY 包含一个没有 id 的 JSON-RPC 错误响应。
  2. 在本地运行时,服务器 SHOULD 仅绑定到 localhost(127.0.0.1),而不是所有网络接口(0.0.0.0)。
  3. 服务器 SHOULD 为所有连接实现适当的身份认证。

如果缺少这些保护,攻击者可能利用 DNS 重绑定从远程网站与本地 MCP 服务器交互。

发送消息

客户端发送的每条 JSON-RPC 消息 MUST 是一个发往 MCP 端点的新 HTTP POST 请求。

  1. 客户端 MUST 使用 HTTP POST 发送 JSON-RPC 消息。
  2. 客户端 MUST 包含一个 Accept Header,同时列出 application/json 和 text/event-stream 两种受支持的内容类型。
  3. 客户端 MUST 在每个 POST 请求中包含请求元数据 Header。
  4. HTTP POST 的正文 MUST 是单个 JSON-RPC 请求_或_通知。客户端 MUST NOT 发送 JSON-RPC 响应。
  5. 如果正文是 JSON-RPC 通知:
    • 如果服务器接受该通知,服务器 MUST 返回 HTTP 状态码 202 Accepted,且不包含正文。
    • 如果服务器无法接受该通知,则 MUST 返回 HTTP 错误状态码(例如 400 Bad Request)。 HTTP 响应正文 MAY 包含一个没有 id 的 JSON-RPC 错误响应。
  6. 如果正文是 JSON-RPC 请求,服务器 MUST 返回 Content-Type: application/json (单个 JSON 对象)或 Content-Type: text/event-stream(SSE 响应流)。客户端 MUST 同时支持两者。
本修订版核心协议没有定义通过可流式 HTTP 从客户端发送到服务器的_通知_。核心协议中唯一由客户端发送的通知 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 NameSource FieldRequired For
Mcp-MethodmethodAll requests
Mcp-Nameparams.name or params.uritools/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 ValueReasonEncoded Header Value
"us-west1"Plain ASCIIMcp-Param-Region: us-west1
"Hello, 世界"Contains non-ASCIIMcp-Param-Greeting: =?base64?SGVsbG8sIOS4lueVjA==?=
" padded "Leading/trailing spacesMcp-Param-Text: =?base64?IHBhZGRlZCA=?=
"line1\nline2"Contains newlineMcp-Param-Text: =?base64?bGluZTEKbGluZTI=?=
"=?base64?literal?="Matches sentinel patternMcp-Param-Val: =?base64?PT9iYXNlNjQ/bGl0ZXJhbD89?=

客户端行为

通过 HTTP 传输构造 tools/call 请求时,客户端 MUST:

  1. 从请求正文中提取所有标准 Header 的值(例如 method、params.name、params.uri)。
  2. 向请求附加 Mcp-Method Header,并在适用时附加 Mcp-Name Header。
  3. 检查工具的 inputSchema,查找标有 x-mcp-header 的属性,并从每个被标注属性的精确属性路径提取值; 如果没有值,则省略 Header(参见 Schema 扩展)。
  4. 按值编码规则编码这些值。
  5. 向请求附加一个 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)拒绝请求。

ScenarioClient BehaviorServer Behavior
Parameter value providedClient MUST include the headerServer MUST validate header matches body
Parameter value is nullClient MUST omit the headerServer MUST NOT expect the header
Parameter not in argumentsClient MUST omit the headerServer MUST NOT expect the header
Client omits header but value is in bodyNon-conforming clientServer MUST reject the request

大小写敏感性

Header 名称(在 RFC 9110(英文)中称为“字段名称”)不区分大小写。 客户端和服务器 MUST 对 Header 名称使用不区分大小写的比较。Header 值(例如方法名称)区分大小写。

服务器验证

处理请求正文的服务器 MUST 拒绝 Header 指定值与请求正文相应值不匹配的请求。 这可防止网络中的不同组件依赖不同真相源时产生潜在安全漏洞(例如,负载均衡器依据 Header 值路由, 而 MCP 服务器依据正文值执行)。

验证 integer 参数值时,服务器 SHOULD 按数值而不是字符串比较 Header 值与正文值 (例如,42.0 和 42 视为相等)。

因 Header 验证失败而拒绝请求时,服务器 MUST 返回 HTTP 状态 400 Bad Request,并且 MUST 使用以下错误代码包含 JSON-RPC 错误响应:

CodeNameDescription
-32020HeaderMismatchThe 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 值包含无效字符。
中间组件对验证失败 MUST 返回适当的 HTTP 错误状态(例如 400 Bad Request), 但不要求返回 JSON-RPC 错误响应。
根据镜像 Header 执行策略(例如按租户路由或限流)的中间组件 SHOULD 验证 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-Id Header:忽略它,并且不生成或回显会话 ID。
  • Last-Event-ID Header:忽略它;流不可恢复。

需要与使用这些协议版本的对端互操作的服务器和客户端,除实现上述版本协商回退外, 还需实现相应修订版中描述的行为(例如 2025-11-25:可流式 HTTP(英文))。

HTTP+SSE 传输(2024-11-05)

弃用:协议版本 2024-11-05 中的 [HTTP+SSE 传输(英文)][http-sse] 自协议版本 2025-03-26 起已弃用,并根据功能生命周期策略 被归类为弃用(SEP-2596(英文))。 新实现 SHOULD NOT 采用它;现有实现 SHOULD 迁移到 可流式 HTTP。 它可能在未来修订版中被移除;参见弃用功能注册表。

客户端和服务器可以按以下方式保持与已弃用的 HTTP+SSE 传输(英文) (来自协议版本 2024-11-05)的向后兼容:

希望支持旧版客户端的服务器应当:

  • 在为可流式 HTTP 传输定义的新“MCP 端点”之外,继续托管旧传输的 SSE 和 POST 端点。
    • 也可以合并旧 POST 端点和新 MCP 端点,但这可能引入不必要的复杂性。

希望支持旧版服务器的客户端应当:

  1. 接受用户提供的 MCP 服务器 URL,该 URL 可能指向使用旧传输或新传输的服务器。
  2. 尝试使用上述定义的 Accept Header 向服务器 URL POST 请求:
    • 如果成功,客户端可以假定该服务器支持新的可流式 HTTP 传输。
    • 如果请求以 HTTP 状态码 400 Bad Request、404 Not Found 或 405 Method Not Allowed 失败, 并且响应正文不是已识别的现代 JSON-RPC 错误(现代服务器会为不支持的版本、未知方法或 Header 验证失败返回此类错误):
      • 向服务器 URL 发出 GET 请求,预期该请求会打开 SSE 流,并以 endpoint 事件作为第一个事件返回。
      • 当 endpoint 事件到达时,客户端可以假定该服务器运行旧版 HTTP+SSE 传输, 并应在所有后续通信中使用该传输。