60e0ffc959
Upgrade checks / Notify on failure (push) Has been cancelled
Upgrade checks / Close issue on success (push) Has been cancelled
Schema Crash Test / Real-world schema crash test (232K schemas) (push) Has been cancelled
Run static analysis / static_analysis (push) Has been cancelled
Tests / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Tests / Tests with lowest-direct dependencies (push) Has been cancelled
Tests / MCP conformance tests (push) Has been cancelled
Tests / Integration tests (push) Has been cancelled
Tests / Package install smoke (push) Has been cancelled
Upgrade checks / Static analysis (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Upgrade checks / Integration tests (push) Has been cancelled
Update MCPServerConfig Schema / update-config-schema (push) Has been cancelled
Update SDK Documentation / update-sdk-docs (push) Has been cancelled
297 lines
11 KiB
Plaintext
297 lines
11 KiB
Plaintext
---
|
|
title: Storage Backends
|
|
sidebarTitle: Storage Backends
|
|
description: Configure persistent and distributed storage for caching and OAuth state management
|
|
icon: database
|
|
tag: NEW
|
|
---
|
|
|
|
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>
|
|
|
|
## Available Backends
|
|
|
|
### In-Memory Storage
|
|
|
|
**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.
|
|
|
|
```python
|
|
from key_value.aio.stores.memory import MemoryStore
|
|
|
|
# Used by default - no configuration needed
|
|
# But you can also be explicit:
|
|
cache_store = MemoryStore()
|
|
```
|
|
|
|
**Characteristics:**
|
|
- ✅ No setup required
|
|
- ✅ Very fast
|
|
- ❌ Data lost on restart
|
|
- ❌ Not suitable for multi-process deployments
|
|
|
|
### File Storage
|
|
|
|
**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.
|
|
|
|
```python
|
|
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)
|
|
```
|
|
|
|
<Warning>
|
|
**Sanitization strategies are required** when using `FileTreeStore`. Without them, keys containing special characters (such as URL-based OAuth client IDs like `https://claude.ai/oauth/claude-code-client-metadata`) will be used as-is in filesystem paths, causing `FileNotFoundError` crashes. The V1 strategies shown above are safe defaults — alphanumeric names pass through as-is for readability, while special characters are hashed to prevent path errors and traversal attacks. Changing sanitization strategies after data has been written is a breaking change, so choose your strategy upfront.
|
|
</Warning>
|
|
|
|
**Characteristics:**
|
|
- ✅ Data persists across restarts
|
|
- ✅ No external dependencies
|
|
- ✅ Human-readable files on disk
|
|
- ❌ Not suitable for distributed deployments
|
|
- ❌ Filesystem access required
|
|
|
|
### Redis
|
|
|
|
**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.
|
|
|
|
```python
|
|
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:
|
|
|
|
```python
|
|
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:
|
|
|
|
```python
|
|
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:**
|
|
- ✅ Distributed and highly available
|
|
- ✅ Fast in-memory performance
|
|
- ✅ Works across multiple server instances
|
|
- ✅ Built-in TTL support
|
|
- ❌ Requires Redis infrastructure
|
|
- ❌ Network latency vs local storage
|
|
|
|
### Other Backends from py-key-value-aio
|
|
|
|
The py-key-value-aio library includes additional implementations for various storage systems:
|
|
|
|
- **DynamoDB** - AWS distributed database
|
|
- **MongoDB** - NoSQL document store
|
|
- **Elasticsearch** - Distributed search and analytics
|
|
- **Memcached** - Distributed memory caching
|
|
- **RocksDB** - Embedded high-performance key-value store
|
|
- **Valkey** - Redis-compatible server
|
|
|
|
For configuration details on these backends, consult the [py-key-value-aio documentation](https://github.com/strawgate/py-key-value).
|
|
|
|
<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>
|
|
|
|
## Use Cases in FastMCP
|
|
|
|
### Server-Side OAuth Token Storage
|
|
|
|
The [OAuth Proxy](/servers/auth/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:
|
|
- **Mac/Windows**: Keys are auto-managed via system keyring, storage defaults to disk. Suitable **only** for development and local testing.
|
|
- **Linux**: Keys are ephemeral, storage defaults to memory.
|
|
|
|
No configuration needed:
|
|
|
|
```python
|
|
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:
|
|
|
|
```python
|
|
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](/deployment/http#oauth-token-security) and [Key and Storage Management](/servers/auth/oauth-proxy#key-and-storage-management) for complete setup details.
|
|
|
|
### Response Caching Middleware
|
|
|
|
The [Response Caching Middleware](/servers/middleware#caching-middleware) caches tool calls, resource reads, and prompt requests. Storage configuration is passed via the `cache_storage` parameter:
|
|
|
|
```python
|
|
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:
|
|
|
|
```python
|
|
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)
|
|
```
|
|
|
|
### Client-Side OAuth Token Storage
|
|
|
|
The [FastMCP Client](/clients/client) uses storage for persisting OAuth tokens locally. By default, tokens are stored in memory:
|
|
|
|
```python
|
|
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.
|
|
|
|
## Choosing a Backend
|
|
|
|
| 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:**
|
|
|
|
1. **Just starting?** Use **Memory** (default) - no configuration needed
|
|
2. **Single server, needs persistence?** Use **File**
|
|
3. **Multiple servers or cloud deployment?** Use **Redis** or **DynamoDB**
|
|
4. **Existing infrastructure?** Look for a matching py-key-value-aio backend
|
|
|
|
## More Resources
|
|
|
|
- [py-key-value-aio GitHub](https://github.com/strawgate/py-key-value) - Full library documentation
|
|
- [Response Caching Middleware](/servers/middleware#caching-middleware) - Using storage for caching
|
|
- [OAuth Token Security](/deployment/http#oauth-token-security) - Production OAuth configuration
|
|
- [HTTP Deployment](/deployment/http) - Complete deployment guide
|