Editorial

MCP · Tasks · SEP-2663 · 13 September 2026

MCP tasks/get -32601: debug the 2026-07-28 Tasks extension

If a long-running MCP tool returns a task handle and the next tasks/get call fails with -32601 Method Not Found, do not assume the task itself is broken. In MCP 2026-07-28, Tasks is a separately negotiated extension, its wire lifecycle changed from the 2025 experimental API, and several current SDK/framework paths still have implementation gaps.

Published 13 September 2026 · sources checked 13 September 2026

io.modelcontextprotocol/tasks

Extension identifier — not implied by core 2026-07-28 support

tasks/get

Poll current state; terminal state carries the final result or error

Mcp-Name

Must carry the taskId on tasks/get, tasks/update and tasks/cancel over Streamable HTTP

-32601

Can be correct for retired methods or evidence of a missing extension dispatch path

The key distinction

MCP 2026-07-28 support does not equal MCP Tasks support

SEP-2663 defines Tasks as the io.modelcontextprotocol/tasks extension. A server may answer a supported request such as tools/call with resultType: "task" only when the client has declared the extension. The client then drives the durable lifecycle through tasks/get, tasks/update and tasks/cancel.

That means a successful 2026-07-28 handshake-free request, a valid server/discover result or a package that contains Task types is not enough evidence. You need extension negotiation and a client/server implementation that actually encodes, dispatches and routes the extension methods on the transport path you use.

Fast diagnosis

What each symptom usually means

SignalLikely boundaryFirst action
tools/call returns resultType: task, then the client rejects itClient did not negotiate or cannot decode the Tasks extensionConfirm clientCapabilities.extensions contains io.modelcontextprotocol/tasks and verify the client SDK actually implements the extension.
tasks/get returns -32601 on MCP 2026-07-28Wrong era, missing extension support, or SDK dispatch gapCheck negotiated extension support before changing task business logic.
tasks/result returns -32601Expected on the modern extensionStop calling the legacy method; poll tasks/get until the task is terminal.
tasks/list returns -32601Expected on the modern extensionDo not enumerate tasks. Persist the taskId returned for the work you created.
tasks/get reaches the wrong worker or cannot find stateMissing or incorrect routing metadataSend Mcp-Method and set Mcp-Name to params.taskId; keep durable task state independent of one process.
Client hammers tasks/get continuouslypollIntervalMs ignoredHonor the server-directed polling interval and changes to it.

Era mismatch

The 2025 experimental API and 2026 extension are not wire-compatible

Boundary2025 experimental Tasks2026-07-28 Tasks extension
CapabilityExperimental core task capabilitiesio.modelcontextprotocol/tasks extension
CreationClient/request opt-in patternsServer-directed after extension negotiation
Statustasks/gettasks/get
Final resulttasks/resultTerminal tasks/get contains result or error
Client inputLegacy task flowtasks/update for input_required
EnumerationLegacy task listing surfacestasks/list removed
Streamable HTTP routingSession-era assumptions were commonMcp-Name must equal taskId on tasks/* requests

A particularly useful clue is tasks/result: SEP-2663 explicitly removes it, so -32601 is the correct modern response. The final result is embedded in the terminal tasks/get response. tasks/list is also removed; persist the returned taskId instead of depending on global enumeration.

Known-good request shape

Poll with extension capability plus task routing metadata

Over Streamable HTTP, a modern task poll needs the normal 2026 request metadata plus transport headers. The critical routing rule is that Mcp-Name equals the task ID for tasks/get, tasks/update and tasks/cancel.

POST /mcp
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tasks/get
Mcp-Name: task_7f31
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 9,
  "method": "tasks/get",
  "params": {
    "taskId": "task_7f31",
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {
        "extensions": {
          "io.modelcontextprotocol/tasks": {}
        }
      }
    }
  }
}

If this shape is correct and you still get -32601, inspect the SDK/framework support matrix before changing your task store. A transport or dispatcher can reject the method before your registered handler ever runs.

Current implementation reality

Schemas can exist before end-to-end Tasks support does

The official TypeScript SDK still tracks the Tasks extension separately from the core 2026 implementation. A current issue documents tasks/get and tasks/cancel being rejected with -32601 before custom extension handlers are reached on one v2 path. The current Python SDK roadmap likewise lists the 2026 Tasks extension as not yet implemented in its main v2 extension set.

Cloudflare's Agents project has a separate open request to wire SEP-2663 into its stateless createMcpHandler path. In other words: do not infer runtime support from generated schemas, type declarations or core protocol compliance alone. Test the exact client, server framework and transport combination you intend to ship.

Repair sequence

Eight checks before writing a workaround

  1. 1. Capture the protocol revision. Prove the request is actually using 2026-07-28 rather than assuming from an SDK version.
  2. 2. Verify extension negotiation. Confirm the client declares io.modelcontextprotocol/tasks and the server advertises/accepts it on the relevant flow.
  3. 3. Inspect the original tool result. A task-aware client must be able to accept resultType: "task" instead of only an ordinary CallToolResult.
  4. 4. Remove legacy methods. Replace tasks/result with terminal tasks/get; do not rely on tasks/list.
  5. 5. Send routing headers. Set Mcp-Method and Mcp-Name: <taskId> on Streamable HTTP task requests.
  6. 6. Honor pollIntervalMs. Poll at the server-directed interval and accept that it can change while the task is working.
  7. 7. Check framework dispatch. If the request is correct but never reaches your handler, confirm whether the framework has an open Tasks-extension gap for that path.
  8. 8. Keep task state durable and authorized. Bind every task to its owner/authorization context, set expiry and quotas, and do not depend on one process or transport session surviving.

Why Mcp-Name matters

Stateless protocol does not mean stateless application work

A task can outlive the HTTP connection and even the server process that created it. The protocol therefore routes subsequent task operations using an explicit task handle. Put durable task state behind that handle, authorize every status/update/cancel call, and make infrastructure capable of routing or resolving the task without an implicit MCP session. Mcp-Name helps infrastructure route the request; it is not an authorization decision by itself.

Sources

Protocol and implementation evidence checked 13 September 2026

Continue the implementation path