
1. 原配置里 BASE_URL 指向本地 Ollama卡在模型侧照着《从0开始搭建MCP服务》搭天气查询时模型调用默认走http://localhost:11434/v1的本地 OllamaGenericMCPClient 从 config 里读 BASE_URL 和 MODEL把 MCP Server 的工具列表转成 function call schema再通过/chat/completions和模型对话。这套设计单独用没问题但一涉及协作就卡换电脑要重装 Ollama同事要重新拉权重想切个大一点的模型又要担心显存。这次我把 MCP Client 的 BASE_URL 切到 TaoToken工具逻辑不改、weather server 不动只把模型出口换成统一 API 通道。第一步先去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 注册并创建 API Key返回后照着下面的步骤改改完收工。准确说MCP 协议帮你解决的是“模型怎么知道有哪些工具、怎么传参数、工具结果怎么回填”这三件事。它并没说模型本身必须跑在哪。原文把模型放在本地是一种省事的选择不是唯一选择。我这次的调整是把这层模型调用从“本地推理进程”换成一个 OpenAI 兼容的统一接入通道。工具侧完全不用感知这次切换mcpServers.weather里的transport、command、args、requireTools保持原样连系统提示词都继续用原来的只是请求模型时改走https://taotoken.net/api认证方式从“无”变成“Bearer YOUR_API_KEY”。改完以后天气查询链路会长成这样用户输入“北京今天天气怎么样” → GenericMCPClient 把工具 schema 和对话历史打包发给云端模型通道 → 模型返回 tool_calls要求先取当前日期 → Client 调用get_current_datetime工具 → Client 把结果交回给模型 → 模型继续生成下一个 tool_calls要求查北京天气 → Client 执行query_weather并返回结果 → 模型输出最终自然语言回答。这个链路里MCP 工具逻辑没有变化唯一变化的只是模型侧的 Base URL 和鉴权头。1.1 天气工具链本身没坏坏的是模型来源很多人在这一步遇到问题是以为 MCP Server 出了毛病。其实weather_serverV2.py用 FastMCP 注册的get_current_datetime和query_weather两个工具都是标准的 stdio 接口只要 Python 环境和mcp、httpx、pytz装好它们就能跑。真正卡住整个流程的是 GenericMCPClient 在调用模型时访问的localhost:11434不响应。用生活里的场景来理解MCP Server 像是一个电话客服团队它们会接电话、查数据、给结果。模型是那个判断“该打给哪个客服、要问什么”的调度员。原来的配置把调度员安排在同一个房间里本地 Ollama房间没人上班电话打进去就没人接。TaoToken 给这个调度员换了一个远程坐席你在网页端拿到工号API Key远端的调度员就开始工作客服团队MCP Server还是原来那批人。1.2 切到统一通道后MCP 三层角色怎么对上对照原文的三个角色Client、Server、API/Tools。这套统一通道只出现在 Client 与大模型之间的连接中不替换任何一层协议角色。GenericMCPClient 仍然是 Clientweather_serverV2.py仍然是 Serverwttr.in 仍然是背后的业务 API。所以这次改动本质上没有改变 MCP 的架构只是把原 config 里“连接模型”的两个字段替换成云端服务的对应值。也正因如此回滚非常容易把 BASE_URL 改回http://localhost:11434/v1、MODEL 改回qwen3:8b原方案立即恢复两份配置可以共存于同一个文件随用随切。2. 准备 Key一套 mcp-client 项目和一个账号假设你已经照着原文把 mcp-client 项目建好并且uv add mcp装好了依赖。如果还没有这里先补一句原文中的初始化命令pip install uv uv init mcp-client cd mcp-client uv venv source .venv/bin/activate # Windows 下执行 .venv\Scripts\activate uv add mcp这些命令和模型通道无关只是为了让你拥有一个能运行原文代码的环境。项目就绪后处理凭证侧。2.1 创建 API Key打开 TaoToken 官网完成注册并登录。进入控制台后找到 API Key 管理创建一个新 Key。创建完成后你会看到一段以平台指定前缀开头的字符串把它当作你的访问凭证不要直接写死在代码里。建议复制到一个临时文本文件后面导出环境变量和写mcp_config.json时会用到。这里有个容易忽略的点官网落地页和控制台页面是同一个站点用浏览器打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 后找的是账户注册、Key 创建、用量查看这类功能而等会填进工具的https://taotoken.net/api是程序请求接口。两者不是一回事前者给你开权限后者供代码调用。别把带参数的网址填到 config 里也别在浏览器里直接访问/api当作控制台那样只会得到一个 JSON 提示看不到任何 UI。2.2 把 Key 写进环境变量导出环境变量的命令如下# macOS / Linux export TAOTOKEN_API_KEYYOUR_API_KEY # Windows PowerShell $env:TAOTOKEN_API_KEYYOUR_API_KEY注意YOUR_API_KEY 要替换成你在官网创建的真实 Key。终端会话关闭后环境变量会消失重新打开终端需要再执行一次。不想每次都 export 的话可以写到 shell 的 rc 文件中但这步不是必须的演示场景保持手动即可。GenericMCPClient 的修改会通过os.getenv(TAOTOKEN_API_KEY)读取这个变量。3. 修改 mcp_config.json只动 model 段mcpServers 原样保留现在打开项目里的 mcp_config.json。原文给的初始结构是{ model: { BASE_URL: http://localhost:11434/v1, MODEL: qwen3:8b }, defaultServer: weather, mcpServers: { weather: { transport: stdio, command: python, args: [E:/RAG_Project/MCP_Project/mcp-client/weather_serverV2.py], env: {}, requireTools: [get_current_datetime, query_weather], systemPrompt: 你是严格遵守规则的天气助手必须执行以下步骤1. 当用户询问天气时必须先调用 get_current_datetime 获取实时日期2. 再调用 query_weather 查询指定城市天气3. 回答格式固定为今天是[日期]天气信息如下4. 禁止使用模型内部日期知识5. 若工具调用失败直接返回错误信息不编造内容。 } } }把它改成下面的内容{ model: { BASE_URL: https://taotoken.net/api, MODEL: 模型广场上的模型ID }, defaultServer: weather, mcpServers: { weather: { transport: stdio, command: python, args: [E:/RAG_Project/MCP_Project/mcp-client/weather_serverV2.py], env: { TAOTOKEN_API_KEY: YOUR_API_KEY }, requireTools: [get_current_datetime, query_weather], systemPrompt: 你是严格遵守规则的天气助手必须执行以下步骤1. 当用户询问天气时必须先调用 get_current_datetime 获取实时日期2. 再调用 query_weather 查询指定城市天气3. 回答格式固定为今天是[日期]天气信息如下4. 禁止使用模型内部日期知识5. 若工具调用失败直接返回错误信息不编造内容。 } } }和原文相比只动了 3 个地方BASE_URL改成https://taotoken.net/apiMODEL改成你在平台模型广场里看到的真实模型 IDenv里加进了TAOTOKEN_API_KEY。其余字段一律不动。3.1 BASE_URL 不要带 /v1从 OpenAI 生态转过来的开发者很容易把 Base URL 写成https://taotoken.net/api/v1。这种直觉来自https://api.openai.com/v1但 TaoToken 的兼容通道已经把版本抽象掉了接口需要的是平台根地址后面由代码自动补上/chat/completions。如果你填了/v1最终请求会变成https://taotoken.net/api/v1/chat/completions服务端很可能返回 404。正确写法就是https://taotoken.net/api后面不要再拼任何路径。有的教程会建议在环境变量里设置OPENAI_BASE_URL如果你的 GenericMCPClient 使用 httpx 手写请求就不存在这个变量作用。直接把配置文件里的 BASE_URL 写对即可。3.2 MODEL 以模型广场为准不要凭记忆写模型名。TaoToken 的模型广场会列出账号当前可用的模型 ID可能有多个版本也可能有不同组织发布的模型。登录 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 查看模型广场把你要用的那个模型 ID 完整复制到模型广场上的模型ID这个位置。复制时注意不要带前后空格也不要自己拼日期后缀。原文用的qwen3:8b在这里未必存在所以这一步必须以实际页面为准。4. 给 GenericMCPClient 补上 Authorization原文的generic_client.py在设计时假设目标模型服务不需要鉴权因为本地 Ollama 默认不校验。TaoToken 是公网 API需要证明调用者身份。我们需要在两个地方改代码实例化时读环境变量请求时带鉴权头。这样改完之后它仍然兼容本地 Ollama如果没有设置 TAOTOKEN_API_KEYAuthorization 头会被省略。4.1 在init里读取环境变量找到 GenericMCPClient 的__init__方法在self.model self.cfg[model][MODEL]之后加一行import os class GenericMCPClient: def __init__(self, cfg, server_nameNone): ... self.base_url self.cfg[model][BASE_URL] self.model self.cfg[model][MODEL] self.api_key os.getenv(TAOTOKEN_API_KEY, )这里把os模块的导入放在代码顶部即可。os.getenv的第二个参数给空字符串表示如果环境变量不存在也不会让程序崩溃。这样回退到本地 Ollama 时依然能用。4.2 给两个请求方法注入 headerscall_ollama方法原本是这样async with httpx.AsyncClient() as client: response await client.post(url, jsonpayload, timeout60.0) response.raise_for_status() return response.json()改成headers {Authorization: fBearer {self.api_key}} if self.api_key else {} async with httpx.AsyncClient() as client: response await client.post(url, jsonpayload, headersheaders, timeout60.0) response.raise_for_status() return response.json()call_ollama_stream方法同样修改headers {Authorization: fBearer {self.api_key}} if self.api_key else {} async with httpx.AsyncClient() as client: async with client.stream(POST, url, jsonpayload, headersheaders, timeout60.0) as response: response.raise_for_status() ...这样凡是走平台通道的请求都会携带Authorization: Bearer YOUR_API_KEY服务端识别到合法 Key 后才会把请求交给对应模型。如果 Key 无效返回 401我们会在排障一节解释处理方式。这个改动没有影响工具调用逻辑也没有破坏 stdio 通信。list_tools_schema、process_query、_maybe_autolist等核心方法都不受影响。5. 运行验证python generic_client.py mcp_config.json weather确认代码和配置都改好后在项目目录下执行python generic_client.py mcp_config.json weather和原文一样第二个参数是weatherClient 会根据defaultServer找到 config 中对应的 mcpServers 条目。程序启动后控制台会先打印已连接 weather 服务并列出可用工具。然后进入对话循环。输入北京今天天气怎么样按下回车后注意观察控制台输出。正常的流程会先出现“正在调用工具: get_current_datetime with args {}”然后出现“正在调用工具: query_weather with args {city: 北京}”。这说明模型已经通过云端通道拿到了工具 schema并正确地按你配置的 systemPrompt 顺序调用。最后你会看到一段中文回答包含日期和天气数据。5.1 看输出是否真的是“按原计划跑通”原文的requireTools: [get_current_datetime, query_weather]会在连接阶段校验工具列表。只要这两个工具名存在于 weather_serverV2.py 中配置检查就通过。整个过程只有模型请求地址变了所以你可以把这次运行看作是“MCP 协议层零改动、模型通道全替换”的一次验证。如果输出里看到了工具调用日志就证明从 config 到 Client 再到 Server 的链路完全正常。5.2 如果不输入中文换个城市试试可以用“上海明天天气怎么样”来做第二次测试。注意 systemPrompt 要求必须先调用 get_current_datetime这是原文刻意设计的依赖约束。云端通道下的模型只要支持 function call就会遵循这个顺序。如果模型不支持工具调用则会直接回答或报错。因此在选择模型 ID 时优先选模型广场里标注支持 function calling / tool use 的模型。6. 排障换成统一通道后最容易碰到的 4 个错这部分对照我实际运行时的观察按错误类型排列。6.1 401 Unauthorized如果 Client 在请求https://taotoken.net/api/chat/completions时收到 401说明服务端不认识你的 Key。先确认环境变量是否正确导出在终端里执行echo $TAOTOKEN_API_KEY看看输出的是YOUR_API_KEY还是真实 Key。它还是YOUR_API_KEY说明你在 export 时没替换占位符。另外确认 GenericMCPClient 进程是从同一个终端启动的新开一个终端窗口不会继承前一个窗口的环境变量。有时 config 里env.TAOTOKEN_API_KEY写的是旧的 Key而环境变量里是最新的 Key两者不一致时以环境变量里被读取到的为准。因为代码里用的是os.getenv而不是读取 config 的env。config 里的env只是传给子进程的。6.2 404 Not Found请求发到了不存在的路径。常见原因是BASE_URL带了/v1。打开 config 再检查一次确保是https://taotoken.net/api末尾没有/v1。如果你使用curl直接测试也请使用curl -X POST https://taotoken.net/api/chat/completions \ -H Authorization: Bearer YOUR_API_KEY \ -H Content-Type: application/json \ -d {model:模型广场上的模型ID,messages:[{role:user,content:hello}]}注意别给这个 Base URL 加 UTM 参数那是网页链接的专属标记程序接口不需要。6.3 模型名不存在返回内容里提到 model not found / model does not exist 时说明 MODEL 字段写错了。原教程里的qwen3:8b在新的通道上不一定存在。请重新打开模型广场把页面显示的模型 ID 整段复制不要参考记忆或旧截图。模型 ID 是大小写敏感的多一个空格都会报错。6.4 stdio 启动失败如果 Client 根本启动不了提示找不到weather_serverV2.py这通常和模型通道无关而是mcpServers.weather.args里的路径在你这台机器上不正确。原文给的是 Windows 的E:/RAG_Project/...换成你自己的绝对路径即可。注意command是python在 macOS/Linux 上如果默认 Python 版本不满足要求可能需要改成python3。这个改动仍属于 mcpServers 的范围但只涉及启动命令不影响模型调用配置。7. 跑通后的核对去控制台看调用记录一次成功的天气查询会经历两次模型交互第一次拿 tool_calls第二次拿最终回答因此控制台里应当出现至少两条模型调用记录。登录 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 进入用量或调用日志页面筛选刚才的时间窗口就能看到对应记录。这个动作做一次就够了它验证了流量确实经过 TaoToken而不是还有什么残留的本地逻辑。对照原文的“下一步”我认为不需要再改其他代码。MCP Server 可以继续扩展更多工具比如数据库查询、文件操作等Client 的通用代码无需为每个工具重写云端通道则负责让模型侧始终保持可用。之后切换模型时只需要把MODEL换成另一个可用模型 ID然后重新运行同样的命令。如果某一天你不想用云端 API把 BASE_URL 和 MODEL 改回本地 Ollama 的值代码也能正常工作有 Authorization 头则自动附带没有则忽略。这种切换方式保留了原文 MCP 架构的全部优点又让模型来源不再是令人头疼的第四台“服务器”。写到最后我也在心里确认了一遍最好的验证永远是最简单的跑一次真实的天气查询看工具日志再去控制台核对一次调用记录五分钟就能确认整套链路工作正常。