PrefectHQ/fastmcp · warning

Using in-memory token storage -- tokens will be lost when th

Error message

Using in-memory token storage -- tokens will be lost when the client restarts. For persistent storage across multiple MCP servers, provide an encrypted AsyncKeyValue backend. See https://gofastmcp.com/clients/auth/oauth#token-storage for details.

What it means

OAuthTokenStorage defaults to an in-memory `MemoryStore` when no `token_storage` backend is supplied. Tokens then disappear on process restart and are not shared across servers, so FastMCP emits a `UserWarning` pointing at the persistent AsyncKeyValue option.

Source

Thrown at fastmcp_slim/fastmcp/client/auth/oauth.py:327

            metadata = client_metadata.model_dump(exclude_none=True)
            # Default token_endpoint_auth_method based on whether a secret is
            # provided, unless the caller already set it via additional_client_metadata.
            if "token_endpoint_auth_method" not in metadata:
                metadata["token_endpoint_auth_method"] = (
                    "client_secret_post" if self._client_secret else "none"
                )
            self._static_client_info = OAuthClientInformationFull(
                client_id=self._client_id,
                client_secret=self._client_secret,
                **metadata,
            )

        token_storage = self._token_storage or MemoryStore()

        if isinstance(token_storage, MemoryStore):
            from warnings import warn

            warn(
                message="Using in-memory token storage -- tokens will be lost when the client restarts. "
                "For persistent storage across multiple MCP servers, provide an encrypted AsyncKeyValue backend. "
                "See https://gofastmcp.com/clients/auth/oauth#token-storage for details.",
                stacklevel=2,
            )

        # Use full URL for token storage to properly separate tokens per MCP endpoint
        self.token_storage_adapter: TokenStorageAdapter = TokenStorageAdapter(
            async_key_value=token_storage, server_url=mcp_url
        )

        self.mcp_url = mcp_url

        super().__init__(
            server_url=mcp_url,
            client_metadata=client_metadata,
            storage=self.token_storage_adapter,
            redirect_handler=self.redirect_handler,

View on GitHub (pinned to 1f02114297)

Solutions

  1. Pass a persistent encrypted backend, e.g. `token_storage=FileStore(...)` or another `AsyncKeyValue` implementation (Redis, etc.).
  2. Wrap the store with the encryption layer as documented at gofastmcp.com/clients/auth/oauth#token-storage.
  3. If the process is intentionally short-lived (a one-shot CLI script), silence the warning deliberately with `warnings.filterwarnings("ignore", message="Using in-memory token storage")`.
  4. Reuse one storage backend instance across clients to share tokens across MCP servers.

Example fix

// before
oauth = OAuth(server_url="https://mcp.example.com")
// after
from key_value.aio.stores.file import FileStore
storage = FileStore(directory="~/.fastmcp/tokens")  # pair with encryption as documented
oauth = OAuth(server_url="https://mcp.example.com", token_storage=storage)
Defensive patterns

Strategy: validation

Validate before calling

from fastmcp.client.auth.oauth import MemoryStore
def uses_persistent_storage(token_storage) -> bool:
    return not isinstance(token_storage, MemoryStore) or token_storage is None and False

Type guard

def is_memory_store(token_storage) -> bool:
    from fastmcp.client.auth.oauth import MemoryStore
    return isinstance(token_storage, MemoryStore)

Try / catch

import warnings
with warnings.catch_warnings(record=True) as caught:
    warnings.simplefilter("always")
    oauth = OAuth(server_url=url)
if any("in-memory token storage" in str(w.message) for w in caught):
    logging.warning("OAuth tokens are ephemeral; configure a persistent AsyncKeyValue store")

Prevention

When it happens

Trigger: Creating `OAuth()` / OAuth client auth without passing `token_storage=`; explicitly passing `MemoryStore()`; the `_bind` hook called from `__init__` detects the MemoryStore instance.

Common situations: Quick-start OAuth examples run in dev; long-lived daemons restarting and forcing users to re-authenticate; multi-server setups expecting shared tokens.

Related errors


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