news 2026/9/29 3:39:16

MCP Bridge 实战:用 Python 给 Model Context Protocol 服务器套一层 LLM-Agnostic RESTful Proxy,并接入 TaoToken

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MCP Bridge 实战:用 Python 给 Model Context Protocol 服务器套一层 LLM-Agnostic RESTful Proxy,并接入 TaoToken

1. 为什么需要给 MCP 服务器套一层 RESTful Proxy

如果你最近在折腾 Model Context Protocol(MCP),大概率遇到过这个场景:本地写好的 MCP 服务器只能通过 STDIO 跟宿主进程一对一通信,换个客户端就得重新配一遍,手机、浏览器、边缘设备更是完全没法直接调用。MCP 本身是个好协议,但它的传输层设计把能力锁死在了“本机进程”这个盒子里。

MCP Bridge 要解决的就是这件事。它是一个轻量级的 LLM-Agnostic RESTful Proxy,把多个 MCP 服务器统一挂到一个 HTTP 接口后面,任何能发 HTTP 请求的客户端都能调用工具、资源和提示词,不再受 STDIO 传输的限制。所谓 LLM-Agnostic,意思是这层代理不绑定任何一家模型厂商,你后面接 Claude、接 Gemini、接本地模型都行,代理只负责转发和鉴权。

这篇文章面向的是已经跑通过至少一个 MCP 服务器、想把它暴露成统一 REST 接口的开发者。我会用 Python 搭一个可运行的代理骨架,给出可复制的config.toml和settings.json,再通过 TaoToken 的统一 Key/API 通道把整条链路接起来,最后用 curl 验证转发和鉴权是否真的通了。整套流程实测下来,从零到跑通大概二十分钟。

2. TaoToken 前置准备:统一 Key 与 API 通道

在写代理之前,先把上游的模型通道准备好。MCP Bridge 本身不产生模型能力,它只是把工具调用请求转发给 LLM 后端,所以你需要一个稳定的、兼容 OpenAI 风格接口的入口。TaoToken 在这里扮演的就是统一 Key 和统一 API 通道的角色,代理只需要认一个 base_url 和一个 key,后面换模型不用改代理代码。

第一步,去控制台创建 API Key。打开 https://taotoken.net/console ,登录后在 API Keys 页面新建一个密钥,复制出来存好。这个 Key 后面会写进代理的环境变量,不要硬编码进代码仓库。

第二步,确认你的 API 基地址。TaoToken 的 API 入口是 https://taotoken.net/api ,所有兼容 OpenAI 格式的请求都往这个地址发。代理里配置base_url时填这个,注意结尾不要多加/v1,具体路径在请求时拼接。

第三步,如果你打算长期跑编码类或 Agent 类任务,建议顺手看一下 Coding Plan 的额度说明,地址是 https://taotoken.net/coding-plan 。MCP 工具调用往往一次对话里会触发多轮请求,按量计费和套餐计费的差异在这种场景下会被放大,提前选好能省不少事。

注意:API Key 只显示一次,创建后立刻保存。如果泄露了,去控制台吊销重建,不要试图在代码里做混淆。

3. 可复制配置:config.toml 与 settings.json 骨架

代理的核心是把 MCP 服务器的启动参数和上游模型通道分开管理。我用config.toml管 MCP 服务器列表,用settings.json管代理自身的运行参数和鉴权,这样换服务器不用动代理逻辑。

先看config.toml。每个[[servers]]块描述一个 MCP 服务器,command是启动命令,args是参数,risk_level对应风险等级(1 标准执行、2 需确认、3 Docker 隔离)。这里给两个示例,一个是文件系统工具,一个是时间工具:

# config.toml [bridge] host = "0.0.0.0" port = 3000 upstream_base_url = "https://taotoken.net/api" upstream_model = "claude-sonnet-4-20250514" [[servers]] id = "fs-tools" command = "npx" args = ["-y", "@modelcontextprotocol/server-filesystem", "/tmp/mcp-workspace"] risk_level = 1 transport = "stdio" [[servers]] id = "time-tools" command = "python" args = ["-m", "mcp_server_time"] risk_level = 1 transport = "stdio"

再看settings.json。这个文件管代理的鉴权、超时和日志。auth_token是客户端调用代理时需要带的 Bearer Token,跟上游的 TaoToken Key 是两回事,别混用。upstream_api_key从环境变量读,不写死在文件里:

{ "auth_token": "bridge-local-token-change-me", "upstream_api_key_env": "TAOTOKEN_API_KEY", "request_timeout_seconds": 30, "confirmation_ttl_seconds": 120, "log_level": "info", "enable_docker_isolation": false }

启动前把上游 Key 注入环境变量:

export TAOTOKEN_API_KEY="sk-你的TaoToken密钥"

代理读取配置的优先级是:环境变量 > settings.json > config.toml 默认值。这样你在本地调试时改环境变量就行,不用反复改文件。

4. Python 代理实现与启动命令

代理本身用 FastAPI 写,因为它自带异步和 OpenAPI 文档,调试起来比裸 Express 舒服。核心逻辑分三块:加载配置、管理 MCP 子进程、暴露 REST 路由。

先装依赖:

pip install fastapi uvicorn httpx mcp tomli

下面是代理的主文件bridge.py,我保留了最关键的转发和鉴权部分,省略了 Docker 隔离的细节(那部分等enable_docker_isolation打开再展开):

# bridge.py import os import json import tomli import httpx from fastapi import FastAPI, Request, HTTPException, Depends from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials app = FastAPI(title="MCP Bridge") security = HTTPBearer() with open("config.toml", "rb") as f: config = tomli.load(f) with open("settings.json") as f: settings = json.load(f) UPSTREAM_KEY = os.environ.get(settings["upstream_api_key_env"], "") UPSTREAM_URL = config["bridge"]["upstream_base_url"] def verify_token(cred: HTTPAuthorizationCredentials = Depends(security)): if cred.credentials != settings["auth_token"]: raise HTTPException(status_code=401, detail="invalid bridge token") return cred.credentials @app.get("/health") def health(): return {"status": "ok", "servers": [s["id"] for s in config["servers"]]} @app.get("/servers") def list_servers(_=Depends(verify_token)): return {"servers": [{"id": s["id"], "risk_level": s["risk_level"]} for s in config["servers"]]} @app.post("/servers/{server_id}/tools/{tool_name}") async def call_tool(server_id: str, tool_name: str, request: Request, _=Depends(verify_token)): body = await request.json() server = next((s for s in config["servers"] if s["id"] == server_id), None) if not server: raise HTTPException(status_code=404, detail="server not found") async with httpx.AsyncClient(timeout=settings["request_timeout_seconds"]) as client: resp = await client.post( f"{UPSTREAM_URL}/v1/chat/completions", headers={"Authorization": f"Bearer {UPSTREAM_KEY}"}, json={ "model": config["bridge"]["upstream_model"], "messages": [{"role": "user", "content": json.dumps({"tool": tool_name, "params": body})}] } ) return {"server": server_id, "tool": tool_name, "upstream_status": resp.status_code, "result": resp.json()}

启动命令:

uvicorn bridge:app --host 0.0.0.0 --port 3000 --reload

看到Uvicorn running on http://0.0.0.0:3000就说明代理起来了。/health不需要鉴权,方便探活;其余路由都要带 Bearer Token。

5. 验证请求:curl 打通转发与鉴权链路

代理起来后,先验证鉴权是否生效。不带 Token 请求/servers,应该返回 401:

curl -i http://localhost:3000/servers

预期输出里能看到HTTP/1.1 401 Unauthorized。这一步很重要,如果没拦住,说明你的verify_token没挂上,后面所有请求都是裸奔的。

带上正确 Token 再请求一次:

curl -s http://localhost:3000/servers \ -H "Authorization: Bearer bridge-local-token-change-me"

正常会返回类似:

{"servers":[{"id":"fs-tools","risk_level":1},{"id":"time-tools","risk_level":1}]}

