PrefectHQ/fastmcp · error · RuntimeError
Task-enabled tools ({names}) require the tasks extension, bu
Error message
Task-enabled tools ({names}) require the tasks extension, but no extension with identifier {TASKS_EXTENSION_ID!r} is registered. Install it with `pip install 'fastmcp[tasks]'` and register it via `mcp.add_extension(TasksExtension(...))`. What it means
A RuntimeError raised during server startup (_validate_task_extension_registered, invoked by the lifespan manager) when task-enabled tools are registered but the tasks extension (identifier TASKS_EXTENSION_ID) is absent. Docket-backed task execution requires that extension; the error lists the offending tool names and the exact install/registration steps.
Source
Thrown at fastmcp_slim/fastmcp/server/mixins/lifespan.py:142
# fail a child that legitimately relies on the root's registration.
if _lifespan_root_active.get():
return
if TASKS_EXTENSION_ID in self._extensions:
return
candidates = list(await self.get_tasks())
# ``get_tasks()`` applies server-level transforms, which can inject
# non-task tools (e.g. ResourcesAsTools' synthetic list/read tools) into
# the result, so re-filter by the actual task config here — mirroring the
# guard the old per-component docket registration applied.
task_components = [c for c in candidates if c.task_config.supports_tasks()]
if not task_components:
return
names = ", ".join(sorted(c.name for c in task_components))
raise RuntimeError(
f"Task-enabled tools ({names}) require the tasks extension, but no "
f"extension with identifier {TASKS_EXTENSION_ID!r} is registered. "
"Install it with `pip install 'fastmcp[tasks]'` and register it via "
"`mcp.add_extension(TasksExtension(...))`."
)
def _capture_shared_context(self: FastMCP) -> None:
"""Snapshot the live ``SharedContext`` ContextVar values.
The SDK v2 dispatcher runs each request handler in the *message
sender's* contextvars (via ``ContextReceiveStream.last_context``), not
the server-lifespan context. App-scoped ``Shared()`` dependencies rely
on ``uncalled_for.SharedContext`` ContextVars set during the lifespan,
which are therefore invisible to handlers. We capture those values here
so ``FastMCPServerMiddleware`` can re-apply them per request.
"""
try:
self._shared_context_snapshot = {View on GitHub (pinned to 1f02114297)
Solutions
- Install the extra: pip install 'fastmcp[tasks]'.
- Register the extension at startup: mcp.add_extension(TasksExtension(...)).
- If background execution is not intended, remove the task_config/task=True settings from the listed tools so they run inline.
Example fix
// before
mcp = FastMCP("server")
@mcp.tool(task=True)
def report(): ...
# RuntimeError at startup
// after
from fastmcp.server.extensions.tasks import TasksExtension
mcp = FastMCP("server")
mcp.add_extension(TasksExtension())
@mcp.tool(task=True)
def report(): ... Defensive patterns
Strategy: validation
Validate before calling
from fastmcp.server.extensions import TASKS_EXTENSION_ID
registered = {getattr(ext, "identifier", None) for ext in mcp.extensions}
task_tools = [t for t in mcp._tool_manager if getattr(t, "task_config", None) and t.task_config.supports_tasks()]
if task_tools and TASKS_EXTENSION_ID not in registered:
raise RuntimeError(f"install fastmcp[tasks] and add_extension(TasksExtension()) for: {[t.name for t in task_tools]}") Try / catch
try:
mcp.run()
except RuntimeError as e:
if "require the tasks extension" in str(e):
# surface install/registration instructions at deploy time
raise SystemExit(f"deployment misconfiguration: {e}")
raise Prevention
- Install the tasks extra in every environment: pip install 'fastmcp[tasks]'.
- Always pair task-enabled tools with mcp.add_extension(TasksExtension(...)) in the same bootstrap module.
- Add a startup smoke test that constructs the server to catch missing extensions before deploy.
- Keep task_config usage and TasksExtension registration in the same PR/config review.
When it happens
Trigger: Decorating tools with task_config that supports_tasks() (e.g. @mcp.tool(task=True) or a task_config with mode other than forbid) while never calling mcp.add_extension(TasksExtension(...)); happens at lifespan startup, not at decoration time.
Common situations: Upgrading FastMCP and adopting the tasks extension without adding the dependency or registration; deploying with the base package where `fastmcp[tasks]` extra was not installed; copying task-enabled example code into an existing server.
Related errors
- jwt_signing_key is required when upstream_client_secret is n
- '{name}' uses a sync function but has task execution enabled
- User server did not start on port {mcp_port}
- Could not create the CLI state directory
- OAuth provider has no server URL. Either pass mcp_url to OAu
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/8fa17c236f5f81a5.
Report an issue: GitHub.