Max Narditdata & ai systems
← Articles
7 mindev

MCP Tasks and elicitation in Claude Code: a question nobody may be there to answer

Claude Code now hands a long job to an MCP server and checks back on it. Once it does, the client stops owning that job: no time limit after backgrounding, no cancel on exit, and a question from a running task that only a person at a terminal can answer. Deadlines and cleanup land on the server author.

Contents

On October 23 the Claude Code team announced support for MCP Tasks and Elicitations: “Tasks let Claude give plugins long-running jobs such as deep research and report back when they’re done,” and elicitations “let plugins ask users for input mid-task.” Both are available in the Claude Code CLI today, with other Claude products to follow.

The @ClaudeDevs post announcing MCP Tasks and Elicitations in Claude, October 23, 2026

Post on X, October 23, 2026, reproduced for review.

Each phrase in that post carries an operational detail the post leaves out. “Report back” is Claude Code polling your server. “Long-running” means no time limit on the client side, and also no cancel when you quit. “Ask users for input mid-task” works when a user is at a terminal; in a headless run, a question from a task ends the task.

The replies asked the same things: how long can a task run, what if the client disconnects, who answers a task that stops to ask something overnight. The Claude Code MCP docs answer most of it in their tables. For the rest I wrote a small stdio server that logs every message, pointed Claude Code 2.1.310 at it, and watched the wire. One run per condition, so read the test results as observations, not guarantees.

What did Claude Code ship for MCP Tasks and elicitation?

MCP Tasks are new: public beta in the Claude Code CLI from v2.1.304, released October 19. Elicitation is not. Claude Code has shown elicitation dialogs since v2.1.76 in March and added URL mode in v2.1.281. What this release adds is elicitation inside a running task.

In the protocol, tasks started as an experimental core feature in the 2025-11-25 revision, and 2026-07-28 moved them into the io.modelcontextprotocol/tasks extension, with polling through tasks/get and answers through tasks/update.

Per the docs, a call becomes a task only on a server connected on revision 2026-07-28, in a session that fetches feature flags (so not on Bedrock, and not with telemetry off), and from the main conversation, not a subagent. Terminal sessions, the Agent SDK and GitHub Actions qualify; the VS Code extension, the desktop app and a one-shot claude -p "<prompt>" don’t. A stream-json or SDK session needs CLAUDE_AUTO_BACKGROUND_TASKS=1, and its input has to stay open, or the run ends without waiting for the task. My one-shot run confirmed the exclusion: the tools/call arrived without the tasks extension, and the server had to answer inline.

How does an MCP Task run in Claude Code?

By polling, so “report back” is a loop on the client side. The server answers tools/call with a task handle instead of a result, Claude Code moves the call into the background, and it asks tasks/get on the server’s pollIntervalMs until the task ends. Claude Code doesn’t use the extension’s push notifications.

My server asked for 3 seconds between polls and got that, to the logger’s 10 ms resolution. Trimmed from the log, seconds since start:

 3.31 IN  tools/call  build_report  capabilities include io.modelcontextprotocol/tasks
 3.31 OUT result: resultType "task", status "working", pollIntervalMs 3000
 3.32 IN  tasks/get   -> working
 6.32 IN  tasks/get   -> working
 9.32 IN  tasks/get   -> working
12.32 IN  tasks/get   -> working
15.32 IN  tasks/get   -> completed, result

The docs clamp the interval to between 250 ms and 30 seconds, with 2 seconds when the field is missing. The model gets a short tool result saying the server started a task and the result will come as a notification. When it comes, it goes to Claude, not into the transcript. An idle Claude picks it up unprompted; otherwise type a prompt asking for it.

How long can an MCP Task run in Claude Code?

As long as the server keeps it alive. Per the docs, a backgrounded task has no Claude Code time limit, and Claude Code doesn’t drop it when its ttlMs passes. The tool-call limits apply only until the server answers with the task handle: the wall-clock limit (about 28 hours by default) and the idle timeout, by default five minutes for HTTP servers and thirty for stdio, adjustable with CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT.

That distinction got lost in the replies. One read:

a task that sends no progress notification for the idle window gets killed, five minutes for connector servers, thirty for stdio.

That is the rule for a plain tool call, or for a task you make Claude wait on with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS=0. A backgrounded task has no idle limit.

What happens to an MCP Task when Claude Code exits or disconnects?

A task on a remote server keeps running, and nothing asks the server to stop. The docs say tasks/cancel goes out when Claude or you stop the task while the server is connected, and is “not sent on exit,” even when the exit dialog lists the task among things that will stop. And a cancel is only a request: the extension makes cancellation cooperative, so the server may finish the work anyway.

