Why MCP Async Tasks Took Two Spec Versions to Actually Work

MCP shipped async tasks in November 2025, but almost no clients implemented them. Here's what made V1 unworkable, and how the July 2026 redesign fixes it.

Cover art for Why MCP Async Tasks Took Two Spec Versions to Actually Work

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.

Running a four-minute deploy tool over MCP
Without Beagle
server holds the connection open, streaming progress back - breaks load balancers, fails on reconnect, no durability guarantee
With Beagle
server returns a task handle immediately; client polls tasks/get for status; tasks/update carries any input-required signal back

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.

3MCP spec versions since launchNov 2024 → Jun 2025 → Nov 2025 → Jul 2026
0Major clients with full V1 task supportat time of Nov 2025 release
12 monthsMinimum deprecation windowfor removed features in the Jul 2026 spec

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/tasks extension in your server capabilities
  • Return a task handle from tools/call instead of blocking
  • Expose tasks/get for status polling and tasks/cancel for teardown
  • Use tasks/update when 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.

Beagle in action#deploys, 2:47pm
The ask
'can someone kick off the staging deploy and let me know when it's done?'
Beagle drafts
calls the deploy MCP tool, receives a task handle, surfaces a "deploy running" card in thread
You approve
polls tasks/get in the background; posts the completion summary with a log link when the task reaches 'completed' - no one has to babysit a terminal
Do this in your workspace →

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.

Or just watch me work

Point me at your website.

I will read up on your business and come back with what I would run for you. No account, no card, about a minute.

I only read what is public. Nothing is saved to your name until you say so.

Keep reading

Beagle does this work for you, in your Slack.1,000 free credits. No card.Hire Beagle