---
name: mcp-reliability-reviewer
description: 审查 MCP 取消竞态、截止时间、重试、幂等性、SSE 流量控制和重连行为。
version: 1.0.0
phase: 13
lesson: 29
tags: [mcp, reliability, cancellation, idempotency, sse, backpressure]
---

从请求开始一直到故障恢复，审查一个 MCP 操作。

如果缺失，索取以下输入：

1. 传输方式：stdio 或 Streamable HTTP。
2. 操作语义和副作用。
3. 空闲超时和绝对最大超时。
4. 进度 token 行为和速率限制。
5. 重试策略和业务幂等性存储。
6. SSE 缓冲区、代理、保活和重连设置。
7. 如果操作使用 Tasks 扩展，则说明持久化 Task 行为。

产出以下章节。

## 取消线路

- 对于 stdio，要求客户端发送引用活动请求 ID 的 `notifications/cancelled` 通知。
- 对于 Streamable HTTP，要求关闭该请求的响应流。拒绝普通的取消 POST。
- 要求不为取消通知发送 JSON-RPC 响应。
- 为 stdio `subscriptions/listen` 拆除保留服务器发送的 `notifications/cancelled`。
- 说明取消未知、格式错误、迟到或无法执行时会发生什么。

## 竞态表

为以下情况给出确定性结果：

| 事件顺序 | 服务器终态 | 最终响应 | 客户端行为 |
|------------|-----------------------|----------------|-----------------|
| 先取消后完成 | Cancelled | 被抑制 | 继续恢复 |
| 先完成后取消 | Completed | 被保留 | 忽略迟到取消 |
| 超时后迟到响应 | 取决于传输的取消 | 按观察到的顺序忽略或抑制 | 在不安全重试前先对账 |
| 进度期间断连 | 取消正在进行的请求 | 没有可恢复的流 | 重连并重新获取 |

## 截止时间策略

要求同时具备空闲超时和绝对最大超时。只有有效、单调递增且经过速率限制的进度才能重置空闲时间。保活注释不算语义进度。最大超时永不重置。

## 重试分类

每个操作返回一种分类：

- `SAFE`：应用契约证明没有副作用。
- `CONDITIONAL`：变更有一个与相同参数一起复用的持久化幂等键。
- `UNSAFE`：变更缺少权威去重。

绝不把新的 JSON-RPC ID、工具注解或传输重连视为业务幂等性。

对于有条件的重试，要求存储参数指纹和已提交结果。拒绝以改变后的参数复用同一个键。

对键声明、参数指纹、业务副作用记录和已提交结果，要求一个原子且持久化的账本边界。进程本地字典或锁并不持久化，也不能协调副本。接受共享数据库事务、事务性发件箱，或强制执行相同键的上游提供方。说明实际位于该边界内的是哪一种副作用。

返回已提交结果的防御性副本。绝不暴露账本持有的可变对象。用并发同键夹具、重新打开夹具和变更别名夹具证明这两项性质。

## 流量控制

- 设置明确的每流或每客户端容量。
- 合并可替换的进度。
- 标记已丢弃进度需要从权威来源重新获取。
- 保留最终 JSON-RPC 响应。
- 为 SSE 设置 `Content-Type: text/event-stream`、`Cache-Control: no-cache` 和 `X-Accel-Buffering: no`。
- 单独定义保活节奏和操作进度。
- 拒绝无界队列。

## 重连计划

- 使用新 ID 打开新请求。
- 恢复订阅过滤器。
- 对 MCP 2026-07-28 不使用 `Last-Event-ID`。
- 重新获取受影响的资源、列表、prompt 或 Task。
- 不要自动重放不安全的变更。
- 使用带抖动且有上限的指数退避。

## 持久化 Tasks

存在 Task 时，将 `tasks/cancel` 与请求取消分开。完整确认只能证明取消意图已被接受。轮询或监听，直到持久化任务达到终态。

## 必需夹具

至少返回以下可执行场景：

1. stdio 在完成前取消；
2. stdio 在迟到取消前完成；
3. HTTP 流在完成前关闭；
4. 进度重置空闲超时，而最大超时仍会触发；
5. 没有幂等键时，使用两个 JSON-RPC ID 的重复变更；
6. 使用一个键和相同参数的重复变更；
7. 用改变后的参数复用键；
8. 慢消费者超过进度缓冲区；
9. 流中断后建立新订阅并从权威来源重新获取；
10. `tasks/cancel` 确认后出现延迟的 worker 取消；
11. 两个独立账本连接对一个键和相同参数发生竞态；
12. 调用方修改返回结果后，从持久化记录得到干净的重放。

当重试策略只描述为“超时就重试”、账本是进程本地的、外部副作用位于所声称的原子边界之外却没有发件箱或上游键、返回记录别名化了可变存储，或未指定队列容量时，拒绝给出生产就绪的结论。
