Skip to main content
Glama
adamabdo-xynora

mcp-capability-guard

mcp-capability-guard

大多数 MCP 服务器会递给模型一把上了膛的枪,并附带一个共享的 Bearer 令牌:一个凭据,就能调用所有工具、所有请求。而这个服务器会让模型为每一颗子弹都请求许可。

这是一个小巧而完整的 MCP 服务器,构建于一个虚构的内存 CRM(Larkspur Supply Co.,七个虚构联系人)之上,演示了能力令牌(capability-token)的写入授权——这个模式提取自一个我在真实 12,000+ 联系人通讯录上运行的生产级 CRM 代理。这里的数据是虚构的;要交付的是其中的强制机制。

设计,分为五层

  1. 分层工具面。 读取操作(list_contacts、get_contact)是免费的。写入操作不存在于单一工具中——没有 add_note 工具,也没有 delete_contact 工具。每次变更都恰好经过两次调用:先 propose_write,再 execute_write。

  2. 能力令牌(核心)。 propose_write 会铸造一个一次性、带 TTL 的授权凭证,绑定到恰好一个精确的变更上——令牌内嵌了变更本身,而不是指向某个变更,因此没有查找表可被投毒,也没有 id 可被重新定向。execute_write 将令牌与变更一起提交,守卫会逐字段校验相等性。用不同的变更提交凭证不仅会失败——还会烧毁该令牌,把攻击者合法的写入也一并带走。

  3. 破坏性层级的人工确认。 change_stage、remove_tag 和 delete_contact 还额外要求操作员通过 MCP 表单引导(elicitation)明确同意,提示语会用一句话说明操作、联系人和负载。询问发生在守卫被咨询之前,因此拒绝不会消耗凭证——而没有引导通道的客户端会得到破坏性写入被拒绝的结果,而不是静默执行。双向失败关闭(fail closed)。

  4. 上层无法覆盖的底线。 处于 Closed-Lost-DNC 阶段(请勿联系、法律保留)的联系人会在存储层内部拒绝所有写入,而存储层对令牌或 MCP 一无所知。一个完全批准的流程——有效凭证、匹配的变更、已确认的人工——仍然会在那里碰壁。这就是纵深防御,而不是一个挂着三块牌子的单一闸门。

  5. 只能追加且不会泄露凭证的审计日志。 每次提议、确认、执行和拒绝都会被记录。令牌 id 只以 8 字符指纹的形式进入日志——而这是一个编译时保证:指纹字段持有一个品牌化 TypeScript 类型,只有截断函数才能产生该类型。自由文本也会按值擦除,因为守卫自身的拒绝消息会点名被拒绝的令牌。(这与我的 webhook-guard 采用相同的按值脱敏纪律——那里针对 HTTP 凭据,这里针对实时凭证。)read_audit 默认拒绝:除非服务器以 exposeAudit: true 构建,否则该工具根本不会被注册。

Related MCP server: tenant-scoped-crm

查看运行效果

npm install
npm run demo

该演示将真实服务器通过内存 MCP 传输连接到脚本化客户端,并叙述八个步骤:两次落地的写入(一次可逆,一次破坏性且已确认),然后是五次攻击——重放、偷梁换柱、被拒绝的确认、目标转移,以及对冻结记录的一次完全批准的写入——每一次都遇到其类型化的拒绝,而存储保持逐字节不变。最后读取审计跟踪,并检查其中是否出现任何完整的令牌 id。演示内联断言每个期望,任何未命中都会以非零退出码退出,因此它兼作冒烟测试,并在每次推送时于 CI 中运行。

npm test              # 158 offline tests
npm run typecheck     # strict TypeScript, no emit

一切都在离线进行:没有 API 密钥、没有网络、没有环境变量,无需配置任何东西。这就是为什么 CI 在每次推送时都会运行整个测试套件(包括演示),且无需任何机密。

证据在测试套件中

