skip to content

In MCP's tasks extension, how does a client feed input to a task already running?

level: middleimportance: should knowfreq 38%

answer

  1. the task parks, it does not ask
  2. a status, not a message to the client
  3. you feed it, you do not re-issue it
  4. the taskId is the address of the update
  5. declining means simply not updating

basics

~10 s

When a task reports the input_required status, the client calls tasks/update with that taskId and supplies what the server asked for. The task then resumes. A running task is never re-issued — only fed.

solid answer

~50 s

In MCP revision 2026-07-28 a task that needs something mid-flight does not fail and does not send the client a request of its own — server-initiated JSON-RPC requests were removed in that revision. Instead the task moves to the `input_required` status, which the client sees on its next `tasks/get` poll or through an optional `notifications/tasks` push. The client then calls `tasks/update`, naming the task by its `taskId` and supplying the input, and the task resumes, normally returning to `working`. The key contrast is with the core protocol: an ordinary call that needs input returns an interim result and the client resolves it by re-issuing the original request with a new JSON-RPC id. A task is already running and already has a durable identity, so there is nothing to re-issue — you update the task in place.

go deeper

for a junior

Remember the pair: the status input_required means the task is waiting for you, and tasks/update is how you answer it.

for a middle

Be able to contrast the two mechanisms cleanly — a task is updated in place via its taskId, while an ordinary call that needs input is resolved by re-issuing the original request with a new JSON-RPC id.

for a senior

Show the operational awareness: a parked task is silent, so poll intervals and server-side park timeouts have to accommodate human-in-the-loop latency, and abandoned tasks should be cancelled rather than left to rot.

for a principal

Own the interaction design — decide which pauses are worth a human round trip at all, and how long the system is willing to hold resources open for an answer that may never come.

## The situation A long-running unit of work often cannot be fully specified up front. A migration hits an ambiguous record and needs a choice. A deployment reaches a gate and needs an approval. A crawler hits an authenticated page and needs a credential. Under MCP revision 2026-07-28 the server cannot simply ask: server-initiated JSON-RPC requests were removed in that revision, so there is no channel down which a running server routine can pose a question and await an answer. The Tasks extension (`io.modelcontextprotocol/tasks`) resolves this with a status plus a method. ## input_required, then tasks/update The task transitions to `input_required`. That is a live, non-terminal status: the work has not failed, it has parked. The client discovers it the same way it discovers any transition — by polling `tasks/get` with the `taskId`, or by receiving an optional `notifications/tasks` push on a `subscriptions/listen` stream if the server offers them. The client then calls `tasks/update`, naming the task and supplying the input the server asked for. The task resumes, typically back to `working`, and eventually reaches a terminal status. The direction of travel is what to remember. Nothing is pushed at the client demanding an answer; the client pulls the fact that input is wanted, and pushes the input back into an existing, identified unit of work. ## The contrast with the core protocol The core protocol has its own answer to "the server needs something from the client", and the two must not be confused. - **Core, synchronous call.** The server returns an interim result whose `resultType` is `"input_required"`. The client satisfies it and then **retries the original request with a new JSON-RPC id**. The original request is finished; a second, fresh request carries the answer forward. - **Task.** The task's *status* becomes `input_required`. The client calls `tasks/update`. The original `tools/call` returned long ago with a handle; the running work is a durable object identified by `taskId`, and it is mutated in place. So the same phrase appears in two roles: `input_required` is a `resultType` value on a synchronous interim result, and a *status* value in the task state machine. A candidate who says "you retry the tools/call" for a task has fused the two mechanisms. The tell is that retrying would start a second task, because a `tools/call` is a request to do work, not a reference to work already in progress. ## Declining In the core pattern, declining is expressed by simply not retrying — there is no error to send back. With a task, the analogous move is not to update it. A client that decides against supplying the input can leave the task parked, or call `tasks/cancel` to ask the server to wind it up, which is the cleaner choice because it lets the server release whatever it is holding. Leaving tasks parked indefinitely is how a server accumulates zombie state, so a well-behaved client cancels what it abandons. ## Practical consequences for clients 1. **You must poll or subscribe to notice.** A task parked in `input_required` is silent by construction. A client that fires a task and only checks back in an hour will have wasted the hour. Poll intervals should be tight enough that a parked task is noticed promptly. 2. **Human-in-the-loop latency is real.** If the input needs a person, the task may sit parked for minutes. The server's own timeouts for a parked task must accommodate that, or interactive tasks will die waiting for their users. 3. **Reconnects are harmless.** The `taskId` is an explicit server-minted handle, so a client that dropped its connection reconnects and calls `tasks/get`. This is the general 2026-07-28 shape — sessions and stream resumability were removed, and durable references are the replacement. 4. **Idempotency of the update.** A client that is unsure whether an update landed should re-read the status rather than blindly resending; if the task has already resumed, a second update for the same pause is at best redundant. ## Interview framing Say it in one sentence and then draw the contrast: a task that needs input parks in the `input_required` status and the client resolves it with `tasks/update` against the `taskId`, whereas an ordinary call that needs input is resolved by re-issuing the original request with a new id. Add that server-initiated requests do not exist in 2026-07-28, so neither path involves the server asking anything, and that declining is expressed by not updating — ideally followed by `tasks/cancel` so the server can clean up.

  • Why can't the task just send the client a request asking for the input?
    Because MCP 2026-07-28 removed server-initiated JSON-RPC requests entirely — there is no ServerRequest union any more. Everything a server needs from a client is expressed as a result or a status the client observes and then acts on. For tasks that is the input_required status plus tasks/update; for ordinary calls it is an interim result the client resolves by re-issuing.
  • How does a client decline to supply the input a task is waiting for?
    By not calling tasks/update. There is no decline message, mirroring the core protocol where declining is expressed by simply not retrying. The considerate follow-up is tasks/cancel, so the server stops holding resources for a task nobody intends to finish; otherwise the parked task is zombie state until the server's own timeout reclaims it.
  • Could a client miss an input_required transition entirely?
    Yes, if it neither polls nor watches notifications/tasks. The parked task is silent, and notifications are best-effort — a push delivered while a subscriptions/listen stream was down is gone, since 2026-07-28 removed resumability. A robust client polls tasks/get on a sane interval and always re-polls after a reconnect.

saying these in an interview costs you the question

  • Says the client retries the original tools/call to supply the input
  • Thinks the server sends the client a request asking for input
  • Treats input_required as a failure that ends the task
  • Believes tasks/update starts a new task rather than resuming one
  • Assumes the client is notified of a parked task without polling or subscribing

context