Tasks: running long jobs without blowing the timeout
The Tasks extension moves to first class in MCP 2026-07-28. How to run long jobs without timeouts, double execution, or pulling the user out of the chat.
The Tasks extension moves to first class in the MCP 2026-07-28 revision. It solves a problem every server that does more than reading eventually hits: a tool call that runs too long.
The problem
A tool call is a request. A request has a timeout, often several, stacked: the client, your reverse proxy, your host, your runtime.
As soon as your tool passes thirty seconds or so, you enter a zone where behaviour depends on which layer gives out first. The typical symptom: works locally, fails in production, and the agent retries, which launches a second run of an expensive job that was already running.
The affected cases are always the same: large exports, document or image generation, batch processing, fetching from a slow external service, expensive computation.
The workarounds people used before
Making the request last. Holds until the first intermittent timeout, and ties up a connection.
Returning a tracking link. Pulls the user out of the chat, which is exactly what MCP was meant to avoid.
Returning a home-made identifier and asking the agent to come back. It works, but every server invents its own convention, and the agent has to guess how often to poll.
Tasks standardises that last approach.
What it changes
The long-running operation becomes a first-class object: it is started, it has a state, it can be followed, and its result is retrieved when ready. The client knows how to handle that lifecycle without a bespoke convention.
Concrete benefits for you:
- No more random timeouts on heavy jobs
- No more double execution caused by agent retries
- A natural place for progress, if you want to expose it
- A job that survives an instance dying, if you built it right
That last point is the link to the rest of the revision. A durable task is shared storage, not process state. Which is exactly what the stateless migration asks for anyway.
How to design it
A task is a domain entity. It has a table, a status, an owner, a timestamp, a result, a retention period. Do not keep it in memory.
Make starting idempotent. If the agent fires the same request twice, you do not want two exports. An idempotency key supplied by the caller, or derived from the parameters, handles it.
Check the owner on read. A task identifier travels through a conversation. It must be worthless to anyone else.
Plan expiry. How long the result is kept, how it is purged. Otherwise your table becomes an accidental archive.
Get the failure state right. A failed task must say why, and say whether retrying is worth it. An ambiguous error turns one failure into a loop.
When not to use it
If your operation takes two seconds, a synchronous call stays simpler and nicer. Tasks adds states to manage, on the server and in the experience.
Rule of thumb: under ten seconds, synchronous. Over thirty, a task. In between, look at your real distribution rather than your average, because it is the tail that breaks.
FAQ
Do all clients support Tasks?
It is an extension, evolving on its own schedule. Plan a reasonable degraded path for clients that do not.
Does it replace my webhooks?
No. Tasks covers the lifecycle of an operation an agent requested. Outbound notifications to other systems remain a separate concern.
What if I already have a job queue?
Good, you have most of it. What remains is exposing the lifecycle through the extension instead of your own convention.
Get your long-running work designed
This is one of the things the audit looks at, alongside state storage and idempotency. A full build runs €4,500 to €7,500 depending on scope.
Interested? Talk about my MCP server →
Related reading
Got an MCP server to audit?
Five minutes to describe it. I reply within one business day with a first written diagnosis, free of charge.
Get my MCP server audited
