PrefectHQ/fastmcp · error · RuntimeError

Progress dependency requires a FastMCP server context.

Error message

Progress dependency requires a FastMCP server context.

What it means

The Progress dependency is request-scoped: entering it looks up the current FastMCP server from a contextvar (_current_server) holding a weak reference. If no server is active (or the referenced server was garbage-collected), it raises this RuntimeError because progress notifications can only be sent within a live server request.

Source

Thrown at fastmcp_slim/fastmcp/server/dependencies.py:1221


class Progress(Dependency["Progress"]):
    """Progress dependency that works in both server and worker contexts.

    In a Docket worker, delegates to the execution's Redis-backed progress
    (observable across processes). Otherwise, uses in-memory tracking.

    The shared default instance acts as a stateless factory — ``__aenter__``
    creates a fresh ``Progress`` per invocation so concurrent tasks never
    share mutable state.
    """

    _impl: ProgressLike | None = None

    async def __aenter__(self) -> Progress:
        server_ref = _current_server.get()
        if server_ref is None or server_ref() is None:
            raise RuntimeError("Progress dependency requires a FastMCP server context.")

        instance = Progress()

        if is_docket_available():
            try:
                from docket.dependencies import current_execution

                instance._impl = current_execution.get().progress
                return instance
            except LookupError:
                pass

        instance._impl = InMemoryProgress()
        return instance

    async def __aexit__(
        self,
        exc_type: type[BaseException] | None,

View on GitHub (pinned to 1f02114297)

Solutions

  1. Use Progress only inside tool/resource/prompt handlers executed through the FastMCP server request path
  2. In tests, run handlers via fastmcp's in-memory Client so the server contextvar is set
  3. For background work, capture and restore the context (FastMCP's background context mechanism) before entering Progress
  4. Don't store the Progress instance beyond the request scope; create it fresh per request

Example fix

// before
async def worker():
    with Progress() as p:  # RuntimeError: no server context
        p.increment()
// after
async def my_tool(progress: Progress) -> str:  # injected inside request
    await progress.increment()
    return "ok"
Defensive patterns

Strategy: type-guard

Validate before calling

from fastmcp.server import dependencies
server = dependencies._current_server.get()
if server is None or server() is None:
    raise SkipProgress  # handle before entering Progress

Type guard

def in_server_context() -> bool:
    from fastmcp.server import dependencies
    ref = dependencies._current_server.get()
    return ref is not None and ref() is not None

Try / catch

try:
    async with Progress() as progress:
        await progress.set_total(10)
except RuntimeError as e:
    if 'server context' in str(e):
        logger.warning('progress unavailable outside request')

Prevention

When it happens

Trigger: Entering `with Progress() as progress:` outside an MCP request — direct function calls in scripts/tests, background tasks spawned without context propagation, or code run after the server request finished (weakref expired).

Common situations: Unit tests invoking tool functions directly instead of through a client; asyncio.create_task inside a tool losing the contextvar; long-lived workers holding a Progress beyond the request lifetime.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/d64b5726819fbb8d. Report an issue: GitHub.