Guard is powered by the
@frontmcp/guard library and integrates directly into tool and agent flows. All guard checks run automatically before execution, with cleanup handled in finalize stages.Why Guard?
| Threat | Without Guard | With Guard |
|---|---|---|
| Client flooding requests | Server overwhelmed | Rate-limited per user/IP |
| Tool running forever | Hangs, resource leak | Timeout protection |
| Unbounded parallelism | Resource exhaustion | Controlled concurrency |
| Malicious IPs | Open access | IP allow/deny filtering |
Quick Start
Add rate limiting and a timeout to any tool with decorator options:How Guard Integrates with Flows
Guard checks are implemented as flow stages that run automatically in the tool and agent execution pipelines:- acquireQuota — Checks global and per-entity rate limits. Throws
RateLimitErrorif exceeded. - acquireSemaphore — Acquires a concurrency slot. Throws
ConcurrencyLimitErrorif no slot available. - execute — Wrapped with
withTimeoutif a timeout is configured. ThrowsExecutionTimeoutErrorif exceeded. - releaseSemaphore — Releases the concurrency slot back to the pool.
- releaseQuota — Cleans up rate limit state.
Rate Limiting
FrontMCP uses a sliding window algorithm for rate limiting. It provides smooth, accurate throttling with O(1) storage per key.Per-Tool Rate Limiting
Global Rate Limiting
Set a server-wide rate limit in your app configuration:Partition Strategies
Partition keys determine how rate limits are bucketed:| Strategy | Description | Use Case |
|---|---|---|
'global' | Single shared bucket | Server-wide limits |
'ip' | Per client IP address | Prevent IP-based abuse |
'session' | Per MCP session ID | Per-connection limits |
'userId' | Per authenticated user | Per-user quotas |
| Custom function | (ctx) => string | Tenant, org, or custom grouping |
Concurrency Control
Concurrency control uses a distributed semaphore to limit how many instances of a tool or agent can execute simultaneously.Per-Tool Concurrency
Mutex Pattern
SetmaxConcurrent: 1 to ensure only one execution at a time:
Queue Behavior
WhenqueueTimeoutMs is set, requests that cannot acquire a slot immediately will wait in a queue:
queueTimeoutMs: 0(default) — Immediately reject if no slot available. ThrowsConcurrencyLimitError.queueTimeoutMs: 5000— Wait up to 5 seconds for a slot. ThrowsQueueTimeoutErrorif the wait expires.
Execution Timeout
Timeout wraps theexecute stage with a deadline. If execution exceeds the configured duration, it throws ExecutionTimeoutError.
Per-Tool Timeout
Default Timeout
Set a default timeout for all tools and agents at the app level:IP Filtering
IP filtering allows or blocks requests based on client IP address, supporting IPv4, IPv6, and CIDR ranges.Filter Precedence
- Deny list is checked first. If matched, the request is blocked with
IpBlockedError(403). - Allow list is checked next. If matched, the request proceeds.
- Default action applies if neither list matches:
'allow'(default) — Request proceeds.'deny'— Request is blocked withIpNotAllowedError(403).
Supported IP Formats
| Format | Example |
|---|---|
| IPv4 address | 192.168.1.1 |
| IPv4 CIDR | 10.0.0.0/8 |
| IPv6 address | 2001:db8::1 |
| IPv6 CIDR | 2001:db8::/32 |
| IPv4-mapped IPv6 | ::ffff:192.168.1.1 |
Proxy Configuration
When your server is behind a reverse proxy (Nginx, CloudFront, etc.), enabletrustProxy to read the client IP from the X-Forwarded-For header:
App-Level Configuration
Thethrottle field in @FrontMcp configures all guard features at the app level:
Configuration Precedence
| Guard Type | Per-Entity Config | App Default | Fallback |
|---|---|---|---|
| Rate limit | @Tool({ rateLimit }) | throttle.defaultRateLimit | No limit |
| Concurrency | @Tool({ concurrency }) | throttle.defaultConcurrency | No limit |
| Timeout | @Tool({ timeout }) | throttle.defaultTimeout | No timeout |
| IP filter | N/A (app-level only) | throttle.ipFilter | No filter |
| Global rate limit | N/A (app-level only) | throttle.global | No limit |
Storage Backends
Guard supports multiple storage backends for distributed deployments.Memory (Development)
The default backend. Suitable for single-instance development. No configuration needed.Redis (Production)
For distributed rate limiting across multiple server instances:Vercel KV / Upstash
For serverless environments:Error Handling
Guard throws specific error classes when limits are exceeded:| Error Class | Code | HTTP Status | When Thrown |
|---|---|---|---|
RateLimitError | RATE_LIMIT_EXCEEDED | 429 | Request exceeds rate limit |
ConcurrencyLimitError | CONCURRENCY_LIMIT | 429 | No concurrency slot available |
QueueTimeoutError | QUEUE_TIMEOUT | 429 | Queue wait time exceeded |
ExecutionTimeoutError | EXECUTION_TIMEOUT | 408 | Execution exceeded deadline |
IpBlockedError | IP_BLOCKED | 403 | Client IP is on deny list |
IpNotAllowedError | IP_NOT_ALLOWED | 403 | Client IP not on allow list |
Agent Guard
Agents support the same guard options as tools:acquireQuota → acquireSemaphore → execute (with timeout) → releaseSemaphore → releaseQuota.
Configuration Reference
RateLimitConfig
| Field | Type | Default | Description |
|---|---|---|---|
maxRequests | number | required | Maximum requests allowed in the window |
windowMs | number | 60000 | Time window in milliseconds |
partitionBy | PartitionKey | 'global' | Partition strategy for bucketing |
ConcurrencyConfig
| Field | Type | Default | Description |
|---|---|---|---|
maxConcurrent | number | required | Maximum simultaneous executions |
queueTimeoutMs | number | 0 | Max wait time for a slot (0 = no wait) |
partitionBy | PartitionKey | 'global' | Partition strategy for bucketing |
TimeoutConfig
| Field | Type | Default | Description |
|---|---|---|---|
executeMs | number | required | Maximum execution time in milliseconds |
IpFilterConfig
| Field | Type | Default | Description |
|---|---|---|---|
allowList | string[] | [] | IPs or CIDR ranges to always allow |
denyList | string[] | [] | IPs or CIDR ranges to always block |
defaultAction | 'allow' | 'deny' | 'allow' | Action when IP matches neither list |
trustProxy | boolean | false | Trust X-Forwarded-For header |
trustedProxyDepth | number | 1 | Max proxy hops to trust |
GuardConfig (App-Level)
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | required | Enable or disable all guard features |
storage | StorageConfig | in-memory | Storage backend configuration |
keyPrefix | string | 'mcp:guard:' | Prefix for all storage keys |
global | RateLimitConfig | — | Global rate limit for all requests |
globalConcurrency | ConcurrencyConfig | — | Global concurrency limit |
defaultRateLimit | RateLimitConfig | — | Default per-entity rate limit |
defaultConcurrency | ConcurrencyConfig | — | Default per-entity concurrency |
defaultTimeout | TimeoutConfig | — | Default per-entity timeout |
ipFilter | IpFilterConfig | — | IP filtering configuration |