Tasks

协议版本: 草案
Tasks 在 MCP 规范的 2025-11-25 版本中引入,目前被认为是实验性的。 Tasks 的设计和行为可能会在未来的协议版本中演变。

模型上下文协议 (MCP) 允许请求方(可以是客户端或服务器,具体取决于通信方向)使用 tasks 来增强其请求。Tasks 是持久的状态机,携带它们包装的请求的底层执行状态信息,旨在用于请求方轮询和延迟结果检索。每个任务由接收方生成的任务 ID 唯一标识。

Tasks 对于表示昂贵的计算和批处理请求非常有用,并且与外部作业 API 无缝集成。

定义

Tasks 将各方表示为"请求方"或"接收方",定义如下:

  • 请求方:任务增强请求的发送者。这可以是客户端或服务器——两者都可以创建任务。
  • 接收方:任务增强请求的接收者,以及执行任务的实体。这可以是客户端或服务器——两者都可以接收和执行任务。

用户交互模型

Tasks 被设计为请求方驱动 - 请求方负责使用任务增强请求并轮询这些任务的结果;同时,接收方紧密控制哪些请求(如果有)支持基于任务的执行并管理这些任务的生命周期。

这种请求方驱动的方法确保了确定性的响应处理,并启用了复杂的模式,例如分派并发请求,只有请求方才有足够的上下文来协调这些请求。

实施可以通过适合其需求的任何接口模式公开任务 - 协议本身不强制要求任何特定的用户交互模型。

功能

支持任务增强请求的服务器和客户端必须在初始化期间声明 tasks 功能。tasks 功能按请求类别结构化,布尔属性指示哪些特定请求类型支持任务增强。

服务器功能

服务器声明它们是否支持任务,如果支持,哪些服务器端请求可以使用任务增强。

功能描述
tasks.list服务器支持 tasks/list 操作
tasks.cancel服务器支持 tasks/cancel 操作
tasks.requests.tools.call服务器支持任务增强的 tools/call 请求
{
  "capabilities": {
    "tasks": {
      "list": {},
      "cancel": {},
      "requests": {
        "tools": {
          "call": {}
        }
      }
    }
  }
}

客户端功能

客户端声明它们是否支持任务,如果支持,哪些客户端请求可以使用任务增强。

功能描述
tasks.list客户端支持 tasks/list 操作
tasks.cancel客户端支持 tasks/cancel 操作
tasks.requests.sampling.createMessage客户端支持任务增强的 sampling/createMessage 请求
tasks.requests.elicitation.create客户端支持任务增强的 elicitation/create 请求
{
  "capabilities": {
    "tasks": {
      "list": {},
      "cancel": {},
      "requests": {
        "sampling": {
          "createMessage": {}
        },
        "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"

这应被解释为除功能之外的细粒度层,遵循以下规则:

  1. 如果服务器的功能不包括 tasks.requests.tools.call,则客户端不得尝试在该服务器的工具上使用任务增强,无论 execution.taskSupport 值如何。
  2. 如果服务器的功能包括 tasks.requests.tools.call,则客户端考虑 execution.taskSupport 的值,并相应地处理它:
    1. 如果 execution.taskSupport 不存在或为 "forbidden",则客户端不得尝试将工具作为任务调用。如果客户端尝试这样做,服务器应该返回 -32601(未找到方法)错误。这是默认行为。
    2. 如果 execution.taskSupport"optional",则客户端可以将工具作为任务或正常请求调用。
    3. 如果 execution.taskSupport"required",则客户端必须将工具作为任务调用。如果客户端不尝试这样做,服务器必须返回 -32601(未找到方法)错误。

协议消息

创建 Tasks

任务增强请求遵循与正常请求不同的两阶段响应模式:

  • 正常请求:服务器处理请求并直接返回实际操作结果。
  • 任务增强请求:服务器接受请求并立即返回包含任务数据的 CreateTaskResult。实际操作结果仅在任务完成后通过 tasks/result 可用。

要创建任务,请求方发送在请求参数中包含 task 字段的请求。请求方可以包括 ttl 值,指示自创建以来所需的任务生存期持续时间(以毫秒为单位)。

请求:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": {
      "city": "New York"
    },
    "task": {
      "ttl": 60000
    }
  }
}

响应:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "task": {
      "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
      "status": "working",
      "statusMessage": "The operation is now in progress.",
      "createdAt": "2025-11-25T10:30:00Z",
      "lastUpdatedAt": "2025-11-25T10:40:00Z",
      "ttl": 60000,
      "pollInterval": 5000
    }
  }
}