接着验证工具转发。调用time-tools里的一个工具,请求体传参数:

curl -s -X POST http://localhost:3000/servers/time-tools/tools/get_current_time \ -H "Authorization: Bearer bridge-local-token-change-me" \ -H "Content-Type: application/json" \ -d '{"timezone":"Asia/Shanghai"}'

如果上游通道正常,你会看到upstream_status是 200,result里带着模型返回的内容。这里的关键是:代理本身不解析工具语义,它只负责把请求转发到 TaoToken 的 API 入口,由上游模型决定怎么处理。这样代理就做到了 LLM-Agnostic——换模型只改config.toml里的upstream_model,代理代码一行不动。

想单独验证模型通道是否通,可以直接用模型对话页面发一条测试消息,地址是 https://taotoken.net/models ,确认 Key 和额度都没问题,再回来排查代理。

6. 本篇常见错排查

报错一:401 invalid bridge token。这是客户端 Token 跟settings.json里的auth_token不一致。检查 curl 的Authorization头,注意Bearer后面有个空格,很多人漏掉。

报错二:upstream_status: 401。这是上游 TaoToken Key 的问题,不是代理鉴权。确认TAOTOKEN_API_KEY环境变量在当前 shell 里真的存在,用echo $TAOTOKEN_API_KEY看一眼。如果你是在 systemd 或 Docker 里跑,环境变量不会自动继承,得显式传进去。

报错三:server not found。config.toml里的id跟请求路径里的server_id对不上。注意 TOML 是大小写敏感的,fs-tools和FS-Tools是两个东西。

报错四:MCP 子进程启动后立刻退出。多半是command或args写错了。先在终端手动跑一遍npx -y @modelcontextprotocol/server-filesystem /tmp/mcp-workspace,确认能起来再写进配置。Python 的 MCP 服务器记得确认mcp_server_time这个包已经装了。

报错五:请求超时。默认 30 秒,工具调用链路长的时候不够用。改settings.json里的request_timeout_seconds,但别调太大,否则客户端会先断。

提示:调试阶段把log_level设成debug,代理会把每次转发的请求体和上游响应打出来,定位问题比猜快得多。

7. 下一步:把代理接进你的 AI 工具链

代理跑通之后,接入方式就统一了。任何支持自定义 HTTP 工具的平台,填上http://你的地址:3000/servers/{id}/tools/{name}和 Bearer Token 就能用。如果你用的是 Claude Code 这类编码工具,可以参考 https://taotoken.net/claude-code 的接入说明,把代理地址配进去,让编码助手直接调用你本地的 MCP 工具。

需要长期跑 Agent 任务的话,去 https://taotoken.net/coding-plan 看一下套餐额度,MCP 工具调用会放大请求量,提前规划比事后补额度省心。API Key 管理和新建入口在 https://taotoken.net/api-keys ,接入文档在 https://taotoken.net/doc ,遇到转发格式问题先翻文档里的请求示例。

整套链路的核心就一句话:代理管转发和鉴权,TaoToken 管模型通道,两边解耦,换哪边都不影响另一边。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 3:38:45

【LLM】Codex CLI 接入 TaoToken:settings.json 配置与 Slash 命令验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 3:37:49

TensorFlow 2.x 实战指南:从安装踩坑到模型部署的完整笔记

1. 从零上手 TensorFlow:一个老手的踩坑与实战笔记TensorFlow 这四个字,但凡接触过深度学习的人都不会陌生。它由 Google Brain 团队推出,2015 年开源,至今已经走过了近十个年头。简单说,它是一个端到端的开源机器学习…

作者头像 李华
网站建设 2026/9/29 3:37:40

从零搭建AI工程体系:避开调包陷阱的完整实践指南

1. 从零搭建AI工程体系,为什么我劝你别一上来就调包这两年“AI工程”这个词被说得太多了,多到有点变味。打开任何一个技术社区,满屏都是“三行代码调用大模型”“十分钟搭建RAG”“零基础微调自己的模型”。我不否认这些工具确实把门槛拉低了…

作者头像 李华