Skip to main content
experimental-ext-tasks repository 包含 MCP Tasks 的完整规范和文档。

modelcontextprotocol/ext-tasks

MCP Tasks 的完整规范和文档。
并非每个 tool call 都会立即返回。有些操作,例如 CI pipelines、批处理、人工审批,可能需要几秒、几分钟甚至更久。MCP Tasks 允许 servers 返回一个持久句柄,而不是阻塞等待;这样 clients 可以轮询进度、在需要时提供输入,并在重新连接后获取最终结果。

为什么不直接阻塞?

你可以一直保持连接,直到工作完成。但 Tasks 解决的是阻塞无法解决的问题:
  • 不需要长期连接。 阻塞会在整个操作期间占用连接。许多 clients 和传输中间层都有超时限制,使得超过几秒的阻塞并不现实。
  • 崩溃恢复能力。 Task ID 是持久句柄。如果 client 断开连接或重启,可以使用同一个 ID 继续轮询。
  • 进度可见性。 Tasks 携带状态元数据(workinginput_requiredcompletedfailedcancelled)和可选状态消息,让 clients 可以看到进度。
  • 执行中交互。 当 task 需要输入时(例如用于用户确认的 elicitation),它会进入 input_required 并暴露请求。Client 通过 tasks/update 响应,不需要第二条连接,也不需要未经请求的 server-to-client 消息。
  • 由 server 决定。 Server 按请求决定是否创建 task。Clients 只需通过扩展能力 opt in 一次,然后处理返回的任意结果形态。不需要按 tool 预热,也不需要按请求设置 flag。

Tasks 如何工作

Tasks 扩展了标准请求流程。当 server 判断某个请求会长时间运行时,它会返回 task handle,而不是最终结果。Client 会轮询直到完成。
  1. 能力协商。 Client 在每个请求的 capabilities 中包含 io.modelcontextprotocol/tasks。Server 在自己的 server/discover capabilities 中声明同一扩展。
  2. Task 创建。 响应受支持的请求时,server 返回 CreateTaskResult(通过 resultType: "task" 标识),其中包含 taskId、初始状态、TTL 和建议轮询间隔。Task 会在响应发送前被持久创建。
  3. 轮询。 Client 使用 taskId 调用 tasks/get。响应携带当前状态;对于终止状态,还会携带最终结果或错误。
  4. 执行中输入。 如果 task 进入 input_requiredtasks/get 响应会包含一个 inputRequests map,其中带有 elicitations 或其他 server requests。Client 通过 tasks/update 完成这些请求。
  5. 完成。 当状态到达 completed 时,result 字段包含原始请求同步返回时应有的内容。如果状态为 failederror 字段包含 JSON-RPC 错误。
  6. 取消。 Client 可以随时发送 tasks/cancel。取消是协作式的,server 会确认取消意图,但没有义务停止工作。

何时使用 Tasks

当使用场景涉及以下情况时,Tasks 很适合: 长时间运行操作。 需要数分钟或数小时的 CI pipelines、批量数据处理或模型训练任务。 人在环工作流。 审批关卡、评审步骤,或任何会暂停等待用户确认的操作。Task 会进入 input_required,client 展示该请求。 外部任务系统。 如果 server 包装的 API 已经使用 job IDs(云部署、异步 API、排队工作),可以在创建 job 时返回 task,并在 job 完成时解析它。 不可靠连接。 移动客户端、间歇性网络,或连接容易断开的环境。Task IDs 可以跨断线保留。 批处理。 处理大量项目(批量导入、大量更新)且部分进度有意义的操作。状态消息可以报告进度。

Task 生命周期

状态含义
working操作正在进行。
input_requiredServer 需要 client 输入后才能继续。见 inputRequests
completed操作已完成。result 字段包含最终输出。
failed执行期间发生 JSON-RPC 错误。error 字段包含详情。
cancelled操作已取消(不一定总会被执行)。
completedfailedcancelled 是终止状态,一旦达到,task 状态不会再变化。

通知

Servers 可以通过 notifications/tasks 推送状态更新。Clients 通过 subscriptions/listen 机制 opt in。每条通知都携带完整 task 状态,因此不需要额外一次 tasks/get 往返。 轮询是默认方式。如果 server 支持通知,clients 可以依赖通知而不是轮询。

实现指南

面向 MCP clients

要消费带 task 的响应,你的 client 必须:
1

声明支持

在每个请求的 capabilities 中包含该扩展:
{
  "params": {
    "_meta": {
      "io.modelcontextprotocol/clientCapabilities": {
        "extensions": {
          "io.modelcontextprotocol/tasks": {}
        }
      }
    }
  }
}
2

处理多态结果

发出受支持请求(例如 tools/call)时,要准备好接收标准结果,或接收带 resultType: "task"CreateTaskResult
3

轮询完成状态

使用返回的 taskId 调用 tasks/get,并遵守 pollIntervalMs 值。持续轮询,直到 task 达到终止状态(completedfailedcancelled)。
4

处理输入请求

如果 task 状态为 input_required,读取 inputRequests map,将请求展示给用户或模型,并通过 tasks/update 提交响应。
5

持久化 task IDs

持久保存 task IDs,以便 client 崩溃或重启后可以继续轮询。

面向 MCP servers

要从 server 返回 tasks:
1

声明能力支持

server/discover capabilities 中包含该扩展:
{
  "capabilities": {
    "extensions": {
      "io.modelcontextprotocol/tasks": {}
    }
  }
}
2

检查 client capabilities

返回 CreateTaskResult 前,确认 client 已在每个请求的 capabilities 中包含该扩展。不要向未声明支持的 client 返回 task。
3

返回 CreateTaskResult

当某个请求会长时间运行时,返回 resultType: "task",以及包含唯一 taskId、初始状态、ttlMspollIntervalMsTask 对象。Task 必须在发送响应前被持久创建。
4

提供 tasks/get

每次轮询时返回当前 task 状态。对于终止状态,包含 resultcompleted 时)或 errorfailed 时)字段。
5

处理 tasks/update

接收以未完成 inputRequests 为 key 的 inputResponses。用空结果确认。忽略未知 key 或已满足 key 的响应。
6

处理 tasks/cancel

用空结果确认取消请求。尽可能执行取消,但取消是协作式的,task 仍可能达到非 cancelled 的终止状态。

客户端支持

MCP Tasks 是核心 MCP 规范的扩展。不同 client 的 host 支持情况不同。
各 clients 的扩展支持情况见客户端矩阵。Task 支持需要 client 和 server 双方显式 opt in。

规范

Tasks 扩展在 experimental-ext-tasks repository 中定义。它使用标准 MCP 扩展协商机制:clients 和 servers 会在初始化期间,在各自 capabilities 的 extensions 字段中声明支持。