Requirements
Development Setup
Option 1: Docker Compose (Recommended)
Projects created withfrontmcp create --target node include Docker files in the ci/ folder:
Option 2: Local Installation
Configuration
Production Setup
Managed Redis Services (Recommended)
Self-Hosted Production
For self-hosted Redis in production:Security Best Practices
- Authentication: Always set
REDIS_PASSWORDin production - Network: Run Redis in private network, not exposed to internet
- TLS: Enable TLS for encrypted connections
- Persistence: Use AOF for durability (
appendonly yes)
Configuration Example
redis block to { provider: 'vercel-kv' } when deploying on Vercel KV—the Cache Plugin will keep reusing the same store without code changes.
Running more than one instance
Redis lets several instances share sessions, but each instance still signs and encrypts with its own secrets. Give every instance the same values:
An anonymous session minted by one instance is honored by any instance with the same
MCP_SESSION_SECRET: the instance that receives the request recreates the transport from the stored session (in distributed mode it relays to, or takes over from, the node recorded with that session).
When Redis is unreachable at startup
Not every Redis consumer reacts the same way when Redis is down as the server starts:redisandtransport.persistencelog the failure ([TransportService] Failed to connect to redis - session persistence disabled) and the server starts. The connection is retried in the background with exponential backoff (1s doubling to 30s); once Redis is reachable, sessions are persisted again and/readyzturns healthy without a restart. Until then, sessions live on the instance that created them.- Every Redis connection FrontMCP opens reconnects on its own and logs connection errors at a rate-limited interval (with a count of suppressed repeats) rather than once per retry.
throttle.storagefails closed: rate limits are a security control, so startup aborts withGuardStorageUnavailableError(throttle.storage (redis) is unavailable: …). This is the default in production, where storagefallbackdefaults to'error'. If Redis goes away while the server is running, a rate-limited call is refused with the sameGuardStorageUnavailableErrorrather than an internal error. To keep serving with per-instance counters instead, opt in explicitly (a mid-run outage then logs one warning, uses per-instance counters, and returns to Redis once it answers):
throttle.storage takes the @frontmcp/utils storage shape ({ type: 'redis', redis: { config } } or { type: 'redis', redis: { url } }), not the top-level redis shape.
Environment Variables
Redis Configuration
Plugin Secrets
In development,
REMEMBER_SECRET is auto-generated and stored in .frontmcp/remember-secret.json. Add this file to .gitignore. In production, always set REMEMBER_SECRET explicitly to ensure consistent encryption across instances.Health Checks
Troubleshooting
Connection Refused
- Verify Redis is running:
redis-cli ping - Check firewall rules
- Verify host/port configuration
- If startup fails, or rate-limited calls are refused, with
GuardStorageUnavailableError, thethrottle.storagebackend is down; see When Redis is unreachable at startup
Clients keep re-initializing or tools repeat their questions
- A
404for a session the client just used, on a load-balanced deployment, means the instances run with differentMCP_SESSION_SECRETvalues - A 2026-07-28 tool that asks its first question again after it was answered, with
mcp-20260728: rejected requestStateandreason: 'bad-signature'in the log, meansVAULT_SECRET(orJWT_SECRET) is unset or differs between instances
Authentication Failed
- Ensure
REDIS_PASSWORDmatches server config - Check for special characters in password (may need URL encoding)
Memory Issues
- Set
maxmemoryandmaxmemory-policyin Redis config - Monitor with
redis-cli INFO memory
Docker Network Issues
When using Docker Compose, the app container should useredis as the hostname (the service name), not localhost: