Mavryn
MCP控制平面——一个服务器来路由它们。
Mavryn是一个代理多个上游MCP服务器的单个MCP服务器。与其在AI工具中配置15台服务器,不如配置一台:Mavryn。它处理发现、命名空间、路由、策略执行和可观察性。
为什么
- 工具蔓延:15个MCP服务器=200多个工具被转储到每个提示符中,浪费令牌并混淆模型
- 无能见度:没有集中记录哪些工具被调用、何时调用或由谁调用
- 没有控制:无法跨服务器过滤、限制或管理工具访问
Mavryn修复了这三个问题。
快速开始
npm install -g mavryn
# Initialize a config
mavryn init
# Add upstream MCP servers
mavryn add github --stdio "npx" --args "-y" "@modelcontextprotocol/server-github"
mavryn add filesystem --stdio "npx" --args "-y" "@modelcontextprotocol/server-filesystem" "/home"
mavryn add slack --stdio "npx" --args "-y" "@modelcontextprotocol/server-slack" --tags comms
# See what's registered
mavryn list
# Start the gateway
mavryn serve然后配置您的AI工具,将Mavryn用作其单个MCP服务器:
{
"mcpServers": {
"mavryn": {
"command": "mavryn",
"args": ["serve"]
}
}
}就是这样。所有上游工具都可用,命名空间为 servername__toolname.
特性
工具名称间距
每个上游工具都有一个清晰的命名空间:
github__create_issue
github__list_repos
filesystem__read_file
filesystem__write_file
slack__send_message没有碰撞。没有歧义。
内置搜索
Mavryn揭露了一个 mavryn_search 允许LLM在所有可用工具中搜索的元工具:
mavryn_search({ query: "read a file" })
→ 1. filesystem__read_text_file (score: 42.3)
2. filesystem__read_file (score: 38.1)
3. filesystem__read_multiple_files (score: 15.7)使用TF-IDF评分和精确匹配增强-不需要外部API调用。
网关状态
这 mavryn_status meta-tool一目了然地显示连接的服务器、运行状况和工具计数。
过滤器
控制暴露的工具:
{
"filters": {
"includeTags": ["dev"],
"excludeTools": ["*__delete_*", "*__drop_*"]
}
}政策
第一次使用glob模式匹配允许/拒绝规则:
{
"policies": [
{ "effect": "deny", "tools": ["*__delete_*", "*__destroy_*"] },
{ "effect": "deny", "tools": ["slack__*"], "tags": ["comms"] },
{ "effect": "allow", "tools": ["*"] }
]
}健康检查
上游服务器上的自动定期健康探测。不健康的服务器将从工具列表中删除,并通过以下方式通知客户端 notifications/tools/list_changed.
{
"healthCheck": {
"enabled": true,
"intervalMs": 30000,
"timeoutMs": 5000
}
}审计跟踪
每个工具调用、拒绝和错误都附加到哈希链SQLite存储中。每一行都包含与前一行链接的规范内容的SHA-256,因此可以检测到攻击者在没有数据库访问权限的情况下意外损坏和篡改。
mavryn audit # View recent entries
mavryn audit --tail 50 # Last 50 entries
mavryn audit --decision deny # Only denials
mavryn audit --tool github__* # Filter by tool name
mavryn audit --user alice # Per-user attribution
mavryn audit --json # Raw JSONL with full row + hashes
mavryn audit verify # Walk the chain; exit 1 on tamper
mavryn audit export --format csv # Stream full DB for SIEM/auditor
mavryn audit backup audit-snapshot.db # Online backup, safe while writing在配置中启用:
{
"audit": {
"enabled": true,
"file": ".mavryn/audit.db"
}
}操作员防篡改(v0.5+)
简单的SHA-256链证明了内部一致性,但并不能防御对审计数据库(包括其 -wal sidecar):它们可以编辑一行并向前重新计算链。要缩小这一差距,请配置 audit.macKey每一新行都使用数据库外的密钥在其规范有效载荷上获得HMAC-SHA256。 mavryn audit verify 检查哈希链和MAC——没有密钥的攻击者无法伪造MAC,因此可以检测到任何重写。
# Generate a 32-byte key (one-time)
openssl rand -base64 32
# Option 1 — env var (simplest, fine for dev)
export MAVRYN_AUDIT_MAC_KEY='base64-string-from-above'{
"audit": {
"enabled": true,
"file": ".mavryn/audit.db",
"macKey": { "source": "env", "ref": "MAVRYN_AUDIT_MAC_KEY" }
}
}// Option 2 — file (k8s secret mounts, systemd LoadCredential)
{
"audit": {
"enabled": true,
"file": ".mavryn/audit.db",
"macKey": { "source": "file", "ref": "/var/run/secrets/mavryn/audit.key" }
}
}如果 audit.macKey 已配置,但无法加载源(env var未设置、文件丢失、键值包含非base64字符、解码后密钥不是32字节), mavryn serve 和 mavryn audit verify 使用特定错误退出非零,而不是静默写入或验证任何内容。配置错误很严重,包括按键中的一个拼写错误,因为 Buffer.from(str, "base64") 它本身会悄无声息地产生派生垃圾。
一个独立的Python引用验证器位于 verifier/mavryn_verify.py。它只使用Python stdlib(sqlite3, hashlib, hmac, json)并逐字节再现TS规范散列和HMAC。审计员可以在不运行任何Mavryn二进制文件的情况下从主机上复制Mavryn数据库并验证加密完整性。vitest套件在每次测试运行时都会交叉检查这两个实现。
小的 audit_meta 表记录 first_mac_seq (在配置密钥下写入的第一行的序列)。验证强制执行单调不变性:每行 seq >= first_mac_seq 必须是MAC’d。具有DB写入但没有密钥访问权限的攻击者无法通过剥离篡改行来清洗篡改行 event_mac 并重新计算未加密的哈希链——丢失的MAC行程单调。从整个列中剥离MAC并删除水印行是逃避检测的唯一方法,并且这种组合攻击仍然存在非零,并发出警告,将其与新启用的密钥区分开来。
HMAC单独做什么 *不* 抵御
- 具有DB写访问权限和相同密钥的操作员。 他们可以重写一行,重新计算其MAC,并验证仍然通过。v0.6的外部锚定(S3对象锁、透明度日志)是分层防御——模式已经保留了
anchor_hash,anchor_seq,anchor_source列,因此v0.6是一个功能添加。 - 截断。 具有DB写入功能的攻击者可以
DELETE FROM events WHERE seq > N并核实报告是否完好无损。HMAC链证明了以下行 *存在* 未发生改变;它不能证明争吵不是 *移除* 结束。通过定期出口来缓解今天的问题mavryn audit export并阻止出口。v0.6锚定也将检测截断。 - 快照回滚。 恢复昨天的
audit.db从备份中写入新行,然后在恢复的状态之上写入新行,这对数据库内链是不可见的。与截断相同的缓解措施。
关键点旋转
v0.5没有内置的重新MAC迁移。改变 audit.macKey 使得预轮换MAC在新密钥下无法验证,重新MAC现有行将伪造这些行在轮换时存在的虚假证明,因此不提供。如果必须旋转:
- 导出旋转前事件
mavryn audit export而旧密钥仍在配置中。 - 从外部验证它们(JSONL导出对于再现JCS+HMAC的Python/Go验证器来说是足够的输入)。
- 将导出视为密封的历史记录。
- 转动钥匙;新密钥下的新行MAC。
mavryn audit verify 旋转后将在第一个预旋转行失败,并显示特定的“第一个MAC已检查,可能是错误的密钥或旋转”消息。这就是设计——验证应该拒绝声称它实际上无法证明的真实性。
升级到v0.5
模式迁移在第一次打开时自动运行,并封装在单个事务中(部分故障会干净地回滚,永远不会让数据库迁移一半)。现有的v0.3.x DB增加了四个可以为空的列和一个 audit_meta 桌子;v0.5之前的行不会被回填——它们仍然只是哈希值,并将其作为遗留值进行验证。
- 不
audit.macKey已配置(默认): 行为从v0.3.x开始没有变化。新行仅为哈希值。verify报告chain intact (hash-only; no audit.macKey configured). audit.macKey在新数据库上配置: 所有行都是MAC。verify报告chain intact, N MAC-verified.audit.macKey在现有的v0.3.x数据库上配置: 旧行仅保留哈希值,新行为MAC。verify明确报告边界:chain intact (M MAC-verified, K legacy hash-only).audit.macKey已配置,但尚未发生工具调用:verify退出非零并发出警告。该状态与剥离MAC和水印的篡改尝试无法区分;通过写一行(任何工具调用)并重新运行验证来解决。
降级。 v0.5数据库将在v0.3.x或v0.4中打开——这些版本不会检查 user_version 新列可以为空,因此它们很乐意用NULL插入行 event_mac 在你的MAC行旁边。在旧版本上验证根本看不到MAC。 不要降级受MAC保护的数据库;如果您可能需要回滚,请先进行备份 mavryn audit backup audit-pre-v05.db 并降级到新的DB。
评估工具
对您的路由质量进行基准测试:
mavryn eval benchmarks/my-tests.json -k 5基准格式:
[
{
"prompt": "read the contents of a file",
"expectedTools": ["filesystem__read_file", "filesystem__read_text_file"]
}
]结构化日志记录
所有网关活动都以结构化JSON形式记录到stderr中。配置级别和可选日志文件:
{
"log": {
"level": "info",
"file": ".mavryn/gateway.log"
}
}完整配置参考
{
"version": 1,
"servers": [
{
"name": "my-server",
"transport": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@some/mcp-server"],
"env": { "API_KEY": "..." }
},
"enabled": true,
"tags": ["dev", "backend"],
"description": "My MCP server"
}
],
"filters": {
"includeTags": [],
"excludeTags": [],
"includeTools": [],
"excludeTools": []
},
"policies": [],
"healthCheck": {
"enabled": true,
"intervalMs": 30000,
"timeoutMs": 5000,
"unhealthyThreshold": 3
},
"defaults": {
"toolCallTimeoutMs": 30000
},
"audit": {
"enabled": false,
"file": ".mavryn/audit.db",
"failClosed": false,
"agentId": "my-agent",
"macKey": { "source": "env", "ref": "MAVRYN_AUDIT_MAC_KEY" }
},
"log": {
"level": "info",
"file": null
}
}运输类型
- 标准:
{ "type": "stdio", "command": "...", "args": [...], "env": {...} } - 上海证券交易所:
{ "type": "sse", "url": "https://...", "headers": {...} } - 可流式传输的HTTP:
{ "type": "streamable-http", "url": "https://...", "headers": {...} }
CLI命令
| 命令 | 描述 |
|---|---|
mavryn init | 创建 mavryn.config.json |
mavryn add | 注册上游服务器 |
mavryn remove | 删除服务器 |
mavryn list | 列出已注册的服务器 |
mavryn serve | 启动网关 |
mavryn audit | 查看审计跟踪 |
mavryn audit verify | 遍历哈希链(和MAC,如果 audit.macKey 已设置) |
mavryn audit export | 以JSONL或CSV格式流式传输完整的审计跟踪 |
mavryn audit backup | 审计数据库的在线备份 |
mavryn eval | 运行路由基准测试 |
建筑
┌─────────────────────────────────┐
│ AI Tool / Agent │
│ (Claude Code, Cursor, etc.) │
└────────────┬────────────────────┘
│ MCP (stdio)
▼
┌─────────────────────────────────┐
│ Mavryn │
│ ┌───────┐ ┌──────┐ ┌───────┐ │
│ │Router │ │Policy│ │ Audit │ │
│ └───┬───┘ └──┬───┘ └───┬───┘ │
│ └────────┼──────────┘ │
│ ┌───┴───┐ │
│ │ Proxy │ │
│ └───┬───┘ │
└───────────────┼─────────────────┘
┌────────┼────────┐
▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────┐
│GitHub│ │FS │ │Slack │
│Server│ │Server│ │Server│
└──────┘ └──────┘ └──────┘安全
Mavryn位于您的AI工具和MCP服务器之间。安全不是可选的。
秘密编辑
所有日志、审核条目和错误消息在写入之前都会被清除。Mavryn检测并编辑:
- API密钥和令牌(GitHub PAT、AWS密钥、Bearer令牌、JWT)
- 键值对中的密码和秘密
- 私钥(RSA、EC、DSA、OpenSSH)
- 带有嵌入式凭据的连接字符串
- 已知的秘密字段名称(
password,token,api_key,authorization等等)
上游响应也会被扫描——如果MCP服务器在其输出中泄漏了一个秘密,Mavryn会在将其传递给客户端之前对其进行编辑。
环境变量引用
永远不要把秘密放进去 mavryn.config.json请改用env-var引用:
{
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "$GITHUB_PERSONAL_ACCESS_TOKEN"
}
}Mavryn决定 $VAR 和 ${VAR} 运行时从进程环境中获取语法。这个秘密永远不会泄露到磁盘上。
上游响应限制
每次工具调用的上游响应上限为10MB。如果服务器返回的有效负载超过此限制,则响应将被截断并显示警告。这可以防止恶意或配置错误的上游造成内存耗尽。
上游工具名称验证
上游服务器的工具名称根据安全字符集进行验证(a-zA-Z0-9_-.:).包含命名空间分隔符的名称(__)被拒绝以防止命名空间注入攻击。每台服务器的工具数量有上限(默认值为500,可通过以下方式配置 maxTools).
工具调用超时
每个上游工具调用都有一个超时(默认为30秒,可按服务器和全局配置)。挂起的或恶意的上游无法无限期地阻止网关。
威胁模型
Mavryn将上游MCP服务器视为 不可信的具体来说:
- 工具名称 暴露前经过验证和消毒
- 工具响应 是否经过形状验证、大小限制和秘密编辑
- 错误消息 上游的数据在到达客户端之前会被编辑
- 运输凭证 从环境变量解析,不存储在配置中
- 政策执行 发生在执行之前,而不是之后
Mavryn确实如此 不 目前可防止:
- 一个受损的上游,返回微妙错误(但有效)的数据
- 通过定时或工具选择模式进行侧通道攻击
- 如果操纵LLM,则通过工具输入参数进行过滤(提示注入)
许可证
麻省理工学院
