
1. 为什么要把 PydanticAI MCP Python 代码服务器切到远程 endpointPydanticAI 的 MCP Python 代码服务器mcp-run-python本质上是一个跑在隔离沙箱里的 Python 执行器你给它一段代码它返回执行结果、依赖列表和返回值。默认用法是本地 stdio 启动也就是客户端通过标准输入输出跟 Deno 进程通信。这个模式在单机调试时很舒服但只要涉及多人协作、CI 环境、容器化部署stdio 就会变成绊脚石——每个客户端都要自己拉起一个 Deno 进程依赖要各自装一遍日志散落在不同终端里排查问题像大海捞针。我试过在三个不同项目里复用同一套 MCP 工具链stdio 模式下最头疼的就是环境漂移A 机器上 Deno 版本是 1.4xB 机器上是 2.x同一个jsr:pydantic/mcp-run-python包解析出来的行为不一致run_python_code返回的dependencies字段有时带 numpy 有时不带。后来把 endpoint 统一改到远程通道客户端只负责发请求执行环境收敛到一处这类问题才消停。这里说的「改到 TaoToken」指的是把 MCP 客户端在调用模型侧能力时使用的 API 通道统一指向 TaoToken 提供的 endpoint。TaoToken 是一个聚合式的大模型 API 接入服务官网在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 根地址是 https://taotoken.net/api 。它的价值在于你不需要为每个模型单独维护一套 Key 和 Base URL一个统一 Key 就能覆盖多家模型MCP 客户端里配置一次后续换模型只改 Model ID。适合读这篇的人有三类一是已经在用 PydanticAI 跑 MCP Python 代码服务器、想从 stdio 迁到远程 endpoint 的开发者二是刚接触 MCP、想找一个能跑通的完整示例的 Python 工程师三是需要在 Agent 工作流里嵌入代码执行能力、又不想自己维护沙箱的团队。下面从环境准备一路写到调用验证和报错排查每一步都给可复制的片段。需要先厘清一个概念MCP 协议本身管的是「客户端 ↔ 工具服务器」的通信而模型调用管的是「客户端 ↔ 模型 API」的通信。把 endpoint 改到 TaoToken改的是后者。很多人把这两层混在一起结果在StdioServerParameters里填 API 地址怎么调都不通。记住server_params里填的是 Deno 启动命令TaoToken 的 Base URL 填在模型客户端那一侧。2. TaoToken 前置准备统一 Key 与 endpoint 填写方式在动手改代码之前先把 TaoToken 这边的准备工作做完。这一步不复杂但顺序错了后面会反复返工。首先是拿 Key。打开 https://taotoken.net/api-keys 登录后创建一个 API Key。建议按用途命名比如pydanticai-mcp-dev方便后面在多个项目里区分。Key 只在创建时完整显示一次复制后先存到密码管理器或本地.env文件里别直接硬编码进mcp_server.py——这个文件大概率会进 Git。然后是确认 Base URL。TaoToken 的 API 根地址是https://taotoken.net/api注意这个地址不带任何路径后缀也不加 UTM 参数。有些客户端要求填到/v1这一层有些只填根地址具体看客户端实现。PydanticAI 的 OpenAI 兼容客户端通常接受根地址由 SDK 自己拼/chat/completions。接着是 Model ID。TaoToken 支持多家模型Model ID 的写法跟官方一致比如gpt-4o、claude-3-5-sonnet-20241022这类。你可以在 https://taotoken.net/models 查到当前可用的完整列表。选模型时注意一点MCP Python 代码服务器本身不依赖模型它只负责执行代码模型是在 Agent 侧决定「要不要调用 run_python_code 工具」以及「传什么代码进去」。所以 Model ID 选一个工具调用tool calling能力稳定的就行别选那些对 function calling 支持不完整的模型否则会出现模型不触发工具、直接编造结果的情况。环境变量建议这样组织放在项目根目录的.envTAOTOKEN_API_KEYsk-你的key TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_MODELgpt-4o然后在 Python 里用python-dotenv加载。这样做的好处是本地开发、CI、容器三套环境只需要换.env代码一行不动。如果你用的是 Claude Code 这类带 OAuth 流程的客户端或者 Cline 的 MCP 配置注意它们的配置文件格式不一样。Claude Code 走的是~/.claude/settings.json或项目级.mcp.jsonCline 走的是 VS Code 设置里的 MCP Servers 段。不管哪种三件套都是固定的Base URL、API Key、Model ID。缺一个都连不上报错信息还各不相同后面第 5 节会逐个对照。还有一个容易忽略的点TaoToken 的 Key 有额度概念。跑 MCP 代码执行示例时模型调用次数不多但如果你把 Agent 设成自动重试一次失败可能触发好几轮请求。建议先在 https://taotoken.net/console 看一眼余额和用量心里有数。3. 可复制配置从 stdio 到远程 endpoint 的完整改造这一节是全文的核心给出可以直接复制运行的配置。分两部分MCP 服务器侧的 stdio 配置保持不变模型客户端侧的 endpoint 改成 TaoToken。先看 MCP 服务器侧。这部分跟原示例一致因为mcp-run-python本身还是通过 Deno 在本地拉起from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client server_params StdioServerParameters( commanddeno, args[ run, -N, -Rnode_modules, -Wnode_modules, --node-modules-dirauto, jsr:pydantic/mcp-run-python, stdio, ], )这段配置里-N允许网络访问-Rnode_modules和-Wnode_modules给读写权限--node-modules-dirauto让 Deno 自动管理依赖目录。这些参数不要随意删删了-N会导致 Pyodide 下载依赖失败删了读写权限会导致缓存写不进去、每次冷启动。然后是模型客户端侧也就是真正要改到 TaoToken 的地方。用 PydanticAI 的 OpenAI 兼容 provider 举例import os from dotenv import load_dotenv from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider load_dotenv() model OpenAIModel( os.getenv(TAOTOKEN_MODEL, gpt-4o), providerOpenAIProvider( base_urlos.getenv(TAOTOKEN_BASE_URL, https://taotoken.net/api), api_keyos.getenv(TAOTOKEN_API_KEY), ), ) agent Agent(model, system_prompt你可以调用 run_python_code 工具执行 Python 代码。)如果你更习惯用 TOML 或 JSON 配置文件比如 Cline、Claude Code 的 MCP 配置格式是这样的。以 Cline 的mcp_settings.json为例{ mcpServers: { pydantic-run-python: { command: deno, args: [ run, -N, -Rnode_modules, -Wnode_modules, --node-modules-dirauto, jsr:pydantic/mcp-run-python, stdio ], env: { TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_API_KEY: sk-你的key, TAOTOKEN_MODEL: gpt-4o } } } }注意env段里放的是模型侧要用的变量不是 MCP 服务器要用的。MCP 服务器只认 Deno 那套参数。这个区分很关键放错了不会报错但模型调用会静默失败。如果你用的是 Codex 的auth.json结构写法又不一样{ base_url: https://taotoken.net/api, api_key: sk-你的key, model: gpt-4o }三件套Base URL、Key、Model ID在任何一种配置里都必须齐全。我见过有人只填了 Base URL 和 Key忘了 Model ID结果客户端用默认模型去请求TaoToken 返回 404 model not found排查半天以为是 Key 的问题。把上面两段合起来完整的mcp_server.py长这样import asyncio import os from dotenv import load_dotenv from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client load_dotenv() code import numpy a numpy.array([1, 2, 3]) print(a) a server_params StdioServerParameters( commanddeno, args[ run, -N, -Rnode_modules, -Wnode_modules, --node-modules-dirauto, jsr:pydantic/mcp-run-python, stdio, ], ) async def main(): async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools await session.list_tools() print(f可用工具数量: {len(tools.tools)}) print(f工具名称: {tools.tools[0].name!r}) result await session.call_tool( run_python_code, {python_code: code} ) print(执行结果:) print(result.content[0].text) if __name__ __main__: asyncio.run(main())这段代码里MCP 部分完全走本地 stdio模型部分通过环境变量指向 TaoToken。两者解耦互不干扰。4. 验证请求一次完整调用与成功结果确认配置写好后跑一次完整调用确认请求确实经过 TaoToken。这一步不能只看「代码有没有输出」要确认模型侧真的走了 TaoToken 通道。先装依赖uv add mcp pydantic-ai python-dotenv然后运行uv run mcp_server.py预期输出分两段。第一段是 MCP 工具发现可用工具数量: 1 工具名称: run_python_code第二段是代码执行结果执行结果: statussuccess/status dependencies[numpy]/dependencies output [1 2 3] /output return_value [ 1, 2, 3 ] /return_value看到statussuccess/status说明 MCP 服务器侧通了Pyodide 沙箱正常执行了 numpy 代码。但这只证明 stdio 链路 OK还没证明模型侧走了 TaoToken。要确认模型侧加一段 Agent 调用from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider model OpenAIModel( os.getenv(TAOTOKEN_MODEL), providerOpenAIProvider( base_urlos.getenv(TAOTOKEN_BASE_URL), api_keyos.getenv(TAOTOKEN_API_KEY), ), ) agent Agent(model, system_prompt需要计算时调用 run_python_code 工具。) async def ask(): result await agent.run(用 Python 算一下 1 到 100 的和) print(result.output) asyncio.run(ask())跑通后去 https://taotoken.net/console 看请求日志。如果日志里出现了这次调用的记录说明请求确实经过了 TaoToken。这一步是很多人跳过的结果出了问题不知道是模型侧还是 MCP 侧排查方向全错。实测下来从发起请求到看到日志延迟通常在几秒内。如果日志里没有记录但代码又输出了结果那大概率是客户端缓存了旧配置或者.env没被加载。检查load_dotenv()的调用位置必须在读取环境变量之前。还有一个验证技巧故意把TAOTOKEN_API_KEY改成一个错误值再跑一次。如果报 401说明请求确实打到了 TaoToken如果还是正常输出说明请求根本没走 TaoToken可能被本地某个代理或缓存拦截了。这个反向验证很管用。5. 常见报错排查401、local proxy failed、reading choices、OAuth这一节对照真实报错逐个给排查路径。这些错误我基本都踩过按出现频率排序。401 Unauthorized。最常见原因通常是 Key 没加载、Key 过期、或者 Key 前面多了空格。先检查.env里有没有引号包裹导致 Key 被当成字符串带引号再检查load_dotenv()是否在OpenAIProvider初始化之前调用。如果用的是 Cline 或 Claude Code检查配置文件里的env段有没有被正确解析——有些客户端要求 Key 放在顶层而不是嵌套在env里。local proxy failed / connection refused。这个报错说明客户端尝试连接一个本地代理端口但那个端口没有服务在监听。常见于之前配置过本地代理、后来关掉了但配置没清。检查HTTP_PROXY、HTTPS_PROXY、ALL_PROXY这几个环境变量如果指向127.0.0.1:某端口先 unset 掉再跑。另外检查base_url有没有被误写成http://localhost:...TaoToken 的地址是https://taotoken.net/api不是本地地址。Error reading choices / choices field missing。这个报错说明请求发出去了但返回的 JSON 结构里没有choices字段。原因通常是 Base URL 填错了层级——比如填成了https://taotoken.net而不是https://taotoken.net/api导致请求打到了官网首页返回的是 HTML 而不是 JSON。另一个可能是 Model ID 写错了服务端返回了错误结构。先确认 Base URL 精确到/api再确认 Model ID 在 https://taotoken.net/models 列表里存在。OAuth 相关报错。Claude Code 这类客户端默认走 OAuth 流程如果你直接填 API Key它可能仍然尝试 OAuth 刷新报 token refresh failed。解决办法是在配置里显式声明使用 API Key 模式或者把 OAuth 相关的缓存文件清掉通常在~/.claude/下。清缓存前先备份别把其他配置一起删了。Deno 侧报错PermissionDenied。这个跟 TaoToken 无关是 MCP 服务器侧的权限问题。检查args里有没有-N、-Rnode_modules、-Wnode_modules。少一个都会导致 Pyodide 初始化失败。如果报的是Module not found检查--node-modules-dirauto有没有加以及当前目录是否有写权限。工具调用不触发。模型侧不报错但run_python_code从来没被调用模型直接编了个答案。这是 Model ID 选得不对选了一个 function calling 支持弱的模型。换一个工具调用能力强的 Model ID 再试。另外检查 system prompt 有没有明确告诉模型「需要计算时调用工具」有些模型需要显式指令才触发。排查时建议按这个顺序先确认 MCP 侧单独能跑通不看模型再确认模型侧单独能跑通不接 MCP最后合起来。分层排查比一上来就端到端调快得多。6. 把 endpoint 固定下来长期编码与 Agent 场景的接入建议跑通示例只是第一步真正要落地到日常编码和 Agent 工作流还得把配置固定下来减少每次手动改环境变量的摩擦。如果你只是偶尔跑一下 MCP 代码执行按第 3 节的.env方案就够了。但如果你要把这套东西接进长期的编码助手或 Agent 流水线建议走 Coding Plan 这条线地址在 https://taotoken.net/coding-plan 。它的好处是额度、模型、通道都预先配好不用每次新建 Key、改 Base URL。对于需要频繁调用工具、跑多轮 Agent 的场景省下的配置时间很可观。接入文档在 https://taotoken.net/doc 里面有各客户端的完整配置示例包括 Claude Code、Cline、Codex 的写法。遇到配置格式不确定的时候直接对照文档比猜快。模型对话的调试入口在 https://taotoken.net/chat 可以用来快速验证某个 Model ID 是否可用、工具调用是否正常不用每次都跑完整代码。一个实用技巧把 MCP 服务器配置和模型配置分成两个文件管理。MCP 侧用mcp.json模型侧用.env两者通过环境变量桥接。这样换模型只改.env换工具只改mcp.json互不影响。团队协作时.env进.gitignoremcp.json进版本控制新人拉下来只需要填自己的 Key。最后提醒一点MCP Python 代码服务器执行的是真实代码虽然跑在 Pyodide 沙箱里但-N参数允许了网络访问。生产环境里如果要执行不可信代码建议把网络权限收掉或者换成更严格的沙箱方案。示例里为了演示 numpy 依赖下载才开了-N实际使用时按需调整。