The MCP async tasks spec shipped in November 2025. Nine months later, a Temporal engineer opened an AI Engineering conference talk with a deliberately obvious question: "Why the heck aren't any agents supporting them?" The answer is worth understanding before you build anything that depends on long-running MCP tool calls.
What MCP async tasks are supposed to solve
MCP tasks let an MCP tool be invoked asynchronously, returning a handle instead of an immediate response, so long-running work like human-in-the-loop approvals can complete in the background. That is the correct motivation. Most MCP tool calls finish in milliseconds - a database lookup, a file read, a search query. But a growing class of tools does not: a CI deploy that takes four minutes, a document-indexing job that scans 200 files, an approval gate that waits for a human to click something. Before tasks, those either timed out or held a connection open, which breaks in any real load-balanced environment.
The protocol allows requestors - client or server, depending on the direction - to augment requests with tasks: durable state machines that carry information about the underlying execution state of the request they wrap, intended for polling and deferred result retrieval. Each task is uniquely identifiable by a receiver-generated task ID. Tasks are designed for expensive computations and batch processing, and integrate with external job APIs.
That is sound design. The problem was the implementation.
Why almost no one shipped V1
The V1 specification, released in November and marked experimental, requires durability across network drops, crashes, and long waits, plus a stateful task list endpoint with no filtering - which makes client-side implementation unusually complex and explains why almost no clients support it yet.
The stateful task list was the sharpest edge. A client that wanted to recover after a crash had to call tasks/list to find out what was still running - but
tasks/list had no scoping mechanism that worked safely without sessions.
Every task the server held had to be enumerated. For a server behind a load balancer, that meant pinning session affinity or building a shared task store, neither of which MCP required.
The human-in-the-loop path was equally painful. V1's recovery mechanism relied on a task list where the client asks the server "what tasks do you have?", and human-in-the-loop input required the server to open a long-lived task result connection and elicit a response from the client. That long-lived connection is what breaks in any environment where HTTP is treated as request-response - which is most of them.
It worked for demos and experiments. It was fragile for real systems. The November release begins to change that direction. "Begins" doing a lot of work in that sentence.
What the July 2026 redesign actually changed
Tasks first shipped as an experimental core feature in 2025-11-25, but production use led to moving it out of the core protocol and into an official extension.
The extension identifier is io.modelcontextprotocol/tasks. That is a meaningful architectural shift: tasks now have their own capability negotiation and independent versioning, so a client that doesn't implement the extension can still speak the core protocol without breaking.
The wire protocol changed substantially:
Experimental tasks moved out of the core protocol into an official extension and got redesigned on the way. The blocking tasks/result method is replaced by polling with tasks/get. A new tasks/update carries client-to-server input. tasks/list is removed. And servers can now return task handles unsolicited, without a per-request opt-in.
That last point is the subtlest change. In V1, tasks required explicit negotiation per request. Now the server decides whether a call should run as a task -
a server can answer tools/call with a task handle, and the client drives it with tasks/get, tasks/update, and tasks/cancel. Task creation is server-directed: the client advertises the extension and the server decides when a call should run as a task.
This is how most async APIs actually work in practice. You call an endpoint; it decides whether to return synchronously or hand you a job ID. The client does not need to know ahead of time.
What this means for teams building on MCP today
The V1 task methods - tasks/result (blocking), tasks/list - are gone in the current spec.
The spec is explicitly breaking for anything built around protocol-level sessions or the old experimental tasks methods, but ships a formal deprecation policy: Roots, Sampling, Logging, and the legacy HTTP+SSE transport are deprecated with a minimum 12-month runway before removal.
If you have an MCP server with tools that run longer than a few seconds, the path forward is:
- Advertise the
io.modelcontextprotocol/tasksextension in your server capabilities - Return a task handle from
tools/callinstead of blocking - Expose
tasks/getfor status polling andtasks/cancelfor teardown - Use
tasks/updatewhen you need client input mid-execution (the replacement for the old elicitation-over-long-connection pattern)
Every request is now self-contained, so it can be routed to any server instance by a plain round-robin load balancer - no deep packet inspection, no session affinity, no shared state at the gateway layer. That is what makes the new design actually deployable. The cost is that your server, or something in front of it, now owns task persistence. The protocol no longer holds the state for you.
A teammate like Beagle, running in Slack, hits this constraint concretely: any tool call that reaches out to an external system and waits for a human decision - an approval, a ticket status, a deploy gate - is exactly the workload tasks were designed for.
The broader July 2026 spec - stateless core, formal extensions framework, hardened OAuth - is worth a separate read. 2026-07-28 is the release that turns MCP from a prototype-friendly protocol into one you can run at scale on infrastructure that already exists. Tasks are just the most instructive case study in how that transition happened.
For the full picture on how MCP tool definitions affect your token budget before you even get to long-running calls, see The Hidden Token Cost of MCP Tool Definitions. For what the session handshake removal means for compatibility, the MCP Version Compatibility field note covers the earlier friction.
MCP async tasks: common questions
What are MCP async tasks?
MCP async tasks let a server return a durable task handle instead of blocking on a long-running tool call. The client polls tasks/get for status updates and retrieves results when the task reaches completed. They are designed for deploys, ETL jobs, document processing, and human-in-the-loop approvals that cannot finish within a normal HTTP timeout.
Why did no clients implement MCP tasks at first?
The November 2025 (V1) design required a stateful tasks/list endpoint with no filtering, durability across network drops, and a long-lived server connection for human-in-the-loop input. That combination was too complex for most client teams to build against on an experimental feature. The July 2026 redesign dropped tasks/list, replaced the blocking tasks/result with polling, and moved tasks into a formal extension.
Are the old MCP task methods still usable?
No. The tasks/result (blocking) and tasks/list methods from the November 2025 experimental spec are removed in the July 2026 specification. Servers that used them need to migrate to tasks/get, tasks/update, and tasks/cancel under the io.modelcontextprotocol/tasks extension.
Do I need to implement MCP tasks for short tool calls?
No. Tasks are opt-in at the server level: the server decides whether a given tools/call response returns inline or as a task handle. Short, synchronous tools can continue to answer inline. You only need the extension if you have tools that run for more than a few seconds or that require mid-execution user input.
What is the difference between MCP tasks and A2A?
MCP tasks handle async execution within a single agent's tool-calling loop - the agent calls a tool, gets a handle, and polls. A2A's architecture is peer-level: tasks have full lifecycles, can be long-running, and support updates and artifacts between independent agents across frameworks and vendors. They solve different layers of the same problem and are typically used together in multi-agent systems.