当接收方接受任务增强请求时,它返回包含任务数据的 CreateTaskResult。响应不包括实际操作结果。实际结果(例如,tools/call 的工具结果)仅在任务完成后通过 tasks/result 可用。

当在响应 tools/call 请求时创建任务,主机应用程序可能希望在任务执行时将控制权返回给模型。这允许模型在等待任务完成时继续处理其他请求或执行额外的工作。

为了支持这种模式,服务器可以在 CreateTaskResult_meta 字段中提供可选的 io.modelcontextprotocol/model-immediate-response 键。此键的值应该是一个字符串,旨在作为立即工具结果传递给模型。 如果服务器不提供此字段,主机应用程序可以回退到其自己的预定义消息。

此指导不具有约束力,并且是临时逻辑,旨在考虑特定用例。此行为可能会在未来的协议版本中作为 CreateTaskResult 的一部分被正式化或修改。

获取 Tasks

在可流式 HTTP (SSE) 传输中,客户端可以随时断开与服务器在响应 tasks/get 请求时打开的 SSE 流的连接。

虽然此说明不对 SSE 流的具体使用做出规定,但所有实施必须继续遵守现有的可流式 HTTP 传输规范

请求方通过发送 tasks/get 请求轮询任务完成情况。请求方应该在确定轮询频率时遵守响应中提供的 pollInterval

请求方应该继续轮询,直到任务达到终端状态(completedfailedcancelled),或者遇到 input_required 状态。请注意,调用 tasks/result 并不意味着请求方需要停止轮询 - 如果请求方没有主动等待 tasks/result 完成,它们应该继续通过 tasks/get 轮询任务状态。

请求:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tasks/get",
  "params": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840"
  }
}

响应:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
    "status": "working",
    "statusMessage": "The operation is now in progress.",
    "createdAt": "2025-11-25T10:30:00Z",
    "lastUpdatedAt": "2025-11-25T10:40:00Z",
    "ttl": 30000,
    "pollInterval": 5000
  }
}

检索任务结果

在可流式 HTTP (SSE) 传输中,客户端可以随时断开与服务器在响应 tasks/result 请求时打开的 SSE 流的连接。

虽然此说明不对 SSE 流的具体使用做出规定,但所有实施必须继续遵守现有的可流式 HTTP 传输规范

任务完成后,通过 tasks/result 检索操作结果。这与仅包含任务数据的初始 CreateTaskResult 响应不同。结果结构与原始请求类型匹配(例如,tools/callCallToolResult)。

要检索已完成任务的结果,请求方可以发送 tasks/result 请求:

虽然 tasks/result 会阻塞,直到任务达到终端状态,但如果请求方没有主动等待结果(例如,如果他们之前的 tasks/result 请求失败或被取消),则可以继续通过 tasks/get 并行轮询。这允许请求方在任务执行期间监控状态变化或显示进度更新,即使在调用 tasks/result 之后也是如此。

请求:

{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "tasks/result",
  "params": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840"
  }
}

响应:

{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy"
      }
    ],
    "isError": false,
    "_meta": {
      "io.modelcontextprotocol/related-task": {
        "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840"
      }
    }
  }
}

任务状态通知

当任务状态发生变化时,接收方可以发送 notifications/tasks/status 通知以通知请求方更改。此通知包括完整的任务状态。

通知:

{
  "jsonrpc": "2.0",
  "method": "notifications/tasks/status",
  "params": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
    "status": "completed",
    "createdAt": "2025-11-25T10:30:00Z",
    "lastUpdatedAt": "2025-11-25T10:50:00Z",
    "ttl": 60000,
    "pollInterval": 5000
  }
}

通知包括完整的 Task 对象,包括更新的 statusstatusMessage(如果存在)。这允许请求方访问完整的任务状态,而无需进行额外的 tasks/get 请求。

请求方不得依赖接收此通知,因为它是可选的。接收方不需要发送状态通知,并且可能选择仅针对某些状态转换发送它们。请求方应该继续通过 tasks/get 轮询以确保它们接收状态更新。

列出 Tasks

要检索任务列表,请求方可以发送 tasks/list 请求。此操作支持分页。

请求:

{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "tasks/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}

响应:

{
  "jsonrpc": "2.0",
  "id": 5,
  "result": {
    "tasks": [
      {
        "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
        "status": "working",
        "createdAt": "2025-11-25T10:30:00Z",
        "lastUpdatedAt": "2025-11-25T10:40:00Z",
        "ttl": 30000,
        "pollInterval": 5000
      },
      {
        "taskId": "abc123-def456-ghi789",
        "status": "completed",
        "createdAt": "2025-11-25T09:15:00Z",
        "lastUpdatedAt": "2025-11-25T10:40:00Z",
        "ttl": 60000
      }
    ],
    "nextCursor": "next-page-cursor"
  }
}

取消 Tasks

要明确取消任务,请求方可以发送 tasks/cancel 请求。

请求:

{
  "jsonrpc": "2.0",
  "id": 6,
  "method": "tasks/cancel",
  "params": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840"
  }
}

响应:

{
  "jsonrpc": "2.0",
  "id": 6,
  "result": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
    "status": "cancelled",
    "statusMessage": "The task was cancelled by request.",
    "createdAt": "2025-11-25T10:30:00Z",
    "lastUpdatedAt": "2025-11-25T10:40:00Z",
    "ttl": 30000,
    "pollInterval": 5000
  }
}

行为要求

这些要求适用于所有支持接收任务增强请求的一方。

任务支持和处理

  1. 未为请求类型声明任务功能的接收方必须正常处理该类型的请求,忽略任何任务增强元数据(如果存在)。
  2. 为请求类型声明任务功能的接收方可以为非任务增强请求返回错误,要求请求方使用任务增强。

任务 ID 要求

  1. 任务 ID 必须是字符串值。
  2. 创建任务时,任务 ID 必须由接收方生成。
  3. 任务 ID 必须在接收方控制的所有任务中是唯一的。

任务状态生命周期

  1. 任务在创建时必须working 状态开始。
  2. 接收方必须仅通过以下有效路径转换任务:
    1. working:可以移动到 input_requiredcompletedfailedcancelled
    2. input_required:可以移动到 workingcompletedfailedcancelled
    3. 具有 completedfailedcancelled 状态的任务处于终端状态,并且不得转换到任何其他状态

任务状态状态图:

  stateDiagram-v2
    [*] --> working

    working --> input_required
    working --> terminal

    input_required --> working
    input_required --> terminal

    terminal --> [*]

    note right of terminal
        Terminal states:
        • completed
        • failed
        • cancelled
    end note

需要输入的状态

使用可流式 HTTP (SSE) 传输,服务器通常在传递响应消息后关闭 SSE 流,这可能导致用于后续任务消息的流存在歧义。

服务器可以通过将消息排队到客户端来处理此问题,以将任务相关的消息与其他响应一起进行边通道传输。

服务器在任务轮询和结果检索期间如何管理 SSE 流方面具有灵活性,客户端应该期望在任何 SSE 流(包括 HTTP GET 流)上传递消息。 一种可能的方法是在 tasks/result 上维护 SSE 流(请参阅有关 input_required 状态的说明)。 在可能的情况下,服务器不应该升级到 SSE 流以响应 tasks/get 请求,因为客户端已表示希望轮询结果。

虽然此说明不对 SSE 流的具体使用做出规定,但所有实施必须继续遵守现有的可流式 HTTP 传输规范

  1. 当任务接收方具有请求方完成任务所需的消息时,接收方应该将任务移动到 input_required 状态。
  2. 接收方必须在请求中包括 io.modelcontextprotocol/related-task 元数据以将其与任务关联。
  3. 当请求方遇到 input_required 状态时,它应该抢先调用 tasks/result
  4. 当接收方接收所有所需的输入时,任务应该转换出 input_required 状态(通常回到 working)。

TTL 和资源管理

  1. 接收方必须在所有任务响应中包括 createdAt ISO 8601 格式的时间戳,以指示任务的创建时间。
  2. 接收方必须在所有任务响应中包括 lastUpdatedAt ISO 8601 格式的时间戳,以指示任务的上次更新时间。
  3. 接收方可以覆盖请求的 ttl 持续时间。
  4. 接收方必须tasks/get 响应中包括实际的 ttl 持续时间(或 null 表示无限)。
  5. 在任务的 ttl 生存期过后,接收方可以删除任务及其结果,无论任务状态如何。
  6. 接收方可以tasks/get 响应中包括 pollInterval 值(以毫秒为单位)以建议轮询间隔。请求方应该在提供时遵守此值。

结果检索

  1. 接受任务增强请求的接收方必须返回 CreateTaskResult 作为响应。此响应应该在接受任务后尽快返回。
  2. 当接收方接收到处于终端状态(completedfailedcancelled)的任务的 tasks/result 请求时,它必须返回底层请求的最终结果,无论是成功的结果还是 JSON-RPC 错误。
  3. 当接收方接收到处于任何其他非终端状态(workinginput_required)的任务的 tasks/result 请求时,它必须阻塞响应,直到任务达到终端状态。
  4. 对于处于终端状态的任务,接收方必须tasks/result 返回底层请求将返回的任何内容,无论是成功的结果还是 JSON-RPC 错误。

关联任务相关消息

  1. 与任务相关的所有请求、通知和响应必须在其 _meta 字段中包括 io.modelcontextprotocol/related-task 键,其值设置为具有与关联任务 ID 匹配的 taskId 的对象。
    1. 例如,任务增强工具调用所依赖的引导必须与该工具调用的任务共享相同的相关任务 ID。
  2. 对于 tasks/gettasks/resulttasks/cancel 操作,请求中的 taskId 参数必须用作识别目标任务的真值来源。请求方不应该在这些请求中包括 io.modelcontextprotocol/related-task 元数据,如果存在此类元数据,接收方必须忽略它,而支持 RPC 方法参数。 同样,对于 tasks/gettasks/listtasks/cancel 操作,接收方不应该在结果消息中包括 io.modelcontextprotocol/related-task 元数据,因为 taskId 已经存在于响应结构中。

任务通知

  1. 当任务状态发生变化时,接收方可以发送 notifications/tasks/status 通知。
  2. 请求方不得依赖接收 notifications/tasks/status 通知,因为它是可选的。
  3. 发送时,notifications/tasks/status 通知不应该包括 io.modelcontextprotocol/related-task 元数据,因为任务 ID 已经存在于通知参数中。

任务进度通知

任务增强请求支持 progress 规范中定义的进度通知。初始请求中提供的 progressToken 在整个任务生存期内保持有效。

任务列表

  1. 接收方应该使用基于光标的分页来限制单个响应中返回的任务数量。
  2. 如果有更多任务可用,接收方必须在响应中包括 nextCursor
  3. 请求方必须将光标视为不透明令牌,不要尝试解析或修改它们。
  4. 如果请求方可以通过 tasks/get 检索任务,则该请求方必须可以通过 tasks/list 检索该任务。

