> ## Documentation Index
> Fetch the complete documentation index at: https://mcp.developerdoc.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# Streamable HTTP

<div id="enable-section-numbers" />

<Info>
  Streamable HTTP 在协议版本 2025-03-26 中引入，用于替代协议版本 2024-11-05 中的 [HTTP+SSE 传输][http-sse]。
</Info>

<Info>
  修订版 2026-07-28 更改了 Streamable HTTP 的行为。客户端必须确保正确处理向后兼容性。变更包括：

  * 移除 GET 流端点。
  * 移除协议级会话。

  请参见下面的[变更日志](/specification/draft/changelog)和[向后兼容性](#backward-compatibility)。
</Info>

在 **Streamable HTTP** 传输中，服务器作为独立进程运行，可以处理多个客户端连接。概览如下：

* 服务器公开一个接受 POST 的单一 HTTP 端点（**MCP 端点**）。
* 客户端将每个 JSON-RPC 请求或通知作为单独的 HTTP POST 发送。
* 服务器使用单个 JSON 对象，或作用域限定到该请求的 [Server-Sent Events][sse] (SSE) 流来回答每个请求；该流先承载请求相关通知，随后承载最终响应。
* 服务器到客户端的交互（sampling、elicitation、roots）按照 [Multi Round-Trip Requests (MRTR)][mrtr] ([SEP-2322][sep-2322]) 作为输入请求嵌入到结果中。
* 长生命周期的变更通知（例如列表变更和资源更新）通过 [`subscriptions/listen`][subscriptions-listen] 请求的响应流投递。

这些交互的时序图请参见[消息流](#message-flow)。

服务器 **MUST** 提供支持 POST 的单一 HTTP 端点路径（下文称为 **MCP 端点**）。例如，它可以是类似 `https://example.com/mcp` 的 URL。

[http-sse]: /specification/2024-11-05/basic/transports#http-with-sse

[sse]: https://en.wikipedia.org/wiki/Server-sent_events

## 安全 & Endpoint

实现 Streamable HTTP 传输时：

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

如果没有这些保护，攻击者可能利用 DNS rebinding 从远程网站与本地 MCP 服务器交互。

## Sending Messages

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

1. 客户端 **MUST** 使用 HTTP POST 发送 JSON-RPC 消息。
2. 客户端 **MUST** 包含 `Accept` 标头，并列出 `application/json` 和 `text/event-stream` 作为受支持的内容类型。
3. 客户端 **MUST** 在每个 POST 请求上包含[请求元数据标头](#request-metadata)。
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** 同时支持两者。

## Receiving Messages

当服务器返回 SSE 响应流（`Content-Type: text/event-stream`）时：

* 服务器 **MAY** 在最终响应之前发送 JSON-RPC *通知*，例如 [`notifications/progress`][notifications-progress] 或 [`notifications/message`][notifications-message]。这些通知 **MUST** 与发起它们的客户端请求相关。
* 服务器 **MUST NOT** 在此流上发送独立的 JSON-RPC *请求*。服务器到客户端的交互（sampling、elicitation、list-roots）按照 [MRTR][mrtr] ([SEP-2322][sep-2322]) 作为输入请求嵌入在 [`InputRequiredResult`][input-required-result] 中，而不是作为单独请求在此流或任何其他流上传递。这是协议版本 `2025-03-26` 至 `2025-11-25` 中 Streamable HTTP 行为的变化；在那些版本中，服务器可以在 SSE 流上发送此类请求。
* 最终 JSON-RPC *响应* **SHOULD** 终止该流。

长生命周期通知流通过发送 [`subscriptions/listen`][subscriptions-listen] 请求获得。服务器的响应本身就是一个保持打开的 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 流。

[notifications-progress]: /specification/draft/basic/patterns/progress

[notifications-message]: /specification/draft/server/utilities/logging

[input-required-result]: /specification/draft/schema#inputrequiredresult

[mrtr]: /specification/draft/basic/patterns/mrtr

[sep-2322]: /seps/2322-MRTR

[subscriptions-listen]: /specification/draft/basic/patterns/subscriptions

## Message Flow

下列图示说明单个 MCP 端点上的消息流。

**请求和响应。** 每个请求都是自己的 POST；服务器按请求选择使用单个 JSON 对象还是 SSE 流进行响应：

```mermaid theme={null}
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)。** 当服务器需要来自客户端的输入（sampling、elicitation 或 roots）时，它不会发送自己的 JSON-RPC 请求。它会返回包含 `inputRequests` 的 [`InputRequiredResult`][input-required-result]，然后客户端使用匹配的 `inputResponses` 重试原始请求（请参见 [Multi Round-Trip Requests][mrtr]）：

```mermaid theme={null}
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`][subscriptions-listen] 打开长生命周期流；响应流保持打开，并且只承载客户端选择接收的通知类型：

```mermaid theme={null}
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
```

## Cancellation

关闭 SSE 响应流 **MUST** 被服务器视为取消该请求。由于每个请求都有自己的响应流，传输层断开连接的含义是明确的。服务器 **SHOULD** 在可行时尽快停止已取消请求的工作，并且 **MUST NOT** 再为其发送任何消息。完整规则请参见 [Cancellation][cancellation]。

[cancellation]: /specification/draft/basic/patterns/cancellation

## Request Metadata

Streamable HTTP 传输会将选定的 JSON-RPC 消息体字段镜像到 HTTP 标头中，以便中介组件（负载均衡器、网关、可观测性工具）无需解析消息体即可路由和检查请求。

### Protocol Version Header

发往 MCP 端点的每个 POST 请求 **MUST** 包含 `MCP-Protocol-Version` 标头。

例如：`MCP-Protocol-Version: 2026-07-28`

标头值 **MUST** 与请求体 `_meta` 中携带的 `io.modelcontextprotocol/protocolVersion` 字段匹配。如果值不匹配，服务器 **MUST** 使用 `400 Bad Request` 和 `HeaderMismatch` JSON-RPC 错误拒绝该请求（请参见[服务器验证](#server-validation)）。

如果服务器没有实现请求的协议版本（无论该版本对服务器未知，还是服务器选择不支持的已知版本），它 **MUST** 以 `400 Bad Request` 和列出其支持版本的 [`UnsupportedProtocolVersionError`][unsupported-version] 响应。请参见
[版本控制：协议版本协商][lifecycle-version]
了解协商流程。

如果服务器没有实现请求的 RPC 方法，它 **MUST** 以 `404 Not Found` 和代码为 `-32601`（`Method not found`）的 JSON-RPC 错误响应。JSON-RPC 错误体会将此情况与未托管现代 MCP 端点的旧版 [HTTP+SSE][http-sse] 服务器返回的 `404` 区分开（请参见[向后兼容性](#backward-compatibility)）。

支持实现早于 `2025-06-18` 协议版本（这些版本未定义 `MCP-Protocol-Version` 标头）的客户端的服务器，**MAY** 将省略该标头的请求视为协议版本 `2025-03-26`。不支持此类客户端的服务器 **MUST** 按照[服务器验证](#server-validation)拒绝没有该标头的请求。

[unsupported-version]: /specification/draft/schema#unsupportedprotocolversionerror

[lifecycle-version]: /specification/draft/basic/versioning#protocol-version-negotiation

### Standard Request Headers

| 标头名称         | 来源字段                          | 适用对象                                             |
| ------------ | ----------------------------- | ------------------------------------------------ |
| `Mcp-Method` | `method`                      | 所有请求和通知                                          |
| `Mcp-Name`   | `params.name` or `params.uri` | `tools/call`, `resources/read`, `prompts/get` 请求 |

这些标头对于合规性是 **REQUIRED** 的。

**`tools/call` 请求：**

```http theme={null}
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` 请求：**

```http theme={null}
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": {}
    }
  }
}
```

### Custom Headers from Tool Parameters

MCP 服务器 **MAY** 使用工具 `inputSchema` 中参数 schema 里的 `x-mcp-header` 扩展属性，指定要镜像到 HTTP 标头中的特定工具参数。有关如何标注工具参数的详细信息，请参见[工具定义][tool-definitions]。

虽然服务器可以选择是否使用 `x-mcp-header`，但客户端 **MUST** 支持此功能。当服务器的工具定义包含 `x-mcp-header` 标注时，符合规范的客户端 **MUST** 将指定的参数值镜像到 HTTP 标头中。

[tool-definitions]: /specification/draft/server/tools#x-mcp-header

#### Schema Extension

`x-mcp-header` 属性指定用于构造标头名称 `Mcp-Param-{name}` 的名称部分。

**对 `x-mcp-header` 值的约束**：

* **MUST NOT** 为空
* **MUST** 匹配 HTTP field-name token 语法（`1*tchar`，[RFC 9110 Section 5.1](https://datatracker.ietf.org/doc/html/rfc9110#section-5.1)）
* **MUST NOT** 包含控制字符，包括回车（CR，`\r`）或换行（LF，`\n`）
* 在 `inputSchema` 的所有 `x-mcp-header` 值中，按大小写不敏感比较 **MUST** 唯一
* **MUST** 仅应用于具有原始类型（integer、string、boolean）的参数。不允许用于类型为 `number` 的参数。Integer 值 **MUST** 位于 JavaScript 的安全范围内（−2<sup>53</sup>+1 到 2<sup>53</sup>−1）
* **MAY** 应用于 `inputSchema` 内任意嵌套深度的属性，而不只是顶层属性

使用 Streamable HTTP 传输的客户端 **MUST** 拒绝任何 `x-mcp-header` 值违反这些约束的工具定义。拒绝意味着客户端 **MUST** 从 `tools/list` 的结果中排除无效工具。客户端在拒绝工具定义时 **SHOULD** 记录警告，包括工具名称和拒绝原因。这确保单个格式错误的工具定义不会阻止其他有效工具被使用。使用其他传输（例如 stdio）的客户端 **MAY** 完全忽略 `x-mcp-header` 标注。

**示例工具定义：**

```json theme={null}
{
  "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 请求：**

```http theme={null}
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"
    }
  }
}
```

#### Value Encoding

客户端 **MUST** 在将参数值包含到 HTTP 标头之前对其进行编码，以确保安全传输并防止注入攻击。

**类型转换**：将参数值转换为其字符串表示：

* `string`：按原样使用该值
* `integer`：转换为十进制字符串表示（例如 `42`、`-7`）
* `boolean`：转换为小写 `"true"` 或 `"false"`

根据 [RFC 9110][rfc9110-values]，HTTP 标头字段值必须由可见 ASCII 字符（0x21-0x7E）、空格（0x20）和水平制表符（0x09）组成。当某个值无法安全地表示为普通 ASCII 标头值时（例如，它包含非 ASCII 字符、控制字符，或存在前导/尾随空白），客户端 **MUST** 使用以下格式对 UTF-8 表示进行 Base64 编码：

```text theme={null}
Mcp-Param-{Name}: =?base64?{Base64EncodedValue}?=
```

前缀 `=?base64?` 和后缀 `?=` 表示该值经过 Base64 编码。这些标记区分大小写，并且 **MUST** 完全按所示形式（小写）出现。需要检查这些值的服务器和中介组件 **MUST** 相应地解码它们。

为避免歧义，客户端 **MUST** 也对任何匹配哨兵模式的普通 ASCII 值进行 Base64 编码（即以 `=?base64?` 开头并以 `?=` 结尾的值）。

**编码示例：**

| 原始值                    | 原因        | 编码后的标头值                                               |
| ---------------------- | --------- | ----------------------------------------------------- |
| `"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=?=`         |
| `"=?base64?literal?="` | 匹配哨兵模式    | `Mcp-Param-Val: =?base64?PT9iYXNlNjQ/bGl0ZXJhbD89?=`  |

[rfc9110-values]: https://datatracker.ietf.org/doc/html/rfc9110#name-field-values

#### Client Behavior

通过 HTTP 传输构造 `tools/call` 请求时，客户端 **MUST**：

1. 从请求体中提取任何标准标头的值（例如 `method`、`params.name`、`params.uri`）。
2. 将 `Mcp-Method` 标头以及适用时的 `Mcp-Name` 标头追加到请求中。
3. 检查工具的 `inputSchema`，查找标记为 `x-mcp-header` 的属性，并提取每个参数的值。
4. 按照[值编码](#value-encoding)规则对值进行编码。
5. 将 `Mcp-Param-{Name}: {Value}` 标头追加到请求中。

<Note>
  如果客户端没有工具的 `inputSchema`（例如尚未调用 `tools/list`），或缓存的 schema 已过期（例如其 TTL 已过期），客户端 **SHOULD** 在不带自定义 `Mcp-Param-*` 标头的情况下发送请求。如果服务器因缺少必需的自定义标头而拒绝请求，客户端 **SHOULD** 调用 `tools/list` 获取当前 `inputSchema`，然后使用适当的标头重试原始请求。客户端 **MAY** 通过其他方式预加载工具定义（例如来自先前会话或配置），以便在尚未调用 `tools/list` 的情况下发出标头。
</Note>

#### Server Behavior for Custom Headers

不识别 `Mcp-Param-{Name}` 标头的中间服务器 **MUST** 按照 [HTTP 语义 RFC][http-semantics] 的要求转发该标头，并在其他方面忽略它。

服务器 **MUST** 拒绝包含已识别的 `Mcp-Param-{Name}` 标头且该标头含有无效字符的请求（请参见[值编码](#value-encoding)）。

任何处理消息体的服务器 **MUST** 验证编码后的标头值（如果经过 Base64 编码，则在解码后）与请求体中的对应值匹配。如果任何验证失败，服务器 **MUST** 使用 `400 Bad Request` HTTP 状态和 JSON-RPC 错误码 `-32001`（`HeaderMismatch`）拒绝请求。

| 场景               | 客户端行为          | 服务器行为               |
| ---------------- | -------------- | ------------------- |
| 提供了参数值           | 客户端 MUST 包含该标头 | 服务器 MUST 验证标头与消息体匹配 |
| 参数值为 `null`      | 客户端 MUST 省略该标头 | 服务器 MUST NOT 期望该标头  |
| 参数不在 arguments 中 | 客户端 MUST 省略该标头 | 服务器 MUST NOT 期望该标头  |
| 客户端省略标头但消息体中有值   | 不符合规范的客户端      | 服务器 MUST 拒绝该请求      |

[http-semantics]: https://www.rfc-editor.org/rfc/rfc9110.html#name-field-names

### Case Sensitivity

标头名称（在 [RFC 9110][rfc9110-names] 中称为 "field names"）不区分大小写。客户端和服务器 **MUST** 对标头名称使用大小写不敏感比较。标头 *值*（例如方法名）区分大小写。

[rfc9110-names]: https://datatracker.ietf.org/doc/html/rfc9110#name-field-names

### Server Validation

处理请求体的服务器 **MUST** 拒绝标头中指定的值与请求体中对应值不匹配的请求。这可以防止网络中的不同组件依赖不同真实来源时产生潜在安全漏洞（例如，负载均衡器按标头值路由，而 MCP 服务器按消息体值执行）。

<Note>
  验证 integer 参数值时，服务器 **SHOULD** 按数值而不是字符串比较标头值和消息体值（例如，`42.0` 和 `42` 被视为相等）。
</Note>

因标头验证失败而拒绝请求时，服务器 **MUST** 返回 HTTP 状态 `400 Bad Request`，并且 **MUST** 包含使用以下错误码的 JSON-RPC 错误响应：

| 代码       | 名称               | 描述                                |
| -------- | ---------------- | --------------------------------- |
| `-32001` | `HeaderMismatch` | HTTP 标头与请求体中的对应值不匹配，或必需标头缺失/格式错误。 |

此错误码位于 JSON-RPC 实现定义的服务器错误范围内（`-32000` 到 `-32099`）。

**示例错误响应：**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32001,
    "message": "Header mismatch: Mcp-Name header value 'foo' does not match body value 'bar'"
  }
}
```

验证失败条件包括：

* 缺少必需的标准标头（`MCP-Protocol-Version`、`Mcp-Method`、`Mcp-Name`）。
* 标头值与对应的请求体值不匹配。
* 标头值包含无效字符。

<Note>
  中介组件 **MUST** 对验证失败返回适当的 HTTP 错误状态（例如 `400 Bad Request`），但不要求返回 JSON-RPC 错误响应。
</Note>

<Note>
  基于镜像标头执行策略的中介组件（例如按租户路由或限流）**SHOULD** 验证 `MCP-Protocol-Version` 标头指示的是要求进行标头与消息体验证的版本。如果版本较旧或缺少该标头，中介组件 **SHOULD** 拒绝请求，而不是信任未经验证的标头值。
</Note>

## Backward Compatibility

同时支持现代（按请求元数据）MCP 版本和需要 `initialize` 握手的旧版版本的客户端，**MAY** 通过先尝试现代请求来检测服务器实现的是哪个时代。遇到 `400 Bad Request` 时，客户端在回退之前 **SHOULD** 检查响应体：现代服务器也会对 [`UnsupportedProtocolVersionError`][unsupported-version]、`MissingRequiredClientCapabilityError` 和标头验证失败使用 `400`。

* 如果响应体包含可识别的现代 JSON-RPC 错误，则服务器使用现代版本的 MCP：应使用公布的 `supported` 版本重试，或修正请求，而不是回退。
* 如果响应体为空，或不是可识别的现代 JSON-RPC 错误，则回退到 `initialize`，并在后续请求中继续使用旧版版本。

时代模型和面向实现者的兼容性矩阵请参见[版本控制：向后兼容性][lifecycle-compat]。

### Earlier Streamable HTTP Revisions

协议版本 `2025-03-26` 到 [`2025-11-25`](/specification/2025-11-25/basic/transports) 也使用 Streamable HTTP 传输，但形态不同：服务器可以通过 `Mcp-Session-Id` 标头分配会话（使用 HTTP DELETE 终止），客户端可以使用 HTTP GET 打开独立的 SSE 流来接收服务器发起的消息，服务器可以在 SSE 流上发送 JSON-RPC *请求*，并且流可以通过 `Last-Event-ID` 恢复。这些机制都不是本修订版的一部分。

仅支持本修订版的服务器如果从较旧客户端收到此类流量，**SHOULD** 按如下方式响应：

* 对 MCP 端点的 HTTP GET 或 DELETE：以 `405 Method Not Allowed` 响应。
* 请求中的 `Mcp-Session-Id` 标头：忽略它，不生成也不回显会话 ID。
* `Last-Event-ID` 标头：忽略它；流不可恢复。

需要与使用那些协议版本的对端互操作的服务器和客户端，除了实现上述版本协商回退外，还要实现对应修订版中描述的行为（例如 [2025-11-25: Streamable HTTP](/specification/2025-11-25/basic/transports#streamable-http)）。

### HTTP+SSE Transport (2024-11-05)

<Warning>
  **Deprecated**：协议版本 2024-11-05 中的 [HTTP+SSE 传输][http-sse] 自协议版本 `2025-03-26` 起已弃用，并根据[功能生命周期策略](/community/feature-lifecycle#deprecating-a-feature)
  ([SEP-2596](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2596)) 被归类为 Deprecated。
  新实现 **SHOULD NOT** 采用它；现有实现 **SHOULD** 迁移到 [Streamable
  HTTP](/specification/draft/basic/transports/streamable-http)。它有资格在未来修订版中移除；请参见[已弃用功能注册表](/specification/draft/deprecated)。
</Warning>

客户端和服务器可以按如下方式与已弃用的 [HTTP+SSE 传输][http-sse]（来自协议版本 2024-11-05）保持向后兼容：

希望支持较旧客户端的**服务器**应该：

* 继续托管旧传输的 SSE 和 POST 端点，同时托管为 Streamable HTTP 传输定义的新 "MCP endpoint"。
  * 也可以合并旧 POST 端点和新的 MCP 端点，但这可能引入不必要的复杂性。

希望支持较旧服务器的**客户端**应该：

1. 从用户处接受 MCP 服务器 URL，该 URL 可能指向使用旧传输或新传输的服务器。
2. 尝试向该服务器 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 传输的服务器，并应在所有后续通信中使用该传输。

[lifecycle-compat]: /specification/draft/basic/versioning#backward-compatibility-with-initialization-based-versions
