[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fu9xCIn2K6zoQvCVkCqH3XgMtv2sxXAM_mhGEa4_403E":3},{"item":4,"related":51},{"id":5,"type":6,"title":7,"slug":8,"summary":9,"body":10,"coverUrl":11,"productScreenshots":12,"productLinks":13,"authorName":14,"authorUrl":15,"authorSubject":16,"category":17,"tags":22,"sourceLabel":39,"sourceName":40,"sourceUrl":41,"status":42,"seoTitle":43,"seoDescription":44,"canonicalUrl":45,"isFeatured":46,"sno":47,"sortOrder":48,"publishedAt":49,"updatedAt":50,"createdAt":50},"c17c736f-efbe-433b-ad2c-e7c9e24f6108","article","MCP Tasks：工具调用为什么也需要“任务状态机”？","mcp-tasks-long-running-tool-calls","MCP Tasks 为长时间运行、可轮询、可取消或需要补充输入的工具调用定义了任务状态机。本文解释任务调用与普通 tools\u002Fcall 的区别、能力协商、状态生命周期、TTL 和工程边界。","很多工具调用在演示里都很短：模型发出请求，服务器马上返回结果。但真实系统里，工具可能要跑一次批量分析、等待外部审批、处理一批文件，或者排队等待一个远程作业。此时如果仍然把工具调用当成“一问一答”，客户端就只能一直占着连接，服务器也很难告诉调用方任务到底进行到哪一步。\n\nMCP Tasks 解决的正是这个边界问题。它不是另一个任务队列产品，而是 MCP 对“这次请求需要异步执行”所定义的一层协议语义。任务会拥有独立的 `taskId` 和状态，调用方可以稍后查询状态、取得结果或取消任务。\n\n## 普通工具调用和任务调用有什么不同\n\n普通的 `tools\u002Fcall` 可以理解为一次同步请求：客户端把参数发给服务器，服务器完成工作后直接返回 `CallToolResult`。这种模式适合查询天气、读取文件或执行一次很快的转换。\n\n任务调用则是两阶段返回。服务器先确认“我已经接下这项工作”，马上返回一个包含任务信息的结果；真正的工具结果要等任务进入终态后，再通过 `tasks\u002Fresult` 取得。这样，客户端不必把一次 HTTP 连接或一次 Agent 回合一直挂到任务结束。\n\n```mermaid\nflowchart TD\n    A[客户端发起带 task 的工具调用] --> B{双方已声明 tasks 能力?}\n    B -- 否 --> C[按普通工具调用处理]\n    B -- 是 --> D[服务器返回 taskId 与 working]\n    D --> E[客户端按 pollInterval 查询 tasks\u002Fget]\n    E --> F{任务状态}\n    F -- working --> E\n    F -- input_required --> G[补充用户或外部输入]\n    G --> E\n    F -- completed --> H[调用 tasks\u002Fresult 取得结果]\n    F -- failed\u002Fcancelled --> I[显示失败或取消原因]\n```\n\n## 谁创建任务，谁负责管理\n\nMCP Tasks 有一个容易被忽略的设计：请求方和接收方不固定。客户端可以给服务器发起带任务的工具调用，服务器也可以向客户端发起带任务的采样或询问请求。谁接收请求，谁就负责真正执行任务并生成任务 ID；谁发起请求，谁就负责轮询和编排后续处理。\n\n这意味着任务并不是“服务器偷偷把请求丢进后台”这么简单。双方要先在初始化阶段交换 `tasks` 能力，声明哪些请求类型支持任务化。服务器还可以在工具列表中进一步说明某个工具的任务支持是 `optional`、`required` 还是 `forbidden`。如果一个工具要求任务化，客户端却仍用普通调用，服务器可以拒绝它。\n\n## 状态机比一个布尔值更有用\n\n任务至少要区分几种状态：`working` 表示正在执行，`input_required` 表示缺少继续执行所需的输入，`completed`、`failed` 和 `cancelled` 则是终态。`input_required` 很重要，因为它把“任务还没完成”和“任务正在等人回答”区分开了。\n\n例如，一个采购 Agent 可能已经查完库存，却需要用户确认预算；一个数据清洗工具可能发现压缩包密码未知；一个代码迁移工具可能需要用户选择是否修改某个高风险文件。它们都不应该被粗暴地标成失败，也不应该无限重试，而是把任务切换到等待输入的状态。\n\n## 它不等于可靠的后台作业系统\n\nMCP Tasks 只规定跨客户端和服务器传递任务状态的方式，并不替你解决队列持久化、重复执行、幂等、分布式锁和故障恢复。服务器仍然需要自己决定任务存在哪里、进程崩溃后如何恢复、任务过期后是否清理结果，以及取消请求能否真正中止底层工作。\n\n规范还允许任务携带 TTL，并建议调用方遵守服务器返回的轮询间隔。TTL 过期后，服务器可以删除任务和结果。因此，客户端不能把任务 ID 当作永久链接；如果结果很重要，就应该及时取回并在自己的系统中保存。\n\n## 什么时候值得使用\n\n如果工具通常在几百毫秒内完成，普通调用更简单。如果工具可能运行数秒、数分钟甚至更久，或者需要跨多个服务编排，任务化会让用户体验和系统资源都更可控。设计时应优先确定三件事：哪些操作允许后台执行，哪些状态变化需要通知用户，以及任务结果是否包含需要单独授权的数据。\n\nMCP Tasks 的价值不在于把每个工具都变成异步作业，而在于给“长时间运行、可查询、可取消、可能需要补充输入”的调用一套共同语言。Agent 能否真正可靠地处理复杂工作，往往取决于它能不能把“我还在做”和“我已经做完”清楚地区分开。\n\n来源：[Model Context Protocol Tasks 官方规范](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fbasic\u002Futilities\u002Ftasks)","\u002Fuploads\u002F2026-09-12\u002Fc1ac67e1-5074-4faa-97c3-c3215edd0646.jpg",[],[],"Foundit","https:\u002F\u002Ffoundit.cn","foundit-ai-editorial",{"id":18,"name":19,"slug":20,"description":21},"6179d3b6-dc34-4483-9ded-3cd9f1b37a47","科普","abbreviation","介绍各领域新兴概念",[23,27,31,35],{"id":24,"name":25,"slug":26},"88d2bc27-0e0f-468a-b907-2991cb97b87b","人工智能","ai",{"id":28,"name":29,"slug":30},"a202d639-99a6-488a-a712-4d4c6ffd7e15","开发","dev",{"id":32,"name":33,"slug":34},"7c76bfc2-f80f-4ee0-a95d-27bd8708b434","技术","slug",{"id":36,"name":37,"slug":38},"63b56667-dcdb-4b8b-bcbe-c405143a7ec2","测评","test","MCP Tasks 官方规范","Model Context Protocol Tasks","https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fbasic\u002Futilities\u002Ftasks","published","MCP Tasks 是什么：让 Agent 工具支持长任务和状态查询","解释 MCP Tasks 如何把长时间运行的工具调用变成可轮询、可取消、可等待输入的任务状态机，并说明它与后台队列的区别。",null,false,54,0,"2026-09-12T00:00:00.000Z","2026-09-12T03:56:41.060Z",[52,62,71],{"id":53,"type":6,"title":54,"slug":55,"summary":56,"coverUrl":57,"authorName":58,"sno":59,"publishedAt":60,"createdAt":61},"0e2211d6-a9cc-4151-aec3-ea60ef2575f2","本地大模型部署：用 Ollama 与 llama.cpp 把模型搬进你自己的机器","local-llm-deployment-ollama-llama-cpp","数据敏感、要离线、想省 API 账单？本地部署值得了解。","https:\u002F\u002Foxqtewbrpuiouqqjrvdv.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fpublic-media\u002F2026-07-20\u002Fbf471546-ff4c-4fee-a01c-8a41157e5a8c.jpg","Foundit AI",76,"2026-07-19T00:00:00.000Z","2026-07-20T01:11:41.120Z",{"id":63,"type":6,"title":64,"slug":65,"summary":66,"coverUrl":67,"authorName":14,"sno":68,"publishedAt":69,"createdAt":70},"5ef7ce44-0678-40b4-95e0-af4fe8a6b0a7","提示词也能缓存：固定前缀为什么能省钱提速？","prompt-caching-prefix-kv-cache","Prompt caching 缓存的不是旧答案，而是模型处理重复提示词前缀时产生的中间状态。本文解释它与语义缓存的区别、为什么顺序会影响命中、如何整理 Agent 上下文，以及多租户场景中的隔离风险。","\u002Fuploads\u002F2026-09-08\u002F182822f9-05a3-4d2b-8766-bc5daf93effd.jpg",42,"2026-09-08T00:00:00.000Z","2026-09-08T03:19:26.522Z",{"id":72,"type":6,"title":73,"slug":74,"summary":75,"coverUrl":76,"authorName":14,"sno":77,"publishedAt":69,"createdAt":78},"7f7b281e-b9d6-406f-8d79-9dfb33145f5e","WebTransport：为什么实时 AI 应用不一定应该使用 WebSocket？","webtransport-realtime-ai-apps","WebSocket 适合通用双向消息，但复杂实时 AI 应用还可能需要可靠流、双向流和可以丢弃的临时数据。本文解释 WebTransport 的 session、stream 和 datagram，比较它与 SSE、WebSocket、WebRTC 的边界，并讨论鉴权与部署。","\u002Fuploads\u002F2026-09-08\u002F2247cab5-87b7-4b92-8871-e6adac14dc47.jpg",44,"2026-09-08T03:19:19.069Z"]