-
Notifications
You must be signed in to change notification settings - Fork 0
add diagrams, schemas, http headers, and specify Gettask Behavior. #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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`. | | ||
LucaButBoring marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| | 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; | ||
|
Comment on lines
+133
to
+141
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These get inlined into
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does that make sense though? For example CreateTaskResult is now interface CreateTaskResult extends Result
{
task: Task
} So with having these in-lined with task you could return an error or result which doesn't really make sense.
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, after further discussion, I think we should use a separate type instead of |
||
| } | ||
| ``` | ||
|
|
||
| ### `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 | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: might want to specify the result types (that is, to clarify |
||
| ```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: | ||
|
|
||
| <details> | ||
|
|
||
|
|
@@ -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 | ||
| } | ||
| }, | ||
| } | ||
| ``` | ||
|
|
||
| </details> | ||
|
|
||
| ### 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. | ||
| <details> | ||
| ``` 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 | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
| </details> | ||
|
|
||
| #### 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. | ||
| <details> | ||
| ```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 | ||
LucaButBoring marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
| ``` | ||
| </details> | ||
|
|
||
| #### 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. | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At least right now this would be a JSONRPCError, though the question stands of how we want to handle failed tool calls |
||
|
|
||
| #### Canceled | ||
| When a task is in the `canceled` state, a call to `tasks/get` MUST return the `Task` with status `canceled`. | ||
| <details> | ||
| ```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 | ||
| }, | ||
| } | ||
| } | ||
| ``` | ||
| </details> | ||
|
|
||
| #### `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). | ||
| <details> | ||
| ```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"] | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
| </details> | ||
|
|
||
| ### 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` | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we also mention |
||
| - `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. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.