PrefectHQ/fastmcp · error · RuntimeError
session is not available because the MCP session has not bee
Error message
session is not available because the MCP session has not been established yet. Check `context.request_context` for None before accessing this attribute.
What it means
Context.session returns the low-level MCP ServerSession. It prefers the per-request session from request_context, falls back to a stored session (e.g. during on_initialize), and raises RuntimeError when neither exists — i.e. no MCP session has been established for this Context.
Source
Thrown at fastmcp_slim/fastmcp/server/context.py:814
In request mode: Returns the session from the active request context.
In background task mode: Returns the session stored at Context creation.
Raises RuntimeError if no session is available.
"""
# Background task mode: use the stored session
if self.is_background_task and self._session is not None:
return self._session
# Request mode: use request context
if self.request_context is not None:
return self.request_context.session
# Fallback to stored session (e.g., during on_initialize)
if self._session is not None:
return self._session
raise RuntimeError(
"session is not available because the MCP session has not been established yet. "
"Check `context.request_context` for None before accessing this attribute."
)
# Convenience methods for common log levels
async def debug(
self,
message: str,
logger_name: str | None = None,
extra: Mapping[str, Any] | None = None,
) -> None:
"""Send a `DEBUG`-level message to the connected MCP Client.
Messages sent to Clients are also logged to the `fastmcp.server.context.to_client` logger with a level of `DEBUG`."""
await self.log(
level="debug",
message=message,
logger_name=logger_name,View on GitHub (pinned to 1f02114297)
Solutions
- Call session-dependent code only from within a request handler or after on_initialize has stored a session.
- Check ctx.request_context is not None (or wrap in try-except RuntimeError) before accessing ctx.session.
- Pass the session explicitly into helpers instead of reading it from Context at arbitrary times.
- For on_initialize-era code, rely on the stored-session fallback rather than caching ctx.session yourself.
Example fix
// before
async def helper(ctx: Context):
await ctx.session.send_log_message(level="info", data="hi") # may raise
// after
async def helper(ctx: Context):
if ctx.request_context is not None:
await ctx.session.send_log_message(level="info", data="hi") Defensive patterns
Strategy: type-guard
Validate before calling
session = ctx.request_context.session if ctx.request_context is not None else None
Type guard
def session_available(ctx) -> bool:
return ctx.request_context is not None or getattr(ctx, "_session", None) is not None Try / catch
try:
session = ctx.session
except RuntimeError:
session = None # no MCP session established yet Prevention
- Gate low-level session calls on ctx.request_context being present.
- In on_initialize handlers, rely on the stored-session fallback rather than caching the session yourself.
- Keep helper functions session-free; pass the session in as a parameter.
When it happens
Trigger: Accessing ctx.session in code that runs before a session exists: outside any request, after the request finished (stale Context), or during early lifecycle phases where neither request_context nor the stored _session is set.
Common situations: Direct low-level session.send_* calls from helpers invoked at import time; tests instantiating Context manually; middleware that runs before initialization completes and assumes a session is present.
Related errors
- request_id is not available because the MCP session has not
- session_id is not available because no session exists. This
- FastMCP instance is no longer available
- Unexpected CreateTaskResult: Context calls should not have t
- No access token available. Cannot perform OBO exchange.
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/e59aa28756cc62f4.
Report an issue: GitHub.