Add storage backend documentation (#2137)

* Add storage backend documentation

* Add storage patterns documentation for wrapper caching strategies

- Add PassthroughCacheWrapper section for multi-tier caching
- Document TTL clamping strategy for optimized memory usage
- Add example for wrapping custom storage implementations
- Explain how to combine fast in-memory caches with persistent remote stores

* Update docs
This commit is contained in:
Jeremiah Lowin 2025-10-19 19:24:13 -04:00 committed by GitHub
commit b362444ddf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 322 additions and 18 deletions

View file

@ -3,7 +3,6 @@ title: User Elicitation
sidebarTitle: Elicitation
description: Handle server-initiated user input requests with structured schemas.
icon: message-question
tag: NEW
---
import { VersionBadge } from "/snippets/version-badge.mdx";

View file

@ -3,6 +3,7 @@ title: Upgrade Guide
sidebarTitle: Upgrade Guide
description: Migration instructions for upgrading between FastMCP versions
icon: up
tag: NEW
---
This guide provides migration instructions for breaking changes and major updates when upgrading between FastMCP versions.

View file

@ -107,15 +107,16 @@
"group": "Advanced Features",
"icon": "stars",
"pages": [
"servers/icons",
"servers/context",
"servers/proxy",
"servers/composition",
"servers/context",
"servers/elicitation",
"servers/icons",
"servers/logging",
"servers/middleware",
"servers/progress",
"servers/proxy",
"servers/sampling",
"servers/middleware"
"servers/storage-backends"
]
},
{

View file

@ -3,7 +3,6 @@ title: Authentication
sidebarTitle: Overview
description: Secure your FastMCP server with flexible authentication patterns, from simple API keys to full OAuth 2.1 integration with external identity providers.
icon: user-shield
tag: NEW
---
import { VersionBadge } from "/snippets/version-badge.mdx"

View file

@ -3,7 +3,7 @@ title: Full OAuth Server
sidebarTitle: Full OAuth Server
description: Build a self-contained authentication system where your FastMCP server manages users, issues tokens, and validates them.
icon: users-between-lines
tag: NEW
---
import { VersionBadge } from "/snippets/version-badge.mdx"

View file

@ -210,16 +210,34 @@ These parameters are included in all token requests to the upstream provider.
</ParamField>
<ParamField body="client_storage" type="KVStorage | None">
<ParamField body="client_storage" type="AsyncKeyValue | None">
Storage backend for persisting OAuth client registrations and encrypted upstream tokens. By default, clients are automatically persisted to disk in `~/.config/fastmcp/oauth-proxy-clients/`, allowing them to survive server restarts as long as the filesystem remains accessible. This means MCP clients only need to register once and can reconnect seamlessly after your server restarts.
For production deployments with token persistence, use this with `jwt_signing_key` and `token_encryption_key` - all three work together to ensure tokens survive restarts. See [OAuth Token Security](/deployment/http#oauth-token-security).
For production deployments with multiple servers or cloud deployments, see [Storage Backends](/servers/storage-backends) for options including Redis, DynamoDB, and custom implementations.
For production token persistence, use this with `jwt_signing_key` and `token_encryption_key` - all three work together to ensure tokens survive restarts. See [OAuth Token Security](/deployment/http#oauth-token-security).
Testing with in-memory storage:
```python
from fastmcp.utilities.storage import InMemoryStorage
from key_value.aio.stores.memory import MemoryStore
# Use in-memory storage for testing (clients lost on restart)
auth = OAuthProxy(..., client_storage=InMemoryStorage())
auth = OAuthProxy(..., client_storage=MemoryStore())
```
Production with Redis for distributed deployments:
```python
from key_value.aio.stores.redis import RedisStore
import os
auth = OAuthProxy(
...,
jwt_signing_key=os.environ["JWT_SIGNING_KEY"],
token_encryption_key=os.environ["TOKEN_ENCRYPTION_KEY"],
client_storage=RedisStore(host="redis.example.com", port=6379)
)
```
</ParamField>

View file

@ -3,7 +3,6 @@ title: Token Verification
sidebarTitle: Token Verification
description: Protect your server by validating bearer tokens issued by external systems.
icon: key
tag: NEW
---
import { VersionBadge } from "/snippets/version-badge.mdx"

View file

@ -1,6 +1,6 @@
---
title: Server Composition
sidebarTitle: Server Composition
sidebarTitle: Composition
description: Combine multiple FastMCP servers into a single, larger application using mounting and importing.
icon: puzzle-piece
---

View file

@ -3,7 +3,6 @@ title: User Elicitation
sidebarTitle: Elicitation
description: Request structured input from users during tool execution through the MCP context.
icon: message-question
tag: NEW
---
import { VersionBadge } from '/snippets/version-badge.mdx'

View file

@ -2,6 +2,7 @@
title: Icons
description: Add visual icons to your servers, tools, resources, and prompts
icon: image
tag: NEW
---
import { VersionBadge } from '/snippets/version-badge.mdx'

View file

@ -461,9 +461,9 @@ from fastmcp.server.middleware.caching import ResponseCachingMiddleware
mcp.add_middleware(ResponseCachingMiddleware())
```
Out of the box, it caches call/list tool, resources, and prompts to an in-memory cache. Sending a notification of a tool/resource/prompt change will invalidate the cache for the affected method. List calls are stored under global keys, if you share a key_value backend across servers, keep this in mind and consider using the PrefixCollectionsWrapper in py-key-value-aio to namespace collections by server.
Out of the box, it caches call/list tool, resources, and prompts to an in-memory cache with TTL-based expiration. Cache entries expire based on their TTL; there is no event-based cache invalidation. List calls are stored under global keys—when sharing a storage backend across multiple servers, consider namespacing collections to prevent conflicts. See [Storage Backends](/servers/storage-backends) for advanced configuration options.
Each method can be configured individually, for example, caching list tools for 30 seconds, skipping caching for tools other than `tool1` and not caching and requests to read resources:
Each method can be configured individually, for example, caching list tools for 30 seconds, limiting caching to specific tools, and disabling caching for resource reads:
```python
from fastmcp.server.middleware.caching import ResponseCachingMiddleware, CallToolSettings, ListToolsSettings, ReadResourceSettings
@ -481,7 +481,11 @@ mcp.add_middleware(ResponseCachingMiddleware(
))
```
It can also be configured to cache to disk:
#### Storage Backends
By default, caching uses in-memory storage, which is fast but doesn't persist across restarts. For production or persistent caching across server restarts, configure a different storage backend. See [Storage Backends](/servers/storage-backends) for complete options including disk, Redis, DynamoDB, and custom implementations.
Disk-based caching example:
```python
from fastmcp.server.middleware.caching import ResponseCachingMiddleware
@ -492,7 +496,31 @@ mcp.add_middleware(ResponseCachingMiddleware(
))
```
See the Contrib modules for caching middleware implementations that support additional features like distributed caching.
Redis for distributed deployments:
```python
from fastmcp.server.middleware.caching import ResponseCachingMiddleware
from key_value.aio.stores.redis import RedisStore
mcp.add_middleware(ResponseCachingMiddleware(
cache_storage=RedisStore(host="redis.example.com", port=6379),
))
```
#### Cache Statistics
The caching middleware collects operation statistics (hits, misses, etc.) through the underlying storage layer. Access statistics from the middleware instance:
```python
from fastmcp.server.middleware.caching import ResponseCachingMiddleware
middleware = ResponseCachingMiddleware()
mcp.add_middleware(middleware)
# Later, retrieve statistics
stats = middleware.statistics()
print(f"Total cache operations: {stats}")
```
### Logging Middleware

View file

@ -0,0 +1,259 @@
---
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
### Disk Storage
**Best for:** Single-server production deployments, persistent caching
Disk storage persists data to the filesystem, allowing it to survive server restarts.
```python
from key_value.aio.stores.disk import DiskStore
from fastmcp.server.middleware.caching import ResponseCachingMiddleware
# Persistent response cache
middleware = ResponseCachingMiddleware(
cache_storage=DiskStore(directory="/var/cache/fastmcp")
)
```
Or with OAuth token storage:
```python
from fastmcp.server.auth.providers.github import GitHubProvider
from key_value.aio.stores.disk import DiskStore
auth = GitHubProvider(
client_id="your-id",
client_secret="your-secret",
base_url="https://your-server.com",
client_storage=DiskStore(directory="/var/lib/fastmcp/oauth")
)
```
**Characteristics:**
- ✅ Data persists across restarts
- ✅ Good performance for moderate load
- ❌ 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"],
token_encryption_key=os.environ["TOKEN_ENCRYPTION_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-aio).
## 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 encrypted upstream tokens. By default, registrations are stored in memory:
```python
# In-memory storage (default behavior - lost on restart)
from fastmcp.server.auth.providers.github import GitHubProvider
auth = GitHubProvider(
client_id="your-id",
client_secret="your-secret",
base_url="https://your-server.com"
)
```
For production with token persistence across restarts, configure persistent storage and encryption keys:
```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",
# Token encryption and signing keys
jwt_signing_key=os.environ["JWT_SIGNING_KEY"],
token_encryption_key=os.environ["TOKEN_ENCRYPTION_KEY"],
# Persistent distributed storage
client_storage=RedisStore(host="redis.example.com", port=6379)
)
```
See [OAuth Token Security](/deployment/http#oauth-token-security) for complete production 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 fastmcp import FastMCP
from fastmcp.server.middleware.caching import ResponseCachingMiddleware
from key_value.aio.stores.disk import DiskStore
mcp = FastMCP("My Server")
# Cache to disk instead of memory
mcp.add_middleware(ResponseCachingMiddleware(
cache_storage=DiskStore(directory="cache")
))
```
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 fastmcp.client.auth import OAuthClientProvider
from key_value.aio.stores.disk import DiskStore
# Store tokens on disk for persistence across restarts
token_storage = DiskStore(directory="~/.local/share/fastmcp/tokens")
oauth_provider = OAuthClientProvider(
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 | ❌ | ❌ |
| Disk | ✅ 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 **Disk**
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-aio) - 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