PrefectHQ/fastmcp · error · RuntimeError

Stateful proxy requires a per-connection server session; no

Error message

Stateful proxy requires a per-connection server session; no connection is available on the current context.

What it means

new_stateful() creates a per-connection stateful proxy client keyed on the server Connection object, which it extracts from the current ServerSession via session._connection. If no Connection is attached to the session (e.g. the proxy client is being created outside a live MCP connection context), it raises RuntimeError because there is no stable per-connection object to key the cache and cleanup on.

Source

Thrown at fastmcp_slim/fastmcp/server/providers/proxy.py:1848

    async def clear(self):
        """Clear all cached clients and force disconnect them."""
        while self._caches:
            _, cache = self._caches.popitem()
            await cache._disconnect(force=True)

    def new_stateful(self) -> Client[ClientTransportT]:
        """Create a new stateful proxy client instance with the same configuration.

        Use this method as the client factory for stateful proxy server.
        """
        session = get_context().session
        # SDK v2: the ServerSession is per-request; the Connection is the stable
        # per-connection object that owns the exit stack. Key the cache and the
        # cleanup callback off it so one proxy client is reused for the whole
        # connection instead of one per request.
        connection = getattr(session, "_connection", None)
        if connection is None:
            raise RuntimeError(
                "Stateful proxy requires a per-connection server session; "
                "no connection is available on the current context."
            )
        proxy_client = self._caches.get(connection, None)

        if proxy_client is None:
            proxy_client = self.new()
            logger.debug(f"{proxy_client} created for {connection}")
            self._caches[connection] = proxy_client

            async def _on_connection_exit():
                self._caches.pop(connection, None)
                logger.debug(f"{proxy_client} will be disconnect")
                # This callback runs while the connection's exit stack is
                # unwinding, which usually happens because the owning task is
                # being cancelled. Shield the disconnect so the forced cleanup
                # actually runs to completion instead of aborting at the first
                # cancellation checkpoint (e.g. acquiring the session lock).

View on GitHub (pinned to 1f02114297)

Solutions

  1. Only create stateful proxy clients inside a live request/connection context where a ServerSession with its Connection exists
  2. In tests, construct a real ClientSession/Connection pair (or a stub object exposing _connection) instead of a bare mock session
  3. Fall back to a non-stateful proxy client when no connection context is available, if statefulness isn't required

Example fix

// before: fails outside a connection
client = provider.new_stateful(session)  # session is a bare mock
// after: guard on connection presence
connection = getattr(session, '_connection', None)
client = provider.new_stateful(session) if connection else provider.new_client()
Defensive patterns

Strategy: try-catch

Validate before calling

connection = getattr(session, '_connection', None)
if connection is None:
    raise RuntimeError('new_stateful() requires a live MCP connection context')

Type guard

def has_connection(session) -> bool:
    return getattr(session, '_connection', None) is not None

Try / catch

try:
    client = provider.new_stateful(session)
except RuntimeError as e:
    if 'no connection is available' in str(e):
        client = provider.new_client()  # stateless fallback

Prevention

When it happens

Trigger: Calling new_stateful() (or a stateful proxy client factory) from a context where the ServerSession has no _connection attribute — e.g. in tests without a real transport, in in-memory/off-protocol invocation, or during startup before any client connects.

Common situations: Unit-testing stateful proxies without spinning up a real server session; calling the factory from background tasks or non-MCP entry points; SDK version changes where the session/connection wiring differs.

Related errors


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