Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/sep-2663-tasks-removal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@modelcontextprotocol/core': major
'@modelcontextprotocol/server': major
'@modelcontextprotocol/client': major
---
SEP-2663: remove 2025-11 experimental tasks (TaskManager, experimental.tasks.* accessors). Tasks are now Extensions Track.
Comment thread
claude[bot] marked this conversation as resolved.
Comment thread
felixweinberger marked this conversation as resolved.
5 changes: 1 addition & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,7 @@ The repo also ships “middleware” packages under `packages/middleware/` (e.g.

### Experimental Features

Located in `packages/*/src/experimental/`:

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

### Zod Schemas

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

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

Expand Down
16 changes: 2 additions & 14 deletions docs/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ All requests have a 60-second default timeout. Pass a custom `timeout` in the op
```ts source="../examples/client/src/clientGuide.examples.ts#errorHandling_timeout"
try {
const result = await client.callTool(
{ name: 'slow-task', arguments: {} },
{ name: 'slow-operation', arguments: {} },
{ timeout: 120_000 } // 2 minutes instead of the default 60 seconds
);
console.log(result.content);
Comment thread
claude[bot] marked this conversation as resolved.
Expand Down Expand Up @@ -581,7 +581,7 @@ let lastToken: string | undefined;
const result = await client.request(
{
method: 'tools/call',
params: { name: 'long-running-task', arguments: {} }
params: { name: 'long-running-operation', arguments: {} }
},
{
resumptionToken: lastToken,
Expand All @@ -596,18 +596,6 @@ console.log(result);

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).

## Tasks (experimental)

> [!WARNING]
> The tasks API is experimental and may change without notice.

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:

- 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.
- 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.

For a full runnable example, see [`simpleTaskInteractiveClient.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/client/src/simpleTaskInteractiveClient.ts).

## See also

- [`examples/client/`](https://github.com/modelcontextprotocol/typescript-sdk/tree/main/examples/client) — Full runnable client examples
Expand Down
34 changes: 16 additions & 18 deletions docs/migration-SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,9 +429,7 @@ Request/notification params remain fully typed. Remove unused schema imports aft
| `extra.requestInfo` | `ctx.http?.req` (standard Web `Request`, only `ServerContext`) |
| `extra.closeSSEStream` | `ctx.http?.closeSSE` (only `ServerContext`) |
| `extra.closeStandaloneSSEStream` | `ctx.http?.closeStandaloneSSE` (only `ServerContext`) |
| `extra.taskStore` | `ctx.task?.store` |
| `extra.taskId` | `ctx.task?.id` |
| `extra.taskRequestedTtl` | `ctx.task?.requestedTtl` |
| `extra.taskStore` / `taskId` / `taskRequestedTtl` | _removed; see §12_ |

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

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

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

## 12. Experimental: `TaskCreationParams.ttl` no longer accepts `null`
## 12. Experimental tasks interception removed

`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.
The 2025-11 task side-channel through `Protocol` is removed (was always `@experimental`). No mechanical migration; remove usages.

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

Type changes in handler context:

| Type | v1 | v2 |
| ------------------------------------------- | ----------------------------- | --------------------- |
| `TaskContext.requestedTtl` | `number \| null \| undefined` | `number \| undefined` |
| `CreateTaskServerContext.task.requestedTtl` | `number \| null \| undefined` | `number \| undefined` |
| `TaskServerContext.task.requestedTtl` | `number \| null \| undefined` | `number \| undefined` |

> These task APIs are `@experimental` and may change without notice.
`TaskStore` / `InMemoryTaskStore` / `CreateTaskOptions` / `isTerminal` (storage layer) and `TaskCreationParams` are also removed; they will return with the SEP-2663 server-directed plugin.

## 13. Client Behavioral Changes

Expand Down
61 changes: 18 additions & 43 deletions docs/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ const result = await client.callTool({ name: 'my-tool', arguments: {} }, Compati
const result = await client.callTool({ name: 'my-tool', arguments: {} });
```

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

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.

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

**Before (v1):**

Comment thread
claude[bot] marked this conversation as resolved.
Outdated
Expand All @@ -619,17 +617,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
```typescript
server.setRequestHandler('tools/call', async (request, ctx) => {
const headers = ctx.http?.req?.headers; // standard Web Request object
const taskStore = ctx.task?.store;
await ctx.mcpReq.notify({ method: 'notifications/progress', params: { progressToken: 'abc', progress: 50, total: 100 } });
return { content: [{ type: 'text', text: 'result' }] };
});
```

Context fields are organized into 4 groups:
Context fields are organized into 3 groups:

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

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

Expand Down Expand Up @@ -870,46 +867,24 @@ try {
}
```

### Experimental: `TaskCreationParams.ttl` no longer accepts `null`
### Experimental tasks interception removed

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
the server decide the lifetime.
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:

This also narrows the type of `requestedTtl` in `TaskContext`, `CreateTaskServerContext`, and `TaskServerContext` from `number | null | undefined` to `number | undefined`.
- `ProtocolOptions.tasks` (the `{ taskStore, taskMessageQueue }` constructor option)
- `protocol.taskManager` getter, `Protocol#_bindTaskManager`
- `RequestOptions.task` / `RequestOptions.relatedTask`, `NotificationOptions.relatedTask`
- `BaseContext.task` (`ctx.task?.store` / `ctx.task?.id` / `ctx.task?.requestedTtl`)
- abstract `assertTaskCapability` / `assertTaskHandlerCapability`
- `client.experimental.tasks.*` / `server.experimental.tasks.*` / `mcpServer.experimental.tasks.*` accessors and the `Experimental{Client,Server,McpServer}Tasks` classes
- streaming methods (`requestStream`, `callToolStream`, `createMessageStream`, `elicitInputStream`) and the `ResponseMessage` types they yielded
- `mcpServer.experimental.tasks.registerToolTask(...)`, `ToolTaskHandler`, `TaskRequestHandler`, `CreateTaskRequestHandler`
- `TaskMessageQueue`, `InMemoryTaskMessageQueue`, `Queued*` message types, `CreateTaskServerContext`, `TaskServerContext`, `TaskToolExecution`
- `examples/{client,server}/src/simpleTaskInteractive*.ts`
Comment thread
claude[bot] marked this conversation as resolved.

**Before (v1):**

```typescript
// Requesting unlimited lifetime by passing null
const result = await client.callTool({
name: 'long-task',
arguments: {},
task: { ttl: null }
});

// Handler context had number | null | undefined
server.setRequestHandler('tools/call', async (request, ctx) => {
const ttl: number | null | undefined = ctx.task?.requestedTtl;
});
```

**After (v2):**

```typescript
// Omit ttl to let the server decide (server may return null for unlimited)
const result = await client.callTool({
name: 'long-task',
arguments: {},
task: {}
});

// Handler context is now number | undefined
server.setRequestHandler('tools/call', async (request, ctx) => {
const ttl: number | undefined = ctx.task?.requestedTtl;
});
```
**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.

> **Note:** These task APIs are marked `@experimental` and may change without notice.
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`.

## Enhancements

Expand Down
13 changes: 0 additions & 13 deletions docs/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -495,19 +495,6 @@ server.registerTool(
);
```

## Tasks (experimental)

> [!WARNING]
> The tasks API is experimental and may change without notice.

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:

- Provide a {@linkcode @modelcontextprotocol/server!index.TaskStore | TaskStore} implementation that persists task metadata and results (see {@linkcode @modelcontextprotocol/server!index.InMemoryTaskStore | InMemoryTaskStore} for reference).
- Enable the `tasks` capability when constructing the server.
- Register tools with {@linkcode @modelcontextprotocol/server!experimental/tasks/mcpServer.ExperimentalMcpServerTasks#registerToolTask | server.experimental.tasks.registerToolTask(...)}.

For a full runnable example, see [`simpleTaskInteractive.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleTaskInteractive.ts).

## Shutdown

For stateful multi-session HTTP servers, capture the `http.Server` from `app.listen()` so you can stop accepting connections, then close each session transport:
Expand Down
23 changes: 11 additions & 12 deletions examples/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,17 @@ Most clients expect a server to be running. Start one from [`../server/README.md

## Example index

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

## URL elicitation example (server + client)

Expand Down
Loading
Loading