MCP Tasks Extension in 2026: Ship Long-Running Tools Without Timeout Failures
Implement the MCP Tasks extension against the 2026-07-28 specification: return a durable task handle from slow tools, poll with tasks/get, answer mid-flight input with tasks/update and test the failure paths before customers find them.
30-DAY SEARCH TREND
CORE JUDGMENT
A standard MCP tool call holds the connection open until the server answers, which is why any job slower than a few seconds gets killed by a client or proxy deadline - and why the agent cannot tell whether the work finished, failed or is still running. The Tasks extension replaces that blocking call with a durable job handle the client polls at its own pace.
Why Blocking Tool Calls Fail in 2026
Anthropic released the Model Context Protocol in November 2024 as a way to wire language models to tools and data. Two years later it is the default wiring layer for agentic software: registries that listed a few hundred servers in 2024 now index tens of thousands, and the project moved to neutral stewardship when Anthropic donated MCP to the Agentic AI Foundation, a directed fund under the Linux Foundation, on 9 December 2025. The 2026-07-28 revision pushed the protocol further, dropping sessions and making the transport stateless while formalising an extensions framework. That scale exposed one stubborn failure mode: the tool call that takes too long. A standard MCP call is synchronous, so the client sends tools/call and holds the connection until the server produces a result. Most clients and transport intermediaries impose deadlines measured in seconds, and anything slower - a video transcode, a transform across a hundred warehouse tables, a multi-page crawl, a long model chain - is aborted mid-flight. The agent then has no way to know whether the work finished, failed, or is still running, users watch a spinner and then an error, and the retry that follows can run the job a second time and bill for it.
What the MCP Tasks Extension Actually Is
Tasks are the protocol-level answer to that failure. They first shipped as an experimental core feature in the 2025-11-25 revision, where support had to be negotiated at three levels (server-wide, per tool, per operation) and asking the user a mid-flight question still meant opening a blocking connection. In the 2026-07-28 specification the maintainers moved Tasks out of the core and into the io.modelcontextprotocol/tasks extension, recorded as SEP-2663, where it sits in the same versioned extensions framework as MCP Apps and Enterprise-Managed Authorization. Because the 2026-07-28 core is stateless, there is no longer a session to hang state on: the task handle is what survives a disconnect, a redeploy or a client restart. The practical shape is simple. The server decides per request whether a call will run long, returns a task handle instead of a result, and the client drives the job to completion. Clients opt in once by advertising the extension capability; no per-tool warm-up and no per-request flag are required.
The Task Lifecycle, Status by Status
Capability negotiation comes first. The client includes io.modelcontextprotocol/tasks under _meta.io.modelcontextprotocol/clientCapabilities.extensions on its requests, and the server advertises the same extension in the capabilities it returns from server/discover. That single flag replaces the three-level negotiation of the experimental version. When the server decides a request is long-running, it answers with a CreateTaskResult identified by resultType set to task, carrying a taskId, an initial status, a TTL and a suggested polling interval; the task is durably created before that response is sent, so the handle is valid even if the client disconnects immediately. The client then calls tasks/get with the taskId, and the response carries the current status plus, for terminal states, the final result or the error. If the server needs input, the status becomes input_required and the tasks/get response includes an inputRequests map; the client satisfies those requests asynchronously with tasks/update instead of holding a connection open. The lifecycle therefore reads working, then optionally input_required, then one of the three terminal states - completed, failed or cancelled - none of which ever change again. Two subtleties matter. A tool result that reports an error still counts as completed, with that result included, while a JSON-RPC-level failure moves the task to failed. Cancellation is cooperative: the server acknowledges tasks/cancel but is not obligated to stop the work, so a cancelled task can still complete. Finally, the experimental version's tasks/list and tasks/result methods no longer exist - status retrieval and final results both come back through tasks/get, and push notifications moved to notifications/tasks, which clients opt into through the subscriptions/listen stream while polling remains the default.
What You'll Need
You need Node.js 22 LTS and the official TypeScript SDK from the Model Context Protocol project, a client that can speak protocol version 2026-07-28 or later, and a fixture workload that genuinely runs for tens of seconds - you cannot test a task lifecycle against a function that returns in 200 milliseconds. A durable store such as Redis or Postgres is optional for a first walkthrough and mandatory for anything you intend to run in production, and an OpenTelemetry collector is worth wiring in early so every task is traceable by its taskId. Check the client's advertised capabilities rather than assuming them, because extension support in clients and SDKs is still uneven across versions. Two prerequisites teams skip and regret. The first is a shared task store: an in-memory map survives a demo and dies on the first redeploy or second replica. The second is a verified capability handshake, because debugging a client that was never going to poll your server is the most expensive afternoon in this entire workflow.
Step 1: Confirm Capability Support Before Writing Handlers
Give your coding agent the extension documentation and the specification release notes, then ask it to print the capability object before it writes a single handler. Concretely: start a server on the 2026-07-28 protocol version, call server/discover, and check that the response advertises the io.modelcontextprotocol/tasks extension under capabilities.extensions. The single most valuable thing your agent can do here is ask you which protocol revision you are targeting, because the extension's shape changed between the experimental 2025-11-25 version and the final 2026-07-28 release, and hardcoding the older three-level capability checks produces a server that clients quietly ignore. Pin the SDK version in package.json, tell the agent the exact revision, and let it read the shipped type definitions instead of guessing the shape from memory.
Step 2: Return a Task Handle Instead of Blocking
Scope the change to the handful of tools that actually run long. Ask your agent to add a handler path that, for slow operations, returns a CreateTaskResult with resultType set to task, a freshly generated taskId, an initial status of working, creation and update timestamps, a TTL and a suggested poll interval, while every fast tool keeps returning its result synchronously. Require the agent to persist the task record before responding, so a crash between the response and the first poll cannot orphan the job, and require it to choose the TTL deliberately rather than copying a default: interactive jobs rarely need more than an hour, batch pipelines may need a day, and an expired handle should produce a distinguishable error instead of a silent null so the client can decide whether to rerun. This is also the moment to decide whether the operation can pause for human approval, because a task that stops at input_required is the natural place to surface a confirmation to a person without freezing a connection.
Step 3: Wire Polling, Mid-Flight Input and Cancellation
Build a thin client that sends the call, handles either a plain result or a task handle, and polls tasks/get at the interval the server suggested, backing off as the job runs long. Stop polling when the status is terminal, read the result or the error from that same response, and if the status is input_required, present the inputRequests to the user or the model and submit the answers with tasks/update before resuming the poll loop. Wire the cancel path to tasks/cancel when the user aborts or the transport closes, and treat the outcome as best effort rather than a guarantee. Four habits prevent most production incidents here. Debounce notification handling, because a fast worker emits transitions faster than a UI can render them. Treat polling as the source of truth and notifications as an optimisation, since notifications are delivered through an opt-in subscription stream that can lapse. Make cancellation idempotent, so cancelling an already-finished task succeeds quietly. And on retry, resume the stored taskId instead of starting a second job, which is what turns one timeout into two invoices.
Step 4: Make Task State Durable and Authorized
Because the 2026-07-28 core is stateless, authorization has to be explicit. There is no session to bind a task to, and a taskId behaves like a capability token in practice: whoever guesses or intercepts one can read the result behind it. Bind every task to the client credentials that created it, check that binding on every tasks/get and tasks/update call, rotate identifiers if they are exposed in logs or URLs, and never log a task ID at info level. Move task state out of process memory into Redis or Postgres, run expiry cleanup on a schedule so orphaned records do not accumulate into a slow-motion bill increase, and enforce a concurrency cap with a bounded queue so a burst of long jobs cannot starve the event loop. Then instrument the path: emit spans keyed by taskId, counters for completion, failure and cancellation, and a duration histogram, because the histogram is what tells you whether your TTL and poll interval are set for the workloads you actually receive.
Step 5: Test the Failure Paths, Not the Happy Path
Ask your coding agent for a table-driven suite over the lifecycle, then explicitly ask for the adversarial cases: cancellation mid-flight, duplicate creation keys under concurrent load, tasks/get against a task that never reached a terminal state, an expired TTL, a server restart against a durable store, out-of-order notification delivery and a result larger than the client's payload limit. Property-based testing pays for itself here - have the agent state the invariants first, such as terminal states absorbing every later transition and timestamps never going backwards, then generate thousands of random transition sequences that try to violate them. Finish with an integration test that drives a real client against your server as a subprocess, because the capability handshake and the polling loop are exactly the parts that unit tests with mocks never exercise.
Best AI Tools for Building Task-Aware MCP Servers in 2026
Claude Code is the strongest primary driver for this work: it reads specification sections, scaffolds a multi-file server and writes the state machine, though it will over-engineer if you do not scope the prompt. Cursor's agent mode is better at inline diffs and refactoring an existing server, at the cost of aggressive context pruning on large repositories, so keep a rules file current. Codex CLI and Gemini CLI are cheap ways to produce parallel scaffolding and schema drafts, but they hold a long architecture thread less reliably. Cline works well when you want an open-source client with explicit plan and act phases against a well-specified task, and Aider is the cleanest choice for surgical edits and a tidy commit history during a refactor. The order that works: Claude Code or Cursor to design and implement, a cheaper agent to generate the test matrix, and a git-native tool to land the changes.
Tips and Common Mistakes
Testing with a fast fixture is the most common mistake, because a task that finishes in 300 milliseconds never exposes the races you are trying to prevent. Keeping task state in process memory is fine for a demo and fatal with two replicas. Treating cancelled as a synonym for failed confuses two different signals, one a user choice and one a defect. Letting the agent invent error codes produces a taxonomy nobody can handle, so hand it the specification's error values and require them. Returning an unbounded result payload will break the client that was supposed to receive it, so chunk large outputs or return a resource link. Skipping capability negotiation means returning a handle to a client that will never poll it. Forgetting TTL cleanup leaves orphaned tasks behind. Retry storms are avoidable by resuming an existing task instead of creating a second one, and the last mistake is trusting the agent's first draft of the state machine - always make it enumerate every legal transition and show why the illegal ones cannot happen.
Where to Go Next
Ship the smallest end-to-end slice first: one slow tool, one handler that returns a durable handle, one client that polls and renders the result. Then layer durability, cancellation, authorization and instrumentation on top. The teams that struggle with the MCP Tasks extension are rarely struggling with the protocol; they are struggling because they tried to build the whole thing at once instead of making a single cancellable job work first.
Do I need to rewrite my MCP server to support the Tasks extension?
What happened to tasks/list and tasks/result?
Can I use Tasks with a client that does not support the extension?
How long can a task run before it expires?
Is task cancellation guaranteed?
Sources & References
Keep exploring AI trends
New analyses are refreshed daily and labeled by the evidence currently attached to them.
Related Signals
View analysis →
MCP Authorization Security in 2026: Harden OAuth 2.1 Token Audiences and ScopesView analysis →
Model Context Protocol in 2026: The MCP Ecosystem ExplainedView analysis →
MCP Servers in 2026: What They Are and How to Build OneView analysis →
AI Agent Sandbox in 2026: Contain Untrusted Agent Code with Zero Blast RadiusView analysis →
LLM Observability in 2026: Tracing, Evals, and Guarding Production AIView analysis →
ABOUT THE ANALYST
Vento Lee
Senior AI Trends Analyst
Vento Lee brings over a decade of experience tracking developer ecosystems, enterprise software markets, and emerging technology trends. Every analysis on Trending Hot combines quantitative signal processing (Google Trends, Reddit, Product Hunt, GitHub, Hacker News) with qualitative market context to help you act on emerging AI opportunities early.
Generated on September 15, 2026