很多人第一次接触 MCP,会天然觉得:

  • tools/call 不就够了吗?
  • 工具能调起来,结果能回来,不就完成了?

这个想法在简单场景里没有问题。

但一旦工具开始变成:

  • 跑几分钟到几小时
  • 中间需要轮询状态
  • 中间可能还要用户补输入
  • 或者根本就是一个 workflow / pipeline / CI job

你会很快发现一个现实:

同步工具调用,根本撑不住真正的长任务。

也正因为这个问题,MCP 才引入了 Tasks 这类能力。

如果只压成一句话:

Tasks 解决的是“现在先发起,结果以后再拿”的执行模式,也就是典型的 call-now / fetch-later。

一、为什么同步工具调用不够了

MCP 早期最容易理解的模型是:

  1. 客户端发现 tool
  2. 客户端发起 tools/call
  3. server 处理
  4. 结果立刻回来

这套模式对短任务很好用,比如:

  • 读一个文件
  • 查一条数据库记录
  • 调一个很快的 API

但到了下面这些场景,就会变得很 awkward:

  • 运行一个完整测试套件
  • 调用一个要分析海量数据的工具
  • 发起一个要经过审批的业务流程
  • 启动一个会持续几分钟的 research agent
  • 走一个需要用户补输入的长链路操作

问题不在于“不能做”,而在于:

  • 客户端不知道这个调用到底还活着没有
  • 如果结果丢了,只能再调一次
  • Agent 自己去轮询,很贵而且不稳定
  • Server 可能被迫写一层专门用来轮询别人的包装层

这就是为什么 Tasks 不是可有可无的附加项,而是 MCP 在进入复杂工作流时必须补的一层。

二、MCP 官方到底怎么定义 Tasks

截至 2026-04-18,MCP 官方对 Tasks 的定义已经很清楚。

SEP-1686: Tasks 里写得非常直接:

  • 它引入了 task primitive
  • 引入了 task ID
  • 让请求方可以查询 task 的状态和结果
  • 用来支持 call-now, fetch-later execution pattern

这几个词特别重要。

因为它说明 Tasks 不是“另起一个 workflow API”,而是:

给原来的请求增加一种可延迟取回结果的执行模式。

也就是说,Tasks 不是替代 tools/call,而是增强 MCP 请求的执行方式。

三、它真正解决的,不是“异步”三个字,而是“把轮询从 Agent 手里拿回来”

我觉得这是最容易被低估的一点。

很多人看到 Tasks,第一反应是:

哦,就是异步。

不完全对。

更准确地说,它解决的是:

让 host / client 用协议层的方式,可靠地追踪长任务,而不是把“反复轮询”这种脏活继续丢给 Agent。

SEP-1686 的 motivation 里其实把这件事讲得很狠:

  • 如果没有 Tasks,开发者往往把一个长任务拆成三个 tool:
    • start_xxx
    • get_xxx_status
    • get_xxx_result
  • 但这样会引出新问题:
    • polling 依赖 prompt engineering
    • Agent 不一定真的按预期一直轮询
    • host application 也没法稳定接管这套约定

这句话基本点中了本质:

只要轮询还要靠 Agent 自己“记得去做”,它就不是可靠的系统能力。

四、官方为什么要做成通用 primitive,而不是只给 tools 单独加异步

这件事也很关键。

SEP-1686 的 rationale 里明确说了:

  • Tasks 是一个 generic task primitive
  • 它不只适用于 tools
  • 也可以适用于 resources/readprompts/getsampling/createMessage 以及未来请求类型

这意味着 Tasks 的设计目标并不是“补一个异步工具调用功能”,而是:

给整个 MCP 协议加上一种统一的 deferred execution 模型。

这会带来两个大好处:

1. 统一

你不需要为每种请求各自发明一套长任务模式。

2. 向后兼容

SEP 里还提到:

  • 不支持 Tasks 的 server 可以忽略 _meta
  • 请求本身仍然合法,不会破坏正常处理

这让 Tasks 成了一种很典型的 additive capability。

五、看一张图,立刻就明白它和同步工具调用的差别

先看传统同步调用:

MCP Server Client / Host MCP Server Client / Host tools/call CallToolResult

这条链的问题是:

  • 如果任务很长,连接可能超时
  • 客户端不清楚 server 是否还在处理
  • 如果结果没到,宿主也很难确定下一步怎么办

再看 Tasks 的模式:

MCP Server Client / Host MCP Server Client / Host tools/call + task metadata notifications/tasks/created tasks/get status=working tasks/get status=completed tasks/result final result

差别就在这:

  • 不再要求一次调用就拿到最终结果
  • 状态和结果被正式拆开
  • host 可以确定性地管理轮询

六、协议层到底长什么样

这部分 MCP 官方给得很具体,我直接按官方思路讲。

1. 发起任务

在请求的 _meta 里加 modelcontextprotocol.io/task

官方示意大概像这样:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "some_method",
  "params": {
    "_meta": {
      "modelcontextprotocol.io/task": {
        "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
        "keepAlive": 60000
      }
    }
  }
}

这里的重点有两个:

  • taskId
  • keepAlive

也就是说,请求方可以明确告诉对方:

  • 这是一个任务化请求
  • 任务结果希望保留多久

2. 查状态

然后可以通过 tasks/get 查询状态。

官方示意里会返回:

  • taskId
  • keepAlive
  • pollFrequency
  • status

像这样:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
    "keepAlive": 30000,
    "pollFrequency": 5000,
    "status": "submitted"
  }
}

这说明协议已经不只是“有没有结果”,而是有了明确的任务状态机。

3. 取最终结果

完成之后,再用 tasks/result 去拿真正结果。

