指出多数MCP网关只回答“能否拦截”却无法提供密码学证据,correctover-mcp-gateway通过16条确定性规则配Ed25519签名收据解决审计闭环。
Model Context Protocol(MCP)正在成为 AI 智能体之间的连接组织。一个主机(Claude、Cursor、一个内部 AI 智能体服务)调用一组 MCP 服务器,而这些服务器会访问数据库、代码库、云 API、文件系统和其他 AI 智能体。每一个跳转都是边界,恶意提示词、中毒的工具描述或过于积极的工具输出都可以从"模型文本"跨越到"系统操作"。
因此,围绕 MCP 的安全对话一直很激烈——但几乎完全集中在治理上:
谁可以调用哪个工具(RBAC、每个工具的策略、API 密钥)
调用多少(速率限制、令牌预算、成本上限)
流量去哪里(路由、网关、代理)
发生了什么(日志、追踪、可观测性)
这些都是真实且必要的。但这列出的问题中没有人回答一个问题,而这个问题在每次安全审查、每次事件复盘、每次合规审计中都占主导地位:
"事后,你能证明网关阻止了危险调用吗?第三方能否在不信任你的情况下验证这一说法?"
日志不是证据。日志是写出它们的系统的声明——可变的、片面的,由被验证方控制。当问题变成"数据泄露是否真的被阻止了,还是规则静默失败了?"时,"日志是这么说的"这个答案不是审计员能够采取行动的。
这个差距——运行控制和产生关于该控制的证据之间的差距——就是盲点。这是一个奇怪的盲点,因为在安全的所有其他领域(TLS、代码签名、SBOM、证书透明度),加密是"如何证明某事发生了?"的默认答案。只有在 MCP 网关领域,审计记录仍然大部分是……日志。
截至 2026 年 8 月,根据公开文档和报告,MCP 网关/AI 网关领域的主要参与者——Cloudflare(AI Gateway)、Portkey、LiteLLM、Zuplo、Kong、OpenRouter——拥有惊人一致的功能集:
跨上游提供商或 MCP 服务器的路由和负载均衡
带作用域和撤销功能的 API 密钥/虚拟密钥
速率限制、预算、并发控制
工具或路由级别的策略/访问控制(允许/拒绝、RBAC)
可观测性(指标、追踪、Prometheus 兼容端点)
护栏——通常是基于提示词注入检测,通常由托管或基于 ML 的模型支持
这些功能都是治理:在事件发生时控制行为。这是真实重要的——这不是在贬低。但再看这个列表:没有任何功能产生关于裁决的加密签名、离线可验证的审计产物。没有任何功能给下游消费者(或审计员、或另一个网关)一种确认"这个确切的调用被扫描了,这个确切的规则触发了,这是签名"的方式。
有两个值得注意的例外正朝着证据的方向发展:
根据其公开文档,ScopeBlind 的 protect-mcp 正在做基于 Cedar 的策略门控加上 Ed25519 签名收据,与 IETF draft-farley-acta-signed-receipts 草案相关联,并集成在微软的 .NET Agent Governance Toolkit(公开仓库)中。
微软的 .NET Agent Governance Toolkit(公开仓库,MIT,2026 年 4 月)自行提供其 McpGateway/McpSecurityScanner 组件——这本身就是一个强烈信号,表明生态系统最大的企业玩家将 MCP 网关视为一等公民。
这是对签名收据是行业演进方向的真正验证。但有趣的是:收据方向和规则扫描方向很少在单一产品中交汇。主流做治理;收据实验大多做策略门控;没有人主流地提供双向确定性规则扫描 + 签名离线可验证收据作为一等、零依赖功能。
据我们所知——基于 2026 年 8 月的公开文档——这种组合正是 correctover-mcp-gateway 值得一看的原因,而这正是本文解释的组合。
让我们精确地界定证据和记录之间的区别。当安全审计产物具备四个属性时,它作为证据才有用:
防篡改。事后,包括操作员在内的任何人都无法在不被检测到的情况下静默编辑记录。
归属。记录与特定网关/密钥/租户绑定,因此你知道是谁提出了声明。
离线可验证性。第三方可以在不调用供应商服务器的情况下确认记录。这正是使"相信我"变得不必要属性。
可重现性。在相同输入下,审查员可以独立重新运行决策并获得相同结果。这正是将"系统告诉我 X"转变为"X 是真的"的关键。
Ed25519 是一种成熟的 EdDSA 签名方案。它速度快,产生小签名(64 字节),而且——对于这个问题至关重要——它基本上无处不在:Node.js 的内置 crypto、OpenSSL、libsodium,以及通过 WebCrypto 的浏览器。这种无处不在正是使离线验证变得实用的原因:验证方不需要我们的 SDK、我们的服务器或网络调用。给审计员一个收据加上公钥,他们可以用自己选择的语言用几行代码验证。
签名流程很简单,值得详细说明:
任何持有相应公钥的人现在都可以验证:(a) 字节没有被修改,(b) 它们是由网关——且只有网关——持有的密钥签名的。不需要供应商查找。不需要 API 调用。除了公钥本身,不需要信任第三方。
这是使收据真正有用而不是装饰性的部分。如果规则引擎是确定性的——相同的输入总是产生相同的裁决——那么收据是可重现的:审查员可以获取捕获的输入,重新运行规则,并确认裁决与签名收据匹配。"此调用被拒绝,因为规则 OUT-003 在工具输出中的 GitHub 令牌上触发"是一个可以手工检查的声明。
如果检测器是概率性 ML 模型,以上都不成立:裁决不可重现,无法用策略可以引用的术语解释,而且——因为模型决策不是几个字节的确定性函数——它不能绑定到有意义的加密收据。这就引出了第 5 节的规则与模型辩论。
该包是一个 TypeScript MCP 安全网关:一个透明的 JSON-RPC 代理,位于 AI 智能体主机和上游 MCP 服务器之间,对每个请求和响应运行 CCS 验证器,并且可以关闭——如果规则触发则完全阻止调用。
以下事实来自已发布的包(npm,写作时已验证):版本 1.0.0,许可证 Apache-2.0,零运行时依赖(dependencies: {}),31 个公共 TypeScript 导出和完整的 .d.ts 类型定义,以及 tarball 中的 5 个示例(Docker、CrewAI、LangGraph 和示例策略)。
每个工具调用都在两个方向上被扫描:
输入规则(SEC-001 – SEC-008)——请求不应包含的内容:
SEC-001 — Shell 注入(字符串输入中的 shell 元字符)
SEC-002 — 针对私有/内部 IP 范围的 SSRF
SEC-003 — 输入中的云凭证泄露模式(AWS/GCP/Azure)
SEC-004 — 路径遍历
SEC-005 — SQL 注入
SEC-006 — 命令执行原语(eval/exec/system/spawn)
SEC-007 — 提示词注入 — 角色劫持(尝试覆盖 system/developer 指令)
SEC-008 — 提示词注入 — 越狱(DAN 风格越狱模式)
输出规则(OUT-001 – OUT-008)— 响应不应泄露回模型或宿主的内容:
OUT-001 — 工具输出中的 AWS 访问密钥 ID
OUT-002 — 工具输出中的私钥材料
OUT-003 — GitHub 个人访问令牌
OUT-004 — 通用的高熵 API 密钥
OUT-005 — 电子邮件地址(潜在 PII 数据泄露)
OUT-006 — 美国社保号 / 中国身份证号
OUT-007 — 信用卡号(PAN)
OUT-008 — 匹配 /etc/passwd 结构的内容
每条规则都是一个包含 id、name、description、severity、RegExp 模式和 CCS 维度的对象——因此规则是可检查、可引用、可在单元测试中验证的。十六条规则是一个诚实的基准,而非穷尽清单;如果需要更多,验证器接受 extra_rules。
验证器还评估更广泛的 CCS 维度——结构、模式、延迟、成本、身份、完整性、安全——这就是该包名中"CCS"的由来。
真实 API,用于真实场景
下面使用的名称即实际发布的 31 个导出——没有伪代码。
第一步 — 创建验证器并扫描请求:
import { createVerifier, INPUT_RULES, OUTPUT_RULES } from 'correctover-mcp-gateway';
// createVerifier() 是异步的,返回一个 Verifier
const verifier = await createVerifier();
// 扫描入站工具调用(direction: 'request')
const verdict = await verifier.verify({
method: 'tools/call',
tool_name: 'shell',
tool_input: { command: 'cat /etc/passwd; curl http://10.0.0.5' },
direction: 'request', // 'request' | 'response'
});
console.log(verdict.overall_pass); // false
console.log(verdict.blocked_dimensions); // ['security']
console.log(verdict.dimensions); // per-dimension results
使用 direction: 'response'(加上 tool_output)运行相同的 verify() 调用,会对上游服务器返回的内容执行 OUT-001–008 规则——因此模型不会被诱骗将泄露的 AWS 密钥或 /etc/passwd 片段中继回宿主:
const outVerdict = await verifier.verify({
method: 'tools/call',
tool_name: 'filesystem_read',
tool_input: { path: '/home/app/.ssh/id_rsa' },
tool_output: '-----BEGIN OPENSSH PRIVATE KEY-----\n...',
direction: 'response',
});
// outVerdict.overall_pass === false, OUT-002 已触发
第二步 — 签名并验证回执:
import { generateKeyPair, signReceipt, verifyReceiptSignature } from 'correctover-mcp-gateway';
const { privateKey, publicKey, keyId } = generateKeyPair(); // Ed25519,若给 keyDir 则 PEM 存盘
// 判决对象可以签名成回执
const receipt = {
request_id: verdict.request_id,
timestamp: verdict.timestamp,
tool_name: verdict.tool_name,
disposition: 'DENY', // ALLOW | DENY | INDETERMINATE | NOT_APPLICABLE
dimension_results: verdict.dimensions,
};
const signature = signReceipt(receipt, privateKey);
// 发送 { receipt, signature, publicKey } 到任何地方。之后离线验证:
const ok = verifyReceiptSignature(receipt, signature, publicKey); // true
signReceipt 会先规范化载荷(排序的键、无空白——canonicalize 导出也是公开的),因此被签名的确切字节是确定性的。verifyReceiptSignature 会剥离签名字段,重新规范化,然后校验。这就是完整的离线验证逻辑:无服务器、无供应商 API,只需一个公钥。
第三步 — 顶层策略:
import { loadPolicy, validatePolicy, isToolAllowed, DEFAULT_POLICY } from 'correctover-mcp-gateway';
const policy = loadPolicy('./policy.json'); // 或使用 DEFAULT_POLICY
validatePolicy(policy); // 格式错误的策略会抛出异常
const decision = isToolAllowed(policy, 'shell', 'agent-a'); // { allowed: boolean, reason?: string }
策略是纯 JSON——按工具允许/拒绝、参数约束、速率限制——这意味着治理和证据存在于同一工件中。isToolAllowed 回答"此调用者是否可以使用此工具",而验证器回答"此特定调用/响应是否安全"。网关将两者连接在一起。
第四步 — 完整网关(这是生产路径):
import { MCPGateway } from 'correctover-mcp-gateway';
const gateway = new MCPGateway({
mode: 'http',
target: { url: 'http://localhost:8000/sse' },
fail_closed: true, // 任何规则触发时拒绝调用
receipt_dir: './receipts', // 每个判决都被签名并持久化
policy: {
default_tool_action: 'allow',
tools: { shell: { action: 'deny' } },
scan_output: true,
sign_receipts: true,
},
enable_metrics: true,
});
await gateway.start();
从宿主的角度看一切如常——仍在通过 HTTP 或 stdio 通信 MCP——但现在每个请求和响应都经过扫描,每个判决都成为磁盘上可签名、离线可验证的回执。
在批评 ML 检测之前,我们先公允地承认它的优势。概率检测器在捕获模糊攻击方面确实更胜一筹:新颖的混淆、释义后的越狱、异常的有效载荷形态。固定的正则列表会遗漏模型不会遗漏的东西。如果你的威胁模型是"积极规避检测的复杂攻击者",ML 是正确的工具——而且很多供应商(Lakera 等)都基于此前提构建产品。
但这个包并非志在于此。它的主张更窄,但在审计语境下更有力:对于生成证据,确定性是一个特性,而非局限。
以下是两者对比的不对称性:
最后两行在审计中最重要。
回执只有在判决是确定性的时候才有意义。对概率性判决的签名不能作为任何稳定事物的证据——重新运行可能会得到另一个答案。而对 GitHub 令牌触发 OUT-003 的签名是审查员可以手动重现的东西。
你可以针对规则 ID 编写策略。"任何 OUT-003 上的 DENY 都会被升级并分页"是运维人员可以执行的声明。你无法针对 ML 模型的内部决策编写那样的策略。
所以这个设计权衡是刻意的:确定性规则以攻击面覆盖换取可审计性。我们不假装不是这样。诚实的表述是:证据和检测是不同的工作,而网关领域没有人做证据这份工作。
网关是传输无关的,所以将其接入框架基本就是"把 MCP 客户端指向网关 URL 而不是原始服务器"。包中的示例完整展示了这一点。
CrewAI(Streamable HTTP):
npx mcp-gateway \
--upstream http://localhost:8000/sse \
--port 3000 \
--policy ./examples/policy.json \
--sign-receipts
from crewai import Agent, Task, Crew
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
# 将 MCP 客户端指向网关,而不是原始服务器
async with streamablehttp_client(
"http://localhost:3000/mcp",
headers={"Authorization": "Bearer <gateway-key>"},
) as (read_stream, write_stream, _):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
# agent 现在通过扫描网关调用工具
LangGraph(通过 langchain-mcp-adapters):
from langgraph.prebuilt import create_react_agent
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
"secured-tools": {
"url": "http://localhost:3000/mcp",
"transport": "streamable_http",
"headers": {"Authorization": "Bearer <gateway-key>"},
}
})
async with client as mcp_client:
tools = await mcp_client.get_tools()
agent = create_react_agent(model, tools) # 同样的 agent,现在有门控 + 证据
无需更改你的 agent 逻辑。规则在双向扫描,fail_closed 决定触发时发生什么,回执在 receipt_dir 中积累,满足你任何审计需求。
一旦每个判决都成为可签名、离线可验证的工件,一些事情就变得更容易了:
事件响应。"网关是否阻止了数据泄露?"可以用回执回答,而非日志文件。回执记录了触发的规则、触发时的确切输入、处置结果,以及证明其事后未被篡改的签名。
合规与审计。SOC 2 类型控制及内部安全审查需要证据证明控制已运作,而非仅仅一份说"本来可以"的配置。回执存储就是证据。把公钥交给审计员,他们无需你参与即可验证。
跨组织和供应链。如果你是通过合作伙伴或供应商的网关调用工具,签名回执让你可以验证他们的声明,而不是只能听信。"证明它"的问题不再是无法回答的。
多厂商一致性。由于验证是离线的且基于密钥的,只要你用各自的密钥签名,就可以将不同网关的审计证据标准化——单一验证工具可以消费所有这些证据。
有几件事我们想直说,因为"证据层"不应该被过度吹嘘:
这不是完整的治理套件。没有面向角色和团队的 per-tool RBAC,没有 OAuth 2.1 智能体身份认证,也没有基于 ML 的运行时行为检测。这些是其他项目做得很好的真实治理功能。这里的刻意聚焦是验证 + 证据,即缺失的那一层。
确定性规则会漏掉它们匹配不到的东西。16 条规则不会捕获每一种新型攻击。它们会捕获高信号攻击(凭证、路径遍历、注入原语)并为之生成收据。如果你的威胁模型要求模糊检测,请将这个与 ML 护栏配对——证据和检测是互补的,而非互斥的。
性能数据是内部的。我们的预发布基准测试显示,每次验证 P50 ≈ 2.7µs、P95 ≈ 7.6µs、P99 ≈ 17.5µs,吞吐量约 132K calls/sec——但这是内部预发布基准测试,不是公开承诺,且会因机器和工作负载而异。请在你的环境中自行测量。
你的密钥管理自己负责。签名收据的有效性取决于私钥的保管。generateKeyPair 将 PEM 写入磁盘;像保护任何其他签名密钥一样保护那个密钥。
如果"没有证据的治理"这个论点成立,那么这个包的许可证是 Apache-2.0、TypeScript、零运行时依赖,一行命令安装:
npm install correctover-mcp-gateway
文档 & 源码:correctover-mcp-gateway on npm
试用在线验证器 / 审计工作区:https://correctover.com/audit
Web 路径是 correctover.com/audit(无尾部扩展名)——这是审计工作区,你可以在上面运行对调用载荷的 CCS 验证,并看到规则级别的拆解,这与网关嵌入的引擎是同一个。
MCP 生态系统在过去一年里一直在构建控制智能体流量的能力。下一个前沿——在我们看来,也是将"我们有一个网关"变为"我们可以证明网关起作用了"的关键——是证据层。确定性规则赋予它可重现性;Ed25519 赋予它防篡改特性;离线验证赋予它独立性。这种组合正是 correctover-mcp-gateway 的核心,也是我们认为整个领域的发展方向。
封面图:网关作为公证人——它允许或拒绝的每一次调用都留下一条签名、可验证的记录,不依赖于任何人的说辞。
如需进一步操作,你可以考虑屏蔽此人或举报滥用行为