KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA

06. MCP Tasks 扩展和异步工具怎样接回 Harness? — keel 龙骨

普通 tool calling 假设调用在一次模型回合内返回;报表导出、批量扫描和人工审批则可能运行数分钟甚至数小时。此时工具调用必须变成可轮询、可取消、可恢复的任务,而不是让模型一直占着 context 等待。

普通 tool calling 假设调用在一次模型回合内返回;报表导出、批量扫描和人工审批则可能运行数分钟甚至数小时。此时工具调用必须变成可轮询、可取消、可恢复的任务,而不是让模型一直占着 context 等待。

适配器状态机

working -> input_required -> working
       -> completed | failed | cancelled

按 2026-08-23 核对的 MCP Tasks 扩展,Server 可以为长请求返回 durable task ID,Client 通过 tasks/get 轮询、通过 tasks/update 补充输入,并以 cooperative tasks/cancel 请求取消。Client 和 Server 必须显式协商 io.modelcontextprotocol/tasks 扩展;Host 不能假设任意 MCP Server 或 Client 都支持它。

Harness 侧应把扩展状态映射为结构化 ToolResult 或 WakeupRequest:working/input_required 只产生等待或输入事件,completed 才能进入下一步,failed/cancelled 走明确错误策略。内部可以在收到 task ID 前记录 submitted,但它不是 Tasks 扩展定义的 task status。

本章边界

本章只研究“长任务状态怎样接回 Harness”,不等于完整 MCP 课程。它不展开现代无状态请求、server/discover、Tools/Resources/Prompts、stdio/Streamable HTTP、OAuth、MRTR、缓存、Apps、Registry 和旧版本兼容。完整缺口与课程顺序见仓库文档 docs/curriculum/tracks/AI-AGENT-DEVELOPMENT-ROADMAP.md。

轮询与取消

轮询器要有 deadline、指数退避、最大 attempt 和 lease;每次 poll 都应使用 task ID 幂等。取消请求要记录请求者和原因,不能把“发出了取消”伪装成“外部任务已停止”。Tasks 的取消是 cooperative:Server 确认收到意图,不保证底层工作立即停止。适配的外部系统若只支持 best-effort cancel,最终结果必须允许 unknown 并进入 reconciliation。

与 Context Budget 的关系

长任务等待期间不要把每次进度全文塞回 prompt。保存结构化进度、最近一次状态和结果引用,只有状态变化或下一步决策确实需要时才 JIT 读取详情。这样可以把 MCP task 的生命周期和 compaction 结合起来:事件历史保留事实,context 只保留当前工作集。

本章实践

在已有 Harness 项目中实现一个 adapter:

  1. start() 返回 task ID 和预计下一次 poll 时间;
  2. poll() 将外部状态映射为结构化结果;
  3. cancel() 写入取消请求并等待终态;
  4. worker 重启后只凭 task ID 和事件历史继续;
  5. 对迟到的 completed 结果做版本/运行状态检查。

本章不要求安装 MCP SDK;先把异步状态映射和测试做对,再在完整 MCP 课程中接入真实传输、能力协商和 SDK。

本章检查点

下一章:怎样建立 Agent 的质量门禁?

进入 keel 阅读