实操干货!MCP Server开发从0到1:用Node与Python双语言打通TaoToken统一API通道
1. 为什么要在本地给 AI 工具接一条统一通道MCP Server 开发这件事最近问的人特别多。简单说MCPModel Context Protocol就是让本地 AI 工具比如 Claude Desktop、Cursor、Cline 这类客户端通过一套标准协议去调用外部能力的中间层。你可以把它理解成 AI 世界的 USB-C 接口以前每个工具都要单独对接一个模型服务现在只要写一个 MCP Server把请求统一转发到一条通道上客户端换不换、模型换不换你的工具代码基本不用动。那为什么标题里强调「TaoToken 统一 API 通道」因为实际开发里最烦的不是协议本身而是 Key 管理。你本地可能同时跑着好几个 AI 工具每个工具都要配一份 API Key、一份 Base URL模型 ID 还各不相同。一旦要换模型或者加一个新工具就得挨个改配置。TaoToken 提供的是 OpenAI 兼容的统一入口一个 Key 就能调用多种模型Base URL 固定模型 ID 按需切换。把它接进 MCP Server 之后你的本地工具只需要认识你这一个 Server剩下的模型路由、鉴权、格式转换全在 Server 内部完成。这篇文章面向的是想从零搭一个 MCP Server 的开发者尤其是前端转过来、对 Node 熟但对 Python 也想上手的同学。我会用 Node 和 Python 两套实现对照着写交付可复制的项目结构、依赖清单、启动脚本最后用 curl 和真实客户端各发一次请求确认通道连通、返回格式正确。全程不涉及任何网络加速工具就是本地开发 标准 HTTP 调用。先说清楚适合谁如果你已经在用某个 AI 客户端想让它能查天气、读本地文件、调你自己的业务接口那 MCP Server 就是你要写的东西如果你只是想验证一下统一 Key 能不能通那第三节的配置和第四节的 curl 就够你跑通。两条路我都铺好。2. 前置准备TaoToken Key、Node 与 Python 环境怎么配动手之前把三样东西备齐一个可用的 TaoToken API Key、Node 18、Python 3.10。这三个缺一个后面都会卡住。先说 Key。打开 https://taotoken.net/api 对应的控制台入口进 API Keys 页面创建一个新 Key。创建完立刻复制页面刷新后就看不全了。这个 Key 就是你 MCP Server 里要用的唯一凭证客户端那边不需要再配第二份。模型 ID 方面TaoToken 走的是 OpenAI 兼容格式你在请求体里写model字段即可具体可选值以控制台模型列表为准本文示例统一用占位符your-model-id你替换成自己账号下能用的那个。Node 环境这块我踩过的坑是版本。MCP 官方 SDK 要求 Node 18如果你机器上是 16npm install可能不报错但运行时fetch相关能力缺失Server 起来就崩。建议先跑node -v # 期望输出 v18.x 或更高如果低于 18用 nvm 切一下nvm install 20 nvm use 20Python 这边要求 3.10因为 MCP 的 Python SDK 用到了较新的类型语法。检查python3 --version # 期望 Python 3.10.x 及以上依赖清单我列一下Node 侧核心是modelcontextprotocol/sdkPython 侧是mcp。HTTP 请求 Node 用内置fetch18 自带Python 用httpx。完整清单语言依赖用途Nodemodelcontextprotocol/sdkMCP 协议实现Nodezod工具参数校验PythonmcpMCP 协议实现Pythonhttpx调用统一 API环境变量统一放一个.env两个语言共用同一份内容避免 Key 写死在代码里TAOTOKEN_API_KEYsk-你的Key TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_MODELyour-model-idNode 侧读环境变量用process.envPython 侧用os.environ下面代码里都会体现。注意.env不要提交到 git加进.gitignore。3. 可复制配置Node 与 Python 双实现的项目结构与启动脚本这一节是全文最干的部分直接给能跑的结构。先看目录Node 和 Python 各一个文件夹共享一份.envmcp-demo/ ├── .env ├── node-server/ │ ├── package.json │ ├── tsconfig.json │ └── src/index.ts └── python-server/ ├── requirements.txt └── server.pyNode 侧package.json关键字段{ name: mcp-node-server, version: 1.0.0, type: module, scripts: { build: tsc, start: node dist/index.js }, dependencies: { modelcontextprotocol/sdk: ^1.0.0, zod: ^3.23.0 }, devDependencies: { typescript: ^5.4.0, types/node: ^20.0.0 } }tsconfig.json用最简配置target设ES2022module设NodeNextoutDir指向dist。这些不展开照抄即可。Node 的src/index.ts核心逻辑注册一个工具ask_model参数是prompt内部把请求转发到 TaoToken 的/v1/chat/completions。关键片段import { McpServer } from modelcontextprotocol/sdk/server/mcp.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; import { z } from zod; const server new McpServer({ name: taotoken-bridge, version: 1.0.0 }); server.tool( ask_model, { prompt: z.string() }, async ({ prompt }) { const res await fetch(${process.env.TAOTOKEN_BASE_URL}/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${process.env.TAOTOKEN_API_KEY}, }, body: JSON.stringify({ model: process.env.TAOTOKEN_MODEL, messages: [{ role: user, content: prompt }], }), }); const data await res.json(); return { content: [{ type: text, text: data.choices[0].message.content }] }; } ); const transport new StdioServerTransport(); await server.connect(transport);Python 侧requirements.txtmcp1.0.0 httpx0.27.0 python-dotenv1.0.0server.py对应实现import os import httpx from mcp.server.fastmcp import FastMCP mcp FastMCP(taotoken-bridge) mcp.tool() async def ask_model(prompt: str) - str: async with httpx.AsyncClient() as client: resp await client.post( f{os.environ[TAOTOKEN_BASE_URL]}/v1/chat/completions, headers{Authorization: fBearer {os.environ[TAOTOKEN_API_KEY]}}, json{ model: os.environ[TAOTOKEN_MODEL], messages: [{role: user, content: prompt}], }, timeout30.0, ) data resp.json() return data[choices][0][message][content] if __name__ __main__: mcp.run()启动脚本Node 侧npm run build npm startPython 侧python server.py。两者都通过 stdio 与客户端通信所以直接命令行跑会「卡住」不动这是正常的它在等客户端发消息。要验证走下一节的 curl 和客户端配置。客户端配置以 Cline 为例在 MCP 设置里加一段{ mcpServers: { taotoken-bridge: { command: node, args: [/绝对路径/mcp-demo/node-server/dist/index.js], env: { TAOTOKEN_API_KEY: sk-你的Key, TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_MODEL: your-model-id } } } }这里三件套必须齐全Base URL、Key、Model ID。少任何一个工具调用都会失败。Claude Code 或 Codex 的auth.json类配置同理把这三项映射进去即可。4. 验证请求curl 与客户端各发一次确认通道连通配置写完别急着接客户端先用 curl 单独验证通道本身通不通。这一步能把「Key 问题」和「MCP 协议问题」分开排障效率高很多。curl 命令curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-你的Key \ -d { model: your-model-id, messages: [{role: user, content: 只回复两个字通了}] }期望返回结构里能看到choices[0].message.content字段内容就是模型回复。如果这一步就报 401说明 Key 或 Authorization 头有问题跟 MCP 无关先解决这个。如果返回里choices是空数组或字段名不对说明模型 ID 写错了或者该模型不支持 chat 格式。curl 通了之后再走客户端。把上一节的 JSON 配置贴进 Cline 的 MCP 设置保存后重启客户端。然后在对话里输入「用 ask_model 工具问一下11 等于几」。正常流程是客户端识别到工具调用意图通过 stdio 把请求发给你的 ServerServer 转发到 TaoToken拿到结果再回传。你会在客户端看到工具调用卡片展开能看到返回文本。实测下来第一次调用最容易卡在两个地方一是路径写成了相对路径客户端工作目录不同导致找不到index.js二是.env没被加载process.env.TAOTOKEN_API_KEY是 undefined请求头变成Bearer undefined服务端直接 401。所以客户端配置里我建议直接把 env 写进 JSON而不是依赖.env文件省得路径问题。验证成功的标志curl 返回正常 JSON客户端工具调用卡片显示返回文本且文本内容和你 curl 时问的语义一致。两个都过通道就算打通了。5. 本篇常见错排查401、local proxy failed、reading choices 怎么解这一节按真实报错来遇到哪个查哪个。401 Unauthorized。最常见。原因三种Key 复制时带了空格或换行Authorization 头拼成了Bearer后面少空格Key 本身被禁用或额度耗尽。排查方法就是拿 curl 单独打一次如果 curl 也 401那就是 Key 问题去控制台重新生成一个。注意别把 Key 写进代码提交到仓库用环境变量。local proxy failed / connection refused。这个报错通常出现在客户端侧意思是客户端连不上你的 MCP Server 进程。原因一般是启动命令路径不对或者 Node/Python 版本不满足。检查command字段指向的可执行文件是否存在args里的脚本路径是不是绝对路径。Python 侧还要确认python命令在你的 PATH 里有些系统只有python3。reading choices of undefined。这个报错来自 Server 内部说明data.choices是 undefined也就是返回体结构和你预期的不一样。八成是模型 ID 写错服务端返回了一个错误对象而不是正常 completion。解决办法在 Server 里先把data打印出来看结构别直接取choices[0]。加一层判断if (!data.choices || !data.choices[0]) { return { content: [{ type: text, text: 接口返回异常: ${JSON.stringify(data)} }] }; }OAuth 相关报错。如果你用的是 Claude Code 这类带 OAuth 流程的客户端配置 MCP Server 时可能会提示 OAuth 失败。注意 MCP Server 本身走的是 stdio不参与客户端的 OAuth。这个报错通常是客户端登录态过期重新登录客户端即可跟你的 Server 代码无关。别去改 Server 的鉴权逻辑。工具调用成功但内容为空。检查返回的content数组里type是不是text有些客户端只渲染text类型。另外确认data.choices[0].message.content不是空字符串有些模型在特定 prompt 下会返回空。排障顺序建议先 curl 验通道再客户端验协议最后看 Server 日志。三步分开别混在一起猜。6. 把通道用起来从验证到长期编码的下一步通道打通之后你手里其实就有了一个可复用的桥接层。Node 和 Python 两套实现选你顺手的那个维护就行另一套当参考。接下来可以做的事把ask_model扩展成多个工具比如summarize、translate、code_review每个工具内部走同一个 Base URL 和 Key只是 prompt 模板不同。这样你的本地 AI 工具就从一个「聊天框」变成了一个能调多种能力的入口。如果你打算长期用它做编码辅助或者 Agent 任务建议把 Key 和模型配置收敛到一处管理别散落在各个客户端的 JSON 里。TaoToken 的 Coding Plan 就是为这种长期编码场景准备的一个 Key 覆盖多种模型切换成本低。需要看具体接入方式的话接入文档里有完整的 Base URL 和参数说明。验证模型返回是否正常可以直接在模型对话页面手动发一条对比 MCP Server 返回的内容确认格式一致。这一步能帮你快速判断问题出在通道还是出在工具封装。最后说个实际经验MCP Server 开发里协议本身不难难的是环境隔离和错误处理。把 curl 验证做成习惯每次改完配置先 curl 一次能省掉大量在客户端里反复重启的时间。通道通了之后剩下的就是往工具里填业务逻辑那部分才是你真正要花心思的地方。