Claude Code MCP Tasks: Background Jobs and Elicitation

Run long MCP tools without blocking Claude Code. Check version, protocol and feature-flag requirements, return a valid task handle and final result, audit elicitation hooks, and understand what survives cancellation, exit or session changes.

Contents
Claude Code MCP Tasks: Background Jobs and Elicitation

For Claude Code MCP Tasks, use a task-capable MCP server and invoke its tool from the main conversation in the terminal CLI on v2.1.304 or later. The server accepts the job, Claude continues working, and the result returns when the job finishes. Check the eligibility conditions before changing your server: an ordinary tool call moved into the background after two minutes uses a different mechanism.

As of 2026-10-24, Claude Code documents MCP Tasks as a public beta. This guide covers the current 2026-07-28 protocol and the conditions that determine whether your call qualifies.

What Tasks and Elicitation do

Use Tasks for long work that the server can accept and track independently, such as builds, test runs, exports, or research. Use Elicitation when the server needs a decision or missing information from you before proceeding.

Three behaviors can otherwise look similar:

MechanismWhat happensWhat the server must implement
Ordinary MCP callClaude waits for the tool’s result.A normal tool implementation.
Automatic backgroundingA main-conversation call still running after two minutes moves into the background. Its result arrives later, but the background call does not survive exiting the session.No Tasks support is required.
MCP TaskThe server returns a task handle when it accepts the job. Claude Code follows that handle and retrieves the outcome. Remote server jobs can continue after the CLI exits.The Tasks extension and persistent task handling.

Elicitation is a separate capability. A report tool might ask which environment to query, then run the export as a Task. A quick tool can request the same clarification without creating a Task.

Elicitation also predates this rollout: the Claude Code v2.1.76 release introduced elicitation dialogs and the Elicitation and ElicitationResult hooks. The newer capability here is server-managed Tasks.

Check whether your call can become an MCP Task

Every condition in the official eligibility checklist must hold. Installing a newer CLI only satisfies the first row.

CheckRequired condition
Claude Code versionv2.1.304 or later.
Server implementationThe server supports the Tasks extension. An MCP connection alone does not establish support.
Transport and protocolAn HTTP, stdio, or claude.ai connector server connected on protocol revision 2026-07-28.
Legacy overridesNeither MCP_SDK_GENERATION=v1 nor MCP_PROTOCOL_NEGOTIATION=legacy can force the connection onto the older protocol.
Feature availabilityThe session fetches feature flags, and Anthropic enables Tasks for that session type.
Supported surfaceTerminal CLI, Agent SDK, or GitHub Actions. The VS Code extension and desktop app do not currently support MCP Tasks.
CallerThe call originates in the main conversation. Calls made by subagents do not become MCP Tasks.
Input modeAn interactive session, or a qualifying Agent SDK or streaming-input session as described below.

For noninteractive operation, an Agent SDK session or a claude -p run using --input-format stream-json additionally requires:

  • CLAUDE_AUTO_BACKGROUND_TASKS=1
  • CLAUDE_CODE_DISABLE_MCP_TASK_BACKGROUND not set to 1
  • CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS not set to 0

Keep its input open: the run does not wait for MCP Tasks after input closes. A one-shot claude -p "..." invocation does not get Tasks. GitHub Actions being a supported surface does not remove these input-mode requirements.

The environment-variable reference identifies several flag-fetching blockers:

  • DISABLE_GROWTHBOOK=1 or true
  • DO_NOT_TRACK=1
  • Any nonempty DISABLE_TELEMETRY
  • Any nonempty CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC

For the last two variables, even 0 or false disables the relevant behavior. Ordinary third-party-provider sessions, including Amazon Bedrock, also skip flag fetching; the reference documents an exception for host-managed embeddings.

Inspect the launching environment and effective settings. The usual settings files are ~/.claude/settings.json, .claude/settings.json, and .claude/settings.local.json, with managed settings also relevant. The settings reference explains their scopes.

Removing a legacy override cannot upgrade a server that lacks the newer protocol. Likewise, API compatibility through a gateway does not establish feature-flag eligibility. If your deployment must retain a blocking setting, use ordinary tool calls.

For interactive sessions, CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS=0 makes Claude wait. CLAUDE_CODE_DISABLE_MCP_TASK_BACKGROUND=1 also makes it wait for Tasks, although ordinary automatic backgrounding can subsequently move a long call. CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 alone does not force MCP Tasks to stay in the foreground.

Run one job and verify the result

Start with an authenticated server whose documentation or implementation establishes Tasks support, then try one non-destructive job. In Bash, check the installation and configured servers before opening the interactive CLI:

claude --version
claude mcp list
claude

For a self-updating installation below the minimum version, run claude update and recheck. These commands are covered by the CLI reference.

Inside Claude Code, use /mcp to confirm the server is connected and complete any required authentication. For a connected test-runner tool, a useful request is:

Run this repository’s test suite through its MCP tool from the main conversation. While it runs, explain the test layout from the README. When the job finishes, report the result and any failures.

Verify the behavior at two levels:

  1. In Claude Code: look for the MCP task count and inspect /tasks. An entry in /tasks by itself is insufficient because ordinary background calls appear there too.
  2. In your server’s trace: confirm that tools/call returned resultType: "task" and that subsequent tasks/get requests refer to the same taskId.

At completion, Claude Code receives the result; ask Claude to report it. If Claude is idle, it can pick up the result automatically. If the call remains ordinary, inspect the actual request’s capabilities and the eligibility checklist before rewriting the tool.

Server authors: return a handle and deliver the outcome

Implement the current Tasks extension rather than copying an older experimental example. The MCP 2026-07-28 changes replaced tasks/result with polling through tasks/get, added tasks/update, and removed tasks/list.

Return a task only when the request permits it

Check the capability on each request at:

params._meta["io.modelcontextprotocol/clientCapabilities"].extensions["io.modelcontextprotocol/tasks"]

Its value is {}. Your server advertises the corresponding extension under capabilities.extensions in its server/discover response. The Tasks extension overview documents both locations.

When the client declares support, the server decides whether that particular operation should become a Task. Without the capability, return an ordinary result when possible. If the operation requires Tasks, the extension defines the missing-capability error -32021; do not return a task handle to an incapable caller.

Persist the task before replying, so its ID already resolves through tasks/get. Keep it answerable across connections, and check authentication and task access on follow-up requests.

This illustrative JSON-RPC response accepts a build. Its ID, timestamps, and eventual result are examples, not an execution record:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resultType": "task",
    "taskId": "6f17bfa2-4c5e-4d21-b563-2f7e83a902bc",
    "status": "working",
    "createdAt": "2026-10-24T08:00:00Z",
    "lastUpdatedAt": "2026-10-24T08:00:00Z",
    "ttlMs": 3600000,
    "pollIntervalMs": 5000
  }
}

The task fields sit directly inside JSON-RPC result. There is no additional task wrapper, and the initial handle needs no content array.

FieldRequirement
resultType"task" for the initial task response.
taskIdRequired, server-generated, and difficult to guess. Claude Code additionally limits it to 128 printable ASCII characters with no spaces.
statusRequired: working, input_required, completed, failed, or cancelled.
createdAt, lastUpdatedAtRequired ISO 8601 timestamp strings.
ttlMsRequired integer milliseconds measured from creation, or null for unlimited retention. It is not a job-duration estimate.
pollIntervalMsOptional integer polling interval in milliseconds; do not send null.
statusMessageOptional progress or status text.

The released extension schema defines the structure. Claude-specific validation is documented in the server-author reference.

If Claude reports Unsupported result type 'task' for tools/call, check whether the incoming request included the extension, then verify that none of taskId, status, createdAt, lastUpdatedAt, or ttlMs is missing. An unsupported status value produces the same error. An invalid task ID instead produces a malformed-task-handle error.

Put the completed tool result in tasks/get

Answer each poll with the task’s current state. A successful tasks/get response uses resultType: "complete" even while the job’s status remains working: the polling request has completed, not necessarily the job.

For the illustrative build above, a completed response is:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "resultType": "complete",
    "taskId": "6f17bfa2-4c5e-4d21-b563-2f7e83a902bc",
    "status": "completed",
    "createdAt": "2026-10-24T08:00:00Z",
    "lastUpdatedAt": "2026-10-24T08:03:00Z",
    "ttlMs": 3600000,
    "result": {
      "resultType": "complete",
      "content": [
        {
          "type": "text",
          "text": "Build completed successfully."
        }
      ]
    }
  }
}

The nested result contains the normal tool result. A tool-level error using isError: true still belongs in a completed task; failed is reserved for a JSON-RPC execution error carried in error.

Implement tasks/cancel as well, but treat cancellation as cooperative. The extension specification does not guarantee that cancellation stops work already underway. Claude Code currently retrieves outcomes through polling, so do not rely on notifications/tasks to deliver the result.

Use Elicitation for decisions the tool cannot make

Ask for the missing environment, destination, or approval before performing the action that depends on it. Form-mode elicitation collects structured fields; URL mode offers a browser flow, such as external sign-in.

During a Task, expose a question through tasks/get with status: "input_required" and an inputRequests map. Each entry uses a unique key and contains the requested method, such as elicitation/create, plus its params. Claude Code sends the answer through tasks/update, using matching keys in inputResponses.

In the interactive CLI, close /tasks if the question is hidden behind it. Declining or pressing Esc answers the elicitation; the server decides whether its job continues.

For a Task requesting user input in a noninteractive session, Claude Code asks the server to cancel it without running Elicitation hooks or the Agent SDK’s onElicitation callback. Supply required choices before starting unattended work, or use an interactive session. This restriction is specific to input requested through MCP Tasks.

Also audit hooks before treating an elicitation as human approval. The hooks reference documents that:

  • Elicitation can answer automatically and suppress the dialog.
  • ElicitationResult can change the user’s response, including replacing a refusal with acceptance if written incorrectly.
  • ElicitationResult does not run when an Elicitation hook already answered.

Review effective hooks from user, project, local, managed, and plugin configuration. Checking only the repository’s settings file can miss the hook that supplies an answer.

What happens on stop, exit, clear, and resume?

Stop a remote Task explicitly if you want to request cancellation; exiting the CLI does not do that. The documented lifecycle distinguishes server execution from Claude Code’s tracking.

ActionResult and next step
Select the Task in /tasks and press x, or ask Claude to stop itClaude Code stops following it and requests cancellation. The server may still finish.
Press Esc during ordinary interactionThis does not stop a background Task.
Exit while a remote Task runsThe server job continues. Resume its original session to follow it again.
Exit with a stdio TaskThe local server process stops. Do not assume its work survives unless the server explicitly supports execution beyond that process.
Use /clear, /branch, or switch sessions with /resume while Claude Code stays openThe result can arrive in the current conversation. After exiting, resume the session where the Task originally started.
Resume the original session interactivelyTracking resumes after the server reconnects, provided it still knows the Task. Keep its name and connection settings unchanged.
Start a new session or use --fork-sessionThe new session does not inherit tracking of the Task.
Resume through one-shot claude -pThat run does not follow the Task; use interactive resume or qualifying streaming input.

If the server is disconnected, reconnect it through /mcp before stopping the Task. Otherwise no cancellation request reaches it, and Claude Code forgets the Task.

Use claude --resume to select the original conversation. The server’s retention policy still matters: a resumable conversation cannot recover a result the server has discarded.

A prompt to audit your MCP setup

Use a read-only audit to identify the smallest useful change before modifying servers or settings. This prompt adapts @Voxyz_ai’s MCP audit suggestion, adding checks for the current response format and streaming-session behavior.

Goal: Audit my Claude Code MCP setup for Tasks and Elicitation.

Read the current official documentation:
https://code.claude.com/docs/en/mcp
https://code.claude.com/docs/en/env-vars
https://code.claude.com/docs/en/hooks
https://modelcontextprotocol.io/extensions/tasks/overview

Scope: Inspect connected MCP servers, their configuration, effective settings, and any MCP server implementation in this repository. Say explicitly if no server implementation is present. Keep credential values out of the report.

Check:
1. Long-running tools: identify builds, test runs, exports, or research that could benefit from Tasks. For my server code, recommend the smallest change to return a valid task handle, persist it across connections, and deliver the final result through tasks/get. For third-party servers, cite evidence for the deployed version's support; otherwise mark support unknown.
2. Eligibility: check the CLI version, transport, actual protocol revision, per-request Tasks capability, feature-flag fetching, provider, supported surface, main conversation versus subagents, and input mode. Include MCP_SDK_GENERATION, MCP_PROTOCOL_NEGOTIATION, privacy/flag-fetching variables, CLAUDE_AUTO_BACKGROUND_TASKS, CLAUDE_CODE_DISABLE_MCP_TASK_BACKGROUND, and CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS. Distinguish one-shot claude -p from stream-json input.
3. Elicitation: find tools that guess missing parameters or perform irreversible actions without obtaining the necessary decision. Inspect Elicitation and ElicitationResult hooks for automatic acceptance or changes to a user's refusal, including hooks outside this repository.
4. Lifecycle: check cancellation, remote versus stdio execution, retention, and resume. Identify unattended Tasks that might request user input.

Output: For each finding, name the tool or setting, cite the evidence, describe current behavior, recommend the smallest change, and give one verification step. Mark conditions you cannot observe as unknown.

Do not edit files, change settings, or invoke operational jobs during this audit. Show recommendations first.

Ready to optimize your LLM workflow?

Join thousands of developers building faster, smarter, and more cost-effective AI applications with BetterToken.

Get Started for Free