ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MCP协议实战:从零搭建一个AI Agent工具服务器,让大模型真正“动手干活“|TaoToken统一Key接入

MCP协议实战:从零搭建一个AI Agent工具服务器,让大模型真正“动手干活“|TaoToken统一Key接入 1. 为什么大模型需要 MCP 工具服务器大模型本身只能生成文本它没法直接读你本地的日志、查数据库、跑脚本。你问它“帮我看看服务器磁盘还剩多少”它只能回你一段df -h的命令执行还得你自己来。这个断层就是 MCPModel Context Protocol要补上的位置。MCP 是 Anthropic 开源的一套协议你可以把它理解成大模型和外部工具之间的“USB 接口”。以前每接一个工具都要写一套适配代码换个大模型客户端又得重写现在只要按 MCP 协议写一个工具服务器所有支持 MCP 的客户端都能直接调用。架构很直白用户提问 → 大模型MCP 客户端判断要不要用工具 → 通过 MCP 协议发给工具服务器 → 服务器执行真实操作 → 结果回传给大模型 → 大模型组织成人话返回。这篇要做的是用 Python 从零写一个能实际干活的 MCP 工具服务器包含系统信息查询、受控命令执行、文件读取三个工具然后通过 TaoToken 统一 Key 接入大模型跑一次端到端验证确认模型能正确触发工具并拿到结果。适合已经会一点 Python、想让 AI Agent 真正“动手”的开发者。全程代码可复制配置路径和参数我都会写清楚。我试过把工具服务器跑通之后最直观的变化是以前要手动复制粘贴命令再贴回对话现在模型自己决定调哪个工具、传什么参数我只看结论。下面按步骤来。2. TaoToken 统一 Key 接入准备工具服务器写好后需要一个能调用大模型、并且支持 MCP 的客户端来驱动它。这里用 TaoToken 做统一接入好处是一个 Key 就能访问多种模型不用为每个模型单独配一套鉴权。TaoToken 的官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。你需要先拿到 API Key。登录后进入控制台在 API Keys 页面创建一个新 Key复制保存好后面配置里要用。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite API Keys 页面是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入时三个要素必须齐全缺一个都会报错Base URL 填https://taotoken.net/apiAPI Key 填你刚创建的那串Model ID 填你要用的模型标识比如claude-sonnet-4-5或gpt-4o这类以你账号里可用的为准。这三个要素在后面的客户端配置里会反复出现先记牢。如果你用的是 Claude Code 这类编码 Agent它本身支持 MCP配置方式略有不同可以参考接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。想先验证模型通不通可以直接在模型对话页 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 发一条消息测试。长期做编码或 Agent 任务的话Coding Plan 更划算入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。环境准备只需要 Python 3.10 以上然后装两个包pip install mcp httpxmcp是官方 Python SDKhttpx用于后续可能的 HTTP 调用。没有一堆乱七八糟的依赖装完就能开工。3. 可复制的 MCP 工具服务器配置与代码这一节是核心我把完整代码拆成骨架、工具逻辑、启动三部分每段都能直接复制。先建一个文件mcp_server.py。第一步定义服务器和工具清单。list_tools()的作用是告诉大模型“我有哪些工具可用”其中description极其关键模型就是靠它判断什么时候该调用哪个工具。import asyncio import json import platform import subprocess import os from mcp.server import Server from mcp.server.stdio import stdio_server from mcp.types import Tool, TextContent server Server(system-tools) server.list_tools() async def list_tools(): return [ Tool( nameget_system_info, description获取当前系统的CPU、内存、磁盘使用情况, inputSchema{type: object, properties: {}, required: []} ), Tool( namerun_command, description在安全沙箱内执行Shell命令返回输出结果, inputSchema{ type: object, properties: { command: {type: string, description: 要执行的Shell命令} }, required: [command] } ), Tool( nameread_file, description读取指定路径的文件内容, inputSchema{ type: object, properties: { path: {type: string, description: 文件的绝对路径} }, required: [path] } ) ]第二步实现工具逻辑。call_tool()根据模型传来的工具名和参数执行真实操作。安全设计我加了两层黑名单拦截毁灭性命令超时限制防止死循环。server.call_tool() async def call_tool(name: str, arguments: dict): if name get_system_info: import psutil cpu_percent psutil.cpu_percent(interval1) memory psutil.virtual_memory() disk psutil.disk_usage(/) info { 系统: platform.system(), CPU使用率: f{cpu_percent}%, 内存: f{memory.used / (1024**3):.1f}GB / {memory.total / (1024**3):.1f}GB ({memory.percent}%), 磁盘: f{disk.used / (1024**3):.1f}GB / {disk.total / (1024**3):.1f}GB ({disk.percent}%) } return [TextContent(typetext, textjson.dumps(info, ensure_asciiFalse, indent2))] elif name run_command: cmd arguments.get(command, ) dangerous [rm -rf, mkfs, dd if, /dev/, chmod 777] if any(d in cmd for d in dangerous): return [TextContent(typetext, text命令被安全策略拦截)] try: result subprocess.run(cmd, shellTrue, capture_outputTrue, textTrue, timeout10) output result.stdout if result.returncode 0 else f错误: {result.stderr} return [TextContent(typetext, textoutput[:2000])] except subprocess.TimeoutExpired: return [TextContent(typetext, text命令执行超时10秒限制)] elif name read_file: path arguments.get(path, ) if not os.path.exists(path): return [TextContent(typetext, textf文件不存在: {path})] try: with open(path, r, encodingutf-8) as f: content f.read(50000) return [TextContent(typetext, textcontent)] except Exception as e: return [TextContent(typetext, textf读取失败: {str(e)})]注意get_system_info用到了psutil需要额外装一下pip install psutil。第三步启动服务器。MCP 工具服务器通过标准输入输出stdio和客户端通信。async def main(): async with stdio_server() as (read_stream, write_stream): await server.run(read_stream, write_stream, server.create_initialization_options()) if __name__ __main__: asyncio.run(main())第四步配置客户端。以支持 MCP 的客户端为例编辑它的配置文件加入下面这段 JSON。注意command和args的路径要换成你本机的真实路径。{ mcpServers: { system-tools: { command: python, args: [/path/to/mcp_server.py] } } }如果你用的是 Claude Code配置方式是在项目里加.mcp.json结构类似但 Base URL、Key、Model ID 三件套要在 TaoToken 的接入配置里写全。Codex 用户则是在auth.json里配好鉴权再在 MCP 配置里引用工具服务器。不管哪种客户端核心都是工具服务器负责执行TaoToken 负责模型鉴权和路由。4. 端到端验证让大模型真正触发工具配置完成后重启客户端接下来做一次完整验证。打开对话输入一句自然语言帮我看看当前系统的 CPU、内存和磁盘使用情况。如果一切正常你会看到模型先判断“这个问题需要调用 get_system_info 工具”然后发起 MCP 调用工具服务器执行psutil采集返回 JSON模型再把 JSON 组织成一段可读的结论。整个过程你不需要手动执行任何命令。再测一个需要传参的工具帮我读一下 /etc/hostname 这个文件的内容。模型应该调用read_file传入path参数返回文件内容。如果文件不存在你会看到“文件不存在”的提示说明错误处理也生效了。最后测命令执行执行一下 df -h 看看磁盘挂载情况。模型调用run_command传入df -h服务器执行后返回输出。你可以故意让它执行rm -rf /tmp/test这类命令验证黑名单拦截是否生效——正常情况下会返回“命令被安全策略拦截”。验证成功的标志有三个模型明确说出“我要调用某个工具”、工具返回了真实数据、模型基于真实数据给出结论。如果模型只是凭空回答而没有触发工具多半是description写得不够清楚或者客户端没正确加载 MCP 配置。5. 常见报错排查实际接入时最容易撞上几类报错我按真实错误信息对照着说。401 Unauthorized这是鉴权失败九成是 API Key 填错或过期。检查 TaoToken 的 Key 是否复制完整Base URL 是否写成https://taotoken.net/api注意不要多加斜杠或路径。如果用的是 Claude Code确认ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY两个环境变量都设对了。local proxy failed / connection refused客户端连不上工具服务器。先确认mcp_server.py路径在配置里是绝对路径再确认python命令在客户端运行环境里能找到。如果你用的是虚拟环境command要写成虚拟环境里的 python 绝对路径比如/Users/you/venv/bin/python。reading choices 报错这通常出现在模型返回结构不符合预期时多半是 Model ID 填错了或者该模型不支持当前调用方式。回到 TaoToken 控制台确认你账号下可用的 Model ID填到配置里。三件套 Base URL、Key、Model ID 任何一个不对都会引发这类解析错误。OAuth 相关报错部分客户端默认走 OAuth 流程但 TaoToken 用的是 API Key 鉴权。需要在客户端配置里显式指定用 API Key 模式关掉 OAuth 自动流程。Claude Code 里可以通过环境变量或 settings 文件指定。工具不触发模型收到了工具清单但不用。优先改description一句话说清“这个工具干什么、什么时候用”。其次检查inputSchema的required是不是太严模型传参偶尔会多传或少传required只放真正必须的字段。返回内容被截断模型上下文窗口有限工具返回太长会被截。我在read_file里限制 50KB、run_command限制 2000 字符你可以按需调整但别无限放大。6. 继续扩展与接入入口基础跑通后扩展方向很明确。接数据库就写一个query_sql工具让模型直接查表接常用 API 就封装成 MCP 工具比如天气、翻译、搜索接文件系统就让模型读写项目文件变成真正的编码助手。最有价值的是把日常运维操作封装进去——查日志、重启服务、清理磁盘、检查告警以后出问题直接跟模型说“帮我看看线上什么情况”它自己去查、自己分析、给结论。要把这套跑起来你需要一个能驱动 MCP 的模型入口。TaoToken 的 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 创建 Key接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里有各客户端的详细配置。想先验证模型是否正常去模型对话页 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 发一条消息即可。长期做编码或 Agent 任务Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 更省心。代码不到 100 行但跑通之后你的大模型就从“只会说”变成了“能做事”。
返回列表