PrefectHQ/fastmcp · error · RuntimeError

request_id is not available because the MCP session has not

Error message

request_id 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.request_id returns the unique MCP request ID from the request_context. When the MCP session has not been established (request_context is None — e.g. the Context is not attached to an in-flight request), there is no request ID to report, so a RuntimeError is raised and the message tells you to check request_context for None first.

Source

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

            return False
        return client_supports_extension(session, extension_id)

    @property
    def client_id(self) -> str | None:
        """Get the client ID if available."""
        rc = self.request_context
        return (
            rc.meta.get("client_id") if rc is not None and rc.meta is not None else None
        )

    @property
    def request_id(self) -> str:
        """Get the unique ID for this request.

        Raises RuntimeError if MCP request context is not available.
        """
        if self.request_context is None:
            raise RuntimeError(
                "request_id is not available because the MCP session has not been established yet. "
                "Check `context.request_context` for None before accessing this attribute."
            )
        return str(self.request_context.request_id)

    @property
    def session_id(self) -> str:
        """Get the MCP session ID for ALL transports.

        Returns the session ID that can be used as a key for session-based
        data storage (e.g., Redis) to share data between tool calls within
        the same client session.

        Returns:
            The session ID for StreamableHTTP transports, or a generated ID
            for other transports.

        Raises:

View on GitHub (pinned to 1f02114297)

Solutions

  1. Gate access on the context: only read ctx.request_id when ctx.request_context is not None.
  2. Move code that needs request_id into the request path (tool/resource/prompt execution, request-scoped middleware).
  3. Use a fallback identifier (e.g. generated uuid) when request_context is None.
  4. In background tasks, capture request_id before spawning the task.

Example fix

// before
async def tool(x: int, ctx: Context):
    log.info("rid=%s", ctx.request_id)  # may raise
// after
async def tool(x: int, ctx: Context):
    rid = ctx.request_id if ctx.request_context is not None else "no-request"
    log.info("rid=%s", rid)
Defensive patterns

Strategy: type-guard

Validate before calling

rid = str(ctx.request_context.request_id) if ctx.request_context is not None else None

Type guard

def has_request_context(ctx) -> bool:
    return ctx.request_context is not None

Try / catch

try:
    rid = ctx.request_id
except RuntimeError:
    rid = str(uuid.uuid4())  # no active request

Prevention

When it happens

Trigger: Accessing ctx.request_id inside code that runs outside a request lifecycle: at import/setup time, inside on_initialize before the first request, in background tasks, or in tests that build a Context manually.

Common situations: Logging middleware hooks that fire before a request exists; startup code calling request_id to correlate logs; unit tests exercising tools without a client session.

Related errors


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