Skip to main content
Full API reference for the @frontmcp/guard package. This library is SDK-agnostic and works with any StorageAdapter backend.
When using @frontmcp/sdk, guard features are integrated automatically via the throttle config and tool/agent decorators. You only need to import from @frontmcp/guard directly if building custom integrations.

Configuration Types

GuardConfig

Top-level configuration for the guard system. Passed to @FrontMcp({ throttle: ... }) or createGuardManager().

RateLimitConfig

Configuration for sliding window rate limiting.

ConcurrencyConfig

Configuration for distributed semaphore concurrency control.

TimeoutConfig

Configuration for execution timeout.

IpFilterConfig

Configuration for IP-based access control.

PartitionKey

Determines how limits are bucketed across requests.
PartitionKeyContext:

Classes

GuardManager

Orchestrates all guard features. Created via createGuardManager() or automatically by the SDK when throttle is configured.

checkRateLimit()

Check per-entity rate limit.
Returns { allowed: true, remaining: Infinity, resetMs: 0 } if no config applies.

checkGlobalRateLimit()

Check global (server-wide) rate limit.
Uses config.global configuration. Returns allowed result if no global config.

acquireSemaphore()

Acquire a concurrency slot for an entity.
Returns SemaphoreTicket on success, null if no config applies. May throw QueueTimeoutError if queue timeout expires.

acquireGlobalSemaphore()

Acquire a global concurrency slot.
Uses config.globalConcurrency configuration.

checkIpFilter()

Check if a client IP is allowed.
Returns undefined only when no IP filter is configured. A missing or unparseable clientIp matches no rule and gets the configured defaultAction, so with defaultAction: 'deny' it is rejected.

isIpAllowListed()

Check if a client IP is explicitly on the allow list.
Returns true only if an IP filter is configured, clientIp is provided, and the IP matches the allow list.

destroy()

Disconnect storage backend and clean up resources.

SlidingWindowRateLimiter

Implements sliding window rate limiting with O(1) storage per key.

check()

Check and consume a rate limit token.
Algorithm: Uses two adjacent fixed-window counters with weighted interpolation. The estimated count is:
If estimatedCount < maxRequests, the request is allowed and the current window counter is atomically incremented. RateLimitResult:

reset()

Reset rate limit counters for a key.

DistributedSemaphore

Implements a distributed counting semaphore with optional queuing.
Default ticketTtlSeconds: 300 (5 minutes).

acquire()

Acquire a semaphore slot.
  • Returns SemaphoreTicket if a slot is acquired.
  • Returns null if queueTimeoutMs <= 0 and no slot is available.
  • Throws QueueTimeoutError if queued and timeout expires.
Uses pub/sub when available for efficient slot release detection, falls back to polling with exponential backoff (100ms to 1000ms). SemaphoreTicket:

getActiveCount()

Get current number of active tickets for a key.

forceReset()

Force-clear all tickets and reset the counter for a key.

IpFilter

IP-based access control with CIDR support for IPv4 and IPv6.
Parses all CIDR rules at construction time using BigInt bitmask representation.

check()

Check if a client IP is allowed.
Evaluation order:
  1. Deny list (takes precedence)
  2. Allow list
  3. Default action — also for a missing or unparseable IP
An IPv4-mapped address (::ffff:203.0.113.7, ::ffff:cb00:7107) is matched as the IPv4 address it maps, and a rule written in mapped form (::ffff:10.0.0.0/104) as the IPv4 rule (10.0.0.0/8). A %zone suffix is ignored. IpFilterResult:

isAllowListed()

Check if an IP is explicitly on the allow list.

Functions

createGuardManager()

Factory function to create a fully initialized GuardManager.
CreateGuardManagerArgs: Behavior:
  1. Creates storage backend from config.storage (or in-memory if not set)
  2. Connects the storage backend. A configured backend that cannot be created or reached rejects with GuardStorageUnavailableError — rate limits fail closed — unless config.storage.fallback is 'memory'. The returned manager applies the same policy if the backend stops answering later: limit checks and slot acquisitions reject with GuardStorageUnavailableError, or, with fallback: 'memory', run on per-instance counters and retry the configured backend every 30 seconds (GuardManagerOptions.retryPrimaryAfterMs). Releasing a concurrency slot never throws. createStorage defaults fallback to 'error' in production and 'memory' otherwise.
  3. Creates namespaced storage with config.keyPrefix, minus any trailing : (the namespace adds its own separator)
  4. Returns initialized GuardManager
config.storage is a StorageConfig from @frontmcp/utils: type selects the backend and its options go under the key of that name — { type: 'redis', redis: { config: { host, port, password?, tls? } } }, { type: 'redis', redis: { url } }, { type: 'vercel-kv', vercelKv: { url, token } } or { type: 'upstash', upstash: { url, token } }. A block without type is auto-detected from the environment.
Keys are mcp:guard:<entity>:<partition>:<kind>:…. Before 1.8.6 the default prefix wrote mcp:guard::<entity>:…; the two versions do not read each other’s counters, so limits briefly split during a rolling deploy.

withTimeout()

Wraps an async function with an execution deadline.
Throws ExecutionTimeoutError if the deadline is exceeded, and aborts the signal passed to fn so the work can stop. Uses AbortController + Promise.race internally.

resolvePartitionKey()

Resolve a partition key strategy to a concrete string value.

buildStorageKey()

Build a namespaced storage key from components.
Examples:

Error Classes

All guard errors extend GuardError, which has code (string) and statusCode (number) properties.

ExecutionTimeoutError

Thrown when execution exceeds the configured timeout.

ConcurrencyLimitError

Thrown when no concurrency slot is available and queueTimeoutMs is 0.

QueueTimeoutError

Thrown when a queued request exceeds its wait time.

IpBlockedError

For your own code to throw when a client IP matches a deny list. The SDK’s built-in throttle.ipFilter does not throw it; it answers the HTTP request with 403 from each flow’s checkIpFilter stage.

IpNotAllowedError

For your own code to throw when a client IP is not on an allow list and defaultAction is 'deny'. Not thrown by the built-in filter.

GuardStorageUnavailableError

Thrown when the configured storage backend cannot be created or reached: by createGuardManager() at SDK startup, and by GuardManager limit checks (checkRateLimit, checkGlobalRateLimit, acquireSemaphore, acquireGlobalSemaphore) if the backend goes away while the server runs. The message names throttle.storage and says to set throttle.storage.fallback: 'memory' to use per-instance counters instead.

Zod Schemas

Validation schemas for all configuration types. Useful for validating user-provided configuration.