mcpgw 是一个用 Rust 写的智能 MCP(Model Context Protocol)网关。
它把 N 个上游 MCP server 聚合起来,但对客户端只暴露少量「元工具」——
由网关在内部做工具检索与按需加载,避免「把上百个工具一次性塞给 LLM」导致的上下文爆炸与选错工具。
🔌 生活类比
把「上百个工具一次性塞给 LLM」想成
把整座图书馆的书全堆到桌上——桌子塞满了,你也根本找不到要用的那本。
mcpgw 更像图书馆门口的
检索台:你先说一句「我想做 X」,它只把
相关的几本递给你;
需要细看时再帮你取来完整那一本;想借走时它替你去书库里把书拿出来。
LLM 始终只面对检索台这一个稳定窗口,而不是整面书墙。
它解决什么问题:工具爆炸
每个上游 MCP server 都会暴露一堆工具。把很多 server 聚合到一起,工具总数会迅速膨胀。
直接把这张长长的工具清单丢给模型,会同时引发三个麻烦:
| 维度 | 没有网关(直接聚合全部工具) | mcpgw(渐进式发现) |
| 上下文占用 | 上百个工具的 schema 全塞进 prompt,撑爆上下文窗口 | 客户端始终只看到 3 个元工具,占用恒定 |
| 选择准确率 | 候选越多,模型越容易选错工具 | 先按查询检索,只把相关候选交给模型 |
| prompt 缓存 | 上游增删工具 → 工具数组变化 → 缓存失效 | 工具数组永不变化 → 缓存稳定命中 |
它的解法:3 个元工具的渐进式发现
mcpgw 不把真实工具直接暴露出去,而是只暴露三个固定的「元工具」,让客户端按
检索 → 看详情 → 执行的节奏,分步把需要的工具「问」出来:
search_tools(query)
用自然语言查询,拿到相关工具候选
→
get_tool_details(name)
看清某个工具的完整入参 schema
→
call_tool(name, args)
带参数真正执行该上游工具
🔬 细节 / 代码对应
无论上游有多少工具、是否增减,客户端
永远只看到这 3 个元工具。
下游 MCP 服务的
list_tools 恒定返回这 3 个,因此
不需要用
list_changed 去改变模型可见的工具列表(上游变化只在网关内部触发重建检索索引)。
crates/downstream/src/lib.rs · GatewayServer::list_tools
// 客户端能看到的工具集合恒定为 3 个元工具
async fn list_tools(&self, _req, _ctx)
-> Result<ListToolsResult, McpError> {
Ok(ListToolsResult::with_all_items(meta_tools()))
}
// meta_tools() == [search_tools, get_tool_details, call_tool]
✅ 关键要点
- mcpgw = 聚合 N 个上游 MCP server 的智能网关,对外只露 3 个稳定元工具。
- 核心能力是渐进式工具发现:检索 → 详情 → 执行,把工具按需「问」出来。
- 三个元工具的真实名字是 search_tools / get_tool_details / call_tool。
💡 设计亮点
渐进式披露做在
网关(server)侧,因此
兼容所有 MCP 客户端、零改造;
又因为对外的工具数组永不变化,对
prompt 缓存友好。
这一选择背后还有现实考量:
tools/list_changed 在协议里是可选能力,主流客户端运行中刷新并不可靠,
所以 mcpgw 不依赖它来改变可见工具列表(决策详见
docs/superpowers/specs/2026-06-08-mcpgw-progressive-discovery-design.md)。