任务在 MCP 规范 2025-11-25 版本中引入,目前被视为实验性功能。
任务的设计和行为可能会在未来协议版本中演进。
定义
任务将参与方表示为“请求方”或“接收方”,定义如下:- 请求方: 任务增强请求的发送方。它可以是客户端或服务器,二者都可以创建任务。
- 接收方: 任务增强请求的接收方,也是执行任务的实体。它可以是客户端或服务器,二者都可以接收和执行任务。
用户交互模型
任务被设计为请求方驱动:请求方负责用任务增强请求,并轮询这些任务的结果;同时,接收方严格控制哪些请求(如果有)支持基于任务的执行,并管理这些任务的生命周期。 这种请求方驱动方式确保响应处理具有确定性,并支持分派并发请求等复杂模式,而只有请求方具备足够上下文来编排这些模式。 实现可以自由通过任何适合自身需求的接口模式公开任务;协议本身不强制任何特定用户交互模型。能力
支持任务增强请求的服务器和客户端 MUST 在初始化期间声明tasks 能力。tasks 能力按请求类别组织,并通过布尔属性指示哪些具体请求类型支持任务增强。
服务器能力
服务器声明其是否支持任务;如果支持,还要声明哪些服务器侧请求可以用任务增强。客户端能力
客户端声明其是否支持任务;如果支持,还要声明哪些客户端侧请求可以用任务增强。能力协商
在初始化阶段,双方会交换其tasks 能力,以确定哪些操作支持基于任务的执行。只有在接收方声明了对应能力时,请求方 SHOULD 才用任务增强请求。
例如,如果服务器能力包含 tasks.requests.tools.call: {},则客户端可以用任务增强 tools/call 请求。如果客户端能力包含 tasks.requests.sampling.createMessage: {},则服务器可以用任务增强 sampling/createMessage 请求。
如果未定义 capabilities.tasks,对等方 SHOULD NOT 在请求期间尝试创建任务。
capabilities.tasks.requests 中的能力集合是穷尽的。如果某种请求类型不存在,则它不支持任务增强。
capabilities.tasks.list 控制该参与方是否支持 tasks/list 操作。
capabilities.tasks.cancel 控制该参与方是否支持 tasks/cancel 操作。
工具级协商
出于任务增强目的,工具调用需要特殊处理。在tools/list 的结果中,工具通过 execution.taskSupport 声明对任务的支持;如果存在,该值可以是 "required"、"optional" 或 "forbidden"。
这应解释为能力之外的细粒度层,并遵循以下规则:
- 如果服务器能力不包含
tasks.requests.tools.call,无论execution.taskSupport的值是什么,客户端都 MUST NOT 尝试对该服务器的工具使用任务增强。 - 如果服务器能力包含
tasks.requests.tools.call,客户端会考虑execution.taskSupport的值,并相应处理:- 如果
execution.taskSupport不存在或为"forbidden",客户端 MUST NOT 尝试以任务方式调用工具。如果客户端尝试这样做,服务器 SHOULD 返回-32601(Method not found) 错误。这是默认行为。 - 如果
execution.taskSupport为"optional",客户端 MAY 以任务方式调用工具,也可以作为普通请求调用。 - 如果
execution.taskSupport为"required",客户端 MUST 以任务方式调用工具。如果客户端没有尝试这样做,服务器 MUST 返回-32601(Method not found) 错误。
- 如果
协议消息
创建任务
任务增强请求遵循不同于普通请求的两阶段响应模式:- 普通请求:服务器处理请求,并直接返回实际操作结果。
- 任务增强请求:服务器接受请求,并立即返回包含任务数据的
CreateTaskResult。实际操作结果会在任务完成后,稍后通过tasks/result提供。
task 字段的请求。请求方 MAY 包含 ttl 值,表示自创建起期望的任务生命周期时长(毫秒)。
请求:
CreateTaskResult。响应不包含实际操作结果。实际结果(例如 tools/call 的工具结果)只有在任务完成后才能通过 tasks/result 获得。
当为响应
tools/call 请求而创建任务时,Host 应用可能希望在任务执行期间将控制权交还给模型。这允许模型在等待任务完成时继续处理其他请求或执行额外工作。为支持这种模式,服务器可以在 CreateTaskResult 的 _meta 字段中提供一个可选的 io.modelcontextprotocol/model-immediate-response 键。该键的值应为字符串,用作立即传递给模型的工具结果。
如果服务器未提供此字段,Host 应用可以回退到自己预定义的消息。本指南不具约束力,是用于处理特定用例的临时逻辑。未来协议版本可能会将此行为作为 CreateTaskResult 的一部分正式化或修改。获取任务
在 Streamable HTTP (SSE) 传输中,客户端 MAY 随时从服务器为响应
tasks/get 请求而打开的 SSE 流断开连接。虽然本说明不对 SSE 流的具体用法作规范性规定,但所有实现 MUST 继续遵守现有的 Streamable HTTP 传输规范。tasks/get 请求来轮询任务完成情况。
请求方在确定轮询频率时 SHOULD 遵守响应中提供的 pollInterval。
请求方 SHOULD 持续轮询,直到任务达到终止状态(completed、failed 或 cancelled),或直到遇到 input_required 状态。请注意,调用 tasks/result 并不意味着请求方需要停止轮询;如果请求方没有主动等待 tasks/result 完成,SHOULD 继续通过 tasks/get 轮询任务状态。
请求:
检索任务结果
在 Streamable HTTP (SSE) 传输中,客户端 MAY 随时从服务器为响应
tasks/result 请求而打开的 SSE 流断开连接。虽然本说明不对 SSE 流的具体用法作规范性规定,但所有实现 MUST 继续遵守现有的 Streamable HTTP 传输规范。tasks/result 检索操作结果。这不同于初始 CreateTaskResult 响应,后者只包含任务数据。结果结构与原始请求类型匹配(例如 tools/call 对应 CallToolResult)。
要检索已完成任务的结果,请求方可以发送 tasks/result 请求:
虽然 tasks/result 会阻塞,直到任务达到终止状态,但如果请求方没有主动阻塞等待结果(例如其先前的 tasks/result 请求失败或被取消),它们可以并行继续通过 tasks/get 轮询。这允许请求方在任务执行期间监控状态变化或显示进度更新,即使已经调用过 tasks/result。
请求:
任务状态通知
当任务状态发生变化时,接收方 MAY 发送notifications/tasks/status 通知,以告知请求方该变化。此通知包含完整任务状态。
通知:
Task 对象,包括更新后的 status 和 statusMessage(如果存在)。这允许请求方访问完整任务状态,而无需额外发起 tasks/get 请求。
请求方 MUST NOT 依赖接收此通知,因为它是可选的。接收方不要求发送状态通知,并且可以选择只针对某些状态转换发送。请求方 SHOULD 继续通过 tasks/get 轮询,以确保收到状态更新。
列出任务
要检索任务列表,请求方可以发送tasks/list 请求。此操作支持分页。
请求:
取消任务
要显式取消任务,请求方可以发送tasks/cancel 请求。
请求:
行为要求
这些要求适用于所有支持接收任务增强请求的参与方。任务支持与处理
- 未为某种请求类型声明任务能力的接收方 MUST 正常处理该类型请求,并忽略任何存在的任务增强元数据。
- 为某种请求类型声明任务能力的接收方 MAY 对非任务增强请求返回错误,要求请求方使用任务增强。
Task ID 要求
- Task IDs MUST 是字符串值。
- Task IDs MUST 由接收方在创建任务时生成。
- Task IDs MUST 在接收方控制的所有任务中唯一。
任务状态生命周期
- 任务创建时 MUST 从
working状态开始。 - 接收方 MUST 仅按以下有效路径转换任务:
- 从
working:可以转为input_required、completed、failed或cancelled - 从
input_required:可以转为working、completed、failed或cancelled - 状态为
completed、failed或cancelled的任务处于终止状态,MUST NOT 转换为任何其他状态
- 从
Input Required 状态
使用 Streamable HTTP (SSE) 传输时,服务器通常会在投递响应消息后关闭 SSE 流,这可能导致后续任务消息应使用哪个流变得不明确。服务器可以通过将消息排队发送给客户端来处理这种情况,从而把任务相关消息作为旁路消息与其他响应一起传递。服务器可以灵活管理任务轮询和结果检索期间的 SSE 流,客户端 SHOULD 预期消息可能在任何 SSE 流上传递,包括 HTTP GET 流。
一种可能方式是在
tasks/result 上维护 SSE 流(见关于 input_required 状态的说明)。
在可行时,服务器 SHOULD NOT 响应 tasks/get 请求升级到 SSE 流,因为客户端已经表示希望轮询结果。虽然本说明不对 SSE 流的具体用法作规范性规定,但所有实现 MUST 继续遵守现有的 Streamable HTTP 传输规范。- 当任务接收方有完成任务所必需、需要发给请求方的消息时,接收方 SHOULD 将任务移至
input_required状态。 - 接收方 MUST 在请求中包含
io.modelcontextprotocol/related-task元数据,以将其与任务关联。 - 当请求方遇到
input_required状态时,它 SHOULD 预先调用tasks/result。 - 当接收方收到所有必需输入后,任务 SHOULD 转出
input_required状态(通常回到working)。
TTL 和资源管理
- 接收方 MUST 在所有任务响应中包含采用 ISO 8601 格式的
createdAt时间戳,以指示任务创建时间。 - 接收方 MUST 在所有任务响应中包含采用 ISO 8601 格式的
lastUpdatedAt时间戳,以指示任务最后更新时间。 - 接收方 MAY 覆盖请求的
ttl时长。 - 接收方 MUST 在
tasks/get响应中包含实际ttl时长(或使用null表示无限制)。 - 在任务的
ttl生命周期结束后,无论任务状态如何,接收方 MAY 删除任务及其结果。 - 接收方 MAY 在
tasks/get响应中包含pollInterval值(毫秒),以建议轮询间隔。请求方在该值存在时 SHOULD 遵守它。
结果检索
- 接受任务增强请求的接收方 MUST 返回
CreateTaskResult作为响应。该结果 SHOULD 在接受任务后尽快返回。 - 当接收方收到针对处于终止状态(
completed、failed或cancelled)任务的tasks/result请求时,它 MUST 返回底层请求的最终结果,无论该结果是成功结果还是 JSON-RPC 错误。 - 当接收方收到针对处于任何其他非终止状态(
working或input_required)任务的tasks/result请求时,它 MUST 阻塞响应,直到任务达到终止状态。 - 对于处于终止状态的任务,接收方 MUST 从
tasks/result返回与底层请求本应返回的完全相同内容,无论该内容是成功结果还是 JSON-RPC 错误。
关联任务相关消息
- 与任务相关的所有请求、通知和响应 MUST 在其
_meta字段中包含io.modelcontextprotocol/related-task键,其值设置为一个对象,且其中taskId与关联任务 ID 匹配。- 例如,任务增强工具调用所依赖的引出 MUST 与该工具调用的任务共享相同的 related task ID。
- 对于
tasks/get、tasks/result和tasks/cancel操作,请求中的taskId参数 MUST 用作标识目标任务的事实来源。请求方 SHOULD NOT 在这些请求中包含io.modelcontextprotocol/related-task元数据;如果存在,接收方 MUST 忽略此类元数据,并以 RPC 方法参数为准。 类似地,对于tasks/get、tasks/list和tasks/cancel操作,接收方 SHOULD NOT 在结果消息中包含io.modelcontextprotocol/related-task元数据,因为taskId已经存在于响应结构中。
任务通知
- 当任务状态发生变化时,接收方 MAY 发送
notifications/tasks/status通知。 - 请求方 MUST NOT 依赖接收
notifications/tasks/status通知,因为它是可选的。 - 发送时,
notifications/tasks/status通知 SHOULD NOT 包含io.modelcontextprotocol/related-task元数据,因为任务 ID 已经存在于通知参数中。
任务进度通知
任务增强请求支持 progress 规范中定义的进度通知。初始请求中提供的progressToken 会在整个任务生命周期内保持有效。
任务列表
- 接收方 SHOULD 使用基于 cursor 的分页,以限制单个响应中返回的任务数量。
- 如果还有更多任务可用,接收方 MUST 在响应中包含
nextCursor。 - 请求方 MUST 将 cursors 视为 opaque tokens,不得尝试解析或修改它们。
- 如果某个任务可由某请求方通过
tasks/get检索,则它 MUST 可由该请求方通过tasks/list检索。
任务取消
- 对于已处于终止状态(
completed、failed或cancelled)的任务,接收方 MUST 使用错误代码-32602(Invalid params) 拒绝取消请求。 - 收到有效取消请求后,接收方 SHOULD 尝试停止任务执行,并且 MUST 在发送响应前将任务转换为
cancelled状态。 - 任务一旦取消,即使执行继续完成或失败,也 MUST 保持
cancelled状态。 tasks/cancel操作未定义删除行为。不过,接收方 MAY 自行决定随时删除已取消任务,包括取消后立即删除或在任务ttl过期后删除。- 请求方 SHOULD NOT 依赖已取消任务保留任何特定时长,并应在取消前检索任何所需信息。
消息流程
基本任务生命周期
带引出的任务增强工具调用
任务增强采样请求
任务取消流程
数据类型
Task
任务表示请求的执行状态。任务状态包括:taskId:任务的唯一标识符status:任务执行的当前状态statusMessage:描述当前状态的可选人类可读消息(可出现在任何状态中,包括失败任务的错误详情)createdAt:任务创建时间的 ISO 8601 时间戳ttl:从创建开始到任务可能被删除之前的时间,单位为毫秒pollInterval:状态检查之间的建议时间,单位为毫秒lastUpdatedAt:任务状态最后更新时间的 ISO 8601 时间戳
任务状态
任务可以处于以下状态之一:working:请求当前正在处理。input_required:接收方需要来自请求方的输入。即使任务尚未达到终止状态,请求方也应调用tasks/result来接收输入请求。completed:请求已成功完成,结果可用。failed:关联请求未成功完成。具体到工具调用,这包括工具调用结果将isError设置为 true 的情况。cancelled:请求在完成前已取消。
任务参数
用任务执行增强请求时,请求参数中会包含task 字段:
ttl(number, optional):请求从创建开始保留任务的时长,单位为毫秒
Related Task 元数据
与任务关联的所有请求、响应和通知 MUST 在_meta 中包含 io.modelcontextprotocol/related-task 键:
tasks/get、tasks/list 和 tasks/cancel 操作,请求方和接收方 SHOULD NOT 在其消息中包含此元数据,因为 taskId 已经存在于消息结构中。
tasks/result 操作 MUST 在其响应中包含此元数据,因为结果结构本身不包含任务 ID。
错误处理
任务使用两种错误报告机制:- 协议错误:用于协议级问题的标准 JSON-RPC 错误
- 任务执行错误:底层请求执行中的错误,通过任务状态报告
协议错误
接收方 MUST 针对以下协议错误情况返回标准 JSON-RPC 错误:tasks/get、tasks/result或tasks/cancel中的taskId无效或不存在:-32602(Invalid params)tasks/list中的 cursor 无效或不存在:-32602(Invalid params)- 尝试取消已处于终止状态的任务:
-32602(Invalid params) - 内部错误:
-32603(Internal error)
- 当接收方要求该请求类型使用任务增强时收到非任务增强请求:
-32600(Invalid request)
接收方不要求无限期保留任务。如果接收方已清除过期任务,返回说明找不到该任务的错误是符合规范的行为。
任务执行错误
当底层请求未成功完成时,任务会转为failed 状态。这包括请求执行期间的 JSON-RPC 协议错误;具体到工具调用,还包括工具结果将 isError 设置为 true 的情况。tasks/get 响应 SHOULD 包含带有失败诊断信息的 statusMessage 字段。
示例:带执行错误的任务
isError 设置为 true 时,任务应达到 failed 状态。
tasks/result endpoint 会返回与底层请求本应返回的完全相同内容:
- 如果底层请求产生 JSON-RPC 错误,
tasks/resultMUST 返回相同的 JSON-RPC 错误。 - 如果请求以 JSON-RPC 响应完成,
tasks/resultMUST 返回包含该结果的成功 JSON-RPC 响应。
安全考量
任务隔离和访问控制
Task IDs 是访问任务状态和结果的主要机制。如果没有适当访问控制,任何能够猜测或获得 task ID 的参与方都可能访问敏感信息,或操纵并非由其创建的任务。 当提供授权上下文时,接收方 MUST 将任务绑定到该上下文。 上下文绑定并不适用于所有应用。一些 MCP 服务器运行在没有授权的环境中,例如单用户工具,或使用不支持授权的传输。 在这些场景中,接收方 SHOULD 清楚记录此限制,因为任何能够猜测 task ID 的请求方都可能访问任务结果。 如果无法进行上下文绑定,接收方 MUST 生成具有足够熵的加密安全 task IDs 以防猜测,并应考虑使用更短的 TTL 时长来缩小暴露窗口。 此外,无法识别请求方的接收方 SHOULD NOT 声明tasks.list 能力,因为列出任务会向任何请求方暴露任务元数据,无论 task ID 熵有多高。
如果上下文绑定可用,接收方 MUST 拒绝针对不属于请求方同一授权上下文的任务的 tasks/get、tasks/result 和 tasks/cancel 请求。对于 tasks/list 请求,接收方 MUST 确保返回的任务列表只包含与请求方授权上下文关联的任务。
此外,接收方 SHOULD 对任务操作实施速率限制,以防止拒绝服务和枚举攻击。
资源管理
- 接收方 SHOULD:
- 对每个请求方的并发任务实施限制
- 强制执行最大
ttl时长,以防资源无限期保留 - 及时清理过期任务以释放资源
- 记录支持的最大
ttl时长 - 记录每个请求方的最大并发任务数
- 实现资源使用情况的监控和告警
审计和日志记录
- 接收方 SHOULD:
- 出于审计目的记录任务创建、完成和检索事件
- 在可用时将 auth context 包含在日志中
- 监控可疑模式(例如大量失败的任务查找、过度轮询)
- 请求方 SHOULD:
- 出于调试和审计目的记录任务生命周期事件
- 跟踪 task IDs 及其关联操作