<!-- description: MCP Tasks is an experimental spec that turns synchronous tool calls into durable state machines — poll for status, retrieve results later, and handle mid-task human input. Here's what it means for long-running AI agents. -->
<!-- date: 2026-03-30 -->
<!-- author: AgentRQ Team -->
<!-- ogimage: https://agentrq.com/assets/og-image.png -->

# MCP Tasks: How the Protocol Is Growing Up for Long-Running Agents

There's a design assumption baked into most AI tool calls today: they finish fast.

You send a request, the tool runs, you get a result. It's synchronous. The agent waits, the tool returns, the model continues. This works fine for looking up a file, running a shell command, or fetching a URL.

It breaks badly when the tool takes minutes — or hours. Or when it needs to ask a human something mid-execution. Or when you want to fire off ten tool calls and not block waiting for each one.

**MCP Tasks**, introduced in the [November 2025 spec revision](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks.md) and currently experimental, is the protocol's answer to this. It turns tool calls into durable state machines that can be polled, queried, and retrieved asynchronously.

## The Problem With Synchronous Tool Calls

Standard MCP tool calls are request/response pairs. The client sends `tools/call`, the server runs the tool, and the client blocks until the result comes back. This is fine for fast operations, but creates three real problems as agents get more capable:

**Long-running operations block the model.** If a tool call takes three minutes, the model sits idle for three minutes. It can't process other work, respond to other inputs, or do anything useful while waiting.

**Expensive computations have no durability.** If the connection drops mid-execution, the work is lost. There's no way to reconnect and pick up where you left off.

**Human-in-the-loop is awkward.** When a tool needs human approval or input partway through, there's no clean mechanism to pause execution, surface the question, wait for a response, and resume.

Tasks solve all three.

## What Tasks Actually Are

A task is a durable state machine wrapping a request. Instead of blocking until completion, the server immediately returns a `CreateTaskResult` with a task ID and status. The client then polls for updates and retrieves the result when it's ready.

The lifecycle looks like this:

**1. Create**: Client sends a normal request with an extra `task` field:

```json
{
  "method": "tools/call",
  "params": {
    "name": "run_long_analysis",
    "arguments": { "dataset": "q1-2026" },
    "task": { "ttl": 3600000 }
  }
}
```

The server accepts immediately and returns:

```json
{
  "result": {
    "task": {
      "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
      "status": "working",
      "pollInterval": 5000,
      "ttl": 3600000
    }
  }
}
```

**2. Poll**: Client polls `tasks/get` at the suggested `pollInterval` (5 seconds here). The model is free to do other work in the meantime.

**3. Retrieve**: Once the task reaches `completed`, the client calls `tasks/result` to get the actual tool output — which looks exactly like a normal tool call response would.

## The Status State Machine

Tasks move through a defined set of states:

- **`working`** — executing
- **`input_required`** — paused, needs something from the requestor
- **`completed`** — done successfully
- **`failed`** — execution failed
- **`cancelled`** — explicitly cancelled

The only valid transitions are: `working` → any terminal state (or `input_required`), and `input_required` → `working` (or any terminal state). Terminal states are permanent — a completed task can never go back to `working`.

This makes the state machine predictable. You always know where you stand.

## The `input_required` Status Is the Interesting One

Most of the spec is mechanical plumbing. `input_required` is where things get genuinely novel.

When a task enters `input_required`, it means the server needs something from the client to continue — typically user input, approval, or a decision. The server signals this through the task status, the client calls `tasks/result` (which blocks, streaming back the server's requests), the human provides input, and the task resumes.

This is the protocol-level primitive for **human-in-the-loop workflows**. The task doesn't fail or time out while waiting for input — it pauses cleanly, surfaces a request, and continues once answered. The model can track this through the polling cycle just like any other status change.

For anyone building agents that need real human oversight — not just a rubber-stamp approval dialog, but genuine mid-task interaction — this is the right abstraction.

## What This Means for Agent Architectures

Tasks make two patterns practical that were previously fragile:

**Concurrent tool dispatch.** Because tool calls no longer block, a client can fire multiple task-augmented requests simultaneously and poll all of them. The model dispatches several expensive operations at once and handles results as they arrive. Parallelism is now a protocol feature, not a client-side hack.

**Reconnectable execution.** Tasks have TTLs and stable IDs. If a client disconnects, it can reconnect later and retrieve the result. The server retains completed task results until the TTL expires. This makes long-running agent sessions resilient to network interruptions.

## The Capability Negotiation Is Worth Understanding

Tasks aren't automatically available for all tool calls. Servers must declare task support in their capabilities, and individual tools can declare `execution.taskSupport` as `"optional"`, `"required"`, or `"forbidden"`.

The `"required"` case is particularly interesting: a tool can mandate that clients use task augmentation. This lets servers expose computationally expensive operations that should never be called synchronously — if you try to call them as a normal blocking request, the server returns an error.

This is a clean way to enforce architectural constraints at the protocol level rather than in documentation that developers may or may not read.

## Where This Sits Today

Tasks are experimental. The spec is in the November 2025 revision and may evolve. A few rough edges are visible — the `input_required` handling with Streamable HTTP transports is explicitly noted as complex, and the spec acknowledges that some guidance is "non-binding and provisional."

But the core model is solid. Durable task IDs, a predictable state machine, polling with suggested intervals, TTL-based cleanup, and a clean separation between task metadata and actual results — these are the right primitives.

The shift from synchronous tool calls to tasks mirrors a broader shift in how capable AI agents actually behave. Fast, stateless tools made sense when agents were answering questions. Long-running, pauseable, reconnectable tasks make sense when agents are doing work.

## AgentRQ and Tasks

This is exactly the problem space AgentRQ lives in. We've been building the human-in-the-loop layer on top of MCP — the task board, the notification channel, the reply mechanism — because agents doing real work need to communicate with humans, not just return strings.

The MCP Tasks spec formalizes this at the protocol level. As the ecosystem catches up, the same patterns that make AgentRQ useful today will be natively supported by MCP clients and servers across the board.

If you're building agents that do anything more complex than a single-step tool call, Tasks is worth understanding now.

---

*The MCP Tasks specification is in the [November 2025 revision](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks.md) of the Model Context Protocol.*