To get the result later, resume the same session interactively, with the server’s name and settings unchanged. A new session, --fork-session or a one-shot claude -p --resume won’t follow the old task. Stdio is a trap here: the server is Claude Code’s child process and goes with it on exit, even though /tasks labels the job “survives exiting this session.”

If the server forgets the ID, Claude Code keeps asking for five minutes, then reports the outcome as unknown, and the docs warn that a second call may repeat the work. A repeated build wastes minutes; a repeated research job or outbound message is a duplicate you pay for.

Who answers an MCP elicitation from a task overnight?

Nobody, and the two unattended modes fail differently. I gave the test server a tool that switches to input_required after a few seconds and asks two things in inputRequests: a form elicitation (“Include unpublished drafts in the report?”) and roots/list.

In the stream-json claude -p run, the tasks/cancel request came right after the input_required poll; both carry the same timestamp in my log, 9.57 seconds. Per the docs, Claude Code doesn’t run your Elicitation hooks or the SDK’s onElicitation callback here, so the hook that can auto-answer elicitation elsewhere can’t rescue a headless task. The model was told the task “asked the user a question that this session cannot show yet,” and reported a failure.

In an interactive session in a detached tmux pane, the form appeared and waited. While it was open, Claude Code stopped polling: no tasks/get between 8.80 and 48.78 seconds, when I answered. To the server, a task waiting on an absent person looks like a client that went quiet. On the client side, claude agents --json reported the session as waiting with "waitingFor": "input needed", the signal an orchestrator can route to a person, as in driving Claude Code from tmux.

When I accepted, one tasks/update carried both answers, the form and the roots. Claude Code sent my form answer straight to the server. Asked about the result afterwards, Claude said it “never saw the question” and “didn’t answer it,” and it knew what I had agreed to only because my test server echoed the answers back in its result.

Form mode has one more rule worth repeating. The docs illustrate it with “a username and password prompt,” but the MCP elicitation spec says servers “MUST NOT use form mode elicitation to request sensitive information such as passwords, API keys, access tokens, or payment credentials,” and must use URL mode for those. In Claude Code, URL mode passes the link to your system’s URL handler, capped per the docs at about 8,000 characters, closer to 4,000 if the URL is mostly percent-escapes.

How do you add MCP Tasks to an MCP server for Claude Code?

Advertise the extension, return a task handle only when a request asks for one, and keep the task ID answerable from any connection. The server lists io.modelcontextprotocol/tasks under extensions in its server/discover capabilities. On revision 2026-07-28 each request carries the client’s capabilities in _meta, and a tools/call that can become a task includes the same extension. Per the docs, returning a task to a call without it gives Claude Unsupported result type 'task' for tools/call.

The handle is the JSON-RPC result of the tools/call. From the server-author section of the docs:

json
{
  "resultType": "task",
  "taskId": "build-7f3a9c2e",
  "status": "working",
  "statusMessage": "Compiling, 40 of 212 files done",
  "createdAt": "2026-10-22T14:03:07Z",
  "lastUpdatedAt": "2026-10-22T14:03:07Z",
  "ttlMs": null,
  "pollIntervalMs": 5000
}

After that, tasks/get answers with "resultType": "complete", the same required fields, and a result on completed or an error on failed; tasks/update takes answers and tasks/cancel takes stops. Claude Code ignores tasks/result, tasks/list and notifications/tasks. On an HTTP server, answer with the handle within the per-request timer, which is the largest of 60 seconds, the server’s tool timeout and MCP_TIMEOUT, then do the work.

The durable ID is what Tasks ask of a server. Revision 2026-07-28 removed protocol sessions, and servers that need state across calls mint their own handles. A stateless server, like the read-only MCP endpoint I compared with an API catalog, can’t offer Tasks without storage that outlives a single request.

MCP Tasks hand the lifecycle of a long job to the server author

Put the four behaviors side by side. Once a call is backgrounded, Claude Code stops timing it. It doesn’t cancel on exit. It stops polling while a question is open. And with nobody at a terminal, it asks the server to cancel instead of asking a person. Maybe that is the design, maybe it is where a public beta happens to stand. Either way the sum today is the same: the server author owns the job’s deadline, its cleanup and its duplicates, often in a tool written on the assumption that the client would watch.

So the work this week is server-side. Put your own timeout on input_required, because in my test the client went silent for as long as the form stayed open, and an overnight form stays open all night. Make the tool safe to call twice, or give it a status tool, since “outcome unknown” invites a retry. Ask for what you can as tool arguments up front; a headless caller will end the task rather than wait. And keep secrets out of forms.

The image I keep from the test is the tmux pane: a form sitting open with nobody to read it, and a server that had heard from its client every three seconds now hearing nothing, with no way to tell a slow human from an absent one.

01 / Discussion

No comment section here — all discussions happen on X.

Max Nardit@mnardit

02 / More articles