PrefectHQ/fastmcp · error · RuntimeError

FastMCP instance is no longer available

Error message

FastMCP instance is no longer available

What it means

The Context.fastmcp property returns the FastMCP server instance via a weak/optional reference (self._fastmcp()). When the reference has been cleared — the server is gone or the Context outlived the request lifecycle — the property raises RuntimeError instead of returning None, forcing callers to handle the loss of the server explicitly.

Source

Thrown at fastmcp_slim/fastmcp/server/context.py:266

    @property
    def origin_request_id(self) -> str | None:
        """Get the request ID that originated this execution, if available.

        In foreground request mode, this is the current request_id.
        In background task mode, this is the request_id captured when the task
        was submitted, if one was available.
        """
        if self.request_context is not None:
            return str(self.request_context.request_id)
        return self._origin_request_id

    @property
    def fastmcp(self) -> FastMCP:
        """Get the FastMCP instance."""
        fastmcp = self._fastmcp()
        if fastmcp is None:
            raise RuntimeError("FastMCP instance is no longer available")
        return fastmcp

    async def __aenter__(self) -> Context:
        """Enter the context manager and set this context as the current context."""
        # Inherit request-scoped state from parent context so middleware
        # and tool contexts share the same in-memory state dict.
        parent = _current_context.get(None)
        if parent is not None:
            self._request_state = parent._request_state

        # Always set this context and save the token
        token = _current_context.set(self)
        self._tokens.append(token)

        # Set current server for dependency injection (use weakref to avoid reference cycles)
        from fastmcp.server.dependencies import _current_server, is_docket_available

        self._server_token = _current_server.set(weakref.ref(self.fastmcp))

View on GitHub (pinned to 1f02114297)

Solutions

  1. Use the Context within the request that produced it; capture needed server data (settings, server name) before the request ends.
  2. Check ctx.request_context (or the underlying reference) before touching .fastmcp in deferred code.
  3. For background work, fetch the server via module-level imports or dependency functions instead of the Context.
  4. If you only need it opportunistically, call self._fastmcp() equivalents defensively / wrap in try-except RuntimeError.

Example fix

// before
async def tool(x: int, ctx: Context):
    asyncio.create_task(later(ctx))  # ctx.fastmcp may be gone
// after
async def tool(x: int, ctx: Context):
    srv = ctx.fastmcp  # resolve while request is alive
    asyncio.create_task(later(srv))
Defensive patterns

Strategy: try-catch

Validate before calling

srv = ctx._fastmcp() if callable(getattr(ctx, "_fastmcp", None)) else None
# only proceed if srv is not None

Type guard

def fastmcp_available(ctx) -> bool:
    try:
        return ctx._fastmcp() is not None
    except Exception:
        return False

Try / catch

try:
    server = ctx.fastmcp
except RuntimeError:
    server = get_server_from_registry()  # fallback lookup

Prevention

When it happens

Trigger: Accessing ctx.fastmcp on a Context whose backing request lifecycle has ended: e.g. holding a Context reference in a closure or background coroutine and reading .fastmcp after the request completes, or a Context created outside a server run.

Common situations: Background tasks or fire-and-forget asyncio tasks capturing ctx and touching it later; long-lived worker threads using a stale Context; tests instantiating Context directly without a bound server.

Related errors


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