如何构建一个用于 AI 的 MCP 服务:用 Python + uv 把本地工具接入 TaoToken 1. 从本地脚本到 AI 工具MCP 服务到底解决什么问题你可能已经写过不少本地 Python 脚本查数据库、读 CSV、调内部接口、跑一段数据清洗。这些脚本自己跑没问题但一旦想让 Claude、Cursor 这类 AI 客户端直接调用就卡住了——每个客户端接入方式不一样工具描述格式不一样参数传递也不一样。MCPModel Context Protocol就是来统一这件事的。MCP 是 AI 的 USB-C 接口。在 USB-C 之前每个设备一个充电口MCP 之前每个 AI 客户端接工具都要单独适配。MCP 定义了一套标准协议让 AI 客户端Host通过 MCP Client 连接到你的 MCP ServerServer 把本地能力以「工具Tool」的形式暴露出去。AI 决定调用哪个工具、传什么参数你的 Python 代码负责真正执行再把结果按协议返回。这篇要做的是用 Python uv 从零搭一个可被 AI 调用的 MCP 服务并让这个服务在需要访问模型能力时通过 TaoToken 的统一 Key/API 通道走。适合谁想让本地脚本、数据库查询、内部 API 被 Claude 等客户端调用的开发者已经会用 Python但没写过 MCP Server 的人以及想把手头零散工具收拢成一个标准入口的人。我试过把几个查询脚本直接塞进客户端配置结果每换一个客户端就要重写一遍参数映射维护成本很高。MCP 的价值就在于Server 写一次任何实现了 MCP Client 的宿主都能接。下面从环境准备开始一步步给出可复制的命令和配置。2. 用 uv 初始化 MCP 项目并接入 TaoToken 通道uv 是 Rust 写的 Python 包与项目管理器装依赖快、虚拟环境管理干净特别适合 MCP 这种「一个 Server 一个独立环境」的场景。先装 uv# macOS / Linux curl -LsSf https://astral.sh/uv/install.sh | sh # Windows PowerShell powershell -ExecutionPolicy ByPass -c irm https://astral.sh/uv/install.ps1 | iex装完确认版本uv --version然后初始化项目。我习惯把 MCP Server 单独放一个目录避免和主项目依赖打架uv init mcp-local-tools cd mcp-local-tools uv venv source .venv/bin/activate # Windows: .venv\Scripts\activate uv add mcp[cli] httpxmcp[cli]提供 FastMCP 和命令行调试工具httpx用于后续调用外部 API。到这里项目骨架就好了。接下来是 TaoToken 的接入位置。TaoToken 在这里扮演的是「统一模型通道」当你的 MCP 工具需要调用大模型比如让模型对查询结果做摘要、做意图解析时不用在每个工具里硬编码各家厂商的 Key 和 Base URL而是统一走 TaoToken 的 API 通道。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 。你需要先在控制台创建一个 API Key然后把它放进环境变量不要写死在代码里# macOS / Linux export TAOTOKEN_API_KEYsk-你的Key # Windows PowerShell $env:TAOTOKEN_API_KEYsk-你的KeyMCP Server 里读取这个环境变量即可。这样做的好处是本地工具、数据库查询、模型调用共用一套凭证管理换客户端时只改配置不改代码。控制台和 Key 管理页面在 https://taotoken.net/console 与 https://taotoken.net/api-keys 接入细节可查 https://taotoken.net/doc 。3. 可复制的 MCP Server 配置与工具代码先写server.py。这里定义两个工具一个查本地 SQLite 数据模拟你的数据库查询场景一个调用 TaoToken 通道让模型对结果做摘要。FastMCP 用装饰器注册工具类型注解会自动生成参数 schema。import os import sqlite3 import httpx from mcp.server.fastmcp import FastMCP mcp FastMCP(local_tools) TAOTOKEN_BASE https://taotoken.net/api TAOTOKEN_KEY os.environ.get(TAOTOKEN_API_KEY, ) mcp.tool() async def query_orders(status: str) - str: 按状态查询本地订单表status 例如 paid / pending / refunded。 conn sqlite3.connect(orders.db) cur conn.cursor() cur.execute(SELECT id, amount, status FROM orders WHERE status ? LIMIT 20, (status,)) rows cur.fetchall() conn.close() if not rows: return f没有状态为 {status} 的订单 return \n.join(f订单 {r[0]} 金额 {r[1]} 状态 {r[2]} for r in rows) mcp.tool() async def summarize_text(text: str) - str: 调用 TaoToken 通道让模型对给定文本做一句话摘要。 if not TAOTOKEN_KEY: return 缺少 TAOTOKEN_API_KEY 环境变量 payload { model: claude-sonnet-4-20250514, messages: [{role: user, content: f用一句话总结{text}}], max_tokens: 200, } headers {Authorization: fBearer {TAOTOKEN_KEY}} async with httpx.AsyncClient(timeout60) as client: resp await client.post(f{TAOTOKEN_BASE}/v1/messages, jsonpayload, headersheaders) if resp.status_code ! 200: return f调用失败{resp.status_code} {resp.text[:200]} data resp.json() return data[content][0][text] if __name__ __main__: mcp.run(transportstdio)注意summarize_text里的三件套Base URL 是https://taotoken.net/apiKey 从环境变量读Model ID 显式写在 payload 里。这三样缺一不可后面排障会反复用到。接着写客户端配置。以 Claude Desktop 为例编辑claude_desktop_config.json设置 → 开发者 → 编辑配置{ mcpServers: { local-tools: { command: /full/path/to/uv, args: [ --directory, /full/path/to/mcp-local-tools, run, server.py ], env: { TAOTOKEN_API_KEY: sk-你的Key } } } }command用which uvWindows 用where uv查到的绝对路径--directory用项目绝对路径。env里把 Key 传进去这样 Server 启动时就能读到。如果你用的是 Cline 或支持 MCP 的编辑器配置结构类似同样是 command args env 三件套。4. 端到端验证从 stdio 调试到客户端真实调用写完之后别急着接客户端先用 MCP 自带的调试器验证工具能不能被正确发现和调用uv run mcp dev server.py这会启动一个本地调试界面列出所有注册的工具。点开query_orders传statuspaid看返回是否符合预期。这一步能排除掉大部分 schema 和依赖问题。调试通过后重启 Claude Desktop。界面上会出现工具图标说明 Server 已被识别。然后发一条自然语言请求帮我查一下状态为 paid 的订单然后总结一下这些订单的情况。正常流程是Claude 先调用query_orders拿到订单列表再把结果作为参数传给summarize_text后者通过 TaoToken 通道请求模型生成摘要最后把摘要返回给你。整个过程你能在客户端看到工具调用链。如果只想单独验证 TaoToken 通道是否通可以绕过 MCP 直接发一个请求curl https://taotoken.net/api/v1/messages \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:claude-sonnet-4-20250514,max_tokens:100,messages:[{role:user,content:说一句你好}]}返回里有content数组且第一项有text就说明 Key、Base URL、Model ID 三件套都对。这一步过了MCP 里的模型调用基本不会出问题。想直接在网页里试模型对话可以打开 https://taotoken.net/model-chat 长期跑编码类 Agent 任务可以看 https://taotoken.net/coding-plan 。5. 常见报错排查401、local proxy failed 与 reading choices401 Unauthorized最常见。先确认TAOTOKEN_API_KEY在 Server 进程里真的读到了。MCP Server 由客户端拉起环境变量不会自动继承你终端里的 export必须在配置文件的env字段里显式传。排查方法在工具里临时返回os.environ.get(TAOTOKEN_API_KEY, EMPTY)[:8]看前几位对不对。local proxy failed / connection refused通常是 Base URL 写错。TaoToken 的 API 基址是https://taotoken.net/api拼路径时注意是/api/v1/messages不要写成/v1/messages漏掉/api。另外确认没有多余的尾部斜杠导致双斜杠。reading choices of undefined这个报错说明你按 OpenAI 的响应结构去解析了但实际返回的是 Anthropic 风格结构。TaoToken 的 messages 接口返回的是content数组取文本要用data[content][0][text]不是data[choices][0][message][content]。如果你用的是 OpenAI 兼容端点则要对应改解析逻辑别混用。OAuth / 认证失败如果你在客户端里配了 OAuth 流程但 Server 走的是 API Key两者会冲突。MCP Server 用 stdio 传输时认证应该完全由 Server 内部处理客户端配置里只传 Key不要额外挂 OAuth。工具不出现检查uv run mcp dev server.py能否列出工具。如果调试器里都没有说明装饰器或导入有问题如果调试器有但客户端没有多半是配置文件路径写错或者没重启客户端。Codex auth.json 场景如果你同时用 Codex 类客户端它的auth.json里也要保证 Base URL、Key、Model ID 三件套一致否则会出现「MCP 工具能调、但模型请求 401」的割裂现象。6. 把工具收拢成标准入口之后搭完这个 Server你会发现原本散落的脚本有了统一出口数据库查询、内部 API、文本处理都注册成工具AI 客户端按需调用。模型调用统一走 TaoToken 通道Key 和 Base URL 只维护一份换客户端时改配置不改代码。下一步可以做的把query_orders换成你真实的数据库连接加上参数校验和超时把summarize_text扩展成支持多轮对话再注册一个写文件的工具让 AI 能落地产出。工具越具体AI 调用越准——别做一个「万能查询」工具而是拆成「按订单号查」「按状态查」「按日期范围查」这种边界清晰的工具。需要创建和管理 Key 时去 https://taotoken.net/api-keys 接入细节查 https://taotoken.net/doc 模型对话验证用 https://taotoken.net/model-chat 。把配置里的绝对路径和 Key 换成你自己的跑通一次端到端调用这套 MCP 服务就能长期用了。