1. 为什么你的 Python Agent 总是接不上外部工具
如果你写过 Python Agent,大概率经历过这个场景:模型能聊天、能推理,但一到“帮我查一下库存”“读一下这个配置文件”“调一下内部工单接口”就卡住了。你不得不为每个工具手写一套函数描述、参数 Schema、调用分发逻辑,接三个工具还行,接十个就开始失控。
MCP(Model Context Protocol,模型上下文协议)就是来解决这个问题的。它是一套让 AI 应用以标准协议连接外部工具、资源和提示模板的开放协议,底层基于 JSON-RPC 2.0,支持本地 STDIO 和远程 Streamable HTTP 两种传输模式。适合谁?适合正在做 Agent、Copilot、企业知识库问答、自动化脚本平台的 Python 开发者,尤其是那些手里已经有一堆 FastAPI 服务、数据处理脚本、内部 RPC 接口,想让 AI 低成本接入的人。
我试过把一个库存查询脚本从“手写 Function Calling”改成“MCP Server + Client”的结构,最直观的感受是:工具发现、参数协商、调用返回这三件事被协议层统一了,客户端不再需要硬编码每个工具的细节。下面从架构分层讲到 Python 落地,每一步都给可复制的配置和验证动作。
MCP 的核心价值不是“模型会不会调函数”,而是“AI 系统怎么以标准化、可组合、可治理的方式连接外部世界”。它把 Host(AI 应用)、Client(协议客户端)、Server(能力提供方)三个角色拆开,让工具能力的暴露和消费解耦。你可以把已有的 Python 服务包装成 MCP Server,也可以让你的 Python Agent 作为 MCP Client 去消费别人的工具,两边都走同一套协议。
2. TaoToken 统一 Key 接入 MCP 的前置准备
在动手写 MCP Server 之前,先解决一个现实问题:你的 Python 应用最终要调用大模型来完成推理和工具选择,而模型 API 的 Key 管理、通道切换、额度控制往往比 MCP 本身还烦。TaoToken 在这里的角色是提供一个统一的 API 通道,让你用一套 Key 接入多种模型,MCP 客户端在需要模型采样时直接走这个通道。
你需要准备三样东西:Base URL、API Key、Model ID。Base URL 填https://taotoken.net/api,API Key 在控制台的 API Keys 页面创建,Model ID 根据你实际使用的模型填写。这三件套在后面的 MCP Client 配置和模型调用里都会用到。
如果你用的是 Claude Code 这类编码工具,配置方式是在 settings 里指定 Base URL 和 Key;如果用的是 Cline 或类似的 MCP 客户端,需要在 MCP 配置里同时写清楚 Server 启动命令和模型通道信息。Codex 的 auth.json 也是同样的逻辑:Base URL、Key、Model ID 三件套缺一不可。
对于 MCP 场景,TaoToken 的接入点主要在两个地方:一是 MCP Client 在 Sampling 阶段需要调用模型时,走 TaoToken 的 API;二是你的 Python Agent 本身如果要做推理,也统一走这个通道。这样你不需要在 MCP Server 里再嵌一套模型调用逻辑,Server 只管暴露工具,模型调用交给 Client 侧的 Host 处理。
实际操作上,你可以在环境变量里统一管理:
export TAOTOKEN_BASE_URL="https://taotoken.net/api" export TAOTOKEN_API_KEY="sk-your-key-here" export TAOTOKEN_MODEL_ID="your-model-id"然后在 Python 代码里读取这些变量。这样做的好处是 MCP Server 和 Client 可以共用同一套配置,切换模型或 Key 时只改环境变量,不用动代码。如果你还没有 Key,可以去控制台创建一个,接入文档里有详细的参数说明。
3. 可复制的 Python MCP Server 与 Client 配置
这一节直接给可运行的代码。先装依赖:
pip install mcp3.1 最小 MCP Server(FastMCP + Streamable HTTP)
from mcp.server.fastmcp import FastMCP mcp = FastMCP("inventory-service", json_response=True) @mcp.tool() def get_available_stock(sku_code: str) -> dict: """查询指定 SKU 的可售库存""" available = 128 return { "skuCode": sku_code, "availableStock": available, "status": "IN_STOCK" if available > 0 else "OUT_OF_STOCK", } @mcp.resource("inventory://policy") def inventory_policy() -> str: """返回库存规则说明""" return "库存低于 20 时触发补货提醒。" @mcp.prompt() def stock_analysis_prompt(sku_code: str) -> str: return f"请分析 SKU {sku_code} 的库存状态,并给出补货建议。" if __name__ == "__main__": mcp.run(transport="streamable-http")这段代码把三类能力都暴露了:@mcp.tool()是可执行动作,@mcp.resource()是可读上下文,@mcp.prompt()是可复用提示模板。启动后默认监听本地端口,你可以通过http://localhost:8000/mcp访问。
3.2 MCP Client 连接远程 Server
import asyncio from mcp import ClientSession from mcp.client.streamable_http import streamable_http_client async def main(): async with streamable_http_client("http://localhost:8000/mcp") as ( read_stream, write_stream, _, ): async with ClientSession(read_stream, write_stream) as session: await session.initialize() tools = await session.list_tools() print([tool.name for tool in tools.tools]) result = await session.call_tool( "get_available_stock", arguments={"sku_code": "SKU-1001"}, ) print(result) asyncio.run(main())3.3 挂载到已有 FastAPI / Starlette 应用
如果你已经有 ASGI 应用,不需要单独再开一个服务:
import contextlib from starlette.applications import Starlette from starlette.routing import Mount from mcp.server.fastmcp import FastMCP mcp = FastMCP("my-app", json_response=True) @mcp.tool() def hello() -> str: return "Hello from MCP!" @contextlib.asynccontextmanager async def lifespan(app: Starlette): async with mcp.session_manager.run(): yield app = Starlette( routes=[ Mount("/mcp", app=mcp.streamable_http_app()), ], lifespan=lifespan, )3.4 MCP 客户端配置片段(JSON)
如果你用的是支持 MCP 的编辑器或客户端,配置文件通常长这样:
{ "mcpServers": { "inventory-service": { "command": "python", "args": ["inventory_mcp_server.py"], "env": { "TAOTOKEN_BASE_URL": "https://taotoken.net/api", "TAOTOKEN_API_KEY": "sk-your-key-here", "TAOTOKEN_MODEL_ID": "your-model-id" } } } }注意这里 Base URL、Key、Model ID 三件套都写全了。如果你的客户端是 Cline 或 Claude Code,配置字段名可能略有不同,但核心信息一致。
4. 验证请求与成功结果
配置写完后,按这个顺序验证。
第一步,启动 MCP Server:
python inventory_mcp_server.py看到服务监听日志后,第二步,用 Client 脚本连接并列出工具:
python mcp_client.py预期输出类似:
['get_available_stock'] meta=None content=[TextContent(type='text', text='{"skuCode": "SKU-1001", "availableStock": 128, "status": "IN_STOCK"}')] isError=False第三步,验证模型通道。在你的 Python Agent 里调用 TaoToken 的 API,确认 Base URL 和 Key 生效:
import os from openai import OpenAI client = OpenAI( base_url=os.environ["TAOTOKEN_BASE_URL"], api_key=os.environ["TAOTOKEN_API_KEY"], ) resp = client.chat.completions.create( model=os.environ["TAOTOKEN_MODEL_ID"], messages=[{"role": "user", "content": "你好"}], ) print(resp.choices[0].message.content)如果这一步返回正常文本,说明模型通道通了。第四步,把 MCP Client 和模型调用串起来:Client 先list_tools()拿到工具列表,把工具描述注入到模型请求里,模型返回工具调用意图后,Client 再call_tool()执行。整个链路跑通后,你会看到模型能正确选择get_available_stock并传入sku_code参数。
实测下来,最容易出问题的环节是工具描述和参数 Schema 的清晰度。如果模型总是选错工具或传错参数,先检查@mcp.tool()的 docstring 和参数类型标注是否足够明确。
5. 本篇常见错误排查
报错一:401 Unauthorized
如果你在调用 TaoToken API 时看到 401,先检查 API Key 是否正确、是否过期、是否在环境变量里被覆盖。常见原因是.env文件里 Key 带了引号或空格。另外确认 Base URL 是https://taotoken.net/api,不要多加路径。
报错二:local proxy failed / connection refused
MCP Client 连接http://localhost:8000/mcp时报连接拒绝,说明 Server 没启动或端口不对。先确认 Server 进程在跑,再确认端口没有被占用。如果你在容器里跑,注意 localhost 的指向问题。
报错三:reading choices 相关错误
模型返回结构解析失败时,常见于choices字段为空或格式不符。检查 Model ID 是否填写正确,以及请求体是否符合 OpenAI 兼容格式。如果你用的是非标准模型,确认它支持 chat completions 接口。
报错四:OAuth / 认证流程卡住
远程 Streamable HTTP 模式下,如果 Server 要求 OAuth,而你的 Client 没有配置认证,会卡在初始化阶段。本地开发建议先用 STDIO 模式跑通,再切到 HTTP 模式补认证。
报错五:工具列表为空
list_tools()返回空列表,通常是 Server 端装饰器没生效或启动的模块不对。确认@mcp.tool()装饰的函数在mcp.run()之前已经定义,且没有语法错误导致模块加载失败。
报错六:Codex auth.json 配置不生效
如果你用 Codex 类工具,auth.json 里需要同时写 Base URL、Key、Model ID。只写 Key 不写 Base URL 会导致请求打到默认端点,出现认证失败。检查 JSON 格式是否合法,字段名是否匹配。
6. 从最小闭环到平台化的落地路径
把 MCP 接进 Python 项目,建议按四个阶段推进。
第一阶段做最小闭环:选一个查询型工具,用 FastMCP 暴露,本地用 STDIO 或 Streamable HTTP 跑通list_tools和call_tool。这个阶段的目标是确认协议链路通,不追求功能多。
第二阶段做 AI 友好的结果结构:收敛返回字段,给每个参数写清楚描述,为常见错误提供结构化错误信息。观察模型是否能稳定选对工具、传对参数。这一步决定了后续扩展的顺畅程度。
第三阶段做治理能力:加认证、审计日志、限流、超时、敏感工具二次确认。远程 HTTP 模式下特别要注意 Origin 校验和 localhost 绑定,不要把服务暴露在0.0.0.0上。
第四阶段做平台化:统一 MCP 网关、工具目录、多业务域 Server 治理、可观测性。这时候你手里的 MCP Server 已经不是几个脚本,而是一套 AI 能力平台。
如果你现在已经在用 Python 和 FastAPI,完全可以从一个最小查询工具开始,把现有业务系统先包装成一个小型 MCP Server。模型通道统一走 TaoToken 的 API,Key 和 Base URL 在环境变量里管理,MCP Server 只管暴露能力,Client 只管消费能力。这样你的 Python 技术栈就能以最低改造成本接入 AI 生态。
需要创建 Key 或查看接入参数的话,API Keys 页面和接入文档里有完整说明。如果你更关注长期编码和 Agent 场景,可以了解一下 Coding Plan 的通道配置方式。模型对话调试可以直接在模型对话页面验证通道是否正常。