🚀 MCP代码执行服务器:超100种MCP工具的零上下文发现

别再每次查询花费30000个令牌了。此桥梁采用无特权安全机制实现了Anthropic的发现模式,在代理任何标准输入输出服务器的同时,将MCP上下文从30000个令牌减少到200个。

本项目是一个MCP代码执行服务器,其核心功能是实现“代码执行与MCP”模式,通过暴露单一工具run_python,让大语言模型(LLM)以编写Python代码的方式来发现、调用和组合其他工具,有效解决了MCP令牌消耗过大的问题,同时在数据科学、安全性和隔离性等方面具有显著优势。
🚀 快速开始
1. 前提条件(macOS或Linux)
- 检查版本:
python3 --version
- 若有需要,通过包管理器或 python.org 安装Python 3.14
- macOS:
brew install podman 或 brew install --cask docker
- Ubuntu/Debian:
sudo apt-get install -y podman 或 curl -fsSL https://get.docker.com | sh
curl -LsSf https://astral.sh/uv/install.sh | sh
podman pull python:3.14-slim
docker pull python:3.14-slim
⚠️ 重要提示
关于Pydantic兼容性(Python 3.14):如果你使用Python 3.14,请确保安装了最新的Pydantic版本(例如,pydantic >= 2.12.0)。一些较旧的Pydantic版本或从PyPI安装了单独的typing包的环境可能会引发如下错误:
TypeError: _eval_type() got an unexpected keyword argument 'prefer_fwd_module'
如果你遇到此错误,请运行:
pip install -U pydantic
pip uninstall typing
并重新运行项目设置(例如,删除 .venv/ 并执行 uv sync)。
2. 安装依赖项
使用uv同步项目环境:
uv sync
3. 启动桥梁
uvx --from git+https://github.com/elusznik/mcp-server-code-execution-mode mcp-server-code-execution-mode run
如果你更喜欢从本地检出的代码运行,等效命令如下:
uv run python mcp_server_code_execution_mode.py
4. 向你的代理注册
将以下服务器配置添加到你的代理的MCP设置文件(例如,mcp_config.json、claude_desktop_config.json等)中:
{
"mcpServers": {
"mcp-server-code-execution-mode": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/elusznik/mcp-server-code-execution-mode",
"mcp-server-code-execution-mode",
"run"
],
"env": {
"MCP_BRIDGE_RUNTIME": "podman"
}
}
}
}
5. 执行代码
result = await mcp_filesystem.read_file(path='/tmp/test.txt')
data = await mcp_search.search(query="TODO")
await mcp_github.create_issue(repo='owner/repo', title=data.title)
显式加载服务器
run_python 仅加载你请求的MCP服务器。在调用该工具时,通过 servers 数组传递这些服务器,以便诸如 mcp_serena 或 mcp_filesystem 之类的代理在沙箱内可用:
{
"code": "print(await mcp_serena.search(query='latest AI papers'))",
"servers": ["serena", "filesystem"]
}
如果你省略该列表,发现助手仍会枚举所有内容,但任何针对未加载服务器的RPC调用将返回 Server '<name>' is not available。
⚠️ 重要提示
servers 数组仅控制为沙箱调用生成哪些代理,它不会设置服务器配置字段(如 cwd)。cwd 属性是主机/服务器配置的一部分,LLM应调用 runtime.describe_server(name) 或检查 runtime.list_loaded_server_metadata() 以在假定服务器的工作目录之前发现配置的 cwd。
✨ 主要特性
与JS “代码模式”的比较
虽然有基于JavaScript的替代方案(如 universal-tool-calling-protocol/code-mode),但本项目是为 数据科学 和 安全性 而构建的:
| 特性 |
本项目(Python) |
JS代码模式(Node.js) |
| 原生语言 |
Python(AI/ML领域的语言) |
TypeScript/JavaScript |
| 数据科学 |
原生支持(pandas、numpy、scikit-learn) |
无法实现/需使用技巧 |
| 隔离性 |
强隔离(Podman/Docker容器) |
弱隔离(Node.js虚拟机) |
| 安全性 |
企业级(无特权、无网络、只读) |
进程级 |
| 设计理念 |
基础设施(独立桥梁) |
库(可嵌入) |
💡 使用建议
如果你希望你的代理分析数据、生成图表、使用科学库,或者需要严格的基于容器的隔离来运行不可信代码,请选择本项目。
解决的问题(其他方案无法解决的)
MCP令牌耗尽之痛
将Claude连接到11个MCP服务器,约100个工具,每个提示需要加载 30000个令牌 的工具模式。在你提出任何问题之前,每次查询就需要花费 0.09美元。扩展到50个服务器时,上下文窗口就会 崩溃。
现有“解决方案”为何失败
- Docker MCP网关:容器管理出色,但仍将 所有工具模式 流式传输到Claude的上下文中,没有进行令牌优化。
- Cloudflare代码模式:V8隔离速度快,但 无法代理现有的MCP服务器(Serena、Wolfram、自定义工具),存在平台锁定问题。
- 学术论文:描述了Anthropic的发现模式,但 没有提供可靠的实现。
- 概念验证:忽略了安全性(无特权)、持久性(冷启动)和代理边缘情况。
解决方案:以发现为优先的架构
- 恒定的200令牌开销,无论服务器数量多少
- 代理任何标准输入输出MCP服务器 到无特权容器中
- 跨服务器模糊搜索,无需预加载模式
- 经过生产验证,具备能力丢弃和安全隔离功能
架构差异
传统MCP(上下文受限)
┌─────────────────────────────┐
│ LLM上下文(30000个令牌) │
│ - serverA.tool1: {...} │
│ - serverA.tool2: {...} │
│ - serverB.tool1: {...} │
│ - …(更多工具) │
└─────────────────────────────┘
↓
LLM选择工具
↓
工具执行
本桥梁(以发现为优先)
┌─────────────────────────────┐
│ LLM上下文(约200个令牌) │
│ “使用discovered_servers(), │
│ query_tool_docs(), │
│ search_tool_docs()” │
└─────────────────────────────┘
↓
LLM发现服务器
↓
LLM加载模式
↓
LLM编写Python代码
↓
桥梁代理执行
结果:恒定的开销。无论你管理10个还是1000个工具,系统提示始终保持合适的大小,模式仅在需要时加载。
功能对比
| 功能 |
Docker MCP网关 |
Cloudflare代码模式 |
研究模式 |
本桥梁 |
| 解决令牌膨胀问题 |
❌ 手动预加载 |
❌ 固定目录 |
❌ 仅停留在理论层面 |
✅ 运行时发现 |
| 通用MCP代理 |
✅ 容器 |
⚠️ 特定平台 |
❌ 未提供 |
✅ 任何标准输入输出服务器 |
| 无特权安全机制 |
⚠️ 可选 |
✅ V8隔离 |
❌ 未解决 |
✅ 丢弃能力的沙箱 |
| 自动发现 |
⚠️ 受目录限制 |
❌ 不适用 |
❌ 未实现 |
✅ 9种配置路径 |
| 工具文档搜索 |
❌ |
❌ |
⚠️ 概念性 |
✅ search_tool_docs() |
| 生产验证 |
⚠️ 取决于你 |
✅ 托管服务 |
❌ 原型 |
✅ 经过测试的桥梁 |
与动态工具集(Speakeasy)的比较
Speakeasy的 动态工具集 使用三步流程:search_tools → describe_tools → execute_tool。虽然这节省了令牌,但会迫使代理进入“冗长”的循环:
- 搜索:“查找处理GitHub问题的工具”
- 描述:“获取
create_issue 的模式”
- 执行:“调用
create_issue”
本桥梁(以代码为优先)简化了这个循环:
- 代码:“导入
mcp_github,搜索‘issues’,如果不存在则创建一个。”
代理编写 单个Python脚本,在一次往返中完成发现、逻辑和执行。它更快、更便宜(减少了中间LLM调用),并且能够处理复杂逻辑(循环、重试),而简单的“执行”工具无法做到。
与OneMCP(Gentoro)的比较
OneMCP 提供了一个“手册”聊天界面,你可以在其中提问并计划执行。这对于简单查询很有用,但会使执行过程变成一个 黑盒。
本桥梁 为代理提供 原始的、沙箱化的控制。代理不再要求黑盒“执行任务”,而是成为程序员,编写与API交互的精确代码。这允许精确处理边缘情况和进行复杂的数据处理,而自然语言规划器可能会遗漏这些。
独特特性
-
两阶段发现 – discovered_servers() 揭示存在的服务器;query_tool_docs(name) 仅加载你需要的模式。
-
跨服务器模糊搜索 – 让模型无需记忆目录名称即可找到工具:
from mcp import runtime
matches = await runtime.search_tool_docs("calendar events", limit=5)
for hit in matches:
print(hit["server"], hit["tool"], hit.get("description", ""))
-
零拷贝代理 – 每个工具调用都在沙箱内进行,通过标准输入输出严格超时镜像。
-
默认无特权 – Podman/Docker容器以 --cap-drop=ALL 运行,根目录只读,无新特权,并具有显式的内存/PID上限。
-
紧凑 + TOON输出 – 大多数运行返回最小的纯文本响应,可通过 MCP_BRIDGE_OUTPUT_MODE=toon 获取确定性的TOON块。
适用人群
- 管理两位数MCP服务器且无法承受上下文膨胀的团队。
- 编排循环、重试和条件语句而非单个工具调用的代理。
- 需要为LLM生成的代码提供无特权隔离的安全意识较强的运维人员。
- 希望重用现有MCP目录而无需手动策划清单的从业者。
设计理念:“无MCP”方法
本服务器遵循 你可能根本不需要MCP 的理念,对于每个小工具都如此。与其为简单任务构建刚性的MCP服务器,你可以使用本服务器为你的代理提供对Bash和Python的 原始、沙箱化访问。
- 临时工具:需要一个脚本来抓取网站或解析文件?只需编写并运行它,无需部署新的MCP服务器。
- 可组合性:在命令之间管道输出,将中间结果保存到文件中,并使用标准Unix工具。
- 安全性:与直接给代理访问你的机器的原始shell不同,本服务器在安全的、无特权的容器中运行所有内容。你可以获得“Bash/代码”的强大功能而无需承担风险。
关键特性
🛡️ 健壮性与可靠性
- 懒运行时检测:即使Podman/Docker未准备好,也能立即启动。仅在请求代码执行时检查运行时。
- 自引用预防:自动检测并跳过会递归启动桥梁的配置。
- 噪声过滤:忽略来自健谈的MCP客户端的良性JSON解析错误(如空行)。
- 智能卷共享:探测Podman虚拟机以确保卷共享正常工作,即使在旧版本中也是如此。
🔒 安全至上
- 无特权容器 - 无需特权辅助程序
- 网络隔离 - 无网络访问
- 只读文件系统 - 不可变根目录
- 丢弃能力 - 无系统访问
- 无特权用户 - 以UID 65534运行
- 资源限制 - 内存、PID、CPU、时间
- 自动清理 - 临时IPC目录
⚡ 性能
- 持久会话 - 跨调用保留变量和状态
- 持久客户端 - MCP服务器保持热启动
- 上下文效率 - 与传统MCP相比,减少95%以上
- 异步执行 - 合理管理资源
- 单一工具 - Claude上下文中仅存在
run_python
🔧 开发者体验
响应格式
- 默认(紧凑) – 响应以纯文本呈现,外加一个最小的
structuredContent 有效负载,仅包含非空字段。stdout/stderr 行保持不变,因此提示保持简洁,同时不牺牲内容。
- 可选TOON – 设置
MCP_BRIDGE_OUTPUT_MODE=toon 以发出 面向令牌的对象表示法 块。我们仍然丢弃空字段,并在 structuredContent 中镜像相同的结构;当你需要为下游提示进行确定性令牌化时,TOON很方便。
- 回退JSON – 如果TOON编码器不可用,我们会自动回退到漂亮的JSON块,同时保留修剪后的有效负载。
发现工作流
- 工具模式中的
SANDBOX_HELPERS_SUMMARY 仅宣传发现助手(discovered_servers()、list_servers()、query_tool_docs()、search_tool_docs() 等)。它从不包含单个服务器或工具的文档。
- 首次使用时,LLM通常调用
discovered_servers()(或 list_servers_sync() 获取缓存列表)来枚举MCP服务器,然后调用 query_tool_docs(server) / query_tool_docs_sync(server) 或 search_tool_docs("keyword") / search_tool_docs_sync("keyword") 来获取相关的文档子集。
- 工具元数据按需流式传输,无论安装了多少服务器或工具,系统提示始终保持在大约200个令牌左右。
- 一旦LLM获得所需的文档,它就会编写Python代码,使用生成的
mcp_<alias> 代理或 mcp.runtime 助手来调用工具。
💡 使用建议
如果你需要简短描述而不探查助手,请调用 runtime.capability_summary() 以打印一段适合回答诸如“代码执行MCP可以做什么?”之类问题的概述。
📦 安装指南
环境变量
| 变量 |
默认值 |
描述 |
MCP_BRIDGE_RUNTIME |
auto |
容器运行时(podman/docker) |
MCP_BRIDGE_IMAGE |
python:3.14-slim |
容器镜像 |
MCP_BRIDGE_TIMEOUT |
30s |
默认超时时间 |
MCP_BRIDGE_MAX_TIMEOUT |
120s |
最大超时时间 |
MCP_BRIDGE_MEMORY |
512m |
内存限制 |
MCP_BRIDGE_PIDS |
128 |
进程限制 |
MCP_BRIDGE_CPUS |
- |
CPU限制 |
MCP_BRIDGE_CONTAINER_USER |
65534:65534 |
以UID:GID运行 |
MCP_BRIDGE_RUNTIME_IDLE_TIMEOUT |
300s |
关闭延迟 |
MCP_BRIDGE_STATE_DIR |
~/MCPs |
主机目录,用于IPC套接字和临时状态 |
MCP_BRIDGE_OUTPUT_MODE |
compact |
响应文本格式(compact 或 toon) |
MCP_BRIDGE_LOG_LEVEL |
INFO |
桥梁日志详细程度 |
服务器发现
主要位置
⚠️ 重要提示
目前 推迟 了对扫描单个代理配置文件(例如,.claude.json、.vscode/mcp.json)的支持。请将所有MCP服务器定义的 .json文件放在 ~/MCPs 目录中,以确保它们被发现。
示例服务器(~/MCPs/filesystem.json)
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
}
}
}
⚠️ 重要提示
为防止递归启动,桥梁会自动跳过任何似乎会再次启动 mcp-server-code-execution-mode 的配置项(包括 uvx … mcp-server-code-execution-mode run)。如果你有意需要将桥梁作为嵌套MCP服务器暴露,请设置 MCP_BRIDGE_ALLOW_SELF_SERVER=1。
Docker MCP网关集成
当你依赖 docker mcp gateway run 来暴露第三方MCP服务器时,桥梁只需执行网关二进制文件。网关负责拉取工具镜像并连接标准输入输出传输,因此请确保主机环境准备就绪:
- 为网关目录中引用的每个注册表运行
docker login(例如,Docker Hub mcp/* 镜像、ghcr.io/github/github-mcp-server)。如果没有缓存的凭证,拉取步骤将在任何工具上线之前失败。
- 为这些服务器提供所需的机密信息 ——
github-official 需要 github.personal_access_token,其他服务器可能需要API密钥或认证令牌。使用 docker mcp secret set <name>(或你的网关配置的任何机制),以便容器在启动时看到这些值。
- 镜像目录所需的任何卷挂载或环境变量(文件系统路径、存储卷等)。缺少挂载或凭证通常会在标准输入输出握手期间显示为
failed to connect: calling "initialize": EOF。
- 如果
list_tools 仅返回内部管理助手(mcp-add、code-mode 等),则网关从未完成初始化外部服务器 —— 检查网关日志以查找缺少的机密信息或注册表访问错误。
状态目录与卷共享
- 运行时工件(包括生成的
/ipc/entrypoint.py 和相关握手元数据)默认位于 ~/MCPs/ 下。设置 MCP_BRIDGE_STATE_DIR 以重新定位它们。
- 当选择的运行时是Podman时,桥梁会自动执行
podman machine set --rootful --now --volume <state_dir>:<state_dir>,以便虚拟机可以挂载该目录。在不支持 --volume 的旧版 podman machine 构建中,桥梁现在会使用 podman machine ssh test -d <state_dir> 探测虚拟机,如果共享已经可用则继续执行。
- Docker Desktop不提供文件共享的CLI;在运行桥梁之前,请确保所选的状态目录在Docker Desktop → 设置 → 资源 → 文件共享中标记为共享。
- 要手动验证共享,请运行
docker run --rm -v ~/MCPs:/ipc alpine ls /ipc(或Podman等效命令)并确认文件可见。
💻 使用示例
基础用法
文件处理
files = await mcp_filesystem.read_file(path='/tmp/test.txt')
for file in files:
content = await mcp_filesystem.read_file(path=file)
if 'TODO' in content:
print(f"TODO in {file}")
高级用法
数据管道
transcript = await mcp_google_drive.get_document(documentId='abc123')
summary = transcript[:500] + "..."
await mcp_salesforce.update_record(
objectType='SalesMeeting',
recordId='00Q5f000001abcXYZ',
data={'Notes': summary}
)
多系统工作流
issues = await mcp_jira.search_issues(project='API', status='Open')
for issue in issues:
details = await mcp_jira.get_issue(id=issue.id)
if 'bug' in details.description.lower():
await mcp_github.create_issue(
repo='owner/repo',
title=f"Bug: {issue.title}",
body=details.description
)
检查可用服务器
from mcp import runtime
print("Discovered:", runtime.discovered_servers())
print("Cached servers:", runtime.list_servers_sync())
print("Loaded metadata:", runtime.list_loaded_server_metadata())
print("Selectable via RPC:", await runtime.list_servers())
loaded = runtime.list_loaded_server_metadata()
if loaded:
first = runtime.describe_server(loaded[0]["name"])
for tool in first["tools"]:
print(tool["alias"], "→", tool.get("description", ""))
if loaded:
summaries = await runtime.query_tool_docs(loaded[0]["name"])
detailed = await runtime.query_tool_docs(
loaded[0]["name"],
tool=summaries[0]["toolAlias"],
detail="full",
)
print("Summaries:", summaries)
print("Cached tools:", runtime.list_tools_sync(loaded[0]["name"]))
print("Detailed doc:", detailed)
results = await runtime.search_tool_docs("calendar events", limit=3)
for result in results:
print(result["server"], result["tool"], result.get("description", ""))
print("Capability summary:", runtime.capability_summary())
print("Docs from cache:", runtime.query_tool_docs_sync(loaded[0]["name"]) if loaded else [])
print("Search from cache:", runtime.search_tool_docs_sync("calendar"))
运行上述代码片段时,LLM看到的示例输出如下:
Discovered: ('stub',)
Loaded metadata: ({'name': 'stub', 'alias': 'stub', 'tools': [{'name': 'echo', 'alias': 'echo', 'description': 'Echo the provided message', 'input_schema': {...}}]},)
Selectable via RPC: ('stub',)
更喜欢 listMcpResources 的客户端可以跳过执行助手代码片段,而是请求 resource://mcp-server-code-execution-mode/capabilities 资源。服务器通过 resources/list 宣传该资源,读取该资源将返回相同的助手摘要以及一个用于显式加载服务器的简短清单。
📚 详细文档
- README.md - 本文件,快速入门
- GUIDE.md - 全面的用户指南
- ARCHITECTURE.md - 技术深度剖析
- HISTORY.md - 发展历程与经验教训
- STATUS.md - 当前状态与路线图
🔧 技术细节
架构
┌─────────────┐
│ MCP客户端 │ (你的代理)
└──────┬──────┘
│ 标准输入输出
▼
┌──────────────┐
│ MCP代码执行 │ ← 发现、代理、管理
│ 桥梁 │
└──────┬──────┘
│ 容器
▼
┌─────────────┐
│ 容器 │ ← 以严格隔离方式执行
│ 沙箱 │
└─────────────┘
零上下文发现
与传统的MCP服务器预加载每个工具定义(有时超过30000个令牌)不同,本桥梁将系统提示固定在大约200个令牌左右,并训练LLM按需发现所需内容:
- LLM调用
discovered_servers() → 了解哪些桥梁可用,而无需加载模式。
- LLM调用
query_tool_docs("serena") → 仅加载该服务器的工具文档,可根据工具进行过滤。
- LLM编写编排代码 → 调用助手,如
mcp_serena.search() 或 mcp.runtime.call_tool()。
结果:无论配置多少个MCP服务器,上下文使用量始终保持有效恒定。
过程:
- 客户端调用
run_python(code, servers, timeout)
- 桥梁加载请求的MCP服务器
- 准备沙箱调用:收集MCP工具元数据,将入口点写入共享的
/ipc 卷,并导出 MCP_AVAILABLE_SERVERS
- 生成的入口点将标准输入输出重新连接到JSON帧消息,并通过容器的标准输入/标准输出管道代理MCP调用
- 持久执行:容器启动一次(如果未运行)并保持活动状态。
- 状态保留:一次调用中定义的变量、导入和函数在后续调用中可用。
- 主机流处理程序处理JSON帧,转发MCP流量,强制执行超时,并使容器保持活动状态以处理下一个请求。
📄 许可证
GPLv3许可证
支持
如有问题或疑问,请参阅文档或提交问题。