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