-
Notifications
You must be signed in to change notification settings - Fork 2
Redis Integration
Value Proposition Fortify your multi-agent architecture with enterprise-grade distributed rate limiting. By integrating Redis, you guarantee atomic enforcement, bulletproof isolation, and resilient high availability across your entire AI ecosystem. Read the full value proposition.
Understand the Redis architecture to ensure robust system design. Redis serves a single, focused purpose in the mysql-mcp architecture: distributed fixed-window rate limiting for Code Mode (mysql_execute_code) and the HTTP Transport layer. It is an entirely optional dependency — the server operates identically without it, falling back to a local in-memory rate limiter.
| Aspect | Detail |
|---|---|
| Client library | node-redis client |
| Connection model | Single client, disableOfflineQueue: true
|
| Key pattern | codemode:rl:${clientId} |
| Data structures | Simple strings holding integer counters |
| Pub/Sub / Streams | Not used |
Note
Redis is not used for schema caching. The schema metadata cache (SchemaManager) is implemented as an in-memory Map within each server process.
The CodeModeSecurityManager establishes a single Redis connection on startup if REDIS_URL is provided. The connection is configured with disableOfflineQueue: true, which means commands issued while disconnected are immediately rejected rather than buffered — this is critical for the fallback mechanism to engage instantly.
┌──────────────────────────────────────────────────────┐
│ mysql-mcp Server │
│ │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ CodeModeSecurityMgr │───▶│ Redis (optional) │ │
│ │ │ │ Port: 6379 │ │
│ │ REDIS_URL set? │ └─────────────────────┘ │
│ │ ├─ Yes: Redis RL │ │
│ │ └─ No: Memory RL │ │
│ └─────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ In-Memory Map │ ◀── Fallback (always │
│ │ (rate limiter) │ available) │
│ └─────────────────────┘ │
└──────────────────────────────────────────────────────┘
If the Redis client throws an error during a rate limit check (network timeout, connection refused, etc.), the system:
- Logs the failure as a structured warning
-
Falls through to the in-memory
Map-based rate limiter - Continues enforcing limits locally without interruption
-
Emits a
mysql_mcp_redis_fallback_to_memory_totalmetric for monitoring
Recovery is automatic — subsequent calls will attempt Redis again if the client reconnects.
The rate limiter uses a fixed window algorithm implemented as an atomic Lua script executed via EVAL:
local current = redis.call('INCR', KEYS[1])
if current == 1 then
redis.call('PEXPIRE', KEYS[1], ARGV[1])
end
return currentHow it works:
-
INCRatomically increments the counter for the client's key - On the first increment (counter == 1), a TTL is set via
PEXPIRE(millisecond precision) - The returned count is compared against configurable limits (e.g., 60 executions per minute)
- When the TTL expires, Redis automatically evicts the key, resetting the window
This approach is race-condition-free because the entire script executes atomically within Redis.
Code Mode Rate Limiting:
codemode:rl:${clientId}
-
Prefix:
codemode:rl:— identifies this as a Code Mode rate limit key -
Suffix:
${clientId}— unique per MCP client connection -
TTL: Configurable via
windowMs(default: 60,000ms / 1 minute)
HTTP Transport Rate Limiting:
http:rl:${ipAddress}
-
Prefix:
http:rl:— identifies this as an HTTP transport rate limit key -
Suffix:
${ipAddress}— client IP address -
TTL: Configurable via
windowMs(default: 60,000ms / 1 minute)
Each client gets an independent counter. Under MCP streamable HTTP transport (NodeStreamableHTTPServerTransport) with multiple agents, rate limits are enforced globally per client session via atomic Redis Lua scripts — an agent cannot circumvent limits by reconnecting.
| Variable | Default | Description |
|---|---|---|
REDIS_URL |
(none) | Redis connection URL (e.g., redis://localhost:6379). If unset, rate limiting uses in-memory only. |
CODEMODE_RATE_LIMIT_MAX |
60 |
Maximum Code Mode executions per client per window |
MCP_RATE_LIMIT_MAX |
100 |
Maximum HTTP requests per IP address per window (HTTP Transport only) |
Important
The stdio transport is not subject to HTTP transport rate limits (MCP_RATE_LIMIT_MAX). However, Code Mode execution (mysql_execute_code) is always subject to CODEMODE_RATE_LIMIT_MAX regardless of transport — enforced globally via Redis or locally in-memory.
The Redis client is configured with disableOfflineQueue: true. This means:
- If the connection drops, commands are not queued — they throw immediately
- The catch block in
checkRateLimit()traps the error and falls through to the in-memory path
| Scenario | Latency | Notes |
|---|---|---|
| Redis healthy | Sub-millisecond | Local network Lua EVAL |
| Redis unreachable | ~0ms penalty | Immediate throw due to disableOfflineQueue
|
| In-memory fallback | Sub-millisecond | Simple Map lookup |
The node-redis client includes automatic reconnection. When the connection is restored:
- The
readyevent fires - Subsequent
checkRateLimit()calls will use Redis again - No manual intervention is required
Redis integration tests use a carefully designed isolation pattern to prevent cross-test contamination.
Each test generates a unique namespace:
const prefix = getRedisTestPrefix(suiteName);This ensures parallel test runs never interfere with each other.
The test utilities explicitly prohibit FLUSHDB and FLUSHALL to prevent wiping real data. Instead, cleanup uses targeted key deletion:
// Scan for keys matching the test prefix
const keys = await redis.keys(`${prefix}*`);
if (keys.length > 0) {
const multi = redis.multi();
for (const key of keys) {
multi.del(key);
}
await multi.exec();
}A waitForKeyExpiry polling utility validates the Lua script's timeout logic in integration tests by repeatedly checking EXISTS until the key expires.
Tip
See src/__tests__/helpers/redis-test-utils.ts for the complete test harness implementation. The test ecosystem comprehensively benchmarks code mode VM sandbox performance against these rate limiting capabilities.
The following application-level Redis metrics are exported via the /metrics endpoint:
Note
Audit Trail: Rate-limiting rejection events are also captured in the file-based audit trail at AUDIT_LOG_PATH for comprehensive security analysis.
| Metric | Type | Description |
|---|---|---|
mysql_mcp_redis_rate_limit_exceeded_total |
counter | Code Mode rate limit rejections |
mysql_mcp_redis_fallback_to_memory_total |
counter | Fallback events to in-memory rate limiter |
mysql_mcp_redis_connected |
gauge | Whether Redis is currently connected (0/1) |
mysql_mcp_redis_lua_eval_latency_p95_ms |
gauge | P95 latency of the rate limit Lua EVAL |
Sync the following JSON Dashboards via your Datadog provisioning tool (e.g., pup, Terraform, or API) to ensure complete visibility:
- AI Efficiency
- Token & Tool Metrics
- MySQL Cluster Telemetry
- Redis Telemetry
- Agent Execution Telemetry
The Redis Telemetry dashboard provides infrastructure-level monitoring including:
- Memory usage and fragmentation ratio
- Keyspace metrics (total keys, expires, evictions)
- Client connections (connected, blocked, rejected)
- Commands per second and slowlog
- Cache hit/miss rate
- Network I/O throughput
- Replication health
OpenTelemetry Tracing Rules: To integrate successfully, ensure your OpenTelemetry configuration adheres to the following rules:
- Utilize
gen_ai.*semantic telemetry conventions. - Configure the OTLP exporter securely.
- Ensure standard
traceparentheaders are propagated across all service boundaries. - Utilize a batch span processor for optimal export performance.
See Observability for dashboard setup instructions.
| Metric | Why | Alert Threshold |
|---|---|---|
mysql_mcp_redis_fallback_to_memory_total |
Indicates Redis connectivity issues | Any increment |
redis.mem.fragmentation_ratio |
High fragmentation wastes memory | > 1.5 |
redis.keys.evicted |
Evictions mean memory pressure | Any non-zero |
redis.clients.blocked |
Blocked clients indicate contention | > 0 sustained |
redis.net.rejected |
Connection limit reached | Any non-zero |
Symptom: Warning logs: Redis rate limit error, falling back to memory
Resolution:
- Verify Redis is running:
docker ps | grep redis - Test connectivity:
redis-cli -h <host> -p 6379 ping - Check
REDIS_URLenvironment variable - The server continues to function via in-memory fallback — no action is strictly required
Symptom: redis.keys.evicted metric is non-zero
Resolution:
- Check
maxmemoryconfiguration - Rate limit keys are tiny (integer counters) and short-lived (60s TTL) — evictions should not occur under normal load
- If evictions persist, another workload may be consuming Redis memory
Symptom: Different agents can exceed the global rate limit
Resolution:
- Verify all server instances use the same
REDIS_URL - Check that
CODEMODE_RATE_LIMIT_MAXis consistent across instances - Confirm Redis is not in cluster mode (the Lua script requires all keys on one node)
- Code Mode - Code Mode API documentation
- Performance Tuning - Connection pooling and rate limiting guidance
- Configuration - Environment variable reference
- Observability - Telemetry and monitoring setup
- Test Ecosystem - Infrastructure setup and testing
Unlock autonomous database orchestration with an enterprise-grade MySQL MCP server. Featuring blazing-fast sandboxed Code Mode, uncompromising schema enforcement, and seamless ecosystem integrations to power secure, intelligent AI workflows.
- Installation
- Configuration
- Architecture
- HTTP Transport
- Tool Filtering
- Code Mode
- Tools
- Prompts
- Resources
- Observability & Telemetry