主题
取消
Model Context Protocol (MCP) 通过通知消息支持对进行中请求的可选取消。客户端 SHOULD(应该)发送取消通知,以表明其先前发出的某个请求应被终止。
当服务端拆除某个订阅流时,它 MUST(必须)发送引用该 subscriptions/listen 请求 ID 的 notifications/cancelled(参见订阅)。服务端 MUST NOT(不得)出于任何其他目的发送 notifications/cancelled。
取消流程
当客户端想要取消一个进行中的请求时,它会发送一条 notifications/cancelled 通知,其中包含:
- 要取消的请求的 ID
- 一个可选的原因字符串,可用于记录日志或展示
json
{
"jsonrpc": "2.0",
"method": "notifications/cancelled",
"params": {
"requestId": "123",
"reason": "User requested cancellation"
}
}特定于传输的取消
客户端如何发出取消信号取决于传输方式:
- Streamable HTTP:关闭 SSE 响应流即为取消信号。服务端 MUST(必须)将客户端断开视为对该请求的取消。此时不需要也不期望发送
notifications/cancelled消息。 - stdio:没有可按请求关闭的流。客户端 MUST(必须)发送引用该请求 ID 的
notifications/cancelled通知。
超时
实现 SHOULD(应该)为所有已发送的请求设置超时,以防止连接挂起和资源耗尽。当请求在超时时间内未收到成功或错误响应时,发送方 SHOULD(应该)取消该请求并停止等待响应。如特定于传输的取消所述,这意味着:
- Streamable HTTP:关闭该请求的响应流,这构成取消。
- stdio:发送引用该请求 ID 的
notifications/cancelled通知。
SDK 及其他中间件 SHOULD(应该)允许按请求配置这些超时。
实现 MAY(可以)选择在收到与该请求对应的进度通知时重置超时计时,因为这表明工作确实在进行。然而,无论是否有进度通知,实现 SHOULD(应该)始终强制执行最大超时,以限制行为异常的客户端或服务端所带来的影响。
行为要求
- 取消通知 MUST(必须)仅引用满足以下条件的请求:
- 先前由客户端发出
- 被认为仍在进行中
- 服务端发送的取消通知 MUST(必须)引用一个
subscriptions/listen请求,以终止该订阅流 - 收到取消通知的服务端 SHOULD(应该):
- 停止处理被取消的请求
- 释放相关资源
- 不为被取消的请求发送响应
- 服务端 MAY(可以)在以下情况下忽略取消通知:
- 所引用的请求未知
- 处理已经完成
- 该请求无法被取消
- 客户端 SHOULD(应该)忽略此后到达的、针对被取消请求的任何响应
时序注意事项
由于网络延迟,取消通知可能在请求处理完成之后才到达,甚至可能在响应已经发送之后才到达。
双方 MUST(必须)优雅地处理这些竞态条件:
sequenceDiagram
participant Client
participant Server
Client->>Server: Request (ID: 123)
Note over Server: Processing starts
Client--)Server: notifications/cancelled (ID: 123)
alt
Note over Server: Processing may have<br/>completed before<br/>cancellation arrives
else If not completed
Note over Server: Stop processing
end
实现说明
- 双方 SHOULD(应该)记录取消原因以便调试
- 应用 UI SHOULD(应该)在请求取消时给出提示
错误处理
无效的取消通知 SHOULD(应该)被忽略:
- 未知的请求 ID
- 已完成的请求
- 格式错误的通知
这既保持了通知"发后即忘"的特性,又兼顾了异步通信中的竞态条件。