有两个套件专门用于确保上述声明真实可靠:

  • test/structural.test.ts 将源代码作为文本读取并固定架构:src/tools.ts 是唯一导入 MCP SDK 的模块;存储层对其上层的任何东西一无所知;守卫和审计模块只导入其头部声明的模块;令牌铸造仅限于守卫;字符串 tokenId 永远不会出现在 src/audit.ts 中。如果重构悄悄将 SDK 代码移入存储层,该套件会在任何行为测试之前失败。

  • test/adversarial.test.ts 让一个敌意模型对抗完全接线的服务器:跳过提议、重放、带烧毁验证的偷梁换柱、将凭证重新指向不同联系人、对冻结记录发起完全批准的进攻、通过注入时钟使凭证过期、绕过确认,以及使用攻击者选择的令牌 id 进行审计完整性检查。每次攻击都必须遇到其精确的类型化拒绝,而在所有这些之后,存储必须保持不变。

其余约 140 个测试逐单元覆盖存储、守卫、审计和工具面,包括确认必须在凭证可被消耗之前运行的顺序不变量。

版本与范围

基于 @modelcontextprotocol/sdk 1.30.0 构建,目标为 MCP 修订版 2025-11-25。2026-07-28 修订版将服务器铸造的、作为普通工具参数传递的句柄确立为跨调用状态(SEP-2567)的规范机制——本仓库中的能力令牌正是该模式,用作授权原语,因此该设计无需更改即可延续到无状态协议中。

两个运行时依赖:SDK 本身,以及 zod,后者是 SDK 自身的对等依赖模式语言——工具输入模式按 SDK 设计就是 zod 模式,因此它与其说是额外依赖,不如说是 SDK 的另一半。没有其他内容进入依赖树。存储、守卫和审计模块是纯 TypeScript,除了 node:crypto 和彼此的类型外零导入,这使得 158 个测试可以在半秒内离线运行。

这不是什么。 本仓库不实现 OAuth 或 MCP 授权规范中的资源服务器角色。那些解决的是另一个问题:在传输边界证明客户端是谁。能力令牌管理的是经过身份验证的会话可以做什么,一次一个写入——两者是组合而非竞争关系,而混淆它们正是服务器最终只有一个授权一切的 Bearer 令牌的原因。传输身份在这里被刻意排除在范围之外,以便授权模式保持清晰。

明确说明的限制

  • CRM 是虚构且基于内存的。持久化、并发和多用户会话是本演示未涉及的真实问题。

  • 令牌存在于服务器内存中;重启即遗忘。在生产环境中,同一模式在持久化存储上运行,并具有相同的单次使用语义。

  • 引导确认的有效性取决于客户端对其的渲染。向用户显示一个光秃秃的“允许?”而不是服务器句子的客户端会削弱保证——这支持将完整句子放入请求中的做法(正如本服务器所做),而不是跳过询问。

  • 存储的备注时间戳使用墙钟,因此演示输出中的一行会因运行而异。守卫和审计日志使用注入的时钟,是确定性的。

适配

该模式可迁移到任何写入有后果的 MCP 服务器:用你的系统替换存储层,保留提议/执行分离,自行决定层级,并将底线规则放在数据层而不是工具层。守卫和审计模块不导入 MCP 的任何内容,可以整体提取出来。

MIT 许可证。

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Security-enforcing MCP proxy that sits between an AI agent and any number of downstream MCP servers, intercepting every tool call through a capability-token policy gateway that can allow, deny, or escalate to human approval before the call reaches any real tool. It also exposes built-in operator tools for approval workflows, audit trail queries, token management, voice/HUD output, and hierarchical
    21
    14
    Apache 2.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    A reference MCP server demonstrating safe agent access to multi-tenant CRM data with tenant isolation enforced in the data layer, role-based permissions, and human confirmation on writes.
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    A secure MCP server for CRM operations (contacts and deals) with Auth0 OIDC authentication, role-based access control (sales-rep read-only vs sales-manager full access), and on-behalf-of token exchange.
    -
  • A
    license
    B
    quality
    A
    maintenance
    A secure MCP server enabling tool calls (kb_search, read_doc, publish_report) through a zero-trust CapabilityBroker with OWASP LLM Top-10 guardrails and human-in-the-loop approval.
    3
    Apache 2.0