1. 从本地脚本到 MCP Server:为什么值得折腾
你可能已经写过不少本地小工具:查天气的脚本、读日志的函数、封装好的数据库查询。它们平时躺在某个utils.py里,用的时候手动python xxx.py跑一下。问题是,当你想让 AI 客户端(比如 Claude Code、Cline、Cursor)直接调用这些能力时,中间缺了一层"协议翻译"。
MCP(Model Context Protocol)就是干这个的。它把本地函数包装成 AI 客户端能理解的标准接口,客户端不需要知道你内部怎么实现,只要按协议发请求就行。而 Python + uv 这套组合,是目前搭 MCP server 最省心的路径之一:uv 管依赖和环境,mcp[cli]提供协议实现和调试工具,你只需要专注写工具函数本身。
这篇要解决的核心场景是:用 python + uv 从零创建一个 MCP server 项目,把本地脚本工具通过 MCP 协议暴露出去,同时让所有模型调用统一走 TaoToken 的 Key/API 通道。适合谁?手上有零散 Python 工具、想让 AI 客户端直接调用的开发者;或者刚开始接触 MCP、想找一个能跑通的最小可复制模板的人。
我会给出完整的pyproject.toml、uv 初始化命令、server 入口代码、客户端配置片段,最后演示一次真实的工具调用验证。整个过程不需要你预先理解 MCP 的全部规范,跟着敲就能跑起来。
先说清楚一件事:MCP server 本身不负责"调用哪个模型",它只负责"暴露哪些工具"。模型调用发生在客户端那一侧,而客户端要访问模型,就需要一个统一的 API 入口。TaoToken 在这里扮演的角色就是那个统一通道——你拿到一个 Key,客户端配置好 Base URL,就能在同一个通道里切换不同模型,不用为每个模型单独维护一套鉴权。这个分工要理清,后面配置才不会乱。
2. TaoToken 前置准备:Key、Base URL 与模型 ID 三件套
在写 server 代码之前,先把客户端侧要用的东西准备好。MCP server 跑起来之后,真正发起模型请求的是 AI 客户端,所以客户端必须知道"往哪发、用什么身份、调哪个模型"。这三样就是 Base URL、API Key、Model ID。
Base URL用https://taotoken.net/api。注意这里不带任何查询参数,就是干净的 API 根地址。有些客户端要求填完整的 chat completions 路径,有些只要根地址,按客户端提示来。
API Key在控制台的 API Keys 页面创建。地址是https://taotoken.net/console/api-keys。创建后复制出来,注意它通常只完整显示一次,先存到安全的地方。如果你用的是 Claude Code 这类工具,Key 会写进它的配置文件;如果是 Cline 这类插件,Key 填在插件的设置面板里。
Model ID是你要调用的具体模型标识。这个在模型对话页面能看到当前可用的模型列表,地址https://taotoken.net/models。不同客户端对 Model ID 的写法要求不一样,有的要完整名称,有的接受简写,以客户端文档为准。
把这三件套记下来,后面配置客户端时直接填。这里有个容易踩的坑:很多人以为 MCP server 里要写 API Key,其实不用。server 只暴露工具,不碰模型鉴权。Key 是客户端的事。我第一次配的时候就搞混了,在 server 代码里塞了个 Key 变量,结果客户端那边又配了一遍,两边对不上,排查了半天。
如果你打算长期跑编码类任务或者 Agent 工作流,可以顺带了解一下 Coding Plan,地址https://taotoken.net/coding-plan。它和按量调用是两种计费思路,具体选哪个看你的使用频率。这篇不展开,先把最小链路跑通。
另外,接入文档在https://taotoken.net/doc,遇到客户端配置格式不确定的时候,去那里对照一下最稳。
3. 可复制配置:pyproject.toml、uv 初始化与 server 入口
现在进入动手环节。先建项目目录,用 uv 初始化。
uv init mcp-server-demo cd mcp-server-demouv init会生成一个基础项目结构,包括pyproject.toml和一个main.py。接着加 MCP 依赖:
uv add "mcp[cli]"如果你习惯用 pip,等价命令是pip install "mcp[cli]",但既然用了 uv,就一路 uv 到底,环境隔离更干净。
加完之后,pyproject.toml里会多出依赖声明。一个可用的最小配置长这样:
[project] name = "mcp-server-demo" version = "0.1.0" description = "A demo MCP server exposing local tools" requires-python = ">=3.10" dependencies = [ "mcp[cli]", ] [build-system] requires = ["hatchling"] build-backend = "hatchling.build"requires-python建议 3.10 以上,MCP 的 Python SDK 用了一些较新的类型语法。mcp[cli]里的cliextra 会带上调试用的命令行工具,后面验证会用到。
接下来写 server 入口。把main.py改成下面这样:
from mcp.server.fastmcp import FastMCP mcp = FastMCP("demo-server") @mcp.tool() def add(a: int, b: int) -> int: """两数相加,返回结果。""" return a + b @mcp.tool() def read_local_file(path: str) -> str: """读取本地文本文件的前 500 个字符。""" with open(path, "r", encoding="utf-8") as f: return f.read(500) if __name__ == "__main__": mcp.run()这里用了FastMCP,它是官方 SDK 里的高层封装,把协议细节都藏起来了。你只要用@mcp.tool()装饰器标记函数,类型注解写清楚,SDK 会自动生成工具描述和参数 schema。add是个纯计算工具,read_local_file演示了访问本地文件的能力——注意这只是演示,生产环境别直接暴露任意路径读取。
依赖装好后,uv 会在项目目录下生成.venv文件夹。想进虚拟环境手动操作的话:
.venv\Scripts\activateWindows 下是这个路径,macOS/Linux 是source .venv/bin/activate。不过大多数时候你不需要手动激活,直接用uv run就行,它会自动用项目环境执行。
如果装包慢,可以指定镜像源:
uv pip install oss2 -i https://mirrors.aliyun.com/pypi/simple/-i参数指定索引地址,国内网络下能快不少。这个技巧在装一些体积大的包时特别有用。
4. 验证请求:跑通 server 与一次真实工具调用
代码写完,先确认 server 本身能正常启动:
uv run main.py不报错、进程挂起等待输入,就说明 server 起来了。这时候它还没被任何客户端连接,属于"待命"状态。
更规范的验证方式是用 MCP 自带的调试工具:
uv run mcp dev main.py这会启动一个开发服务器,并在浏览器里打开 MCP Inspector。Inspector 是个可视化调试界面,左边列出你注册的所有工具,右边可以填参数、点调用、看返回。这是验证工具逻辑最快的方式,不用先配客户端。
在 Inspector 里选中add,参数填a=3, b=5,点执行,返回应该是8。再试read_local_file,传一个你本地真实存在的文本文件路径,应该能看到前 500 个字符。两个都通了,说明 server 侧没问题。
接下来配客户端。以 Cline 为例,在 MCP 设置里添加一个 server,配置大致是:
{ "mcpServers": { "demo-server": { "command": "uv", "args": ["run", "--directory", "/你的项目绝对路径/mcp-server-demo", "main.py"] } } }注意--directory后面要填绝对路径,相对路径在客户端启动子进程时容易找不到。配好保存,客户端会尝试拉起这个 server,状态变成绿色或显示已连接就成功了。
然后在对话里让 AI 调用工具,比如输入"帮我算一下 12 加 30",客户端会识别出add工具并调用,返回 42。这一步跑通,整条链路就活了:客户端 → MCP server → 本地工具函数。
模型请求走的是 TaoToken 通道,你需要在客户端的模型设置里填好前面那三件套。Cline 里是在 API Provider 选 OpenAI Compatible,Base URL 填https://taotoken.net/api,Key 填你创建的,Model ID 填你要用的模型。这样 AI 的推理走 TaoToken,工具调用走本地 MCP server,两条线各司其职。
如果你用的是 Claude Code,配置方式不同,它读的是~/.claude/settings.json或项目级配置,MCP server 的注册和模型通道的配置是分开的两块。具体格式去https://taotoken.net/doc对照,那里有各客户端的配置示例。
5. 常见报错排查:401、local proxy failed 与 reading choices
配的时候大概率会撞上几个典型错误,这里按真实报错逐个拆。
401 Unauthorized。这个基本是 Key 的问题。要么 Key 填错了,要么 Key 没带上,要么客户端把 Key 发到了错误的地址。先检查 Base URL 是不是https://taotoken.net/api,有没有多写或少写路径段。再确认 Key 有没有多余空格——从网页复制时经常带尾随空格,肉眼看不出来。如果都正常,去控制台看这个 Key 是不是被禁用或额度用尽。
local proxy failed / connection refused。这个通常出现在客户端启动 MCP server 子进程的时候。原因可能是command写的uv不在客户端的 PATH 里,或者--directory路径不对。解决办法是把uv换成绝对路径,比如C:\Users\你的用户名\.local\bin\uv.exe,路径用where uv查。另外确认项目目录下.venv存在,依赖装全了。
Error reading choices / choices 字段解析失败。这个报错说明客户端收到了响应,但结构不符合预期。常见于 Base URL 填成了完整 endpoint 而客户端又自己拼了一次路径,导致请求打到了错误的路由。把 Base URL 改回根地址https://taotoken.net/api试试。还有一种可能是 Model ID 写错了,服务端返回了错误结构,客户端解析时崩了。去模型对话页面确认当前可用的 Model ID。
OAuth 相关报错。有些客户端默认走 OAuth 流程,但 TaoToken 用的是 API Key 鉴权。遇到 OAuth 报错,去客户端设置里把鉴权方式改成 API Key 或 Bearer Token,别让它走 OAuth。这个在 Claude Code 的某些版本里会出现,改配置项就行。
工具调用没反应。server 连上了,但 AI 不调用工具。先确认工具函数的 docstring 写清楚了——SDK 用 docstring 生成工具描述,描述太模糊 AI 不知道什么时候该用。其次确认参数类型注解完整,缺注解会导致 schema 生成失败。最后在 Inspector 里单独测一遍工具,排除是工具本身的问题还是客户端的问题。
排查顺序建议:先 Inspector 测工具 → 再确认客户端能拉起 server → 最后查模型通道的 Key 和 Base URL。分层定位,别一上来就怀疑最远的那一环。
6. 把通道固定下来:后续扩展与统一 Key 的实践
最小链路跑通之后,接下来就是往里加工具。每加一个,用@mcp.tool()装饰,写好类型注解和 docstring,然后在 Inspector 里验一遍。工具多了之后,建议按功能拆文件,用mcp.add_tool()动态注册,别全堆在main.py里。
统一 Key 通道的价值在工具变多之后会越来越明显。你可能有多个客户端、多个项目,如果每个都单独配一套模型鉴权,管理成本会很高。走 TaoToken 一个通道,Key 集中管理,换模型只改 Model ID,不用动 Key。这对经常在 Claude、GPT 之间切换的场景特别省事。
长期跑编码或 Agent 任务的话,Coding Plan 那条线可以了解一下,地址https://taotoken.net/coding-plan。它和按量调用的区别在于计费模型,适合高频稳定使用的场景。具体怎么选,看你每天的实际调用量。
最后留一个实用习惯:把客户端的 MCP 配置和模型配置分开存,MCP 配置跟着项目走,模型配置跟着客户端走。这样换项目时不用重配模型,换客户端时不用重配工具。我试过把两者混在一个配置文件里,结果迁移的时候改得头大,分开之后清爽很多。
工具函数里如果要访问外部资源,记得加超时和异常处理。MCP server 崩了,客户端那边只会看到一个模糊的连接错误,排查起来很费劲。在函数内部把异常捕获住,返回有意义的错误信息,比让进程直接挂掉要好得多。