@frontmcp/guard

中文文档
1.12.2发布于 2026/11/15Apache-2.0TypeScriptESM + CJS构建来源已验证近 30 天下载 1.2万

FrontMCP的费率限制、货币控制、超时、IP过滤和交通警卫设施

中文使用文档
文档目录23 节
  1. 安装
  2. 使用量
  3. 在 FrontMCP 服务器中
  4. 独自一人
  5. 限制费率
  6. 货币管制
  7. 超时
  8. IP 过滤
  9. 分区密钥
  10. 警卫经理
  11. 配置参考
  12. GuardConfig
  13. RateLimitConfig
  14. ConcurrencyConfig
  15. TimeoutConfig
  16. IpFilterConfig
  17. 存储
  18. 错误
  19. API 参考
  20. 文档
  21. 相关软件包
  22. 捐款
  23. 许可证

@ frontmcp/ 守护

FrontMCP的速率限制,货币限制,执行超时和IP过滤. @frontmcp/sdk 用它来 throttle 选项 @FrontMcp 编辑 rateLimit, (中文(简体) ), concurrency 财务报告和审定财务报表 timeout 选项,所以在 FrontMCP 服务器中,您设置了这些选项,而不要导入此软件包。 直接安装以自行使用限制器. 他们把柜台放在后面 StorageAdapter 接口 @frontmcp/utils,因此它们与记忆,Redis,Vercel KV,Upstash和Cloudflare KV存储一起工作.

npm License

安装

npm install @frontmcp/guard @frontmcp/lazy-zod zod

@frontmcp/lazy-zod 是一个对等依赖(配置方案使用),它需要 zod 4. 节点.js 24或后. FrontMCP服务器不需要此安装 : @frontmcp/sdk 取决于 @frontmcp/guard 然后再出口里面的一切.

使用量

在 FrontMCP 服务器中

为工具设定限制, 并为整个服务器设定默认值 。 SDK将这些选项传递给此套件:

import { App, FrontMcp, Tool, ToolContext } from '@frontmcp/sdk';

@Tool({
  name: 'export_tickets',
  description: 'Export every ticket as CSV. At most 2 exports an hour per caller, one at a time.',
  inputSchema: {},
  rateLimit: { maxRequests: 2, windowMs: 60 * 60_000, partitionBy: 'userId' },
  concurrency: { maxConcurrent: 1, queueTimeoutMs: 5_000 },
  timeout: { executeMs: 30_000 },
})
class ExportTickets extends ToolContext {
  async execute() {
    return { csv: 'id,title' };
  }
}

@App({ id: 'help-desk', name: 'Help Desk', tools: [ExportTickets] })
class HelpDeskApp {}

@FrontMcp({
  info: { name: 'help-desk', version: '1.0.0' },
  apps: [HelpDeskApp],
  throttle: {
    enabled: true,
    defaultRateLimit: { maxRequests: 60, windowMs: 60_000, partitionBy: 'userId' },
    global: { maxRequests: 1_000, windowMs: 60_000, partitionBy: 'ip' },
    ipFilter: { denyList: ['192.0.2.0/24'] },
  },
})
export default class Server {}

守护选项 覆盖每个选项在服务器中所做的,并且调用者返回错误.

独自一人

createGuardManager 构建一个 GuardManager 从一个配置对象:

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

const guard = await createGuardManager({
  config: {
    enabled: true,
    defaultRateLimit: { maxRequests: 100, windowMs: 60_000, partitionBy: 'session' },
    defaultConcurrency: { maxConcurrent: 5 },
    ipFilter: { denyList: ['10.0.0.0/8'], defaultAction: 'allow' },
  },
});

const ipResult = guard.checkIpFilter('203.0.113.5');
if (ipResult && !ipResult.allowed) throw new Error('IP refused');

const rateLimit = await guard.checkRateLimit('my-tool', undefined, { sessionId: 'sess-123' });
if (!rateLimit.allowed) throw new Error(`Retry after ${rateLimit.retryAfterMs}ms`);

