PrefectHQ/fastmcp · error · RuntimeError
FastMCP instance is no longer available
Error message
FastMCP instance is no longer available
What it means
LowLevelServer keeps only a weak reference (weakref.ref) to the FastMCP instance to avoid a circular reference (fastmcp_slim/fastmcp/server/low_level.py:459). The `fastmcp` property dereferences that weakref, and if the FastMCP object has been garbage collected it raises this RuntimeError instead of returning None. It is a lifecycle bug in user code, not an MCP protocol error: the low-level server outlived the FastMCP server it wraps.
Source
Thrown at fastmcp_slim/fastmcp/server/low_level.py:511
# the server was constructed without an explicit `request_state_security`
# policy, seal under a per-process ephemeral key (single-process
# deployments); multi-replica deployments pass a shared-key policy. The
# low-level server always has a name (FastMCP autogenerates one), so the
# audience claim is always populated.
security = fastmcp._request_state_security or RequestStateSecurity.ephemeral()
self.middleware.append(
cast(
"ServerMiddleware[LifespanResultT]",
RequestStateBoundary(security, default_audience=self.name),
)
)
@property
def fastmcp(self) -> FastMCP:
"""Get the FastMCP instance."""
fastmcp = self._fastmcp_ref()
if fastmcp is None:
raise RuntimeError("FastMCP instance is no longer available")
return fastmcp
def create_initialization_options(
self,
notification_options: NotificationOptions | None = None,
experimental_capabilities: dict[str, dict[str, Any]] | None = None,
extensions: dict[str, dict[str, Any]] | None = None,
) -> InitializationOptions:
# ensure we use the FastMCP notification options
if notification_options is None:
notification_options = self.notification_options
return super().create_initialization_options(
notification_options=notification_options,
experimental_capabilities=experimental_capabilities,
extensions=extensions,
)
def get_capabilities(View on GitHub (pinned to 1f02114297)
Solutions
- Keep a strong, long-lived reference to the FastMCP instance (module-level variable, app state, or fixture) for as long as the LowLevelServer/session is alive.
- Construct and store both objects together: `mcp = FastMCP('demo'); llm = LowLevelServer(mcp)` and keep `mcp` in scope.
- If the reference must be dropped, also drop the LowLevelServer/session at the same time so no dangling dereference occurs.
- Check for test-framework garbage collection (e.g. pytest fixtures that del the server) and use a session-scoped fixture to hold the FastMCP instance.
Example fix
# before
server = LowLevelServer(FastMCP('demo')) # FastMCP instance immediately unreachable
run(server)
# after
mcp = FastMCP('demo') # strong reference kept alive
server = LowLevelServer(mcp)
run(server) Defensive patterns
Strategy: type-guard
Validate before calling
import weakref
ref = getattr(server, '_fastmcp_ref', None)
if not isinstance(ref, weakref.ref) or ref() is None:
raise RuntimeError('FastMCP instance was garbage collected; recreate both objects') Type guard
def fastmcp_alive(server) -> bool:
ref = getattr(server, '_fastmcp_ref', None)
return ref is not None and ref() is not None Try / catch
try:
mcp = server.fastmcp
except RuntimeError as e:
if 'no longer available' in str(e):
mcp = FastMCP('demo') # recreate and keep a strong reference
server = LowLevelServer(mcp)
else:
raise Prevention
- Always assign the FastMCP instance to a long-lived variable before constructing LowLevelServer.
- Use session-scoped fixtures in tests so the FastMCP object outlives the server/session.
- Never construct LowLevelServer from a temporary expression like LowLevelServer(FastMCP('x')).
- Check for explicit del or scoping bugs that drop the only reference to the FastMCP instance.
When it happens
Trigger: Accessing `server.fastmcp` (or any code path that touches it, e.g. `create_initialization_options`/`get_capabilities` via the experimental-capability merge) after the FastMCP instance has been garbage collected — typically when only the LowLevelServer was kept alive and the FastMCP object was never assigned to a long-lived variable.
Common situations: Scripts that build a FastMCP server inline (`LowLevelServer(FastMCP('demo'))` without storing the FastMCP instance); test suites where the FastMCP fixture goes out of scope while the session/server object persists; refactors that dropped a module-level or app-level reference to the server.
Related errors
- Client is not connected. Use the 'async with client:' contex
- ClientGroup is already connected
- FastMCP instance is no longer available
- FastMCP server instance is no longer available
- module {__name__!r} has no attribute {name!r}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/b9579f69368c46d8.
Report an issue: GitHub.