-
Notifications
You must be signed in to change notification settings - Fork 1.6k
SEP-2663: Tasks Extension #2663
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
Merged
CaitieM20
merged 58 commits into
modelcontextprotocol:main
from
LucaButBoring:feat/ext-tasks
May 15, 2026
Merged
Changes from all commits
Commits
Show all changes
58 commits
Select commit
Hold shift + click to select a range
7715860
SEP-2663: Tasks Extension
LucaButBoring edb77c8
SEP-2663: Flatten CreateTaskResult
LucaButBoring 5b125bd
SEP-2663: Put under Agents WG for now
LucaButBoring 87a3f98
SEP-2663: Add requestState security guidance
LucaButBoring e224fc0
SEP-2663: Rephrase distinction between protocol-level errors and othe…
LucaButBoring 23d2392
SEP-2663: Reformat document
LucaButBoring d3ad509
SEP-2663: Append units to duration fields
LucaButBoring 4f85991
SEP-2663: Add requestState to GetTaskRequest
LucaButBoring ef21c6a
SEP-2663: Remove reference to initialization
LucaButBoring 4526a80
SEP-2663: Reformat document
LucaButBoring ed4c83e
SEP-2663: Add task status notification requirements
LucaButBoring 0c1771a
SEP-2663: Address task resumption and expiry
LucaButBoring c54e5ee
SEP-2663: State removal of old tasks and extension rationale
LucaButBoring 3f3ed02
SEP-2663: Clarify requestState consistency limitations
LucaButBoring cbb156c
SEP-2663: Clarify protocol versioning in backwards-compatibility section
LucaButBoring 451f5e1
SEP-2663: Allow IncompleteResult before task creation
LucaButBoring ee55336
SEP-2663: Fix units in task status notifications
LucaButBoring ffca36a
SEP-2663: Clarify MRTR+Task server behavior
LucaButBoring d963ad0
SEP-2663: Allow errors on update and cancel methods
LucaButBoring 6d954fe
Merge branch 'main' into feat/ext-tasks
LucaButBoring 2643deb
SEP-2663: Fix typos and formatting issues
LucaButBoring a1ed070
SEP-2663: Do not poll until cancelled
LucaButBoring c58c652
SEP-2663: Clarify state retention after task cancellation
LucaButBoring ebe238a
SEP-2663: Allow ttlSeconds to change during a task
LucaButBoring c4ff02d
SEP-2663: Send task status notifications on subscriptions/listen
LucaButBoring cfd09d3
SEP-2663: Do not require polling+streaming
LucaButBoring 6275891
SEP-2663: Use Ms suffix consistently on durations
LucaButBoring a05d7f9
Merge branch 'main' into feat/ext-tasks
LucaButBoring 82fb2c4
SEP-2663: Remove tasks from core spec; adjust MRTR
LucaButBoring 3b383d1
SEP-2663: Rename incomplete to input_required
LucaButBoring f53121c
SEP-2663: Add mcpkit as reference implementation
LucaButBoring e768085
Merge branch 'main' of https://github.com/modelcontextprotocol/modelc…
LucaButBoring 3e6eaf4
Update seps/2663-tasks-extension.md
LucaButBoring 16d03e6
SEP-2663: Remove mentions of tasks from MRTR
LucaButBoring 5324be3
SEP-2663: Format document
LucaButBoring 3f33c7d
SEP-2663: Specify cancellation notifications don't cancel tasks
LucaButBoring 3f1c3cf
SEP-2663: Remove requestState
LucaButBoring 304aa7b
SEP-2663: Remove task schema categories
LucaButBoring f6112cf
SEP-2663: Add overview docs for Tasks Extension
LucaButBoring a9ea0a4
Merge branch 'main' into feat/ext-tasks
LucaButBoring 6e4fd57
SEP-2663: Specify error for servers that require tasks
LucaButBoring 46394d2
SEP-2663: Remove redundant 'On success' from cancellation ack
LucaButBoring 7828857
SEP-2663: Trim partial-response sentence in tasks/update
LucaButBoring c248297
SEP-2663: Rename section to 'Task Update Requests'
LucaButBoring 782d37a
SEP-2663: Link to MRTR spec for inputRequests
LucaButBoring 527e5c5
SEP-2663: Add auth check requirement to security implications
LucaButBoring 1d3813a
SEP-2663: Rename notifications/tasks/status to notifications/tasks
LucaButBoring 25d1c9d
SEP-2663: Move detailed task types into task status section
LucaButBoring b15331e
SEP-2663: Add explicit polling response requirements
LucaButBoring 2dba297
SEP-2663: Disallow progress/logging notifications on tasks
LucaButBoring 1152e58
SEP-2663: Add spec language for client behavior on inputRequests
LucaButBoring 7a66448
SEP-2663: Use relative MRTR link instead of absolute URL
LucaButBoring f2aca22
SEP-2663: Reformat document
LucaButBoring 470072b
SEP-2663: Accepted
LucaButBoring 5b2c24d
Update seps/2663-tasks-extension.md
LucaButBoring 91d72e9
SEP-2663: Remove task examples and reformat
LucaButBoring 38ece65
SEP-2663: Add changelog entry
LucaButBoring c47bd84
Merge branch 'main' into feat/ext-tasks
LucaButBoring File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,267 @@ | ||
| --- | ||
| title: MCP Tasks | ||
| description: Asynchronous task execution for long-running MCP operations | ||
| --- | ||
|
|
||
| The [experimental-ext-tasks repository](https://github.com/modelcontextprotocol/experimental-ext-tasks) contains the full specification and documentation for MCP Tasks. | ||
|
|
||
| <Card | ||
| title="modelcontextprotocol/experimental-ext-tasks" | ||
| icon="github" | ||
| href="https://github.com/modelcontextprotocol/experimental-ext-tasks" | ||
| > | ||
| Full specification and documentation for MCP Tasks. | ||
| </Card> | ||
|
|
||
| Not every tool call returns instantly. Some operations — CI pipelines, batch | ||
| processing, human approvals — take seconds, minutes, or longer. MCP Tasks let | ||
| servers return a durable handle instead of blocking, so clients can poll for | ||
| progress, provide input when needed, and retrieve the final result after | ||
| reconnecting. | ||
|
|
||
| ## Why not just block? | ||
|
|
||
| You could hold the connection open until the work finishes. Tasks solve | ||
| problems that blocking cannot: | ||
|
|
||
| - **No long-lived connections.** Blocking ties up a connection for the duration | ||
| of the operation. Many clients and transport intermediaries impose timeouts | ||
| that make this impractical beyond a few seconds. | ||
| - **Crash resilience.** A task ID is a durable handle. If the client | ||
| disconnects or restarts, it can resume polling with the same ID. | ||
| - **Progress visibility.** Tasks carry status metadata (`working`, | ||
| `input_required`, `completed`, `failed`, `cancelled`) and optional status | ||
| messages, giving clients visibility into progress. | ||
| - **Mid-flight interaction.** When a task needs input (e.g., an elicitation for | ||
| user confirmation), it moves to `input_required` and surfaces the request. | ||
| The client responds via `tasks/update` — no second connection or unsolicited | ||
| server-to-client messages required. | ||
| - **Server-directed.** The server decides per-request whether to create a task. | ||
| Clients opt in once via the extension capability and handle whichever result | ||
| shape arrives. No per-tool warmup or per-request flag. | ||
|
|
||
| ## How Tasks work | ||
|
|
||
| Tasks extend the standard request flow. When a server decides a request will be | ||
| long-running, it returns a task handle instead of the final result. The client | ||
| polls for completion. | ||
|
|
||
| 1. **Capability negotiation.** The client includes | ||
| `io.modelcontextprotocol/tasks` in its per-request capabilities. The server | ||
| advertises the same extension in its own `server/discover` capabilities. | ||
|
|
||
| 2. **Task creation.** In response to a supported request, the server returns a | ||
| `CreateTaskResult` (identified by `resultType: "task"`) containing a `taskId`, | ||
| initial status, TTL, and suggested polling interval. The task is durably | ||
| created before the response is sent. | ||
|
|
||
| 3. **Polling.** The client calls `tasks/get` with the `taskId`. The response | ||
| carries the current status and, for terminal states, the final result or | ||
| error. | ||
|
|
||
| 4. **Mid-flight input.** If the task moves to `input_required`, the `tasks/get` | ||
| response includes an `inputRequests` map with elicitations or other server | ||
| requests. The client fulfills these via `tasks/update`. | ||
|
|
||
| 5. **Completion.** When the status reaches `completed`, the `result` field | ||
| contains what the original request would have returned synchronously. If the | ||
| status is `failed`, the `error` field contains the JSON-RPC error. | ||
|
|
||
| 6. **Cancellation.** The client can send `tasks/cancel` at any time. | ||
| Cancellation is cooperative — the server acknowledges the intent but is not | ||
| obligated to stop the work. | ||
|
|
||
| ```mermaid | ||
| sequenceDiagram | ||
| participant Client | ||
| participant Server | ||
|
|
||
| Client->>Server: tools/call (with tasks capability) | ||
| Server-->>Client: CreateTaskResult (taskId, status: working) | ||
|
|
||
| loop Poll until terminal | ||
| Client->>Server: tasks/get (taskId) | ||
| Server-->>Client: Task (status: working) | ||
| end | ||
|
|
||
| Note over Client,Server: Server needs user input | ||
| Client->>Server: tasks/get (taskId) | ||
| Server-->>Client: Task (status: input_required, inputRequests) | ||
| Client->>Server: tasks/update (taskId, inputResponses) | ||
| Server-->>Client: ack | ||
|
|
||
| loop Poll until terminal | ||
| Client->>Server: tasks/get (taskId) | ||
| Server-->>Client: Task (status: working) | ||
| end | ||
|
|
||
| Client->>Server: tasks/get (taskId) | ||
| Server-->>Client: Task (status: completed, result) | ||
| ``` | ||
|
|
||
| ## When to use Tasks | ||
|
|
||
| Tasks are a good fit when your use case involves: | ||
|
|
||
| **Long-running operations.** CI pipelines, batch data processing, or model | ||
| training jobs that take minutes or hours. | ||
|
|
||
| **Human-in-the-loop workflows.** Approval gates, review steps, or any operation | ||
| that pauses for user confirmation. The task moves to `input_required` and the | ||
| client presents the request. | ||
|
|
||
| **External job systems.** If your server wraps an API that already uses job IDs | ||
| (cloud deployments, async APIs, queued work), return a task when you create the | ||
| job and resolve it when the job completes. | ||
|
|
||
| **Unreliable connections.** Mobile clients, intermittent networks, or | ||
| environments where connections drop. Task IDs survive disconnects. | ||
|
|
||
| **Batch processing.** Operations that process many items (bulk imports, mass | ||
| updates) where partial progress is meaningful. Status messages report progress. | ||
|
|
||
| ## Task lifecycle | ||
|
|
||
| | Status | Meaning | | ||
| | ---------------- | -------------------------------------------------------------------------- | | ||
| | `working` | The operation is in progress. | | ||
| | `input_required` | The server needs client input before continuing. See `inputRequests`. | | ||
| | `completed` | The operation finished. The `result` field contains the final output. | | ||
| | `failed` | A JSON-RPC error occurred during execution. The `error` field has details. | | ||
| | `cancelled` | The operation was cancelled (not always honored). | | ||
|
|
||
| `completed`, `failed`, and `cancelled` are terminal — once reached, the task's | ||
| state does not change. | ||
|
|
||
| ## Notifications | ||
|
|
||
| Servers can push status updates via `notifications/tasks/status`. Clients opt | ||
| into these through the `subscriptions/listen` mechanism. Each notification | ||
| carries the full task state, eliminating the need for an extra `tasks/get` | ||
| round-trip. | ||
|
|
||
| Polling is the default. If a server supports notifications, clients can rely on | ||
| them instead of polling. | ||
|
|
||
| ## Implementation guide | ||
|
|
||
| ### For MCP clients | ||
|
|
||
| To consume task-augmented responses, your client must: | ||
|
|
||
| <Steps> | ||
| <Step title="Declare support"> | ||
|
|
||
| Include the extension in per-request capabilities: | ||
|
|
||
| ```json | ||
| { | ||
| "params": { | ||
| "_meta": { | ||
| "io.modelcontextprotocol/clientCapabilities": { | ||
| "extensions": { | ||
| "io.modelcontextprotocol/tasks": {} | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| </Step> | ||
| <Step title="Handle polymorphic results"> | ||
|
|
||
| When issuing a supported request (e.g., `tools/call`), be prepared to receive | ||
| either the standard result or a `CreateTaskResult` with `resultType: "task"`. | ||
|
|
||
| </Step> | ||
| <Step title="Poll for completion"> | ||
|
|
||
| Call `tasks/get` with the returned `taskId`, respecting the `pollIntervalMs` | ||
| value. Continue polling until the task reaches a terminal status (`completed`, | ||
| `failed`, or `cancelled`). | ||
|
|
||
| </Step> | ||
| <Step title="Handle input requests"> | ||
|
|
||
| If the task status is `input_required`, read the `inputRequests` map, present | ||
| the requests to the user or model, and submit responses via `tasks/update`. | ||
|
|
||
| </Step> | ||
| <Step title="Persist task IDs"> | ||
|
|
||
| Store task IDs durably so polling can resume after a client crash or restart. | ||
|
|
||
| </Step> | ||
| </Steps> | ||
|
|
||
| ### For MCP servers | ||
|
|
||
| To return tasks from your server: | ||
|
|
||
| <Steps> | ||
| <Step title="Advertise support"> | ||
|
|
||
| Include the extension in your `server/discover` capabilities: | ||
|
|
||
| ```json | ||
| { | ||
| "capabilities": { | ||
| "extensions": { | ||
| "io.modelcontextprotocol/tasks": {} | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| </Step> | ||
| <Step title="Check client capabilities"> | ||
|
|
||
| Before returning a `CreateTaskResult`, verify that the client included the | ||
| extension in its per-request capabilities. Never return a task to a client that | ||
| did not declare support. | ||
|
|
||
| </Step> | ||
| <Step title="Return CreateTaskResult"> | ||
|
|
||
| When a request will be long-running, respond with `resultType: "task"` and a | ||
| `Task` object containing a unique `taskId`, initial status, `ttlMs`, and | ||
| `pollIntervalMs`. The task must be durably created before sending the response. | ||
|
|
||
| </Step> | ||
| <Step title="Serve tasks/get"> | ||
|
|
||
| Return the current task state on each poll. For terminal states, include the | ||
| `result` (on `completed`) or `error` (on `failed`) field. | ||
|
|
||
| </Step> | ||
| <Step title="Handle tasks/update"> | ||
|
|
||
| Accept `inputResponses` keyed to outstanding `inputRequests`. Acknowledge with | ||
| an empty result. Ignore responses for unknown or already-satisfied keys. | ||
|
|
||
| </Step> | ||
| <Step title="Handle tasks/cancel"> | ||
|
|
||
| Acknowledge cancellation requests with an empty result. Honor them when | ||
| possible, but cancellation is cooperative — the task may still reach a | ||
| non-`cancelled` terminal status. | ||
|
|
||
| </Step> | ||
| </Steps> | ||
|
|
||
| ## Client support | ||
|
|
||
| <Note> | ||
|
|
||
| MCP Tasks is an extension to the [core MCP specification](/specification). Host | ||
| support varies by client. | ||
|
|
||
| </Note> | ||
|
|
||
| See the [client matrix](/extensions/client-matrix) for extension support across | ||
| clients. Task support requires explicit opt-in from both client and server. | ||
|
|
||
| ## Specification | ||
|
|
||
| The Tasks extension is specified in the [experimental-ext-tasks repository](https://github.com/modelcontextprotocol/experimental-ext-tasks). It uses the standard MCP [extension negotiation](/extensions/overview#negotiation) mechanism: clients and servers declare support in the `extensions` field of their capabilities during initialization. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would love for my mcp server to be able to attach p50/p90/p95 metrics to a task to help shape the polling frequency of the harness. where would be the appropriate place to submit this proposal?