const ticket = await guard.acquireSemaphore('my-tool', undefined, { sessionId: 'sess-123' });
if (!ticket) throw new Error('No free slot');
try {
  // ... do the work ...
} finally {
  await ticket.release();
}

await guard.destroy();

没有 storage 配置管理器将其计数器保存在内存中,每个进程一组,并通过它发出警告 logger 当你通过一个.

限制费率

SlidingWindowRateLimiter 使用滑动窗口计数器。 它保留两个相邻的固定窗口计数器 并按窗口的倒数来计算 windowMs 现在。 这大概是一个真实的滑动窗口,每把钥匙都有恒定的存储,没有连续的一扇固定窗口允许在其边缘. 视窗与时钟对齐.

班级采用存储适配器. createMemoryStorage 其他适配器来自 @frontmcp/utils,它与此软件包一起安装;将其添加到自己的依赖性中以导入.

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

const storage = createMemoryStorage();
await storage.connect();
const limiter = new SlidingWindowRateLimiter(storage);

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

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

允许的检查计算请求数 . RateLimitResult 拥有:

  • allowed:请求能否继续
  • remaining: 本窗口所剩的大致请求
  • resetMs: 毫秒直至当前窗口结束
  • retryAfterMs:当被封锁时,等待多长时间

reset(key, windowMs) 删除密钥的计数器.

货币管制

DistributedSemaphore 限制一个关键处刑次数。 钥匙有 maxConcurrent 槽,每个被存储为自己的密钥. 执行者要求有一个自由的插槽,该插槽有写出(如果缺席),并带有其活命的出票时间(TTL,默认为300秒),并且每三分之一延长TTL,直到它打电话 release()。因此,该插槽的保存时间与执行运行的时间相同,TTL只释放一个已死亡的过程的插槽而不释放它. 取出或续作只触及一个仍然持有同一张罚单的插槽,因此存储需要原子相比较和去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去 用另一个适配器, acquire() 掷出 GuardStorageUnsupportedError,以及 createGuardManager 当 globalConcurrency 或者说 defaultConcurrency 已经设定.

当每个插槽被取下时,一个呼叫者可以等待一个,初时每100米投票一次,后退一次. 如果存储支持发布/订阅(memory, Redis,以及带有发布/订阅打开的Upstash),一个被发布的插槽立刻会唤醒等待呼叫者.

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

const storage = createMemoryStorage();
await storage.connect();
const semaphore = new DistributedSemaphore(storage, 300 /* ticket TTL in seconds */);

const ticket = await semaphore.acquire(
  'my-tool:global', // key
  5, // max concurrent
  10_000, // how long to wait for a slot, in ms (0 = don't wait)
  'my-tool', // name used in error messages
);

if (ticket) {
  try {
    // ... do the work ...
  } finally {
    await ticket.release();
  }
}

acquire 返回时 null 当每个槽被取走,等待被取走的时候 0投掷 QueueTimeoutError 当它等待的时候,没有空隙. getActiveCount(key) 返回已取槽的数目,以及 forceReset(key) 释放每个插槽.

超时

withTimeout 运行带有最后期限的同步函数。 它传递函数 a AbortSignal 当时间流逝时,它将被中止,而以 ExecutionTimeoutError。函数继续运行,除非它听到信号.

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

const response = await withTimeout(
  (signal) => fetch('https://api.example.com/data', { signal }),
  5_000, // timeout in ms
  'fetch-data', // name used in error messages
);

IP 过滤

IpFilter 请检查access-date=中的日期值 (帮助) 客户端IP对照允许和拒绝地址列表和CIDR范围,IPv4和IPv6. 一个 IPv4 的 IPv6 地址 (::ffff:192.168.1.1,而双层套接字为 IPv4 客户端报告)与 IPv4 地址相匹配。 相配使用大意算术,因此精确地横跨了整个IPv6地址空间.

拒绝列表先被检查: 拒绝其中的IP, 无论允许列表内容如何 。 然后,允许列表,然后 defaultAction。允许列表本身拒绝任何内容:添加 defaultAction: 'deny' 拒绝其他地址 缺少或无法解析的 IP 匹配规则并获得 defaultAction这样 check(undefined) 拒绝 defaultAction: 'deny'。 。 。 .

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' }

isAllowListed(ip) 告诉你一个IP是否在允许列表中,比如跳过对信任地址的速率限制.

分区密钥

一个分区键决定哪个调用共享利率限制计数或一组货币槽:

战略要求共享一个数
'global'所有的人
'ip'同一客户端IP的电话. 没有IP,同一个电话 userId;没有两个,一个桶
'session'在同一届会议上的呼吁
'userId'同一认证用户的呼叫, 或当没有用户时在同一会话中

您也可以通过 PartitionKeyContext,已经 sessionId (总是设定)和可选 clientIp 财务报告和审定财务报表 userId数字 :

import type { RateLimitConfig } from '@frontmcp/guard';

const config: RateLimitConfig = {
  maxRequests: 100,
  windowMs: 60_000,
  partitionBy: (ctx) => (ctx.userId ? `user:${ctx.userId}` : `session:${ctx.sessionId}`),
};

警卫经理

GuardManager 结合一个配置后面的速率限制,货币控制和IP过滤. createGuardManager 创建它的存储并连接它.

配置有两个级别:

  • 全球,适用于每项请求: global (费率限额)和 globalConcurrency。 。 。 .
  • 默认,适用于不通过自己的实体: defaultRateLimit, (中文(简体) ), defaultConcurrency, (中文(简体) ), defaultTimeout。 。 。 .

一个实体通过的配置取代了默认;它不会增加它.

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