这个模式的最大价值是:

状态和结果终于分开了。

七、Tasks 的状态机,为什么很像真正的 workflow system

MCP Python SDK 的 experimental tasks 文档把生命周期讲得很直白。

一个 task 常见会经过这些状态:

  • working
  • input_required
  • completed
  • failed
  • cancelled

这里最值得注意的是 input_required

因为这说明 Tasks 不是只为“后台慢任务”准备的,它还适合:

  • 中间需要用户确认
  • 中间需要 elicitation / sampling

这就让它比“简单异步 job”更接近 agent workflow 的现实。

八、为什么很多现实系统会特别需要它

SEP-1686 列了很多非常具体的用例,我觉得很有代表性。

比如:

  • Healthcare & Life Sciences 的长时间计算分析
  • Enterprise automation 的复杂业务流程
  • Code migration workflows
  • 大规模测试执行平台
  • Deep research 工具
  • Agent-to-Agent communication 里的慢任务处理

这几个例子背后其实都是同一个问题:

任务本身不适合被一次性阻塞式地执行完。

你要么:

  • 允许它在后台跑
  • 允许 host 稳定轮询
  • 允许结果稍后取回

不然系统就会卡在“要么一直等,要么自己乱拆轮询工具”的尴尬状态里。

九、为什么 Tasks 比“拆三个工具”更优雅

很多人会说:

我现在也能自己做啊,写 start_jobget_statusget_result 三个工具不就行了?

表面上看可以,实际上问题很多。

1. 约定不统一

每个 server 都会自己造一套轮询风格。

2. Agent 不稳定

模型可能:

  • 忘了轮询
  • 轮询频率不合适
  • 乱猜任务 ID
  • 过早结束回合

SEP-1686 甚至直接提到一个典型问题:

  • 模型有时会调用一次 get 之后就说“我在等”,但不会自己继续恢复

这正是为什么协议层需要把这件事接住。

3. Host 很难接管

如果轮询只是应用约定,不是协议原语,host 无法稳定接管 orchestration。

Tasks 的意义就在于:

把长任务的管理,从 prompt 约定提升到协议原语。

十、放一段最小示意代码,直观很多

下面我用接近官方协议思路的伪代码,演示一下为什么 Tasks 比同步 tool call 更像生产系统。

task_id = "task_123"

# 1. 先发起一个 task-augmented request
client.call_tool(
    "run_large_test_suite",
    arguments={"repo": "backend-api"},
    meta={
        "modelcontextprotocol.io/task": {
            "taskId": task_id,
            "keepAlive": 60000
        }
    }
)

# 2. Host 轮询任务状态,而不是把轮询交给模型自己记
while True:
    status = client.request("tasks/get", {"taskId": task_id})
    if status["status"] == "completed":
        break
    if status["status"] in {"failed", "cancelled"}:
        raise RuntimeError(status["status"])
    sleep(status.get("pollFrequency", 5))

# 3. 最后再拿结果
result = client.request("tasks/result", {"taskId": task_id})
print(result)

这段代码最重要的不是轮询本身,而是 ownership 变了:

  • 以前是 Agent 自己靠 prompt 记得去轮询
  • 现在是 host / client 用协议层能力接管

这是工程质量上的巨大差别。

十一、它为什么对多 Agent 系统也重要

这一点我觉得后面会越来越多人意识到。

SEP-1686 里甚至专门点到了:

  • 在 multi-agent systems 里,慢 agent 会造成 cascading delays

这件事非常现实。

如果一个 Agent 之间的调用还是全同步的,那么:

  • 一个慢任务会拖住整条链
  • 其他 agent 不能并发做自己的事

有了 Tasks 之后,更合理的形态会是:

  • 当前 agent 把慢任务丢到后台
  • host 按协议层管理轮询
  • 其他 agent 继续做别的事
  • 结果准备好后再取回

这就是为什么我会说:

Tasks 不只是为“慢工具”准备的,它其实也是多 Agent 并发系统的基础设施。

十二、截至 2026-04-18,我认为可以下的判断

基于 MCP 官方 SEP、架构文档和 SDK 文档,我觉得下面几条已经很稳:

1. Tasks 解决的不是普通异步,而是可协议化的 deferred execution

重点是:

  • status tracking
  • deferred result retrieval
  • host-driven polling

2. 只靠同步工具调用,覆盖不了真正的长任务和 workflow

特别是分钟级到小时级任务。

3. 把轮询交给 Agent,是贵而且不稳定的

协议层 Tasks 的价值,恰恰是把这件事从 prompt 工程里拿出来。

4. Tasks 会越来越重要,因为 MCP 正在进入更复杂的 workflow 和 multi-agent 场景

而这些场景天然需要 call-now / fetch-later。

十三、我的结论

所以,回到标题:

为什么 Agent 不能只靠同步工具调用?

因为同步工具调用只适合“很快返回”的场景。

一旦进入长任务、复杂 workflow、用户中途补输入、多 Agent 并发这些现实问题,你就需要一种正式的协议机制,来处理:

  • 任务已发起
  • 状态可追踪
  • 结果可延迟取回

而 Tasks 正是在解决这件事。

如果让我用一句话总结:

tools/call 解决“怎么开始干”,tasks 解决“干很久以后怎么稳稳拿回结果”。

参考资料

  • Model Context Protocol, SEP-1686: Tasks, created 2025-10-20
    https://modelcontextprotocol.io/seps/1686-tasks
  • Model Context Protocol, Architecture overview
    https://modelcontextprotocol.io/docs/learn/architecture
  • MCP Python SDK, Tasks (Experimental)
    https://py.sdk.modelcontextprotocol.io/experimental/tasks/
Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