news 2026/9/29 21:13:34

用 FastMCP 从零构建第一个 MCP 服务:Python 示例与 TaoToken 配置骨架

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 FastMCP 从零构建第一个 MCP 服务:Python 示例与 TaoToken 配置骨架

1. 为什么我要用 FastMCP 搭第一个 MCP 服务

如果你最近在折腾 AI Agent、Claude Desktop 或者 Cursor 这类工具,大概率听过 MCP(Model Context Protocol)这个词。简单说,MCP 就是一套让大模型能"调用外部工具"的协议标准——模型本身不会查数据库、不会读文件、不会调你的内部接口,但通过 MCP 服务,它就能像插了 USB 一样把这些能力接进来。FastMCP 则是 Python 生态里把这件事做得最省心的库:几行代码就能把一个普通 Python 函数注册成 MCP 工具,还自带 Streamable HTTP、stdio 等多种传输方式。

这篇面向的是第一次上手 FastMCP 的 Python 开发者。我会带你从零跑通一个最小可用的 MCP 服务:先写服务端,再写客户端调用,最后把 TaoToken 的统一 Key/API 通道接进config.toml骨架里,让整个链路从本地调试到模型调用形成闭环。全程 Python 3.10+ 验证过,代码可以直接复制。

场景很具体:你本地有个小工具函数(比如查天气、算汇率、读配置),想让它被 AI 客户端调用。以前你得写一堆 HTTP 路由、参数校验、错误处理,现在用 FastMCP 一个装饰器搞定。下面按"装环境 → 写服务 → 写客户端 → 接 TaoToken → 排错"的顺序走一遍。

2. 环境准备与 TaoToken 前置配置

2.1 安装 FastMCP 与依赖

先建个干净的虚拟环境,避免和系统里的包打架:

python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install fastmcp

FastMCP 会自动带上httpx、pydantic这些依赖。装完可以验证一下版本:

python -c "import fastmcp; print(fastmcp.__version__)"

我实测下来,0.4.x 之后的版本对 Streamable HTTP 支持比较稳,如果你装到的是更老的版本,建议pip install -U fastmcp升一下。

2.2 TaoToken 是什么,为什么这里要接它

MCP 服务本身只是"工具提供方",真正调用它的是模型。而模型调用需要一个统一的 API 通道——TaoToken 就是干这个的:它把不同模型的调用收敛成一套 Key 和一套 API 地址,你在config.toml里配一次,后面换模型、加模型都不用改业务代码。官网在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api 。

对 MCP 场景来说,TaoToken 的价值在于:你的 MCP 服务负责"提供工具",TaoToken 负责"让模型能调这些工具",两边解耦。下面先把 Key 拿到手。

2.3 获取 API Key

登录后进控制台,在 API Keys 页面创建一个新 Key。建议按用途命名,比如mcp-local-dev,方便后面区分。创建后立刻复制保存——多数平台只显示一次。

拿到 Key 后,先别急着写代码,用一条 curl 验证通道是否通:

curl https://taotoken.net/api/v1/models \ -H "Authorization: Bearer sk-你的Key"

返回一个模型列表的 JSON 就说明 Key 和网络都没问题。这一步很关键,很多人后面 MCP 调不通,其实是 Key 或网络的问题,提前排掉能省不少时间。

3. 可复制的 FastMCP 服务端与客户端配置

3.1 服务端最小示例(server.py)

先写一个"打招呼 + 算加法"的双工具服务,覆盖字符串和数值两种参数类型:

# server.py from fastmcp import FastMCP mcp = FastMCP(name="MyFirstServer") @mcp.tool def greet(name: str) -> str: """Greet a user by name.""" return f"Hello, {name}!" @mcp.tool def add(a: int, b: int) -> int: """Add two integers.""" return a + b if __name__ == "__main__": mcp.run( transport="streamable-http", host="127.0.0.1", port=9000, )

