From cb3f52c3781fe352bd21335a020a814c1023c7cb Mon Sep 17 00:00:00 2001 From: Caitie McCaffrey Date: Mon, 13 Apr 2026 15:55:46 -0700 Subject: [PATCH] add diagrams, schemas, http headers, and specify Gettask Behavior. --- seps/2557-tasks-stabilization.md | 253 ++++++++++++++++++++++++++++++- 1 file changed, 245 insertions(+), 8 deletions(-) diff --git a/seps/2557-tasks-stabilization.md b/seps/2557-tasks-stabilization.md index 65d4435a8..d041b712b 100644 --- a/seps/2557-tasks-stabilization.md +++ b/seps/2557-tasks-stabilization.md @@ -3,13 +3,18 @@ - **Status**: Draft - **Type**: Standards Track - **Created**: 2026-04-12 -- **Author(s)**: Luca Chang (@LucaButBoring) +- **Author(s)**: Luca Chang (@LucaButBoring), Caitie McCaffrey (@CaitieM20) - **Sponsor**: Caitie McCaffrey (@CaitieM20) - **PR**: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2557 ## Abstract -This proposal builds on [tasks](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks) by introducing several simplifications to the original functionality to prepare the feature for stabilization, following implementation and usage feedback since the initial experimental release. In particular, this proposal allows tasks to be returned in response to non-task requests to remove unneeded stateful handshakes, and it collapses `tasks/result` into `tasks/get`, removing the error-prone interaction between the `input_required` task status and the `tasks/result` method. Additionally, following the acceptance of [SEP-2260: Require Server requests to be associated with a Client request](./2260-Require-Server-requests-to-be-associated-with-Client-requests.md), we are removing client-hosted elicitation/sampling tasks, as they further complicate the transport-related interactions that SEP-2260 intends to simplify. +This proposal builds on [tasks](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks) by introducing several simplifications to the original functionality to prepare the feature for stabilization, following implementation and usage feedback since the initial experimental release. In particular, this proposal allows tasks to be returned in response to non-task requests to remove unneeded stateful handshakes, and it collapses `tasks/result` into `tasks/get`, removing the error-prone interaction between the `input_required` task status and the `tasks/result` method. + +This SEP also incorporates changes into `Tasks` necessary following the acceptance of: +- [SEP-2260: Require Server requests to be associated with a Client request](./2260-Require-Server-requests-to-be-associated-with-Client-requests.md) +- [SEP-2322: Multi Round-Trip Requests](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322) +- [SEP-2243: Http Standardization](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2243) ## Motivation @@ -49,12 +54,11 @@ To both improve the adoption of tasks and to reduce their upfront messaging over ## Specification The following changes will be made to the tasks specification: - -1. With respect to task creation: +<1. With respect to task creation:> 1. We will deprecate the following capability declarations: 1. Client capabilities: - 1. `tasks` (the entire capability, given that all supported client methods are now invalid, per [SEP-2260](./2260-Require-Server-requests-to-be-associated-with-Client-requests.md)) - 1. Server capabilities: + 1. `tasks` (the entire capability, and all sub-capabilities, given that all supported client methods are now invalid, per [SEP-2260](./2260-Require-Server-requests-to-be-associated-with-Client-requests.md)) + . Server capabilities: 1. `tasks.cancel` (only the capability declaration is deprecated; _not_ the `tasks/cancel` method itself) 1. `tasks.requests.tools.call` 1. We will deprecate the `execution.taskSupport` field from the `Tool` shape. @@ -72,7 +76,101 @@ The following changes will be made to the tasks specification: 1. We may expand task support to additional client-to-server request types in the future, and implementors are still advised against implementing tasks as a tool-specific protocol operation. 1. We will require `tasks/cancel` to be supported even if a server is incapabable or unwillling of offering actual task cancellation, similar to `notifications/cancelled` (it should instead return an error). -Below (collapsed) is an example of a tool call with an unsolicited task-augmentation, with an elicitation during the request: +### Task Capabilities Changes Summary +The below table summarizes the changes to the task-related capabiliteis: +| Role | Capability | Status | Description | +| --- | --- | --- | --- | +|Server | Tasks.Reqeusts.Tools.Call | removed | +|Server | Task.Cancel | removed | | +|Server | Tasks.List | still supported | | +|Client | Tasks.Requests.Sampling.CreateMessage | removed | no longer supported SEP-2260 | +|Client | Tasks.Requests.Elicitation.Create | removed | no longer supported SEP-2260 | +| Client| Tasks.Cancel | removed | no longer needed | +| Client| Tasks.List | removed | no longer needed | + +### Task Methods Changes Summary +The below table summarizes the changes to the task-related methods: +| Method | Status | Description | +| --- | --- | --- | +| tasks/get | still supported | Consolidates the entire polling lifecycle into a single method. | +| tasks/result | removed | No longer needed; results are inlined into `tasks/get`. | +| tasks/input_resposne | removed | No longer needed; results are inlined into `tasks/get`. | +| tasks/cancel | still supported | Required to be supported even if actual cancellation is not possible. | +| tasks/list | still supported | Some open questions on how this should be implemented without sessions. | + +### Task Schema Changes +The `Task` schema defining the task metadata remains unchanged. + +### Client Reqeuests for `task/get` +```typescript +interface GetTaskRequest extends JSONRPCRequest { + method "tasks/get"; + params: { + /** + * The task identifier to query. + */ + taskId: string; + /** + * Optional field to allow the client to respond to a server's request for more information + * when the task is in `input_required` state. + */ + inputResponses?: InputResponses; + }; +} +``` +### Server Response for `task/get` +```typescript +interface GetTaskResult extends Result +{ + /** + * Required field containing the Task Metadata Object. + */ + task: Task; + /** + * Optional field containing the InputRequests that specify the additional information needed from the client. Present only when task status is `input_required`. + */ + inputRequests?: InputRequests; + /** + * Optional field containing the Result of a Task. Present only when task status is `completed`. + */ + result?: JSONObject; + + /** + * Optional field containing the error that caused the task to fail. Present only when task status is `failed`. + */ + error?: JSONObject; +} +``` + +### `ResultType` +The ResultType field was introduced in [SEP-2322: Multi Round-Trip Requests](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322) to handle polymorphic results. `Tasks` has the same issue where a server may return a `ToolCallResult` or a `Task`. To address this, we propose the addition of the `task` ResultType to indicate that a Response contains a `Task` object. + +```typescript +type ResultType = "complete" | "incomplete" | "task" +``` + +For backwards compatibility ResultType is inferred to be `complete`. Therefore all calls which return a `Task` (i.e.`task/get`, `task/cancel`) calls must set `task` as the ResultType moving forward. + +### Example Task Flow +```mermaid +sequenceDiagram + participant U as User + participant C as Client + participant S as Server + C->>S: tools/call (id: 1) + S-->>C: Result (id: 1, taskId: 123, status: working) + C->>S: tasks/get (taskId: 123) + S-->>C: Result (taskId: 123, status: input_required, inputRequests: {...}) + C->>U: Prompt User for Input + U-->>C: Provided Input + C->>S: tasks/get (taskId: 123, inputResponses: {...}) + S-->>C: Result (taskId: 123, status: working) + C-->>S: tasks/get (taskId: 123) + S-->>C: Result (taskId: 123, status: completed, result: {...}) + + +``` +Below (collapsed) is the full json example of a tool call with an unsolicited task-augmentation that matches the diagram above:
@@ -98,6 +196,7 @@ The server determines (via bespoke logic) that it wants to create a task to repr { "jsonrpc": "2.0", "id": 2, + "result_type": "task", "result": { "task": { "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", @@ -130,6 +229,7 @@ On each request while the task is in a `"working"` status, the server returns a { "jsonrpc": "2.0", "id": 3, + "result_type": "task", "result": { "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", "status": "working", @@ -158,6 +258,7 @@ Eventually, the server reaches the point at which it needs to send an elicitatio { "id": 4, "jsonrpc": "2.0", + "result_type": "task", "result": { "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", "status": "input_required", @@ -202,6 +303,7 @@ For thoroughness, let's consider a case where the client happens to poll `tasks/ { "id": 5, "jsonrpc": "2.0", + "result_type": "task", "result": { "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", "status": "input_required", @@ -284,6 +386,7 @@ Eventually, the server completes the request, so it stores the final `CallToolRe { "jsonrpc": "2.0", "id": 7, + "result_type": "task", "result": { "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", "status": "completed", @@ -300,12 +403,146 @@ Eventually, the server completes the request, so it stores the final `CallToolRe ], "isError": false } + }, +} +``` + +
+ +### Tasks/Get Behavior by Task State +A `Task` can be in one of the following states: `working`, `completed`, `failed`, `canceled`, or `input_required`. This section defines the expected behavior of a call to `tasks/get` when in each state. + +All responses to `task/get` MUST include the `task` object. + +#### Working +The response MUST include the `task` object with `working` status. +
+``` json +{ + "jsonrpc": "2.0", + "id": 1, + "result_type": "task", + "result": { + "task": { + "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", + "status": "working", + "statusMessage": "The operation is in progress.", + "createdAt": "2025-11-25T10:30:00Z", + "lastUpdatedAt": "2025-11-25T10:40:00Z", + "ttl": 60000, + "pollInterval": 5000 + } } } ``` +
+#### Completed +When a task is in the `completed` state, a call to `tasks/get` MUST return the `Task` with status `completed` and include the final result of the task. +
+```json +{ +"jsonrpc": "2.0", + "id": 1, + "result_type": "task", + "result": { + "task": { + "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", + "status": "completed", + "statusMessage": "The operation has completed successfully.", + "createdAt": "2025-11-25T10:30:00Z", + "lastUpdatedAt": "2025-11-25T10:40:00Z", + "ttl": 60000, + "pollInterval": 5000 + }, + "content": [ + { + "type": "text", + "text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy" + } + ], + "isError": false + } +} +```
+#### Failed +When a task is in the `failed` state, a call to `tasks/get` should return an error in the `result` field indicating the reason for the failure. + +TBD On what this looks like. + +#### Canceled +When a task is in the `canceled` state, a call to `tasks/get` MUST return the `Task` with status `canceled`. +
+```json +{ +"jsonrpc": "2.0", + "id": 1, + "result_type": "task", + + "result": { + "task": { + "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", + "status": "cancelled", + "statusMessage": "The operation has been cancelled.", + "createdAt": "2025-11-25T10:30:00Z", + "lastUpdatedAt": "2025-11-25T10:40:00Z", + "ttl": 60000, + "pollInterval": 5000 + }, + } +} +``` +
+ +#### `input_required` +If Server Task Status is `input_required` this indicates that the `Task` requires additional input from the client before it can proceed. The server MUST return the `Task` with status set to `input_required` and a `IncompleteResult` from [SEP-2322: Multi Round-Trip Requests](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322). +
+```json +{ +"jsonrpc": "2.0", + "id": 1, + "result": { + "task": { + "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", + "status": "input_required", + "statusMessage": "The operation requires additional input.", + "createdAt": "2025-11-25T10:30:00Z", + "lastUpdatedAt": "2025-11-25T10:40:00Z", + "ttl": 60000, + "pollInterval": 5000 + }, + "inputRequests": { + "github_login": { + "method": "elicitation/create", + "params": { + "mode": "form", + "message": "Please provide your GitHub username", + "requestedSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": ["name"] + } + } + } + } + } +} +``` +
+ +### HTTP Streamable Transport Headers +[SEP-2243](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2243) introduces standard headers in the Streamable HTTP Transport to facilitate more efficient routing. Routing on `TaskId`is also desirable since there is often state associated with a specific Task that needs to be consistently routed to the same server instance. + +For Tasks the following Headers MUST be set by the client when making requests over the Streamable HTTP Transport: +- `Mcp-Method`: `tasks/get`, `tasks/cancel` +- `Mcp-Name`: should contain the `taskId` of the Task being requested or cancelled. + ## Rationale ### Removing `tasks/result` @@ -346,7 +583,7 @@ The removal of `tasks/result` is not backwards-compatible. At a protocol level, The following adjustments related to unsolicited tasks are breaking changes: -1. We will allow `CreateTaskResult` to be returned in response to `CallToolRequest` when no `task` field is present in the request. +1. We will allow `CreateTaskResult` to be returned in response to `CallToolRequest` when no `task` field is present in the client request. 1. We will allow `CallToolResult` to be returned in response to `CallToolRequest` even when the `task` field is present in the request. At a protocol level, this should be handled according to the protocol version. Under the `2025-11-25` protocol version, these cases **SHOULD** be handled as malformed responses, but under subsequent protocol versions, they **MUST** be treated as valid per the updated specification language.