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
- Pass a persistent encrypted backend, e.g. `token_storage=FileStore(...)` or another `AsyncKeyValue` implementation (Redis, etc.).
- Wrap the store with the encryption layer as documented at gofastmcp.com/clients/auth/oauth#token-storage.
- 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")`.
- 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
- Always pass a persistent encrypted AsyncKeyValue backend for long-running clients
- Share one storage instance across clients that should share tokens
- Only use MemoryStore for throwaway scripts, suppressing the warning explicitly
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
- Cannot specify 'required_scopes' when providing a custom tok
- Missing required OIDC endpoints
- AzureProvider requires at least one non-OIDC scope in requir
- Could not extract project_id from config_url: {issuer_url}
- module {__name__!r} has no attribute {name!r}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/873e076b7cfb4161.
Report an issue: GitHub.