io.modelcontextprotocol/tasks, SEP-2663), giving your servers a production-ready distributed task scheduler with one extension registration and a decorator change.
What Are MCP Background Tasks?
In MCP, a tool call is blocking by default. When a client calls a tool, it sends a request and waits for the response. For operations that take seconds or minutes, this creates a poor user experience. Background tasks solve this by letting a server tell a supporting client:- Start the tool and return a task ID immediately
- Poll for status as the tool runs
- Retrieve the result when ready — or answer a question the tool asks mid-run
task=True to a tool decorator and register the tasks extension, and your function gains background execution with progress reporting, distributed processing, and horizontal scaling.
MCP Background Tasks vs Python Concurrency
You can always use Python’s concurrency primitives (asyncio, threads, multiprocessing) or external task queues in your FastMCP servers. FastMCP is just Python—run code however you like. MCP background tasks are different: they’re protocol-native. This means MCP clients that support the tasks extension can start a call, poll it, and retrieve its result through the standard MCP interface. The coordination happens at the protocol level, not inside your application code.Enabling Background Tasks
Background tasks require thefastmcp-tasks package:
TasksExtension on your server, then add task=True to a tool decorator. task=True marks the tool as capable of background execution; the extension is what actually runs it — a task=True tool on a server with no tasks extension registered raises at server startup.
client.call_tool(...) looks the same either way.
Background tasks are a modern-protocol feature: the tasks capability is negotiated over 2026-07-28 connections, so a client pinned to mode="legacy" never triggers one — the tool always runs synchronously for it.
Execution Modes
For fine-grained control over task execution behavior, useTaskConfig instead of the boolean shorthand. The tasks extension defines three execution modes:
task=True→TaskConfig(mode="optional")task=False→TaskConfig(mode="forbidden")
mode="required" tool is called by a client that didn’t opt in, FastMCP returns a “missing required capability” error rather than running it synchronously.
Poll Interval
When a client polls for task status, the server can suggest how frequently to check back:Server-Wide Default
To enable background task support for all tools by default, passtasks=True to the constructor. Individual decorators can still override this with task=False.
Configuration
TasksExtension takes the backend configuration directly, with FASTMCP_DOCKET_* environment variables as defaults — so TasksExtension() works out of the box against an env-configured deployment:
Backends
FastMCP supports two backends for task execution, each with different tradeoffs.In-Memory Backend (Default)
The in-memory backend (memory://) requires zero configuration and works out of the box.
Advantages:
- No external dependencies
- Simple single-process deployment
- Ephemeral: If the server restarts, all pending tasks are lost
- Higher latency: ~250ms task pickup time vs single-digit milliseconds with Redis
- No horizontal scaling: Single process only—you cannot add additional workers
Redis Backend
For production deployments, use Redis (or Valkey) as your backend:- Persistent: Tasks survive server restarts
- Fast: Single-digit millisecond task pickup latency
- Scalable: Add workers to distribute load across processes or machines
Credentials at Rest
A background task runs long after the request that submitted it has ended, but it still needs to know who asked for the work. FastMCP captures that identity at submission time in a task context snapshot: the caller’s access token and every inbound HTTP header, includingAuthorization. The worker restores the snapshot before the tool body runs, so get_access_token() and get_http_headers() return the submitting caller.
That snapshot lives in the backend for the task’s TTL. With memory:// it never leaves the process. With Redis or Valkey it is a stored value, and by default it is stored as plaintext JSON. A rediss:// URL encrypts the connection, not the data the backend holds. Anyone who can read the backend can read the tokens.
Set FASTMCP_TASKS_ENCRYPTION_KEY to encrypt the snapshot before it is written:
Workers
Every FastMCP server with task-enabled tools automatically starts an embedded worker. You do not need to start a separate worker process for tasks to execute. To scale horizontally, add more workers:Additional workers only work with Redis/Valkey backends. The in-memory backend is single-process only.
Gathering Input Mid-Task
A tool can ask the client a question partway through — the same guard pattern used for multi-round-trip input on foreground calls: instead of awaiting a response, the tool returns one, and FastMCP re-runs it once the client answers.input_required, the client answers, and FastMCP re-invokes the tool with the answer attached. No worker ever sits idle waiting on a round-trip — the same tool works identically whether it’s called synchronously or as a background task, and a FastMCP client answers the question automatically through its elicitation handler.
Progress Reporting
TheProgress dependency lets you report progress back to clients. Inject it as a parameter with a default value, and FastMCP will provide the active progress reporter.
await progress.set_total(n)— Set the total number of stepsawait progress.increment(amount=1)— Increment progressawait progress.set_message(text)— Update the status message
Docket Dependencies
FastMCP exposes Docket’s full dependency injection system within your task-enabled functions. BeyondProgress, you can access the Docket instance, worker information, and use advanced features like retries and timeouts.
CurrentDocket(), you can schedule additional background tasks, chain work together, and coordinate complex workflows. See the Docket documentation for the complete API, including retry policies, timeouts, and custom dependencies.
