1. 为什么你的 Agent 需要一个 MCP 中间层如果你正在做 AI Agent大概率遇到过这种局面Agent 要读本地文件、要查数据库、要调内部 HTTP 接口、还要操作浏览器每接一个能力就写一套适配代码工具一多主流程里全是 if-else 和胶水逻辑。MCPModel Context Protocol模型上下文协议要解决的就是这件事——它把「Agent 怎么连外部资源」抽象成统一协议Agent 只跟 MCP Server 对话具体连的是文件、数据库还是某个 API全部下沉到 Server 里。一句话概括MCP 是 Agent 和外部工具之间的统一插座。Agent 是电器MCP Server 是插线板你换电器不用重装修电路。它适合谁适合已经跑通单轮对话、准备把 Agent 做成可维护工程的开发者也适合手上有一堆内部系统、想让模型安全调用又不想把密钥散落各处的人。这篇不聊概念空转直接交付一套可运行的 MCP 服务端骨架、Agent 侧配置片段以及用 TaoToken 统一 Key/API 通道接入的示例最后给出启动、连通性和性能验证动作。源码结构我会拆到你能直接复制粘贴的程度。需要先明确一个边界MCP 负责「工具怎么被描述和调用」模型推理仍然走大模型 API。所以你会看到两条链路——一条是 MCP 的 stdio 进程通信一条是 Agent 到模型服务的 HTTP 请求。把这两条链路分清楚后面排障会轻松很多。2. TaoToken 前置把模型通道统一成一条在搭 Agent 之前先把模型调用这条链路固定下来。我试过在多个项目里分别维护不同厂商的 Key 和 endpoint工具一多环境变量就乱成一团。TaoToken 的价值在于提供一个统一的 API 通道OpenAI 兼容格式Agent 侧只认一个 base_url 和一个 Key换模型不用改业务代码。你需要先拿到 Key。进入控制台创建 API Key建议按项目维度建别所有环境共用一个。地址是 https://taotoken.net/api Key 管理在 https://taotoken.net/console/api-keys 。拿到之后把它写进环境变量不要硬编码进源码export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api如果你用的是 Claude Code 这类编码 AgentTaoToken 也提供了对应的接入方式可以参考 https://taotoken.net/doc 里的说明Anthropic 兼容通道在 https://taotoken.net/ClaudeCodeAnthropic 。模型对话调试可以直接用 https://taotoken.net/models 页面验证 Key 是否可用省得在代码里反复试错。注意Key 只放服务端环境变量前端和 MCP Server 的日志里都不要打印完整 Key。MCP Server 如果要把模型能力暴露给 Agent也应该由 Agent 侧持有 KeyServer 只做工具执行。这一步做完你手上应该有两个东西一个可用的模型通道一个待搭建的 MCP 工具层。接下来进入正题。3. 可复制配置MCP Server 骨架与 Agent 接入3.1 环境与依赖Python 3.10 即可MCP 官方 SDK 安装很轻pip install mcp openaimcp提供 Server/Client 能力openai用来走 TaoToken 的兼容接口。目录结构建议这样别把所有东西塞一个文件agent-mcp/ ├── server/ │ ├── main.py # MCP Server 入口 │ └── tools/ │ ├── calc.py # 计算工具 │ └── files.py # 文件读取工具 ├── agent/ │ └── runner.py # Agent 主循环 └── .env3.2 MCP Server 骨架先写一个带两个工具的 Server一个做四则运算一个读受限目录下的文本文件。工具注册用装饰器参数用类型注解SDK 会自动生成 schema 给模型看# server/main.py from mcp.server.fastmcp import FastMCP import os mcp FastMCP(agent-tools) SAFE_DIR os.path.abspath(./workspace) mcp.tool() def calculate(expression: str) - float: 计算四则运算表达式。 参数 expression: 形如 188*23-34 的字符串。 返回: 计算结果。 allowed set(0123456789-*/(). ) if not set(expression) allowed: raise ValueError(表达式包含非法字符) return eval(expression, {__builtins__: {}}, {}) mcp.tool() def read_text(path: str) - str: 读取 workspace 目录下的文本文件。 参数 path: 相对 workspace 的路径。 full os.path.abspath(os.path.join(SAFE_DIR, path)) if not full.startswith(SAFE_DIR): raise ValueError(路径越界) with open(full, r, encodingutf-8) as f: return f.read()[:4000] if __name__ __main__: mcp.run(transportstdio)这里有两个工程细节值得说。第一eval前做了字符白名单别直接裸 evalAgent 传进来的参数不可信。第二文件工具做了路径越界检查这是 MCP 工具最容易踩的安全坑——模型可能被诱导去读../../etc/passwd这类路径。3.3 Agent 侧接入 MCPAgent 主循环要做三件事启动 MCP Server 会话、把工具列表转成模型能理解的 function schema、拿到模型返回的 tool_call 后路由到对应 MCP 工具。下面这段是核心# agent/runner.py import asyncio, json, os from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client from openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ[TAOTOKEN_BASE_URL], ) server_params StdioServerParameters( commandpython, args[./server/main.py], envNone, ) 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() schema [{ type: function, function: { name: t.name, description: t.description, parameters: t.inputSchema, }, } for t in tools.tools] messages [{role: user, content: 帮我算一下 188*23-34}] resp client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolsschema, ) msg resp.choices[0].message if msg.tool_calls: call msg.tool_calls[0] args json.loads(call.function.arguments) result await session.call_tool(call.function.name, args) print(工具返回:, result.content) asyncio.run(main())跑起来后你会看到工具返回4288.0。这条链路打通意味着你的 Agent 已经能通过 MCP 调用外部能力而且新增工具只需要在 Server 里加一个mcp.tool()Agent 侧零改动。3.4 上下文管理的关键参数高性能 Agent 的瓶颈往往不在模型而在上下文膨胀。三个参数建议显式控制工具返回内容截断上面read_text的 4000 字符、历史消息窗口只保留最近 N 轮 工具结果摘要、以及工具 schema 的按需注入工具超过 20 个时先让模型选工具类别再注入具体 schema。这些不是 MCP 协议强制的但决定了你的 Agent 能不能长期稳定跑。4. 验证请求与成功结果启动验证分两步。先单独验证 MCP Server 能不能被 Inspector 拉起这是最快的排障手段mcp dev server/main.py浏览器打开提示的本地地址能看到calculate和read_text两个工具手动传参调用返回正常就说明 Server 本身没问题。这一步能把「Server 写错」和「Agent 接错」两类问题分开。再验证完整链路python agent/runner.py预期输出类似工具返回: [TextContent(typetext, text4288.0)]如果模型没有触发 tool_call先检查toolsschema是否传进去了再检查模型是否支持 function calling。TaoToken 通道下换个支持工具调用的模型即可模型列表在 https://taotoken.net/models 可以查。性能验证给一个可量化的动作连续调用 50 次calculate统计 P95 延迟。MCP 本地 stdio 通信本身通常在毫秒级如果你看到单次超过 200ms大概率是 Server 里做了阻塞 IO 或每次调用重建了会话。会话要复用别在工具函数里重新stdio_client。5. 本篇常见错排查报错ModuleNotFoundError: No module named mcp确认 pip 装在了当前 Python 环境虚拟环境激活了吗。用python -c import mcp; print(mcp.__file__)定位。Agent 启动后卡住无输出stdio 模式下 Server 的 stdout 被协议占用任何print调试都会污染通信。调试信息一律走 stderr或者用 Inspector。工具调用返回Invalid arguments模型生成的参数和 schema 不匹配。检查类型注解是否准确expression: str别写成expression。schema 是模型唯一的依据。路径越界报错这是安全机制生效不是 bug。把要读的文件放进workspace目录或者调整SAFE_DIR。模型不调用工具直接编答案prompt 里明确要求「需要计算时必须调用工具」同时确认tool_choice没被设成none。Key 报 401检查TAOTOKEN_API_KEY是否带上了Bearer前缀重复OpenAI SDK 会自动加环境变量里只放sk-开头的原始值。6. 把通道和工具层分开维护搭完这套骨架你会发现工程上真正省心的地方在于职责分离MCP Server 只管工具怎么执行和安全边界Agent 只管编排和模型交互模型通道交给 TaoToken 统一收口。三者独立演进加工具不动 Agent换模型不动工具。下一步可以做的把 Server 拆成多个按领域划分的 MCP 进程文件、数据库、内部 API 各一个Agent 侧维护多个 Session给工具加调用审计日志把高频工具结果做本地缓存。这些都是在当前骨架上增量加不用重构。如果你还没配好模型通道先去 https://taotoken.net/api-keys 建 Key接入文档在 https://taotoken.net/doc 编码类 Agent 的长期使用可以看 https://taotoken.net/coding-plan 。工具层跑通之后模型对话调试用 https://taotoken.net/models 验证整条链路就闭环了。