任务取消

  1. 接收方必须使用错误代码 -32602(无效参数)拒绝已处于终端状态(completedfailedcancelled)的任务的取消请求。
  2. 收到有效的取消请求后,接收方应该尝试停止任务执行,并且必须在发送响应之前将任务转换到 cancelled 状态。
  3. 任务被取消后,即使执行继续完成或失败,它必须保持 cancelled 状态。
  4. tasks/cancel 操作不定义删除行为。但是,接收方可以随时自行决定删除已取消的任务,包括在取消后立即或任务 ttl 过期后。
  5. 请求方不应该依赖已取消的任务在任何特定持续时间内保留,并应在取消之前检索任何所需的信息。

消息流

基本任务生命周期

  sequenceDiagram
    participant C as 客户端 (请求方)
    participant S as 服务器 (接收方)
    Note over C,S: 1. 任务创建
    C->>S: 带任务字段的请求 (ttl)
    activate S
    S->>C: CreateTaskResult (taskId, status: working, ttl, pollInterval)
    deactivate S
    Note over C,S: 2. 任务轮询
    C->>S: tasks/get (taskId)
    activate S
    S->>C: working
    deactivate S
    Note over S: 任务处理继续...
    C->>S: tasks/get (taskId)
    activate S
    S->>C: working
    deactivate S
    Note over S: 任务完成
    C->>S: tasks/get (taskId)
    activate S
    S->>C: completed
    deactivate S
    Note over C,S: 3. 结果检索
    C->>S: tasks/result (taskId)
    activate S
    S->>C: 结果内容
    deactivate S
    Note over C,S: 4. 清理
    Note over S: 从创建开始的 ttl 周期后,任务被清理

任务增强的工具调用与引导

  sequenceDiagram
    participant U as 用户
    participant LLM
    participant C as 客户端 (请求方)
    participant S as 服务器 (接收方)

    Note over LLM,C: LLM 发起请求
    LLM->>C: 请求操作

    Note over C,S: 客户端使用任务增强
    C->>S: tools/call (ttl: 3600000)
    activate S
    S->>C: CreateTaskResult (task-123, status: working)
    deactivate S

    Note over LLM,C: 客户端继续处理其他请求<br/>而任务在后台执行
    LLM->>C: 请求其他操作
    C->>LLM: 其他操作结果

    Note over C,S: 客户端轮询状态
    C->>S: tasks/get (task-123)
    activate S
    S->>C: working
    deactivate S

    Note over S: 服务器需要来自客户端的信息<br/>任务移动到 input_required

    Note over C,S: 客户端轮询并发现 input_required
    C->>S: tasks/get (task-123)
    activate S
    S->>C: input_required
    deactivate S

    Note over C,S: 客户端打开结果流
    C->>S: tasks/result (task-123)
    activate S
    S->>C: elicitation/create (related-task: task-123)
    activate C
    C->>U: 提示用户输入
    U->>C: 提供信息
    C->>S: 引导响应 (related-task: task-123)
    deactivate C
    deactivate S

    Note over C,S: 客户端关闭结果流并恢复轮询

    Note over S: 任务继续处理...<br/>任务移回 working

    C->>S: tasks/get (task-123)
    activate S
    S->>C: working
    deactivate S

    Note over S: 任务完成

    Note over C,S: 客户端轮询并发现完成
    C->>S: tasks/get (task-123)
    activate S
    S->>C: completed
    deactivate S

    Note over C,S: 客户端检索最终结果
    C->>S: tasks/result (task-123)
    activate S
    S->>C: 结果内容
    deactivate S
    C->>LLM: 处理结果

    Note over S: 结果从创建开始保留 ttl 周期

任务增强的采样请求

  sequenceDiagram
    participant U as 用户
    participant LLM
    participant C as 客户端 (接收方)
    participant S as 服务器 (请求方)

    Note over S: 服务器决定发起请求

    Note over S,C: 服务器请求客户端操作 (任务增强)
    S->>C: sampling/createMessage (ttl: 3600000)
    activate C
    C->>S: CreateTaskResult (request-789, status: working)
    deactivate C

    Note over S: 服务器在等待结果时继续处理

    Note over S,C: 服务器轮询结果
    S->>C: tasks/get (request-789)
    activate C
    C->>S: working
    deactivate C

    Note over C,U: 客户端可以向用户展示请求
    C->>U: 查看请求
    U->>C: 批准请求

    Note over C,LLM: 客户端可以涉及 LLM
    C->>LLM: 请求完成
    LLM->>C: 返回完成

    Note over C,U: 客户端可以向用户展示结果
    C->>U: 查看结果
    U->>C: 批准结果

    Note over S,C: 服务器轮询并发现完成
    S->>C: tasks/get (request-789)
    activate C
    C->>S: completed
    deactivate C

    Note over S,C: 服务器检索结果
    S->>C: tasks/result (request-789)
    activate C
    C->>S: 结果内容
    deactivate C

    Note over S: 服务器继续处理

    Note over C: 结果从创建开始保留 ttl 周期

任务取消流程

  sequenceDiagram
    participant C as 客户端 (请求方)
    participant S as 服务器 (接收方)

    Note over C,S: 1. 任务创建
    C->>S: tools/call (请求 ID: 42, ttl: 60000)
    activate S
    S->>C: CreateTaskResult (task-123, status: working)
    deactivate S

    Note over C,S: 2. 任务处理
    C->>S: tasks/get (task-123)
    activate S
    S->>C: working
    deactivate S

    Note over C,S: 3. 客户端取消
    Note over C: 用户请求取消
    C->>S: tasks/cancel (taskId: task-123)
    activate S

    Note over S: 服务器停止执行 (尽力而为)
    Note over S: 任务移动到 cancelled 状态

    S->>C: 任务 (status: cancelled)
    deactivate S

    Note over C: 客户端接收确认

    Note over S: 服务器可以自行决定删除任务

数据类型

Task

任务表示请求的执行状态。任务状态包括:

  • taskId:任务的唯一标识符
  • status:任务执行的当前状态
  • statusMessage:描述当前状态的可选人类可读消息(可以存在于任何状态,包括失败任务的错误详细信息)
  • createdAt:任务创建时的 ISO 8601 时间戳
  • ttl:从创建开始到任务可能被删除的时间(以毫秒为单位)
  • pollInterval:状态检查之间的建议时间(以毫秒为单位)
  • lastUpdatedAt:任务状态上次更新时的 ISO 8601 时间戳

任务状态

任务可以处于以下状态之一:

  • working:请求正在处理中。
  • input_required:接收方需要来自请求方的输入。请求方应该调用 tasks/result 来接收输入请求,即使任务尚未达到终端状态。
  • completed:请求成功完成并且结果可用。
  • failed:关联的请求未成功完成。对于工具调用,这包括工具结果将 isError 设置为 true 的情况。
  • cancelled:请求在完成前被取消。

任务参数

使用任务执行增强请求时,task 字段包括在请求参数中:

{
  "task": {
    "ttl": 60000
  }
}

字段:

  • ttl(数字,可选):从创建开始保留任务的请求持续时间(以毫秒为单位)

相关任务元数据

与任务关联的所有请求、响应和通知必须_meta 中包括 io.modelcontextprotocol/related-task 键:

{
  "io.modelcontextprotocol/related-task": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840"
  }
}

这将消息与其发起的任务在整个请求生命周期中关联起来。

对于 tasks/gettasks/listtasks/cancel 操作,请求方和接收方不应该在其消息中包括此元数据,因为 taskId 已经存在于消息结构中。 tasks/result 操作必须在其响应中包括此元数据,因为结果结构本身不包含任务 ID。

错误处理

Tasks 使用两种错误报告机制:

  1. 协议错误:用于协议级别问题的标准 JSON-RPC 错误
  2. 任务执行错误:底层请求执行中的错误,通过任务状态报告

协议错误

接收方必须为以下协议错误情况返回标准 JSON-RPC 错误:

  • tasks/gettasks/resulttasks/cancel 中的无效或不存在的 taskId-32602(无效参数)
  • tasks/list 中的无效或不存在的光标:-32602(无效参数)
  • 尝试取消已处于终端状态的任务:-32602(无效参数)
  • 内部错误:-32603(内部错误)

此外,接收方可以返回以下错误:

  • 当接收方要求该请求类型的任务增强时的非任务增强请求:-32600(无效请求)

接收方应该提供信息性错误消息来描述错误原因。

示例:需要任务增强

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32600,
    "message": "Task augmentation required for tools/call requests"
  }
}

示例:未找到任务

{
  "jsonrpc": "2.0",
  "id": 70,
  "error": {
    "code": -32602,
    "message": "Failed to retrieve task: Task not found"
  }
}

示例:任务已过期

{
  "jsonrpc": "2.0",
  "id": 71,
  "error": {
    "code": -32602,
    "message": "Failed to retrieve task: Task has expired"
  }
}
接收方不需要无限期保留任务。如果接收方已清除过期任务,则返回错误说明无法找到任务是合规行为。

示例:任务取消被拒绝(已终端)

{
  "jsonrpc": "2.0",
  "id": 74,
  "error": {
    "code": -32602,
    "message": "Cannot cancel task: already in terminal status 'completed'"
  }
}

任务执行错误

当底层请求未成功完成时,任务移动到 failed 状态。这包括请求执行期间的 JSON-RPC 协议错误,或者对于工具调用,当工具结果将 isError 设置为 true 时。tasks/get 响应应该包括包含有关失败的诊断信息的 statusMessage 字段。

示例:具有执行错误的任务

{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f820fe840",
    "status": "failed",
    "createdAt": "2025-11-25T10:30:00Z",
    "lastUpdatedAt": "2025-11-25T10:40:00Z",
    "ttl": 30000,
    "statusMessage": "Tool execution failed: API rate limit exceeded"
  }
}

对于包装工具调用请求的任务,当工具结果将 isError 设置为 true 时,任务应该达到 failed 状态。

tasks/result 端点完全返回底层请求将返回的内容:

  • 如果底层请求导致 JSON-RPC 错误,tasks/result 必须返回相同的 JSON-RPC 错误。
  • 如果请求使用 JSON-RPC 响应完成,tasks/result 必须返回包含该结果的成功 JSON-RPC 响应。

安全考虑

任务隔离和访问控制

任务 ID 是访问任务状态和结果的主要机制。如果没有适当的访问控制,任何可以猜测或获取任务 ID 的一方都可能访问敏感信息或操纵他们没有创建的任务。

当提供授权上下文时,接收方必须将任务绑定到所述上下文。

上下文绑定并非对所有应用程序都实用。某些 MCP 服务器在没有授权的环境中运行,例如单用户工具,或使用不支持授权的传输。 在这些情况下,接收方应该清楚地记录此限制,因为任务结果可能可被任何可以猜测任务 ID 的请求方访问。 如果上下文绑定不可用,接收方必须生成具有足够熵的加密安全任务 ID 以防止猜测,并应考虑使用较短的 TTL 持续时间以减少暴露窗口。

如果上下文绑定可用,接收方必须拒绝不属于与请求方相同授权上下文的任务的 tasks/gettasks/resulttasks/cancel 请求。对于 tasks/list 请求,接收方必须确保返回的任务列表仅包括与请求方的授权上下文关联的任务。

此外,接收方应该对任务操作实施速率限制以防止拒绝服务和枚举攻击。

资源管理

  1. 接收方应该
    1. 强制执行每个请求方的并发任务限制
    2. 强制执行最大 ttl 持续时间以防止无限期资源保留
    3. 及时清理过期任务以释放资源
    4. 记录支持的最大 ttl 持续时间
    5. 记录每个请求方的最大并发任务数
    6. 实施资源使用的监控和警报

审计和日志记录

  1. 接收方应该
    1. 记录任务创建、完成和检索事件以进行审计
    2. 在可用时在日志中包括授权上下文
    3. 监控可疑模式(例如,许多失败的任务查找、过度轮询)
  2. 请求方应该
    1. 记录任务生命周期事件以进行调试和审计
    2. 跟踪任务 ID 及其关联的操作