const guard = await createGuardManager({
  config: {
    enabled: true,
    storage: { type: 'redis', redis: { config: { 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',
    },
  },
  logger: console,
});

const context = { sessionId: 'sess-1', clientIp: '203.0.113.5' };
const globalRateLimit = await guard.checkGlobalRateLimit(context);
const entityRateLimit = await guard.checkRateLimit('my-tool', undefined, context);
const globalTicket = await guard.acquireGlobalSemaphore(context);
const ticket = await guard.acquireSemaphore('my-tool', undefined, context);

await ticket?.release();
await globalTicket?.release();
await guard.destroy();
方法回返
checkIpFilter(ip)一个 IpFilterResult,或 undefined 当没有 ipFilter
isIpAllowListed(ip)IP是否在允许列表中
checkRateLimit(name, config, context)A 类 RateLimitResult没有 config 没有 defaultRateLimit,总是允许
checkGlobalRateLimit(context)A 类 RateLimitResult 反对 global
acquireSemaphore(name, config, context)A 类 SemaphoreTicket,或 null 当没有空档或者没有限制时
acquireGlobalSemaphore(context)A 类 SemaphoreTicket 反对 globalConcurrency,或 null
destroy()断开存储

经理不申请 defaultTimeout 本身:从 guard.config 并传递给 withTimeout。 。 。 .

配置参考

GuardConfig

外地类型默认说明
enabledboolean所需经费卫视是否开播. @frontmcp/sdk 读取; createGuardManager 没有
storageStorageConfig内存存储后端, 从 @frontmcp/utils
keyPrefixstring'mcp:guard:'每个存储密钥的前缀( 后缀) : 已删除)
globalRateLimitConfig无每次请求的费率限额
globalConcurrencyConcurrencyConfig无每个实体的货币限额
defaultRateLimitRateLimitConfig无对没有自己的实体的费率限制
defaultConcurrencyConcurrencyConfig无非本实体的货币限额
defaultTimeoutTimeoutConfig无没有自己实体的超时
ipFilterIpFilterConfig无IP 过滤

RateLimitConfig

外地类型默认说明
maxRequestsnumber所需经费每个窗口允许的请求
windowMsnumber60000窗口长度( 毫秒)
partitionByPartitionKey'global'呼叫共享一个数

ConcurrencyConfig

外地类型默认说明
maxConcurrentnumber所需经费允许立即处决
queueTimeoutMsnumber0等待自由空档的时间有多长(0 立即拒绝)
partitionByPartitionKey'global'调用共享槽

TimeoutConfig

外地类型默认说明
executeMsnumber所需经费最大执行时间( 毫秒)

IpFilterConfig

外地类型默认说明
allowListstring[]无IP 地址或 CIDR 范围允许
denyListstring[]无IP 地址或 CIDR 区域拒绝
defaultAction'allow' | 'deny''allow'两个列表上的IP会发生什么,或者当客户端IP不知时
trustProxybooleanfalse阅读者 @frontmcp/sdk,不通过 IpFilter数字 : true 将客户端 IP 从 X-Forwarded-For· ; false 交给我 FRONTMCP_TRUST_PROXY
trustedProxyDepthnumber1阅读者 @frontmcp/sdk 何时 trustProxy 实值 true: 服务器附件前有多少代理 X-Forwarded-For

存储

警卫把一切藏在后面 StorageAdapter 接口 @frontmcp/utils。 。 。 . createGuardManager 从 storage 与 createStorage数字 :

后端用它来
内存( E)type: 'memory',默认值)开发,测试和单流程服务器. 每个过程都靠自己
复数( R)type: 'redis'(中文(简体) )多个共享限制的例子。 发布/订阅等待槽的呼叫者
Vercel KV (英语:type: 'vercel-kv'(中文(简体) )Vercel 上的服务器
上调( U)type: 'upstash'(中文(简体) )无服务器功能: HTTP 之上的 Redis, 可选的发布/订阅
Cloudflare KV (英语:type: 'cloudflare-kv'(中文(简体) )Cloudflare工人, KV 命名空间传入

storage 是一个 StorageConfig,例如 { type: 'redis', redis: { config: { host, port } } } 或者说 { type: 'redis', redis: { url } }没有 type 这是 'auto',它从环境变量中选择后端.

storage.fallback 决定后端无法到达时会发生什么. 与 'error',生产中的默认值(NODE_ENV=production, (中文(简体) ), createGuardManager 拒绝方式 GuardStorageUnavailableError: 速率限制未关闭。 与 'memory',在其他地方的默认, 它从 per-intance 计数器开始并登录一个警告。 如果后端稍后停止回答, 同样的设置也适用: 每次检查都会失败 GuardStorageUnavailableError,或,与 'memory',从 per-intance 计数器服务到后端再次回答.

密钥为 <keyPrefix><entity>:<partition>:<kind>:… 单人 : 前缀之后, 例如 mcp:guard:export_tickets:global:rl:…。在1.8.6之前,生成默认前缀 mcp:guard::export_tickets:…更古老的例子写的计数器不是较新的,所以限制在滚动部署时简单分拆.

错误

每个错误都会延伸 GuardError,它有一个机器可读 code 和一个HTTP statusCode。 。 。 . instanceof GuardError 还确认同一过程中该软件包的另一个副本的错误.

错误类代码状态被丢弃
ExecutionTimeoutErrorEXECUTION_TIMEOUT408withTimeout当时间流逝时
QueueTimeoutErrorQUEUE_TIMEOUT429DistributedSemaphore.acquire当它等待的时候,没有空隙
GuardStorageUnavailableErrorGUARD_STORAGE_UNAVAILABLE503createGuardManager 和经理的支票, 当无法到达存储
ConcurrencyLimitErrorCONCURRENCY_LIMIT429您的代码(和 @frontmcp/sdk),何时 acquireSemaphore 返回时 null
IpBlockedErrorIP_BLOCKED403您的代码, 用于拒绝列表中的 IP
IpNotAllowedErrorIP_NOT_ALLOWED403您的代码, 对于一个不在允许列表的 IP
import { ExecutionTimeoutError, withTimeout } from '@frontmcp/guard';

try {
  await withTimeout(() => new Promise((resolve) => setTimeout(resolve, 10_000)), 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 参考

所有东西都从包根导出.

仁爱出口
类GuardManager, (中文(简体) ), SlidingWindowRateLimiter, (中文(简体) ), DistributedSemaphore, (中文(简体) ), IpFilter
职能createGuardManager, (中文(简体) ), withTimeout, (中文(简体) ), resolvePartitionKey(partitionBy, context), (中文(简体) ), buildStorageKey(entity, partition, suffix?)
错误GuardError, (中文(简体) ), ExecutionTimeoutError, (中文(简体) ), ConcurrencyLimitError, (中文(简体) ), QueueTimeoutError, (中文(简体) ), IpBlockedError, (中文(简体) ), IpNotAllowedError, (中文(简体) ), GuardStorageUnavailableError
Zod 计划guardConfigSchema, (中文(简体) ), rateLimitConfigSchema, (中文(简体) ), concurrencyConfigSchema, (中文(简体) ), timeoutConfigSchema, (中文(简体) ), ipFilterConfigSchema, (中文(简体) ), partitionKeySchema
类型GuardConfig, (中文(简体) ), GuardLogger, (中文(简体) ), GuardManagerOptions, (中文(简体) ), CreateGuardManagerArgs, (中文(简体) ), RateLimitConfig, (中文(简体) ), RateLimitResult, (中文(简体) ), ConcurrencyConfig, (中文(简体) ), SemaphoreTicket, (中文(简体) ), TimeoutConfig, (中文(简体) ), IpFilterConfig, (中文(简体) ), IpFilterResult
分区类型PartitionKey, (中文(简体) ), PartitionKeyStrategy, (中文(简体) ), CustomPartitionKeyFn, (中文(简体) ), PartitionKeyContext
Schema 输入GuardConfigInput, (中文(简体) ), RateLimitConfigInput, (中文(简体) ), ConcurrencyConfigInput, (中文(简体) ), TimeoutConfigInput, (中文(简体) ), IpFilterConfigInput

文档

  • 守护选项数字 : rateLimit, (中文(简体) ), concurrency, (中文(简体) ), timeout 财务报告和审定财务报表 throttle 在 FrontMCP 服务器中 组件 此软件包导出
  • 限制和时间安排: 相同的选项, 逐步
  • 错误类别: 呼叫者返回错误

捐款

资料来源: libs/guard欢迎提出问题和拉动请求;见 捐款额。 。 。 .

许可证

阿帕奇2.0 (英语). 见 自由主义。 。 。 .

版本与发布记录

@frontmcp/guard 共发布 98 个版本,首次发布于 2026/03/17;过去 12 个月发布了 98 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.12.2latest2026/11/151 天前
1.12.12026/11/132 天前
1.12.02026/11/114 天前
1.12.0-rc.1rc2026/11/114 天前
1.11.32026/11/106 天前
1.11.22026/11/096 天前

其他发布通道:beta → 1.1.2-beta.1,rc → 1.12.0-rc.1。

关于 @frontmcp/guard 的常见问题

@frontmcp/guard 是什么?

FrontMCP的费率限制、货币控制、超时、IP过滤和交通警卫设施

如何安装 @frontmcp/guard?

在项目目录运行 npm install @frontmcp/guard,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@frontmcp/lazy-zod(1.12.2)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@frontmcp/guard 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@frontmcp/guard 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@frontmcp/guard 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@frontmcp/guard 可以商用吗?

@frontmcp/guard 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@frontmcp/guard 的下载量有多少?

根据 npm 官方下载统计,@frontmcp/guard 在 2026/10/16 – 2026/11/14 这 30 天内被下载 11,947 次,日均约 398 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@frontmcp/guard 还在维护吗?

最新版本 1.12.2 发布于 2026/11/15(1 天前);至今共发布 98 个版本,其中过去 12 个月发布了 98 个;首次发布于 2026/03/17。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。