docs/servers/storage-backends.mdx
import { VersionBadge } from "/snippets/version-badge.mdx"
<VersionBadge version="2.13.0" />FastMCP uses pluggable storage backends for caching responses and managing OAuth state. By default, all storage is in-memory, which is perfect for development but doesn't persist across restarts. FastMCP includes support for multiple storage backends, and you can easily extend it with custom implementations.
<Tip> The storage layer is powered by **[py-key-value-aio](https://github.com/strawgate/py-key-value)**, an async key-value library maintained by a core FastMCP maintainer. This library provides a unified interface for multiple backends, making it easy to swap implementations based on your deployment needs. </Tip>Best for: Development, testing, single-process deployments
In-memory storage is the default for all FastMCP storage needs. It's fast, requires no setup, and is perfect for getting started.
from key_value.aio.stores.memory import MemoryStore
# Used by default - no configuration needed
# But you can also be explicit:
cache_store = MemoryStore()
Characteristics:
Best for: Single-server production deployments, persistent caching
File storage persists data to the filesystem as one JSON file per key, allowing it to survive server restarts. This is the default backend for OAuth storage on Mac and Windows.
from pathlib import Path
from key_value.aio.stores.filetree import (
FileTreeStore,
FileTreeV1KeySanitizationStrategy,
FileTreeV1CollectionSanitizationStrategy,
)
from fastmcp.server.middleware.caching import ResponseCachingMiddleware
storage_dir = Path("/var/cache/fastmcp")
store = FileTreeStore(
data_directory=storage_dir,
key_sanitization_strategy=FileTreeV1KeySanitizationStrategy(storage_dir),
collection_sanitization_strategy=FileTreeV1CollectionSanitizationStrategy(storage_dir),
)
# Persistent response cache
middleware = ResponseCachingMiddleware(cache_storage=store)
Characteristics:
Best for: Distributed production deployments, shared caching across multiple servers
<Note> Redis support requires an optional dependency: `pip install 'py-key-value-aio[redis]'` </Note>Redis provides distributed caching and state management, ideal for production deployments with multiple server instances.
from key_value.aio.stores.redis import RedisStore
from fastmcp.server.middleware.caching import ResponseCachingMiddleware
# Distributed response cache
middleware = ResponseCachingMiddleware(
cache_storage=RedisStore(host="redis.example.com", port=6379)
)
With authentication:
from key_value.aio.stores.redis import RedisStore
cache_store = RedisStore(
host="redis.example.com",
port=6379,
password="your-redis-password"
)
For OAuth token storage:
import os
from fastmcp.server.auth.providers.github import GitHubProvider
from key_value.aio.stores.redis import RedisStore
auth = GitHubProvider(
client_id=os.environ["GITHUB_CLIENT_ID"],
client_secret=os.environ["GITHUB_CLIENT_SECRET"],
base_url="https://your-server.com",
jwt_signing_key=os.environ["JWT_SIGNING_KEY"],
client_storage=RedisStore(host="redis.example.com", port=6379)
)
Characteristics:
The py-key-value-aio library includes additional implementations for various storage systems:
For configuration details on these backends, consult the py-key-value-aio documentation.
<Warning> Before using these backends in production, review the [py-key-value documentation](https://github.com/strawgate/py-key-value) to understand the maturity level and limitations of your chosen backend. Some backends may be in preview or have specific constraints that make them unsuitable for production use. </Warning>The OAuth Proxy and OAuth auth providers use storage for persisting OAuth client registrations and upstream tokens. By default, storage is automatically encrypted using FernetEncryptionWrapper. When providing custom storage, wrap it in FernetEncryptionWrapper to encrypt sensitive OAuth tokens at rest.
Development (default behavior):
By default, FastMCP automatically manages keys and storage based on your platform:
No configuration needed:
from fastmcp.server.auth.providers.github import GitHubProvider
auth = GitHubProvider(
client_id="your-id",
client_secret="your-secret",
base_url="https://your-server.com"
)
Production:
For production deployments, configure explicit keys and persistent network-accessible storage with encryption:
import os
from fastmcp.server.auth.providers.github import GitHubProvider
from key_value.aio.stores.redis import RedisStore
from key_value.aio.wrappers.encryption import FernetEncryptionWrapper
from cryptography.fernet import Fernet
auth = GitHubProvider(
client_id=os.environ["GITHUB_CLIENT_ID"],
client_secret=os.environ["GITHUB_CLIENT_SECRET"],
base_url="https://your-server.com",
# Explicit JWT signing key (required for production)
jwt_signing_key=os.environ["JWT_SIGNING_KEY"],
# Encrypted persistent storage (required for production)
client_storage=FernetEncryptionWrapper(
key_value=RedisStore(host="redis.example.com", port=6379),
fernet=Fernet(os.environ["STORAGE_ENCRYPTION_KEY"])
)
)
Both parameters are required for production. Wrap your storage in FernetEncryptionWrapper to encrypt sensitive OAuth tokens at rest - without it, tokens are stored in plaintext. See OAuth Token Security and Key and Storage Management for complete setup details.
The Response Caching Middleware caches tool calls, resource reads, and prompt requests. Storage configuration is passed via the cache_storage parameter:
from pathlib import Path
from fastmcp import FastMCP
from fastmcp.server.middleware.caching import ResponseCachingMiddleware
from key_value.aio.stores.filetree import (
FileTreeStore,
FileTreeV1KeySanitizationStrategy,
FileTreeV1CollectionSanitizationStrategy,
)
mcp = FastMCP("My Server")
cache_dir = Path("cache")
cache_store = FileTreeStore(
data_directory=cache_dir,
key_sanitization_strategy=FileTreeV1KeySanitizationStrategy(cache_dir),
collection_sanitization_strategy=FileTreeV1CollectionSanitizationStrategy(cache_dir),
)
# Cache to disk instead of memory
mcp.add_middleware(ResponseCachingMiddleware(cache_storage=cache_store))
For multi-server deployments sharing a Redis instance:
from fastmcp.server.middleware.caching import ResponseCachingMiddleware
from key_value.aio.stores.redis import RedisStore
from key_value.aio.wrappers.prefix_collections import PrefixCollectionsWrapper
base_store = RedisStore(host="redis.example.com")
namespaced_store = PrefixCollectionsWrapper(
key_value=base_store,
prefix="my-server"
)
middleware = ResponseCachingMiddleware(cache_storage=namespaced_store)
The FastMCP Client uses storage for persisting OAuth tokens locally. By default, tokens are stored in memory:
from pathlib import Path
from fastmcp.client.auth import OAuth
from key_value.aio.stores.filetree import (
FileTreeStore,
FileTreeV1KeySanitizationStrategy,
FileTreeV1CollectionSanitizationStrategy,
)
# Store tokens on disk for persistence across restarts
token_dir = Path("~/.local/share/fastmcp/tokens").expanduser()
token_storage = FileTreeStore(
data_directory=token_dir,
key_sanitization_strategy=FileTreeV1KeySanitizationStrategy(token_dir),
collection_sanitization_strategy=FileTreeV1CollectionSanitizationStrategy(token_dir),
)
oauth_provider = OAuth(
mcp_url="https://your-mcp-server.com/mcp/sse",
token_storage=token_storage
)
This allows clients to reconnect without re-authenticating after restarts.
| Backend | Development | Single Server | Multi-Server | Cloud Native |
|---|---|---|---|---|
| Memory | ✅ Best | ⚠️ Limited | ❌ | ❌ |
| File | ✅ Good | ✅ Recommended | ❌ | ⚠️ |
| Redis | ⚠️ Overkill | ✅ Good | ✅ Best | ✅ Best |
| DynamoDB | ❌ | ⚠️ | ✅ | ✅ Best (AWS) |
| MongoDB | ❌ | ⚠️ | ✅ | ✅ Good |
Decision tree: