PrefectHQ/fastmcp · error · RuntimeError

No active context found. This can happen if: - Called outs

Error message

No active context found. This can happen if:
  - Called outside an MCP request handler
  - Called in a background task before the context was established
Check `context.request_context` for None before accessing.

What it means

FastMCP exposes a Context dependency that resolves the active per-request MCP context from a contextvar; in background tasks it first consults a snapshot factory (_background_context_factory) captured when the task was spawned. If neither a live request context nor a captured background context exists, entering the context manager raises this RuntimeError. The library throws it because there is genuinely no MCP request in flight, so request-scoped data (session, request_context) cannot be provided.

Source

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

    async def __aenter__(self) -> Context:
        from fastmcp.server.context import _current_context

        # Try foreground context first (normal MCP request)
        context = _current_context.get()
        if context is not None:
            return context

        # In a background-task worker there is no foreground context; the tasks
        # extension installs a factory that builds and enters a worker Context
        # from the restored task snapshot. Core has no task engine of its own,
        # so this is None unless the extension is active.
        factory = _background_context_factory
        if factory is not None:
            background = await factory()
            if background is not None:
                return background

        raise RuntimeError(
            "No active context found. This can happen if:\n"
            "  - Called outside an MCP request handler\n"
            "  - Called in a background task before the context was established\n"
            "Check `context.request_context` for None before accessing."
        )

    async def __aexit__(
        self,
        exc_type: type[BaseException] | None,
        exc_value: BaseException | None,
        traceback: TracebackType | None,
    ) -> None:
        from fastmcp.server.context import _current_context

        ctx = _current_context.get()
        if ctx is not None and ctx.is_background_task:
            await ctx.__aexit__(exc_type, exc_value, traceback)

View on GitHub (pinned to 1f02114297)

Solutions

  1. Only access Context inside code executed as part of an MCP request (tool/resource/prompt handler invoked via a client)
  2. If you must run background work, capture the context snapshot before spawning (FastMCP's background context factory) or pass needed data explicitly as arguments
  3. Guard with `if ctx.request_context is not None` where the API allows, or check availability before entering
  4. In tests, use fastmcp's in-memory Client fixture so handlers run inside a real request context

Example fix

// before
async def cleanup():
    with Context() as ctx:
        await ctx.info("done")
// after
async def my_tool(ctx: Context) -> str:
    await ctx.info("done")  # ctx provided by the request
    return "ok"
Defensive patterns

Strategy: type-guard

Validate before calling

from fastmcp.server.dependencies import get_http_request, _current_request
# availability probe
in_request = _current_request.get() is not None

Type guard

def has_active_context() -> bool:
    from fastmcp.server import dependencies
    ctx = dependencies._current_context.get(None)
    return ctx is not None or dependencies._background_context_factory is not None

Try / catch

try:
    async with Context() as ctx:
        await ctx.info("working")
except RuntimeError as e:
    if "No active context" in str(e):
        logger.warning("context unavailable; skipping request-scoped logging")

Prevention

When it happens

Trigger: Calling `with Context() as ctx:` (async) from code running outside an MCP request handler — e.g. in a plain asyncio task, at module import, in tests, or in a background worker spawned without capturing the context.

Common situations: Scheduling asyncio.create_task from a tool without the context snapshot mechanism; unit tests calling tool functions directly instead of through a client; logging/telemetry code that touches ctx after the request ended.

Related errors


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