FrontMCP supports multi-pod deployments with automatic session failover. When a pod dies, surviving pods detect the failure via Redis heartbeat keys and atomically claim orphaned sessions using a Lua CAS (compare-and-swap) script.Documentation Index
Fetch the complete documentation index at: https://docs.agentfront.dev/llms.txt
Use this file to discover all available pages before exploring further.
Quick Start
Enable distributed mode with Redis:Architecture
The HA module has three components that work together:Heartbeat Service
Each pod writes a heartbeat key to Redis every 10 seconds with a 30-second TTL. When a pod dies, its key expires automatically.Session Takeover
When a request arrives for a session owned by a dead pod, the receiving pod runs an atomic Lua script against Redis:- Read the session data
- Verify the current
nodeIdmatchesexpectedOldNodeId(the dead pod) - Atomically update
nodeIdto the new pod and setreassignedAt/reassignedFrom - Return success or failure
Notification Relay
MCP notifications (progress updates, resource changes) targeting sessions on other pods are relayed via Redis Pub/Sub:- Each pod subscribes to
mcp:ha:notify:{nodeId} - When a notification targets a session on another pod, it is published to that pod’s channel
- The receiving pod delivers the notification to the local transport
Configuration
Configure HA settings viafrontmcp.config.ts:
| Field | Type | Default | Description |
|---|---|---|---|
heartbeatIntervalMs | number | 10000 | How often each pod writes its heartbeat |
heartbeatTtlMs | number | 30000 | TTL for heartbeat key (should be 2-3x interval) |
takeoverGracePeriodMs | number | 5000 | Wait time before claiming orphaned sessions |
redisKeyPrefix | string | mcp:ha: | Redis key prefix for all HA keys |
Orphan Session Scanner
In addition to on-demand session takeover (when a request arrives for a dead pod’s session), FrontMCP runs a periodic orphan scanner that proactively detects and claims sessions from dead pods:- Runs every heartbeat interval (default: 10s)
- Compares all session
nodeIdvalues against alive heartbeat keys - Claims orphaned sessions via the same atomic Lua CAS script
- Fires a callback for each claimed session (logged at INFO level)
Load Balancer Affinity
FrontMCP sets two identifiers on both Streamable HTTP and SSE responses for load balancer routing:- Cookie:
__frontmcp_node--- set during the initialize handshake - Header:
X-FrontMCP-Machine-Id--- set on every response in distributed mode
NGINX Sticky Sessions
The affinity cookie ensures subsequent requests from the same MCP client hit the same pod. If the pod dies, the load balancer routes to a different pod, which triggers session takeover.
SSE-Specific Routing
SSE (Server-Sent Events) requires special attention because the/sse endpoint creates a long-lived connection. POST requests to /message must reach the pod with the active SSE stream.
FrontMCP handles this in two layers:
- LB Affinity (primary): The
__frontmcp_nodecookie is set during SSE initialization, so the load balancer routes subsequent POST requests to the correct pod. - Notification Relay (fallback): If a POST arrives at the wrong pod, FrontMCP detects that the session exists on another node and relays the message via Redis Pub/Sub to the owning pod, which delivers it through the active SSE stream.
Kubernetes
Deploy with 3 replicas and a Redis instance:Errors
| Error | When | Action |
|---|---|---|
SessionClaimConflictError | Another pod already claimed the session | Retry the request --- the load balancer will route to the new owner |
HaConfigurationError | Redis not configured but FRONTMCP_DEPLOYMENT_MODE=distributed | Add redis configuration to @FrontMcp() decorator |
Verifying HA
Related
Transport Security
CORS, bind address, DNS rebinding, and host validation
Health Checks
Configure /healthz and /readyz probes
Redis Setup
Redis connection and session store configuration
Runtime Modes
Standalone, distributed, and serverless modes