Client task support is opt-in. Install the
fastmcp-tasks package (pip install "fastmcp[tasks]") and import it — importing fastmcp_tasks anywhere (which you do to use call_tool_task) enables task support for every Client in the process. Without it, a Client never advertises the tasks capability, so the server runs its calls synchronously and background tasks simply don’t happen.Tasks also require the modern protocol. The capability is negotiated over 2026-07-28 connections. mode="auto" (the client default) negotiates it automatically; mode="legacy" never does. See protocol negotiation.Transparent Calls
With task support enabled, just call the tool. If the server runs it as a background task,call_tool polls it to completion under the hood and returns the same result you’d get from a synchronous call — the task is invisible.
Driving a Task Explicitly
When you want to do other work while a task runs — or check on it, or cancel it — usecall_tool_task instead. It returns a ToolTask handle immediately rather than waiting for completion.
call_tool_task requires the server to actually run the call as a task — if the tool isn’t task=True, or the server doesn’t have the tasks extension registered, it raises ToolError. Use it when you specifically need the handle; use call_tool when you just want the result.
Checking Status
Waiting with Control
task.wait() polls until a terminal state (or a specific one you name), without answering any input the task asks for — use it when you want to observe an input_required pause yourself rather than have it answered automatically.
Getting the Result
task.result() drives the task the rest of the way — including answering any input it asks for — and returns the finished result, same as client.call_tool would. Awaiting the task directly is shorthand for this.
ToolError. Pass raise_on_error=False to call_tool_task to get an error result back instead.
Cancellation
Answering Questions Mid-Task
A task can pause partway through to ask a question, the same way a foreground multi-round-trip tool does. Pass anelicitation_handler and both call_tool and task.result() answer it automatically as part of driving the task to completion:
elicitation_handler, a task that asks for input raises ToolError rather than hanging. See server-side background tasks for how a tool asks a question in the first place.
Example
Putting it together, here is a client that submits a background task withcall_tool_task and awaits its result:

