Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@frontmcp/guard

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@frontmcp/guard

Rate limiting, concurrency control, timeout, IP filtering, and traffic guard utilities for FrontMCP

Source
npmnpm
Version
1.2.0
Version published
Weekly downloads
1.9K
-30.89%
Maintainers
1
Weekly downloads
 
Created
Source

@frontmcp/guard

npm version license

Rate limiting, concurrency control, timeout enforcement, and IP filtering for FrontMCP applications. Built on the StorageAdapter interface from @frontmcp/utils, so it works with Memory, Redis, Vercel KV, and Upstash backends out of the box.

Installation

npm install @frontmcp/guard
# or
yarn add @frontmcp/guard

Peer dependency:

npm install zod@^4

Quick Start

import { createGuardManager } from '@frontmcp/guard';

const guard = await createGuardManager({
  config: {
    enabled: true,
    global: { maxRequests: 100, windowMs: 60_000 },
    defaultTimeout: { executeMs: 30_000 },
    ipFilter: {
      denyList: ['10.0.0.0/8'],
      defaultAction: 'allow',
    },
  },
});

// Check IP filter
const ipResult = guard.checkIpFilter('203.0.113.5');

// Check rate limit
const rlResult = await guard.checkRateLimit('my-tool', undefined, {
  sessionId: 'sess-123',
});

// Acquire concurrency slot
const ticket = await guard.acquireSemaphore(
  'my-tool',
  { maxConcurrent: 5 },
  {
    sessionId: 'sess-123',
  },
);
try {
  // ... do work ...
} finally {
  await ticket?.release();
}

Modules

ModuleMain ExportPurpose
errors/GuardError + subclassesError hierarchy with machine-readable codes and HTTP status codes
schemas/guardConfigSchemaZod validation schemas for all configuration objects
partition-key/resolvePartitionKeyResolves request partition keys (ip, session, userId, global, custom)
rate-limit/SlidingWindowRateLimiterSliding window counter rate limiter
concurrency/DistributedSemaphoreDistributed semaphore for concurrency control
timeout/withTimeoutAsync execution timeout wrapper
ip-filter/IpFilterIP allow/deny list filtering with CIDR support
manager/GuardManager + createGuardManagerOrchestrator combining all guard modules

Rate Limiting

Uses the sliding window counter algorithm. Two adjacent fixed-window counters are maintained; their counts are combined with a time-weighted interpolation to approximate a true sliding window. This provides O(1) storage per key while avoiding the burst edges of simple fixed-window counters.

import { SlidingWindowRateLimiter } from '@frontmcp/guard';

const limiter = new SlidingWindowRateLimiter(storageAdapter);

const result = await limiter.check(
  'user:42', // partition key
  100, // max requests
  60_000, // window in ms
);

if (!result.allowed) {
  console.log(`Rate limited. Retry after ${result.retryAfterMs}ms`);
}

The RateLimitResult includes:

  • allowed -- whether the request can proceed
  • remaining -- approximate remaining requests in this window
  • resetMs -- milliseconds until the current window resets
  • retryAfterMs -- (only when blocked) suggested retry delay

Concurrency Control

The DistributedSemaphore limits the number of concurrent executions for a given key. Each execution acquires a "ticket" via atomic incr on a counter key. Individual ticket keys are stored with a TTL for crash safety -- if a process dies without releasing, the ticket TTL expires and the counter self-corrects.

When all slots are full, callers can optionally wait in a queue with exponential backoff polling. If the storage backend supports pub/sub, slot releases trigger immediate wakeup of waiting callers.

import { DistributedSemaphore } from '@frontmcp/guard';

const semaphore = new DistributedSemaphore(storageAdapter, 300 /* ticket TTL seconds */);

const ticket = await semaphore.acquire(
  'my-tool:global', // key
  5, // max concurrent
  10_000, // queue timeout ms (0 = no wait)
  'my-tool', // entity name (for error messages)
);

if (!ticket) {
  // Rejected (queueTimeoutMs was 0 and all slots full)
  return;
}

try {
  await doWork();
} finally {
  await ticket.release();
}

Additional methods:

  • getActiveCount(key) -- returns the current number of active tickets
  • forceReset(key) -- resets the counter and removes all ticket keys

Timeout

The withTimeout utility wraps an async function with a deadline using AbortController + Promise.race. Throws ExecutionTimeoutError if the function does not complete within the specified duration.

import { withTimeout } from '@frontmcp/guard';

const result = await withTimeout(
  () => fetchData(),
  5_000, // timeout in ms
  'fetch-data', // entity name (for error messages)
);

IP Filtering

The IpFilter class checks client IP addresses against allow and deny lists. Supports individual IP addresses and CIDR notation for both IPv4 and IPv6. IPv4-mapped IPv6 addresses (e.g., ::ffff:192.168.1.1) are also handled.

Precedence: the deny list is always checked first. If an IP matches the deny list, it is blocked regardless of the allow list. If an allow list is configured and the IP does not match any allow rule, the defaultAction determines the outcome.

All matching is performed using bigint arithmetic for correctness across the full IPv6 address space.

import { IpFilter } from '@frontmcp/guard';

const filter = new IpFilter({
  allowList: ['192.168.0.0/16'],
  denyList: ['192.168.1.100'],
  defaultAction: 'deny',
});

const result = filter.check('192.168.2.50');
// { allowed: true, reason: 'allowlisted', matchedRule: '192.168.0.0/16' }

const blocked = filter.check('192.168.1.100');
// { allowed: false, reason: 'denylisted', matchedRule: '192.168.1.100' }

The isAllowListed(ip) method provides a quick check for whether an IP is on the allow list, which can be used to bypass rate limiting for trusted addresses.

Partition Keys

Partition keys determine how rate limits and concurrency slots are bucketed. Built-in strategies:

StrategyBehavior
'global'Single shared bucket for all callers (default)
'ip'One bucket per client IP address
'session'One bucket per session ID
'userId'One bucket per authenticated user ID (falls back to session ID)

You can also pass a custom function:

const config: RateLimitConfig = {
  maxRequests: 100,
  windowMs: 60_000,
  partitionBy: (ctx) => `org:${ctx.userId?.split(':')[0]}`,
};

The PartitionKeyContext passed to custom functions contains sessionId (always present), plus optional clientIp and userId.

Guard Manager

GuardManager is the central orchestrator. It combines rate limiting, concurrency control, IP filtering, and timeout configuration into a single interface. The createGuardManager factory handles storage initialization.

The manager supports two levels of configuration:

  • Global -- applied to every request (global, globalConcurrency)
  • Default -- applied to entities that do not specify their own config (defaultRateLimit, defaultConcurrency, defaultTimeout)

Per-entity configuration takes precedence over defaults.

import { createGuardManager } from '@frontmcp/guard';

const guard = await createGuardManager({
  config: {
    enabled: true,
    storage: { provider: 'redis', host: 'localhost', port: 6379 },
    keyPrefix: 'myapp:guard:',
    global: { maxRequests: 1000, windowMs: 60_000, partitionBy: 'ip' },
    globalConcurrency: { maxConcurrent: 50, partitionBy: 'global' },
    defaultRateLimit: { maxRequests: 100, windowMs: 60_000, partitionBy: 'session' },
    defaultConcurrency: { maxConcurrent: 10, queueTimeoutMs: 5_000 },
    defaultTimeout: { executeMs: 30_000 },
    ipFilter: {
      denyList: ['10.0.0.0/8'],
      allowList: ['10.0.1.0/24'],
      defaultAction: 'allow',
      trustProxy: true,
      trustedProxyDepth: 2,
    },
  },
  logger: console,
});

// Use the manager
const globalRl = await guard.checkGlobalRateLimit({ sessionId: 'sess-1' });
const entityRl = await guard.checkRateLimit('my-tool', undefined, { sessionId: 'sess-1' });
const ticket = await guard.acquireSemaphore('my-tool', undefined, { sessionId: 'sess-1' });

// Cleanup
await guard.destroy();

Configuration Reference

GuardConfig

FieldTypeDefaultDescription
enabledboolean--Whether the guard system is active
storageStorageConfigmemoryStorage backend configuration
keyPrefixstring'mcp:guard:'Prefix for all storage keys
globalRateLimitConfig--Global rate limit for ALL requests
globalConcurrencyConcurrencyConfig--Global concurrency limit
defaultRateLimitRateLimitConfig--Default rate limit for entities without explicit config
defaultConcurrencyConcurrencyConfig--Default concurrency for entities without explicit config
defaultTimeoutTimeoutConfig--Default timeout for entity execution
ipFilterIpFilterConfig--IP filtering configuration

RateLimitConfig

FieldTypeDefaultDescription
maxRequestsnumber--Maximum requests allowed per window
windowMsnumber60000Time window in milliseconds
partitionByPartitionKey'global'Partition key strategy

ConcurrencyConfig

FieldTypeDefaultDescription
maxConcurrentnumber--Maximum concurrent executions
queueTimeoutMsnumber0Max wait time in queue (0 = reject immediately)
partitionByPartitionKey'global'Partition key strategy

TimeoutConfig

FieldTypeDefaultDescription
executeMsnumber--Maximum execution time in milliseconds

IpFilterConfig

FieldTypeDefaultDescription
allowListstring[]--IP addresses or CIDR ranges to always allow
denyListstring[]--IP addresses or CIDR ranges to always block
defaultAction'allow' | 'deny''allow'Action when IP matches neither list
trustProxybooleanfalseTrust X-Forwarded-For header
trustedProxyDepthnumber1Max proxies to trust from X-Forwarded-For

Storage Backends

The guard library delegates all persistence to the StorageAdapter interface from @frontmcp/utils. Choose a backend based on your deployment:

BackendUse Case
MemoryDevelopment, testing, single-process deployments. Not suitable for distributed setups.
RedisProduction multi-instance deployments. Provides atomic operations and optional pub/sub for semaphore wakeup.
Vercel KVVercel-hosted applications. Redis-compatible API.
UpstashServerless environments. HTTP-based Redis compatible.

If no storage config is provided, the factory falls back to in-memory storage and logs a warning.

Error Handling

All errors extend GuardError, which carries a machine-readable code and an HTTP statusCode.

Error ClassCodeStatusWhen
GuardError(base)--Base class for all guard errors
ExecutionTimeoutErrorEXECUTION_TIMEOUT408Execution exceeds configured timeout
ConcurrencyLimitErrorCONCURRENCY_LIMIT429Concurrency limit reached (no queue or queue disabled)
QueueTimeoutErrorQUEUE_TIMEOUT429Waited in concurrency queue but timed out
IpBlockedErrorIP_BLOCKED403Client IP is on the deny list
IpNotAllowedErrorIP_NOT_ALLOWED403Client IP is not on the allow list
import { GuardError, ExecutionTimeoutError } from '@frontmcp/guard';

try {
  await withTimeout(() => slowOp(), 5_000, 'slow-op');
} catch (err) {
  if (err instanceof ExecutionTimeoutError) {
    console.log(err.code); // 'EXECUTION_TIMEOUT'
    console.log(err.statusCode); // 408
    console.log(err.timeoutMs); // 5000
  }
}

API Reference

Classes

ExportModuleDescription
SlidingWindowRateLimiterrate-limitSliding window counter rate limiter
DistributedSemaphoreconcurrencyDistributed semaphore with ticket-based tracking
IpFilterip-filterIP allow/deny list with CIDR support
GuardManagermanagerCentral orchestrator for all guard modules

Functions

ExportModuleDescription
withTimeouttimeoutWrap an async function with a deadline
resolvePartitionKeypartition-keyResolve a partition key string from strategy and context
buildStorageKeypartition-keyBuild a namespaced storage key
createGuardManagermanagerFactory to create and initialize a GuardManager

Error Classes

ExportModuleDescription
GuardErrorerrorsBase error class
ExecutionTimeoutErrorerrorsTimeout exceeded
ConcurrencyLimitErrorerrorsConcurrency limit reached
QueueTimeoutErrorerrorsQueue wait timed out
IpBlockedErrorerrorsIP on deny list
IpNotAllowedErrorerrorsIP not on allow list

Zod Schemas

ExportModuleDescription
partitionKeySchemaschemasValidates partition key strategy or custom function
rateLimitConfigSchemaschemasValidates RateLimitConfig
concurrencyConfigSchemaschemasValidates ConcurrencyConfig
timeoutConfigSchemaschemasValidates TimeoutConfig
ipFilterConfigSchemaschemasValidates IpFilterConfig
guardConfigSchemaschemasValidates the full GuardConfig

Types

ExportModuleDescription
RateLimitConfigrate-limitRate limit configuration
RateLimitResultrate-limitResult from a rate limit check
ConcurrencyConfigconcurrencyConcurrency control configuration
SemaphoreTicketconcurrencyAcquired concurrency slot handle
TimeoutConfigtimeoutTimeout configuration
IpFilterConfigip-filterIP filter configuration
IpFilterResultip-filterResult from an IP filter check
PartitionKeyStrategypartition-keyBuilt-in partition key strategies union
CustomPartitionKeyFnpartition-keyCustom partition key resolver function
PartitionKeyContextpartition-keyContext passed to partition key resolvers
PartitionKeypartition-keyUnion of strategy string or custom function
GuardConfigmanagerFull guard configuration
GuardLoggermanagerMinimal logger interface
CreateGuardManagerArgsmanagerArguments for createGuardManager

License

Apache-2.0

Keywords

rate-limiting

FAQs

Package last updated on 05 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts