{"record":{"id":"d64b5726819fbb8d","repo":"PrefectHQ/fastmcp","slug":"progress-dependency-requires-a-fastmcp-server-cont","errorCode":null,"errorMessage":"Progress dependency requires a FastMCP server context.","messagePattern":"Progress dependency requires a FastMCP server context\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/dependencies.py","lineNumber":1221,"sourceCode":"\n\nclass Progress(Dependency[\"Progress\"]):\n    \"\"\"Progress dependency that works in both server and worker contexts.\n\n    In a Docket worker, delegates to the execution's Redis-backed progress\n    (observable across processes). Otherwise, uses in-memory tracking.\n\n    The shared default instance acts as a stateless factory — ``__aenter__``\n    creates a fresh ``Progress`` per invocation so concurrent tasks never\n    share mutable state.\n    \"\"\"\n\n    _impl: ProgressLike | None = None\n\n    async def __aenter__(self) -> Progress:\n        server_ref = _current_server.get()\n        if server_ref is None or server_ref() is None:\n            raise RuntimeError(\"Progress dependency requires a FastMCP server context.\")\n\n        instance = Progress()\n\n        if is_docket_available():\n            try:\n                from docket.dependencies import current_execution\n\n                instance._impl = current_execution.get().progress\n                return instance\n            except LookupError:\n                pass\n\n        instance._impl = InMemoryProgress()\n        return instance\n\n    async def __aexit__(\n        self,\n        exc_type: type[BaseException] | None,","sourceCodeStart":1203,"sourceCodeEnd":1239,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/dependencies.py#L1203-L1239","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Use Progress only inside tool/resource/prompt handlers executed through the FastMCP server request path","In tests, run handlers via fastmcp's in-memory Client so the server contextvar is set","For background work, capture and restore the context (FastMCP's background context mechanism) before entering Progress","Don't store the Progress instance beyond the request scope; create it fresh per request"],"exampleFix":"// before\nasync def worker():\n    with Progress() as p:  # RuntimeError: no server context\n        p.increment()\n// after\nasync def my_tool(progress: Progress) -> str:  # injected inside request\n    await progress.increment()\n    return \"ok\"","handlingStrategy":"type-guard","validationCode":"from fastmcp.server import dependencies\nserver = dependencies._current_server.get()\nif server is None or server() is None:\n    raise SkipProgress  # handle before entering Progress","typeGuard":"def in_server_context() -> bool:\n    from fastmcp.server import dependencies\n    ref = dependencies._current_server.get()\n    return ref is not None and ref() is not None","tryCatchPattern":"try:\n    async with Progress() as progress:\n        await progress.set_total(10)\nexcept RuntimeError as e:\n    if 'server context' in str(e):\n        logger.warning('progress unavailable outside request')","preventionTips":["Accept Progress as an injected handler parameter instead of constructing it","Create Progress per request; don't cache instances across requests or tasks","Use context-propagating task spawning inside handlers","Run tests via the fastmcp in-memory Client, not direct function calls"],"tags":["progress","context","fastmcp"],"backgroundTag":"no-active-server-context","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}