Skip to content

Repository files navigation

mcpgw — 渐进式工具发现的 MCP 网关

Guide Live

mcpgw 是一个用 Rust 编写的 MCP(Model Context Protocol)网关,它将多个上游 MCP server 聚合在一起,但不会把成百上千的工具一次性塞进 LLM 的上下文中,而是只对下游客户端暴露 3 个稳定的「元工具」,让模型能够渐进式地发现并调用工具:

元工具 作用
search_tools(query) 用自然语言查询,返回最相关的工具(BM25 / 向量 / 混合 / subagent 重排,纯本地默认 BM25)
get_tool_details(name) 获取某个工具的完整定义(schema + 所属上游)
call_tool(name, arguments) 按限定名(server__tool)调用,网关转发到对应上游
run_code(code)(可选) deny-by-default QuickJS 沙箱里运行模型编写的 JS,通过注入的 callTool / 类型化 <server>.<tool> / listTools 编排多个工具(支持 Promise.all 并行),每次调用仍然经过既有的 RBAC→审批→审计门;仅在配置 [code_mode] 时暴露(默认关闭)

这样无论后端接入了多少上游、多少工具,模型看到的永远只是 3 个(开启 code-mode 后为 4 个)工具,上下文不会随工具数量膨胀

在此基础上,mcpgw 还提供了一整套面向安全公网暴露的能力(全部 opt-in、默认关闭、fail-closed): 内置 TLS、API-Key / OAuth 2.1 鉴权、细粒度 RBAC、危险操作的人工审批、只读可视化 dashboard、Prometheus metrics,以及第 4 个元工具 code-mode(在沙箱里运行模型编写的 JS 来编排多个工具调用)。

Overview Page


架构一览

flowchart LR
    subgraph Clients["下游客户端(LLM / MCP client)"]
        C1["stdio"]
        C2["streamable-HTTP"]
    end
    subgraph mcpgw["mcpgw 进程"]
        DS["downstream<br/>(rmcp Server: 4 元工具)"]
        AUTH["鉴权 + RBAC + 审批<br/>(api-key / OAuth → Principal)"]
        GW["gateway<br/>ArcSwap 快照 + 重建"]
        RET["retrieval<br/>bm25 / vector / hybrid / subagent"]
        OBS["observe / metrics / dashboard<br/>(审计 · /metrics · 只读面板)"]
    end
    subgraph Upstreams["上游 MCP servers"]
        U1["stdio 子进程"]
        U2["streamable-HTTP"]
    end
    C1 & C2 --> DS --> AUTH --> GW
    GW <-->|聚合工具 / 转发调用| U1 & U2
    GW --- RET
    DS -.-> OBS
Loading

下游 = 网关对客户端暴露的 MCP server;上游 = 网关连接的那些 MCP server。 一次 call_tool 的完整路径详见 L1 概览RBAC+审批 L3


快速开始

1. 构建

cargo build                      # 产出 target/debug/mcpgw(加 --release 出优化版)

2. 环境变量(可选,但推荐)

某些配置项(API-Key 密钥、dashboard 管理员 token、上游 credential、检索后端 API key 等)通过 TOML 中引用环境变量名 来传递,实现"配置与机密分离":

# 示例:mcpgw.toml 中不写明文密钥,而是写环境变量名
[[server.http.api_key]]
name = "demo"
env = "MCPGW_DEMO_KEY"          # 密钥本身从环境变量读取

mcpgw 启动时会自动从工作目录(及所有父目录)加载 .env 文件(使用 dotenvy),无需手动 export:

cp .env.example .env            # 从模板复制
# 编辑 .env,填入你的密钥
./target/debug/mcpgw --config mcpgw.toml serve   # 直接启动即可

.env 已加入 .gitignore,不会被误提交。团队协作时参考 .env.example 了解需要哪些变量。

3. 最小配置:聚合一个上游,启动本地网关

新建 mcpgw.toml

[retrieval]
strategy = "bm25"                # 纯本地,无需任何 API key

[server]
stdio = true                     # 下游使用 stdio(供同机 MCP 客户端 spawn)

# 一个 stdio 上游(示例:官方 everything server;替换成你自己的命令即可)
[[upstream]]
name = "demo"                    # 命名空间前缀 → 工具名形如 demo__<tool>
transport = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-everything"]
env_passthrough = ["PATH", "HOME"]   # 只透传白名单环境变量给子进程
call_timeout_ms = 30000

4. 使用向量检索 / 语义搜索(可选)

