news 2026/10/3 19:24:22

从MCP实践到开发简单的MCP服务:用TaoToken统一Key打通FastMCP的stdio与SSE

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从MCP实践到开发简单的MCP服务:用TaoToken统一Key打通FastMCP的stdio与SSE

1. 为什么我要自己写一个 MCP 服务

MCP 全称 Model Context Protocol,简单说就是一套让大模型能安全调用外部工具和数据的标准接口。你可以把它理解成「AI 世界的 USB-C」——不管对面是 Claude、Cursor 还是你自己写的客户端,只要插上这个标准口,就能调用你定义好的函数。FastMCP 则是 Python 生态里把这套协议封装得最舒服的库,装完就能用装饰器把普通函数变成 MCP 工具。

这篇文章适合谁?如果你已经用过别人做好的 MCP 服务器(比如高德地图、飞书那种),但想搞清楚「这东西到底怎么从零写出来」,那正好。我会带你用 Python + FastMCP 从零搭一个能算除法、能打招呼的小服务,先跑通 stdio 本地调用,再切成 SSE 远程模式,最后用 TaoToken 统一 Key 把模型调用这条链路接上。整个过程你都能复制粘贴跟做。

我试过直接照着官方文档硬啃,结果卡在「stdio 和 SSE 到底啥区别」上半天。后来才明白:stdio 是客户端把服务当子进程启动,靠标准输入输出通信,适合本地单机;SSE 是服务先跑起来监听端口,客户端通过 HTTP 长连接连过去,适合远程或多人共用。两种模式代码几乎一样,就差一个mcp.run()的参数。

先明确目标:我们要做的 MCP 服务提供两个工具,divide(a, b)做除法并处理除零错误,hello(name)返回问候语。跑通后,任何支持 MCP 的客户端都能调用它们。而模型调用这一层,我用 TaoToken 的统一 Key 来承接,省得每个客户端都去配一遍不同厂商的密钥。

2. TaoToken 前置准备:统一 Key 与 API 通道

在写服务之前,先把模型调用这条链路准备好。MCP 服务本身不一定要调模型,但真实场景里,客户端(比如 Claude Code、Cline)需要模型来理解用户意图、决定调哪个工具。这时候如果每个客户端都单独配 Key,管理起来很乱。TaoToken 的思路是给你一个统一的 API 通道和 Key,客户端只要填 Base URL + Key + Model ID 三件套就能用。

第一步,去官网注册并拿到 Key。地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,注册后在控制台里创建 API Key。控制台入口:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite 。Key 生成后复制保存,后面配置客户端要用。

第二步,确认 API 通道地址。TaoToken 的 API 端点是 https://taotoken.net/api ,注意这个地址不加 UTM 参数,直接填就行。它兼容 OpenAI 风格的接口,所以大部分支持自定义 Base URL 的客户端都能接。

第三步,选模型。你可以在模型对话页面先试试哪个模型顺手:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。对于 MCP 这种需要理解工具描述、生成结构化调用的场景,建议选指令遵循能力强的模型。选好后记下 Model ID,配置时要用。

这里有个关键点:MCP 服务和模型调用是两条独立的链路。MCP 服务负责「暴露工具」,模型负责「决定调哪个工具」。TaoToken 管的是后者。所以你在客户端里要配两样东西——MCP 服务器的连接方式(stdio 命令或 SSE URL),以及模型的 Base URL + Key + Model ID。两者配合,才能实现「用户说句话,模型决定调你的 divide 工具,客户端执行并返回结果」的完整闭环。

如果你打算长期跑编码类或 Agent 类任务,可以了解下 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,遇到配置问题可以先翻这里。API Keys 管理页:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。

3. 可复制配置:FastMCP 服务端与客户端接入片段

现在开始写代码。先建虚拟环境,隔离依赖:

python3 -m venv mcpenv source mcpenv/bin/activate pip install fastmcp

装完后写服务端文件add-mcp.py:

from fastmcp import FastMCP from fastmcp.exceptions import ToolError mcp = FastMCP("Demo") @mcp.tool() def divide(a: float, b: float) -> float: """Divide a by b.""" if b == 0: raise ToolError("Division by zero is not allowed.") if not isinstance(a, (int, float)) or not isinstance(b, (int, float)): raise TypeError("Both arguments must be numbers.") return a / b @mcp.tool() def hello(name: str) -> str: return f"Hello, {name}!" if __name__ == "__main__": mcp.run()

这段代码里,@mcp.tool()装饰器把普通函数注册成 MCP 工具,函数的 docstring 会成为工具描述,模型靠它判断什么时候调用。ToolError抛出的错误信息一定会传给客户端,适合放用户能看懂的提示。

stdio 模式直接python add-mcp.py就行,默认就是 stdio。SSE 模式改一行:

if __name__ == "__main__": mcp.run(transport="sse", host="127.0.0.1", port=8000)

客户端配置方面,以 Cline / Claude Code 这类支持 MCP 的工具为例,stdio 模式的配置片段(JSON)如下:

{ "mcpServers": { "demo-mcp": { "command": "python", "args": ["/绝对路径/add-mcp.py"] } } }

SSE 模式的配置片段:

{ "mcpServers": { "demo-mcp": { "url": "http://127.0.0.1:8000/sse" } } }

注意 SSE 模式下服务要先启动,客户端才连得上。另外模型调用那层,在客户端里填 TaoToken 的三件套:

{ "baseUrl": "https://taotoken.net/api", "apiKey": "你的_TaoToken_Key", "modelId": "你选的模型ID" }

Base URL、Key、Model ID 三个缺一不可。如果你用的是 Claude Code 这类走 Anthropic 协议的工具,接入方式略有不同,参考 https://taotoken.net/claudecode?utm_source=taotoken_aicg_blog_end&utm_content=claudecode&utm_campaign=rewrite 。Codex 用户如果涉及auth.json,同样要保证 Base URL、Key、Model ID 三件套完整。

4. 验证请求与成功结果:stdio 与 SSE 两种模式实测

先验证 stdio。启动服务:

python add-mcp.py

终端会输出类似Starting MCP server 'Demo' with transport 'stdio'的日志。这说明服务在等客户端通过标准输入输出通信。此时在客户端里配置好上面的 stdio JSON,重启客户端,你应该能在工具列表里看到divide和hello。

测试调用:让模型算10 除以 2。模型会生成对divide的调用,参数a=10, b=2,返回5.0。再试5 除以 0,应该收到Division by zero is not allowed.这个错误提示,而不是崩溃。这一步验证了工具注册、参数传递、错误处理三条链路都通。

再验证 SSE。改代码后启动:

python add-mcp.py

日志会变成Starting MCP server 'Demo' with transport 'sse',并显示监听127.0.0.1:8000。用 curl 快速探活:

curl -N http://127.0.0.1:8000/sse

你会看到连接保持打开,服务端持续推送事件。这就是 SSE 的特点——长连接、服务端单向推送。然后在客户端里把配置换成 SSE 的 URL 版本,重启后同样能看到工具列表,调用结果和 stdio 一致。

两种模式对比一下:

维度stdioSSE
启动方式客户端拉起子进程服务独立启动
通信标准输入输出HTTP 长连接
适用场景本地单机、简单远程、多人共用
配置项command + argsurl
端口占用无需要

实测下来,stdio 更适合开发调试,改完代码重启客户端就行;SSE 适合部署到服务器给团队用,但要注意端口和网络可达性。如果你在容器里跑 SSE,host 要设成0.0.0.0而不是127.0.0.1,否则外部连不进来。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

配置过程中最容易撞的几个坑,我按真实报错对照说。

401 Unauthorized:这个基本是 Key 问题。检查 TaoToken 的 Key 有没有复制完整,有没有多余空格。如果客户端同时配了 MCP 和模型,确认 401 是来自模型调用还是 MCP 服务。模型调用报 401 就去 API Keys 页面重新生成一个:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。MCP 服务本身一般不涉及 401,除非你加了自定义鉴权。

local proxy failed:这个报错通常出现在客户端尝试连接本地服务时。如果是 stdio 模式,检查command和args里的路径是不是绝对路径,Python 解释器路径对不对。如果是 SSE 模式,确认服务真的在跑,curl能通。还有一种情况是客户端配了系统代理,导致本地127.0.0.1的请求被代理拦截,这时候把本地地址加入代理例外即可。