几个要点:FastMCP(name=...)里的名字会出现在客户端日志里,起个能认出来的;@mcp.tool装饰器会把函数签名自动转成 MCP 的 JSON Schema,所以类型注解必须写全,name: str不能省成name;mcp.run()里transport="streamable-http"是重点,这是目前推荐的 HTTP 传输方式,比老的 SSE 更省连接。

启动服务:

python server.py

看到类似Uvicorn running on http://127.0.0.1:9000的日志就说明起来了。注意 MCP 的 HTTP 端点在/mcp路径下,不是根路径。

3.2 客户端调用脚本(client.py)

# client.py import asyncio from fastmcp import Client config = { "mcpServers": { "local": { "url": "http://127.0.0.1:9000/mcp", "transport": "streamable-http", } } } client = Client(config) async def main(): async with client: tools = await client.list_tools() print("available tools:", [t.name for t in tools]) greet_result = await client.call_tool("greet", {"name": "world"}) print("greet:", greet_result) add_result = await client.call_tool("add", {"a": 3, "b": 4}) print("add:", add_result) if __name__ == "__main__": asyncio.run(main())

async with client:会自动管理连接生命周期,退出时释放资源,别手动去 close。call_tool的第一个参数是工具名,第二个是参数字典,键名必须和服务端函数参数名一致。

3.3 TaoToken 的 config.toml 配置骨架

MCP 客户端(比如 Claude Desktop、Cursor)通常读一个config.toml或mcp.json来知道有哪些服务。把 TaoToken 作为模型通道接进来时,骨架长这样:

# config.toml [model] provider = "taotoken" base_url = "https://taotoken.net/api" api_key = "sk-你的Key" default_model = "你的默认模型名" [mcp_servers.local] url = "http://127.0.0.1:9000/mcp" transport = "streamable-http" [mcp_servers.local.env] TAOTOKEN_BASE_URL = "https://taotoken.net/api" TAOTOKEN_API_KEY = "sk-你的Key"

这里把模型通道和 MCP 服务分开配:[model]段管模型调用,[mcp_servers.*]段管工具服务。env段是给 MCP 服务进程注入环境变量用的,如果你的 MCP 工具内部也要调模型,就从这里读 Key,别硬编码在代码里。

注意:api_key不要提交到 Git。本地开发用.env或系统环境变量,config.toml加进.gitignore。

4. 验证请求与成功结果

4.1 先验证 MCP 服务本身

服务端跑起来后,用 curl 探一下端点是否活着:

curl -i http://127.0.0.1:9000/mcp

Streamable HTTP 端点对 GET 的响应可能不是 200,但只要不是Connection refused,就说明端口通了。更靠谱的验证是直接跑客户端:

python client.py

预期输出:

available tools: ['greet', 'add'] greet: Hello, world! add: 7

看到available tools列出两个工具名,说明服务端注册成功;greet和add都返回正确结果,说明调用链路通了。

4.2 再验证 TaoToken 通道

单独测一下模型通道,确认 Key 有效:

curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer sk-你的Key" \ -H "Content-Type: application/json" \ -d '{ "model": "你的模型名", "messages": [{"role": "user", "content": "ping"}] }'

返回带choices的 JSON 就说明通道正常。这一步和 MCP 服务是独立的——MCP 管工具,TaoToken 管模型,两边都通,整个闭环才算成立。

4.3 端到端串起来

把 MCP 服务地址填进你的 AI 客户端(Claude Desktop 的claude_desktop_config.json或 Cursor 的 MCP 设置),模型通道指向 TaoToken。然后在对话里让模型调用greet工具,比如输入"用 greet 工具跟 alice 打个招呼"。模型会通过 TaoToken 通道发起请求,TaoToken 转发给模型,模型决定调用 MCP 的greet工具,MCP 服务返回结果,整条链路跑通。

5. 本篇常见错误排查

5.1 Connection refused

最常见。按顺序查:服务端是否真的在跑(看终端有没有 Uvicorn 日志);端口是不是 9000(被占用就换 9001);URL 有没有带/mcp路径——很多人写成http://127.0.0.1:9000就报这个错。防火墙一般本地回环不拦,但如果用了容器,要确认端口映射。

5.2 工具列表为空

list_tools()返回空数组,通常是装饰器没生效。检查两点:@mcp.tool有没有写在函数正上方(中间不能隔空行或注释);函数有没有类型注解。FastMCP 靠类型注解生成 Schema,def greet(name):这种没注解的会被跳过。

5.3 参数校验失败

调用时报ValidationError,多半是参数名或类型对不上。服务端是def add(a: int, b: int),客户端就得传{"a": 3, "b": 4},传{"x": 3}会直接报错。类型也要匹配,传字符串"3"给int参数,Pydantic 有时能转有时不能,别赌,老老实实传对类型。

5.4 TaoToken 返回 401

Key 错了或没带。检查Authorization: Bearer sk-xxx格式,Bearer 后面有个空格,别漏。Key 前后有没有多余空格或换行,复制时容易带上。如果 Key 是在别的环境生成的,确认它没被删除或过期。

5.5 Streamable HTTP 握手超时

客户端连上了但一直卡住,可能是传输方式配错。服务端用streamable-http,客户端也必须写streamable-http,两边不一致会握手失败。另外确认 FastMCP 版本够新,老版本可能不支持这个 transport。

6. 下一步:把 MCP 服务接进你的工作流

跑通最小示例后,你可以往几个方向扩:给工具加更复杂的参数(列表、嵌套对象),FastMCP 会自动生成 Schema;用@mcp.resource注册资源而不只是工具;把服务部署到内网让团队共用。模型通道这边,TaoToken 的 Coding Plan 适合长期编码和 Agent 场景,接入文档在 https://taotoken.net/api-keys 和 https://taotoken.net/doc 可以查到更细的配置项。

我踩过的一个坑是:一开始把 Key 硬编码在server.py里,后来换环境忘了改,调了半天才发现。现在统一走config.toml的env段注入,代码里只读环境变量,清爽很多。你如果只是本地玩,先跑通greet和add这两个工具,再往上加复杂度,别一上来就搞多服务编排。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 21:13:19

EMI辐射发射超标实战解析:频点定位与整改路径

1. 这不是“运气不好”,是EMI辐射发射超标在敲门上周三下午三点十七分,我盯着频谱分析仪屏幕上那根刺眼的红色尖峰,手里的咖啡凉了都没察觉——它稳稳地钉在327MHz处,比Class B限值高出6.8dBμV。这不是第一次,但这次特…

作者头像 李华
网站建设 2026/9/29 21:12:19

学习Python的第三周

跟着雷老板上 Python 课有一阵子了,最大的感受就是:上课听得懂,自己写代码又是另一回事课堂上跟着敲示例,每一段代码都能顺利跑起来,当时心里还暗自觉得好像不难。可一到课后独立完成练习,各种 bug 扎堆出现…

作者头像 李华
网站建设 2026/9/29 21:11:52

AI日报制作全流程:从信息筛选到高效输出的工程实践

1. 一份AI日报的诞生:从信息洪流到可读清单每天早上七点,我的手机屏幕上会准时弹出十几个信息源推送。arXiv 的新论文、几个头部实验室的博客更新、开源社区的 commit 记录、行业媒体的快讯、还有几个私密社群里同行转发的截图和链接。这些信息加在一起&…

作者头像 李华
网站建设 2026/9/29 21:11:23

芯片烧录自己做还是外包?成本、工艺与品控深度解析

芯片烧录到底自己做还是外包?这问题几乎每个做硬件的团队都会撞上一次。小批量打样的时候,手工烧录几十片根本不是事,可一旦铺到量产,几百上千片的烧录时间、误操作率、设备折旧全都在账上。更别说还有些型号要用专用烧录座&#…

作者头像 李华