默认的 bm25 策略是纯本地、无需外部服务的。如果你的工具数量较大,或者希望更精准的 语义搜索,可以切换到基于 embedding 的策略。

vector —— 纯向量检索

将工具描述转为 embedding,查询时做余弦相似度匹配。embedding 失败时自动降级为 BM25。

前置条件:需要一个 OpenAI 兼容的 embedding endpoint(OpenAI、Azure、vLLM 等)。

[retrieval]
strategy = "vector"
top_k = 10

[retrieval.vector]
base_url = "https://api.openai.com/v1"   # 或其他兼容 endpoint
model = "text-embedding-3-small"
api_key_env = "OPENAI_API_KEY"           # 从环境变量读取,不写明文

# dim = 1536                             # 可选:维度校验(不填则自动推断)
# timeout_ms = 30000                     # 可选:请求超时(默认 30s)
# batch_size = 32                        # 可选:批量大小

.env 中设置:

OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxx

hybrid —— BM25 + 向量 RRF 融合(推荐)

同时运行 BM25 和向量检索,用 倒数排名融合(RRF) 合并两个排名,兼具 关键词匹配语义理解的优势。同样需要 embedding endpoint。

[retrieval]
strategy = "hybrid"
top_k = 10

[retrieval.vector]
base_url = "https://api.openai.com/v1"
model = "text-embedding-3-small"
api_key_env = "OPENAI_API_KEY"

subagent —— BM25 预筛选 + Chat 模型重排

先用 BM25 粗筛候选,再让一个小型 chat 模型从候选中选出最相关的工具。 适合有大量工具、希望借助 LLM 理解能力的场景。

前置条件:需要一个 OpenAI 兼容的 chat API。

[retrieval]
strategy = "subagent"
top_k = 10

[retrieval.subagent]
base_url = "https://api.openai.com/v1"
model = "gpt-4o-mini"                    # 小模型即可,只做重排
api_key_env = "OPENAI_API_KEY"
# candidates = 20                        # 可选:预筛选候选数(默认 20)

策略对比

策略 外部依赖 适用场景
bm25 工具较少(<50),关键词匹配足够好用
vector Embedding API 工具较多,需要语义搜索
hybrid Embedding API 推荐:兼顾关键词 + 语义,最稳健
subagent Chat API 工具非常多(>100),需要 LLM 理解力

5. 运行

./target/debug/mcpgw --config mcpgw.toml serve
# stderr 是日志;stdout 是 MCP 协议帧。把它配置到你的 MCP 客户端即可使用。

将下游改为 HTTP + 只读面板(适合浏览器查看、或远程客户端连接):

[server]
stdio = false                    # 只开 HTTP,后台运行不依赖 stdin

[server.http]
enabled = true
bind = "127.0.0.1:8970"          # 下游 MCP 端点:http://127.0.0.1:8970/mcp
path = "/mcp"

[dashboard]
enabled = true
bind = "127.0.0.1:8971"          # 浏览器打开 http://127.0.0.1:8971(只读)

默认端口约定:下游 MCP 8970、dashboard 8971、metrics 8972,均默认仅绑定 127.0.0.1。 绑定非 loopback 地址且无鉴权会被启动期 fail-closed 拒绝(除非显式设置 allow_public_unauthenticated = true)——详见 公网暴露指南

6. 命令行(离线测试检索,不启动服务)

# search / get-details 在工作区根目录运行,默认使用 --catalog tests/fixtures/tools.json
./target/debug/mcpgw search "weather forecast"
./target/debug/mcpgw get-details github__create_issue

主要能力(全部 opt-in,默认关闭)

能力 说明 文档
渐进式发现 3 元工具 + 可插拔检索(BM25 / 向量 / 混合 / subagent 重排,远端后端默认 30s 超时) retrieval L2
上游聚合 stdio 子进程与 streamable-HTTP 上游,env 白名单、每调用超时、tools/list_changed 热重建 upstream L2 · gateway L2
公网暴露安全 内置 TLS、API-Key / OAuth 2.1 资源服务器、fail-closed 暴露门 公网暴露指南
RBAC 角色 default-deny + deny-overrides,发现过滤 + 调用拦截 + 决策审计 RBAC+审批 L3 · rbac L2
人工审批 危险工具调用在 RBAC 放行后再经过人审第二道门(阻塞→批准/拒绝/超时) RBAC+审批 L3 · gateway 审批 L4
幂等调用 副作用工具显式 key、SQLite 持久化、并发 single-flight 与结果/墓碑重放;提供保留期内 at-most-once dispatch(非 exactly-once) idempotency L2
可视化面板 只读 dashboard:调用/追踪/指标/活动 + 上游/工具,可选 Bearer 鉴权的运行时禁用 / 在线改配 / 审批裁决 dashboard L2 · L3
可观测性 仅元数据的结构化审计 JSONL + Prometheus /metrics 导出 observe L2 · metrics L2
code-mode 沙箱 第 4 个元工具 run_code:deny-by-default QuickJS(rquickjs)沙箱运行模型编写的 JS,通过 callTool/类型化 <server>.<tool>/listTools 编排上游(支持 Promise.all 并行),每次调用复用既有 RBAC→审批→审计门不旁路;双重时限 + 4 资源闸 + code_busy 并发封顶;[code_mode] opt-in、restart-required(L3 会话/L4 流式延后) codemode L2 · L3 · L4

幂等副作用调用

幂等保护默认关闭,使用独立 SQLite 文件显式开启。terminal 结果默认保留 24 小时;retention_hours = 0 表示永久保留。默认最多保存 1 MiB 结果,超限时保存不可重放墓碑,而不是截断结果。

[idempotency]
enabled = true
store_path = "mcpgw-idempotency.sqlite"
retention_hours = 24
max_result_bytes = 1048576
store_failure_mode = "reject" # reject | warn
require = ["payments__*", "github__create_*"]

direct call_tool 在 envelope 顶层传 idempotency_key。code-mode 可用 callTool(name, args, {idempotencyKey: "..."})<server>.<tool>(args, {idempotencyKey: "..."});options 只接受 idempotencyKey,不会向上游传播该 key。已认证 HTTP 和固定 stdio identity 可用 key;匿名 HTTP keyed call 会被拒绝。

网关在保留期内提供 at-most-once dispatch,不是 exactly-once。timeout、transport 未知和进程在 durable started 之后崩溃都会返回 indeterminate;同 key 不再下发。不要自动重试,也不要直接换新 key。必须先通过上游查询、事件或 人工流程 reconcile 原业务意图,确认需要再次执行后才能使用新 key。多进程共享同一个幂等 SQLite 文件、自动重试、 upstream key propagation 均不在支持范围内。详见 idempotency L2


开发

cargo build                                              # 构建
cargo test --all-features                                # 全部测试(含 mock-stdio / HTTP e2e 需 --all-features)
cargo test --all-features -- --ignored                   # 门控的真实冒烟 / 二进制 e2e(绑端口/启进程)
cargo clippy --all-targets --all-features -- -D warnings  # 静态检查,零告警
cargo fmt --all                                          # 格式化

dashboard 前端(Svelte 5 + Vite,dist/ 已入库故 cargo 不依赖 node):

cd crates/dashboard/ui && npm install && npm test && npm run build   # 改 UI 源码后须重建 dist/(字节可复现)

文档

完整的分层文档(L1 概览 → L2 组件 → L3 内部细节 → L4 逐文件 API)详见 docs/

  • L1 概览 —— 整体架构、数据流、里程碑状态
  • 公网暴露指南 —— TLS / 隧道 / 反代 / API-Key / OAuth / RBAC / 审批的安全配置
  • RBAC + 审批 L3 —— auth → RBAC → 审批流水线与 fail-closed/fail-fast 决策矩阵
  • 幂等调用 L2 —— 显式 key、SQLite 状态机、single-flight、indeterminate 与保证边界
  • 过程产物(spec / plan / 路线图)见 docs/superpowers/

特性

  • 渐进式工具发现:将数百个工具压缩为 3 个元工具,避免上下文爆炸
  • 可插拔检索策略:BM25(默认)、向量、混合(RRF)、subagent 重排
  • 多传输协议:stdio 子进程与 HTTP 上游/下游,可混合使用
  • 企业级安全
    • 内置 TLS、API-Key / OAuth 2.1 鉴权
    • 细粒度 RBAC(角色 default-deny + deny-overrides)
    • 危险操作人工审批(human-in-the-loop)
    • fail-closed / fail-fast 设计
  • 可观测性
    • 结构化审计日志(仅元数据,不含敏感内容)
    • Prometheus metrics 导出
    • 只读可视化 dashboard(可选 Bearer 鉴权的写能力)
  • code-mode 沙箱:QuickJS 沙箱中运行模型生成的 JS,安全编排多个工具调用
  • 生产就绪
    • 热重载上游配置
    • 优雅关闭与降级启动
    • 资源限制与并发控制
    • 全面的测试覆盖(578 passed / 11 ignored)

许可证

详见仓库 LICENSE 文件(若有)。

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages