Skip to content

Commit adb443e

Browse files
[SEP-2663] refactor!: remove 2025-11 experimental tasks (impl + references)
Removes the 2025-11 experimental tasks side-channel through Protocol: TaskManager, processInbound*/processOutbound*, task interception, the experimental.tasks.* client/server accessors, and all task-augmented request handling. Also extends beyond the implementation deletion to scrub remaining references in examples, docs, and comments. The only task-related symbol remaining in packages/*.ts is `taskSupport` in ToolExecutionSchema, kept solely to match spec.types.ts (which still declares it); both are removed together in the next commit (spec regen). CHANGELOG entries are preserved (historical record). Migration docs retain a brief removal note. `microtask`/`platformBackgroundTask` are JS/platform terminology, not MCP tasks. Satisfies: SEP-2663 (core-removal half; tasks are now Extensions Track).
1 parent 86276ed commit adb443e

63 files changed

Lines changed: 260 additions & 17759 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@modelcontextprotocol/core': major
3+
'@modelcontextprotocol/server': major
4+
'@modelcontextprotocol/client': major
5+
---
6+
SEP-2663: remove 2025-11 experimental tasks (TaskManager, experimental.tasks.* accessors). Tasks are now Extensions Track.

CLAUDE.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,7 @@ The repo also ships “middleware” packages under `packages/middleware/` (e.g.
104104

105105
### Experimental Features
106106

107-
Located in `packages/*/src/experimental/`:
108-
109-
- **Tasks**: Long-running task support with polling/resumption (`packages/core/src/experimental/tasks/`)
107+
Located in `packages/*/src/experimental/`. Currently empty.
110108

111109
### Zod Schemas
112110

@@ -201,7 +199,6 @@ The `ctx` parameter in handlers provides a structured context:
201199
- `notify(notification)`: Send related notification back
202200
- `http?`: HTTP transport info (undefined for stdio)
203201
- `authInfo?`: Validated auth token info
204-
- `task?`: Task context (`{ id?, store, requestedTtl? }`) when task storage is configured
205202

206203
**`ServerContext`** extends `BaseContext.mcpReq` and `BaseContext.http?` via type intersection:
207204

docs/client.md

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ All requests have a 60-second default timeout. Pass a custom `timeout` in the op
544544
```ts source="../examples/client/src/clientGuide.examples.ts#errorHandling_timeout"
545545
try {
546546
const result = await client.callTool(
547-
{ name: 'slow-task', arguments: {} },
547+
{ name: 'slow-operation', arguments: {} },
548548
{ timeout: 120_000 } // 2 minutes instead of the default 60 seconds
549549
);
550550
console.log(result.content);
@@ -581,7 +581,7 @@ let lastToken: string | undefined;
581581
const result = await client.request(
582582
{
583583
method: 'tools/call',
584-
params: { name: 'long-running-task', arguments: {} }
584+
params: { name: 'long-running-operation', arguments: {} }
585585
},
586586
{
587587
resumptionToken: lastToken,
@@ -596,18 +596,6 @@ console.log(result);
596596

597597
For an end-to-end example of server-initiated SSE disconnection and automatic client reconnection with event replay, see [`ssePollingClient.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/client/src/ssePollingClient.ts).
598598

599-
## Tasks (experimental)
600-
601-
> [!WARNING]
602-
> The tasks API is experimental and may change without notice.
603-
604-
Task-based execution enables "call-now, fetch-later" patterns for long-running operations (see [Tasks](https://modelcontextprotocol.io/specification/latest/basic/utilities/tasks) in the MCP specification). Instead of returning a result immediately, a tool creates a task that can be polled or resumed later. To use tasks:
605-
606-
- Call {@linkcode @modelcontextprotocol/client!experimental/tasks/client.ExperimentalClientTasks#callToolStream | client.experimental.tasks.callToolStream(...)} to start a tool call that may create a task and emit status updates over time.
607-
- Call {@linkcode @modelcontextprotocol/client!experimental/tasks/client.ExperimentalClientTasks#getTask | client.experimental.tasks.getTask(...)} and {@linkcode @modelcontextprotocol/client!experimental/tasks/client.ExperimentalClientTasks#getTaskResult | getTaskResult(...)} to check status and fetch results after reconnecting.
608-
609-
For a full runnable example, see [`simpleTaskInteractiveClient.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/client/src/simpleTaskInteractiveClient.ts).
610-
611599
## See also
612600

613601
- [`examples/client/`](https://github.com/modelcontextprotocol/typescript-sdk/tree/main/examples/client) — Full runnable client examples

docs/migration-SKILL.md

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -429,9 +429,7 @@ Request/notification params remain fully typed. Remove unused schema imports aft
429429
| `extra.requestInfo` | `ctx.http?.req` (standard Web `Request`, only `ServerContext`) |
430430
| `extra.closeSSEStream` | `ctx.http?.closeSSE` (only `ServerContext`) |
431431
| `extra.closeStandaloneSSEStream` | `ctx.http?.closeStandaloneSSE` (only `ServerContext`) |
432-
| `extra.taskStore` | `ctx.task?.store` |
433-
| `extra.taskId` | `ctx.task?.id` |
434-
| `extra.taskRequestedTtl` | `ctx.task?.requestedTtl` |
432+
| `extra.taskStore` / `taskId` / `taskRequestedTtl` | _removed; see §12_ |
435433

436434
`ServerContext` convenience methods (new in v2, no v1 equivalent):
437435

@@ -482,24 +480,24 @@ If a `*Schema` constant was used for **runtime validation** (not just as a `requ
482480

483481
`isCallToolResult(value)` still works, but `isSpecType` covers every spec type by name.
484482

485-
## 12. Experimental: `TaskCreationParams.ttl` no longer accepts `null`
483+
## 12. Experimental tasks interception removed
486484

487-
`TaskCreationParams.ttl` changed from `z.union([z.number(), z.null()]).optional()` to `z.number().optional()`. Per the MCP spec, `null` TTL (unlimited lifetime) is only valid in server responses (`Task.ttl`), not in client requests. Omit `ttl` to let the server decide.
485+
The 2025-11 task side-channel through `Protocol` is removed (was always `@experimental`). No mechanical migration; remove usages.
488486

489-
| v1 | v2 |
490-
| ---------------------- | ---------------------------------- |
491-
| `task: { ttl: null }` | `task: {}` (omit ttl) |
492-
| `task: { ttl: 60000 }` | `task: { ttl: 60000 }` (unchanged) |
487+
| Removed | Notes |
488+
| --- | --- |
489+
| `ProtocolOptions.tasks` | drop the option |
490+
| `protocol.taskManager` | gone |
491+
| `RequestOptions.task` / `.relatedTask`, `NotificationOptions.relatedTask` | drop the option |
492+
| `BaseContext.task` (`ctx.task?.*`) | gone |
493+
| `assertTaskCapability` / `assertTaskHandlerCapability` overrides | delete the override |
494+
| `*.experimental.tasks.*` accessors, `Experimental{Client,Server,McpServer}Tasks` | removed |
495+
| `requestStream` / `callToolStream` / `createMessageStream` / `elicitInputStream` | removed; no streaming variant |
496+
| `registerToolTask`, `ToolTaskHandler`, `TaskRequestHandler`, `CreateTaskRequestHandler` | removed |
497+
| `TaskMessageQueue`, `InMemoryTaskMessageQueue`, `Queued*`, `CreateTaskServerContext`, `TaskServerContext`, `TaskToolExecution` | removed |
498+
| `ResponseMessage`, `TaskStatusMessage`, `TaskCreatedMessage`, `ResultMessage`, `takeResult`, `toArrayAsync` | removed |
493499

494-
Type changes in handler context:
495-
496-
| Type | v1 | v2 |
497-
| ------------------------------------------- | ----------------------------- | --------------------- |
498-
| `TaskContext.requestedTtl` | `number \| null \| undefined` | `number \| undefined` |
499-
| `CreateTaskServerContext.task.requestedTtl` | `number \| null \| undefined` | `number \| undefined` |
500-
| `TaskServerContext.task.requestedTtl` | `number \| null \| undefined` | `number \| undefined` |
501-
502-
> These task APIs are `@experimental` and may change without notice.
500+
`TaskStore` / `InMemoryTaskStore` / `CreateTaskOptions` / `isTerminal` (storage layer) and `TaskCreationParams` are also removed; they will return with the SEP-2663 server-directed plugin.
503501

504502
## 13. Client Behavioral Changes
505503

docs/migration.md

Lines changed: 18 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ const result = await client.callTool({ name: 'my-tool', arguments: {} }, Compati
493493
const result = await client.callTool({ name: 'my-tool', arguments: {} });
494494
```
495495

496-
The return type is now inferred from the method name via `ResultTypeMap`. For example, `client.request({ method: 'tools/call', ... })` returns `Promise<CallToolResult | CreateTaskResult>`.
496+
The return type is now inferred from the method name via `ResultTypeMap`. For example, `client.request({ method: 'tools/call', ... })` returns `Promise<CallToolResult>`.
497497

498498
For **custom (non-spec)** methods, keep the result-schema argument — see [Sending custom-method requests](#sending-custom-method-requests). Only drop the schema when calling a spec method.
499499

@@ -599,9 +599,7 @@ The `RequestHandlerExtra` type has been replaced with a structured context type
599599
| `extra.closeSSEStream` | `ctx.http?.closeSSE` (only on `ServerContext`) |
600600
| `extra.closeStandaloneSSEStream` | `ctx.http?.closeStandaloneSSE` (only on `ServerContext`) |
601601
| `extra.sessionId` | `ctx.sessionId` |
602-
| `extra.taskStore` | `ctx.task?.store` |
603-
| `extra.taskId` | `ctx.task?.id` |
604-
| `extra.taskRequestedTtl` | `ctx.task?.requestedTtl` |
602+
| `extra.taskStore` / `taskId` / `taskRequestedTtl` | _removed — see "Experimental tasks interception removed" below_ |
605603

606604
**Before (v1):**
607605

@@ -619,17 +617,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
619617
```typescript
620618
server.setRequestHandler('tools/call', async (request, ctx) => {
621619
const headers = ctx.http?.req?.headers; // standard Web Request object
622-
const taskStore = ctx.task?.store;
623620
await ctx.mcpReq.notify({ method: 'notifications/progress', params: { progressToken: 'abc', progress: 50, total: 100 } });
624621
return { content: [{ type: 'text', text: 'result' }] };
625622
});
626623
```
627624

628-
Context fields are organized into 4 groups:
625+
Context fields are organized into 3 groups:
629626

630627
- **`mcpReq`** — request-level concerns: `id`, `method`, `_meta`, `signal`, `send()`, `notify()`, plus server-only `log()`, `elicitInput()`, and `requestSampling()`
631628
- **`http?`** — HTTP transport concerns (undefined for stdio): `authInfo`, plus server-only `req`, `closeSSE`, `closeStandaloneSSE`
632-
- **`task?`**task lifecycle: `id`, `store`, `requestedTtl`
629+
- **`sessionId?`**transport session identifier (top-level)
633630

634631
`BaseContext` is the common base type shared by both `ServerContext` and `ClientContext`. `ServerContext` extends each group with server-specific additions via type intersection.
635632

@@ -870,46 +867,24 @@ try {
870867
}
871868
```
872869

873-
### Experimental: `TaskCreationParams.ttl` no longer accepts `null`
870+
### Experimental tasks interception removed
874871

875-
The `ttl` field in `TaskCreationParams` (used when requesting the server to create a task) no longer accepts `null`. Per the MCP spec, `null` TTL (meaning unlimited lifetime) is only valid in server responses (`Task.ttl`), not in client requests. Clients should omit `ttl` to let
876-
the server decide the lifetime.
872+
The 2025-11 experimental tasks side-channel woven through `Protocol` has been removed in preparation for the SEP-2663 Tasks Extension. The following are gone with no in-place replacement:
877873

878-
This also narrows the type of `requestedTtl` in `TaskContext`, `CreateTaskServerContext`, and `TaskServerContext` from `number | null | undefined` to `number | undefined`.
874+
- `ProtocolOptions.tasks` (the `{ taskStore, taskMessageQueue }` constructor option)
875+
- `protocol.taskManager` getter, `Protocol#_bindTaskManager`
876+
- `RequestOptions.task` / `RequestOptions.relatedTask`, `NotificationOptions.relatedTask`
877+
- `BaseContext.task` (`ctx.task?.store` / `ctx.task?.id` / `ctx.task?.requestedTtl`)
878+
- abstract `assertTaskCapability` / `assertTaskHandlerCapability`
879+
- `client.experimental.tasks.*` / `server.experimental.tasks.*` / `mcpServer.experimental.tasks.*` accessors and the `Experimental{Client,Server,McpServer}Tasks` classes
880+
- streaming methods (`requestStream`, `callToolStream`, `createMessageStream`, `elicitInputStream`) and the `ResponseMessage` types they yielded
881+
- `mcpServer.experimental.tasks.registerToolTask(...)`, `ToolTaskHandler`, `TaskRequestHandler`, `CreateTaskRequestHandler`
882+
- `TaskMessageQueue`, `InMemoryTaskMessageQueue`, `Queued*` message types, `CreateTaskServerContext`, `TaskServerContext`, `TaskToolExecution`
883+
- `examples/{client,server}/src/simpleTaskInteractive*.ts`
879884

880-
**Before (v1):**
881-
882-
```typescript
883-
// Requesting unlimited lifetime by passing null
884-
const result = await client.callTool({
885-
name: 'long-task',
886-
arguments: {},
887-
task: { ttl: null }
888-
});
889-
890-
// Handler context had number | null | undefined
891-
server.setRequestHandler('tools/call', async (request, ctx) => {
892-
const ttl: number | null | undefined = ctx.task?.requestedTtl;
893-
});
894-
```
895-
896-
**After (v2):**
897-
898-
```typescript
899-
// Omit ttl to let the server decide (server may return null for unlimited)
900-
const result = await client.callTool({
901-
name: 'long-task',
902-
arguments: {},
903-
task: {}
904-
});
905-
906-
// Handler context is now number | undefined
907-
server.setRequestHandler('tools/call', async (request, ctx) => {
908-
const ttl: number | undefined = ctx.task?.requestedTtl;
909-
});
910-
```
885+
**Also removed:** the storage layer (`TaskStore`, `InMemoryTaskStore`, `CreateTaskOptions`, `isTerminal`) and `TaskCreationParams`. They will return as part of the SEP-2663 server-directed plugin in a follow-up.
911886

912-
> **Note:** These task APIs are marked `@experimental` and may change without notice.
887+
There is no migration path for the removed surface; it was always `@experimental`. Under SEP-2663, tasks reattach via a `DispatchMiddleware` (`mcp.use(tasksPlugin({ store }))`) and handlers read task context from `ctx.ext.task` instead of `ctx.task`.
913888

914889
## Enhancements
915890

docs/server.md

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -495,19 +495,6 @@ server.registerTool(
495495
);
496496
```
497497

498-
## Tasks (experimental)
499-
500-
> [!WARNING]
501-
> The tasks API is experimental and may change without notice.
502-
503-
Task-based execution enables "call-now, fetch-later" patterns for long-running operations (see [Tasks](https://modelcontextprotocol.io/specification/latest/basic/utilities/tasks) in the MCP specification). Instead of returning a result immediately, a tool creates a task that can be polled or resumed later. To use tasks:
504-
505-
- Provide a {@linkcode @modelcontextprotocol/server!index.TaskStore | TaskStore} implementation that persists task metadata and results (see {@linkcode @modelcontextprotocol/server!index.InMemoryTaskStore | InMemoryTaskStore} for reference).
506-
- Enable the `tasks` capability when constructing the server.
507-
- Register tools with {@linkcode @modelcontextprotocol/server!experimental/tasks/mcpServer.ExperimentalMcpServerTasks#registerToolTask | server.experimental.tasks.registerToolTask(...)}.
508-
509-
For a full runnable example, see [`simpleTaskInteractive.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleTaskInteractive.ts).
510-
511498
## Shutdown
512499

513500
For stateful multi-session HTTP servers, capture the `http.Server` from `app.listen()` so you can stop accepting connections, then close each session transport:

examples/client/README.md

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,17 @@ Most clients expect a server to be running. Start one from [`../server/README.md
2424

2525
## Example index
2626

27-
| Scenario | Description | File |
28-
| --------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
29-
| Interactive Streamable HTTP client | CLI client that exercises tools/resources/prompts, notifications, elicitation, and tasks. | [`src/simpleStreamableHttp.ts`](src/simpleStreamableHttp.ts) |
30-
| Backwards-compatible client (Streamable HTTP → SSE) | Tries Streamable HTTP first, falls back to legacy SSE on 4xx responses. | [`src/streamableHttpWithSseFallbackClient.ts`](src/streamableHttpWithSseFallbackClient.ts) |
31-
| SSE polling client (legacy) | Polls a legacy HTTP+SSE server and demonstrates notification handling. | [`src/ssePollingClient.ts`](src/ssePollingClient.ts) |
32-
| Parallel tool calls | Runs multiple tool calls in parallel. | [`src/parallelToolCallsClient.ts`](src/parallelToolCallsClient.ts) |
33-
| Multiple clients in parallel | Connects multiple clients concurrently to the same server. | [`src/multipleClientsParallel.ts`](src/multipleClientsParallel.ts) |
34-
| OAuth client (interactive) | OAuth-enabled client (dynamic registration, auth flow). | [`src/simpleOAuthClient.ts`](src/simpleOAuthClient.ts) |
35-
| OAuth provider helper | Demonstrates reusable OAuth providers. | [`src/simpleOAuthClientProvider.ts`](src/simpleOAuthClientProvider.ts) |
36-
| Client credentials (M2M) | Machine-to-machine OAuth client credentials example. | [`src/simpleClientCredentials.ts`](src/simpleClientCredentials.ts) |
37-
| URL elicitation client | Drives URL-mode elicitation flows (sensitive input in a browser). | [`src/elicitationUrlExample.ts`](src/elicitationUrlExample.ts) |
38-
| Task interactive client | Demonstrates task-based execution + interactive server→client requests. | [`src/simpleTaskInteractiveClient.ts`](src/simpleTaskInteractiveClient.ts) |
27+
| Scenario | Description | File |
28+
| --------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
29+
| Interactive Streamable HTTP client | CLI client that exercises tools/resources/prompts, notifications, and elicitation. | [`src/simpleStreamableHttp.ts`](src/simpleStreamableHttp.ts) |
30+
| Backwards-compatible client (Streamable HTTP → SSE) | Tries Streamable HTTP first, falls back to legacy SSE on 4xx responses. | [`src/streamableHttpWithSseFallbackClient.ts`](src/streamableHttpWithSseFallbackClient.ts) |
31+
| SSE polling client (legacy) | Polls a legacy HTTP+SSE server and demonstrates notification handling. | [`src/ssePollingClient.ts`](src/ssePollingClient.ts) |
32+
| Parallel tool calls | Runs multiple tool calls in parallel. | [`src/parallelToolCallsClient.ts`](src/parallelToolCallsClient.ts) |
33+
| Multiple clients in parallel | Connects multiple clients concurrently to the same server. | [`src/multipleClientsParallel.ts`](src/multipleClientsParallel.ts) |
34+
| OAuth client (interactive) | OAuth-enabled client (dynamic registration, auth flow). | [`src/simpleOAuthClient.ts`](src/simpleOAuthClient.ts) |
35+
| OAuth provider helper | Demonstrates reusable OAuth providers. | [`src/simpleOAuthClientProvider.ts`](src/simpleOAuthClientProvider.ts) |
36+
| Client credentials (M2M) | Machine-to-machine OAuth client credentials example. | [`src/simpleClientCredentials.ts`](src/simpleClientCredentials.ts) |
37+
| URL elicitation client | Drives URL-mode elicitation flows (sensitive input in a browser). | [`src/elicitationUrlExample.ts`](src/elicitationUrlExample.ts) |
3938

4039
## URL elicitation example (server + client)
4140

0 commit comments

Comments
 (0)