reading choices 相关报错:这类错误一般出现在模型返回格式不符合预期时。比如模型没有按 OpenAI 格式返回choices数组,客户端解析失败。排查方向是确认 Base URL 填的是https://taotoken.net/api,模型 ID 拼写正确,以及该模型是否支持当前客户端的调用方式。换个模型试试往往能快速定位。

OAuth 报错:如果你接的是需要 OAuth 的服务(比如某些企业工具),报错通常是重定向 URL 没配或 token 过期。这类问题跟 MCP 本身无关,按对应平台的 OAuth 文档配好回调地址即可。Claude Code 走 Anthropic 协议时如果遇到鉴权问题,参考 https://taotoken.net/claudecode?utm_source=taotoken_aicg_blog_end&utm_content=claudecode&utm_campaign=rewrite 里的接入说明。

再补一个高频问题:SSE 模式下客户端连不上,但 curl 能通。这多半是客户端对 SSE 的 URL 路径要求不同,有的要/sse,有的要/mcp。FastMCP 默认 SSE 路径是/sse,如果你改过path参数,客户端也要同步改。stdio 模式下如果工具列表为空,检查@mcp.tool()装饰器有没有漏,以及函数有没有被正确导入。

6. 把这条链路用起来:从本地调试到远程部署

走到这里,你已经有了一个能跑的 MCP 服务,两种传输模式都验证过,模型调用也通过 TaoToken 统一接上了。接下来怎么用,取决于你的场景。

本地开发阶段,建议一直用 stdio。改代码、重启客户端、看日志,循环最快。等工具稳定了,再切 SSE 部署到一台常开的机器上。部署时记得把 host 改成0.0.0.0,端口选一个不冲突的,防火墙放行。如果团队多人用,SSE 模式下一个服务实例就能支撑多个客户端连接。

模型这层,TaoToken 的价值在于你不用为每个客户端单独管 Key。一个 Key 配到所有客户端里,换模型也只改 Model ID。对于需要长期跑 Agent 任务的场景,Coding Plan 会更划算:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。想先试试模型效果的,去模型对话页面直接聊:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。

最后说个实用技巧:FastMCP 的工具描述(docstring)直接决定模型能不能正确调用。写描述时把「什么时候用、参数含义、返回什么」说清楚,比堆一堆参数类型更有用。比如divide的描述写成「计算 a 除以 b,b 为零时返回错误」,模型就很少调错。这个细节比代码本身更影响实际体验。

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

OpenClaw 零代码搭建教程:Windows 11 上把 API 改到 TaoToken 的完整配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/3 19:17:12

第 13 篇:推理引擎一次猜几个字——草稿 + 验证(零门槛入门系列)

上一篇:第 12 篇《重启不丢记忆》 | 下一篇:第 14 篇《一次服务很多人》 一句话导读:一次只生成一个词太慢,那就先猜几个、再让大模型一次性核对——猜对的直接白赚,猜错的无损丢弃。本篇讲清它的直觉与算术…

作者头像 李华
网站建设 2026/10/3 19:14:59

M 系列 Mac 跑靶场:架构不兼容时先确认三件事

授权与合规声明 本文全部操作对象均为自建隔离靶场(本机容器或隔离虚拟机),涉及安全测试的环节必须以取得合法授权为前提。未经授权的渗透测试违反《中华人民共和国网络安全法》与《刑法》相关条款,须承担相应法律责任。本文只讲环…

作者头像 李华
网站建设 2026/10/3 19:14:00

Zabbix 7.0对接钉钉Webhook的完整实践指南

1. 这不是“配个URL就完事”的告警推送——Zabbix 7.0对接钉钉Webhook的真实水深你搜“zabbix7.0 钉钉 webhook”,十篇教程里八篇开头就是“登录钉钉群 → 添加机器人 → 复制Webhook地址 → Zabbix里填进去 → 测试发送”。我试过,也照着这么干过&#…

作者头像 李华
网站建设 2026/10/3 19:11:41

从零搭建Agent技能体系:结构、触发与迭代的skills实践

“skills”这个词最近在我本地的工作目录里出现得实在太频繁了。不管是Claude那边的SKILL.md,还是Cursor里越分越细的能力卡片,又或者自己用Agent框架时随手建的技能包,“把能力下沉成文件”这件事,正在快速取代过去那种在对话框里…

作者头像 李华