取消

社区译文;来源: MCP 80041ab0

模型上下文协议(MCP)支持通过通知消息选择性地取消正在处理的请求。客户端SHOULD发送取消通知,表明应终止此前由其发出的请求。

当服务器关闭某个订阅流时,服务器MUST发送引用该 subscriptions/listen 请求 ID 的 notifications/cancelled(参见订阅 )。服务器MUST NOT将 notifications/cancelled 用于任何其他目的。

取消流程

客户端要取消正在处理的请求时,会发送一条 notifications/cancelled 通知,其中包含:

  • 要取消的请求 ID
  • 可选的原因字符串,可用于日志记录或显示
{
  "jsonrpc": "2.0",
  "method": "notifications/cancelled",
  "params": {
    "requestId": "123",
    "reason": "User requested cancellation"
  }
}

特定于传输的取消方式

客户端如何发出取消信号取决于传输:

  • 可流式 HTTP(Streamable HTTP):关闭 SSE 响应流即为取消信号。服务器MUST将客户端断开连接视为取消该请求。不需要也不应期待 notifications/cancelled 消息。
  • stdio:没有可供关闭的逐请求流。客户端MUST发送引用请求 ID 的 notifications/cancelled 通知。

超时

实现SHOULD为所有已发送请求设置超时,以防止连接挂起和资源耗尽。如果请求在超时时间内未收到成功或错误响应,发送方SHOULD取消请求并停止等待响应。根据特定于传输的取消方式 ,这意味着:

  • 可流式 HTTP(Streamable HTTP):关闭该请求的响应流,即构成取消。
  • stdio:发送引用该请求 ID 的 notifications/cancelled 通知。

SDK 和其他中间件SHOULD允许按请求配置这些超时。

实现MAY在收到与该请求对应的进度通知 时重置超时计时,因为这表明工作确实正在进行。但是,无论是否收到进度通知,实现都SHOULD始终强制执行最大超时,以限制行为不当的客户端或服务器造成的影响。

行为要求

  1. 取消通知MUST只能引用符合以下条件的请求:
    • 此前由客户端发出
    • 被认为仍在处理中
  2. 服务器发送的取消通知MUST引用 subscriptions/listen 请求,以终止该订阅流
  3. 收到取消通知的服务器SHOULD:
    • 停止处理已取消的请求
    • 释放关联资源
    • 不再为已取消的请求发送响应
  4. 在以下情况下,服务器MAY忽略取消通知:
    • 引用的请求未知
    • 处理已经完成
    • 请求无法取消
  5. 客户端SHOULD忽略之后到达的、针对已取消请求的任何响应

时序注意事项

由于网络延迟,取消通知可能在请求处理完成后到达,甚至可能在响应已经发出后才到达。

双方都MUST妥善处理这些竞态条件:

  sequenceDiagram
   participant Client
   participant Server

   Client->>Server: 请求(ID: 123)
   Note over Server: 开始处理
   Client--)Server: notifications/cancelled(ID: 123)
   alt
      Note over Server: 取消到达前<br/>处理可能已经完成
   else 尚未完成
      Note over Server: 停止处理
   end

实现说明

  • 双方都SHOULD记录取消原因,以便调试
  • 应用 UI SHOULD在请求取消时给出提示

错误处理

无效的取消通知SHOULD被忽略:

  • 未知的请求 ID
  • 已完成的请求
  • 格式错误的通知

这样既能保持通知“发送后不等待响应”的性质,也能容纳异步通信中的竞态条件。