Python MCP实战:构建 FastAPI 服务端与客户端示例,把 endpoint 改到 TaoToken
1. 从 FastAPI 到 MCP为什么要把 endpoint 改到统一通道如果你已经用 FastAPI 写过接口那 MCP 对你来说其实不陌生。MCPModel Context Protocol做的事情本质上是把「一个能被调用的函数」包装成模型或客户端可以识别的「工具」让调用方不用关心你内部是查数据库、调模型还是读文件只要按工具名和参数传进去就行。而fastapi-mcp这个库的价值就在于你原本写好的 FastAPI 路由加几行代码就能暴露成 MCP 工具不用重写一套协议层。这篇要解决的真实场景是这样的你本地有一个 FastAPI 服务里面注册了几个工具函数客户端通过 SSE 连上来调用。跑通之后你会发现一个问题——客户端里写死的http://127.0.0.1:8000/sse只能在本机用一旦要换到统一通道、要加鉴权、要让多个客户端共用一套 endpoint就得改配置。所以本文分两段先把最小可跑的 MCP 服务端 客户端跑起来再把客户端的 endpoint 和鉴权改到 TaoToken 统一通道顺带把 401 和连接失败这两类报错排查清楚。适合谁看写过一点 FastAPI、想快速把现有接口变成 MCP 工具的后端同学或者正在用 Cline、Claude Code 这类客户端想自己搭一个 MCP 服务端做实验的人。整篇的代码都可以直接复制依赖清单和 curl 验证步骤都会给全。先说结论性的操作路径方便你心里有数第一步装依赖第二步写main.py注册工具并挂载 SSE第三步写客户端连本地验证第四步把客户端 endpoint 换成 TaoToken 的地址并带上 Key第五步用 curl 和客户端各验证一次第六步对着 401 / 连接失败两类报错逐条排查。下面按这个顺序展开。需要提前说明一点MCP 的工具注册依赖 FastAPI 路由上的operation_id和tags这两个字段决定了工具叫什么名字、哪些路由会被暴露。很多人第一次跑发现「工具列表是空的」八成就是tags没对上。这个坑我在第 5 节会专门讲。2. TaoToken 前置统一通道与鉴权准备在把 endpoint 改过去之前先把 TaoToken 这一侧的准备做完。TaoToken 在这里扮演的角色是「统一通道」你的 MCP 客户端不再直连本地127.0.0.1:8000而是把请求发到 TaoToken 的 API 地址由它统一处理鉴权和转发。这样做的好处是客户端配置只需要维护一份 Base URL 和 Key换环境不用改代码。你需要准备三样东西我把它叫做「三件套」后面所有配置都围绕它展开配置项说明示例值Base URL统一通道地址https://taotoken.net/apiAPI Key鉴权凭证在控制台生成sk-xxxxxxxxModel ID调用的模型标识按控制台可选列表填Base URL 用https://taotoken.net/api注意这个地址不带任何查询参数。API Key 需要你去控制台自己生成路径是 API Keys 页面生成后只显示一次记得先存到环境变量里别直接写进代码提交到仓库。Model ID 按你实际要用的模型填客户端调用时会带上。生成 Key 的入口在这里API Keys 页面在https://taotoken.net/console/api-keys登录后新建一个 Key复制出来。如果你还没注册官网入口是https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content注册完再进控制台。把 Key 写进环境变量Linux / macOS 用export TAOTOKEN_API_KEYsk-你的keyWindows PowerShell 用$env:TAOTOKEN_API_KEYsk-你的key这样客户端代码里用os.environ[TAOTOKEN_API_KEY]读取就不会把密钥硬编码。这一步看着简单但后面排查 401 的时候第一件事就是确认这个环境变量在当前终端里到底有没有生效——很多人是在 A 终端 export在 B 终端跑客户端结果 Key 是空的。另外提醒一句TaoToken 是统一通道不是让你绕过什么限制它的定位是帮你把多个客户端的 endpoint 和鉴权收敛到一处管理。所以配置的时候按正常 API 调用的方式对待就行Base URL 和 Key 都按文档填。如果你打算长期跑编码类或 Agent 类任务可以顺带了解下 Coding Plan入口在https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content它更适合持续调用的场景。本文的示例用按量调用就够了先把链路跑通。3. 可复制配置服务端 main.py 与客户端 settings这一节给全代码。先建目录结构mcp-demo/ ├── main.py ├── requirements.txt └── test/ └── mcp_client.pyrequirements.txt内容fastapi0.115.0 uvicorn0.30.6 fastapi-mcp0.3.0 mcp1.2.0 httpx0.27.2安装pip install -r requirements.txt服务端main.py核心是用operation_id定义工具名用tags[mcp]标记要暴露的路由from fastapi import FastAPI from fastapi_mcp import FastApiMCP import uvicorn app FastAPI( titleMCP Demo API, description把 FastAPI 路由暴露为 MCP 工具, version0.1.0, ) app.get( /answer, operation_idget_data, tags[mcp], summary根据问题获取答案, ) async def get_data(question: str, type: str): print(f收到问题: {question}, 类型: {type}) return f这是关于 {question} 的答案。 mcp FastApiMCP( app, name问题检索mcp, description测试描述, include_tags[mcp], ) mcp.mount_sse(mount_path/sse) if __name__ __main__: uvicorn.run(app, host0.0.0.0, port8000)这里有两个关键点必须对上operation_idget_data会成为 MCP 工具名客户端调用时用的就是这个名字include_tags[mcp]告诉FastApiMCP只扫描带mcp标签的路由标签写错工具列表就是空的。客户端test/mcp_client.py先连本地验证再改成 TaoTokenimport asyncio import os from mcp import ClientSession from mcp.client.sse import sse_client # 本地验证用这个 LOCAL_URL http://127.0.0.1:8000/sse # 改到 TaoToken 统一通道时用这个 TAOTOKEN_URL https://taotoken.net/api/sse TAOTOKEN_KEY os.environ.get(TAOTOKEN_API_KEY, ) async def simple_client(url: str, headers: dict | None None): try: async with sse_client(url, headersheaders or {}) as (read, write): async with ClientSession(read, write) as session: await session.initialize() print(MCP 会话初始化成功) tools_result await session.list_tools() print(可用的工具:) for tool in tools_result.tools: print(f - {tool.name}: {tool.description}) call_result await session.call_tool( get_data, arguments{question: 测试问题, type: test}, ) if call_result.content: print(f调用结果: {call_result.content[0].text}) except Exception as e: print(f客户端连接失败: {e}) if __name__ __main__: asyncio.run(simple_client(LOCAL_URL))改成 TaoToken 通道时把最后一行换成headers {Authorization: fBearer {TAOTOKEN_KEY}} asyncio.run(simple_client(TAOTOKEN_URL, headersheaders))如果你用的是 Cline 或 Claude Code 这类客户端配置通常写在 JSON 或 TOML 里。以 JSON 形式的 MCP 配置为例三件套要写全{ mcpServers: { taotoken-demo: { url: https://taotoken.net/api/sse, headers: { Authorization: Bearer sk-你的key }, model: 你的ModelID } } }注意url、headers.Authorization、model这三项一个都不能少缺 Key 会 401缺 Model ID 部分客户端会报模型未指定。如果你用的是 Codex 的auth.json形式结构类似把 Base URL 和 Key 填到对应字段即可。4. 验证请求本地启动、curl 与成功结果先启动服务端python main.py看到 Uvicorn 输出Uvicorn running on http://0.0.0.0:8000就说明起来了。另开一个终端跑客户端python test/mcp_client.py预期输出MCP 会话初始化成功 可用的工具: - get_data: 根据问题获取答案 调用结果: 这是关于 测试问题 的答案。同时服务端终端会打印收到问题: 测试问题, 类型: test说明调用链路是通的。再用 curl 直接验证 SSE 端点是否可达curl -N http://127.0.0.1:8000/sse-N关闭缓冲你会看到 SSE 的事件流持续输出按 CtrlC 退出。这一步能确认服务端挂载没问题。改到 TaoToken 通道后用 curl 验证鉴权是否生效curl -N https://taotoken.net/api/sse \ -H Authorization: Bearer $TAOTOKEN_API_KEY如果返回正常的事件流说明 Key 和 Base URL 都对。如果返回 401看下一节。再跑一次客户端用 TaoToken 那段代码预期输出和本地一致只是请求实际走的是统一通道。到这里endpoint 改到 TaoToken 的动作就完成了。整个过程里服务端代码一行没改改的只是客户端的 URL 和 headers——这正是统一通道的价值。如果你还想单独验证模型对话是否正常可以到模型对话页面发一条测试消息入口在https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content确认 Key 在对话场景下也能用排除是 Key 本身的问题。5. 常见报错排查401、连接失败与工具列表为空这一节按真实报错逐条来。401 Unauthorized。最常见的原因是 Key 没传或传错。先确认环境变量在当前终端生效echo $TAOTOKEN_API_KEY如果输出为空说明 export 没生效或跑在了另一个终端。其次检查 header 格式必须是Authorization: Bearer sk-xxxBearer和 Key 之间有一个空格少空格会 401。第三确认 Key 没有多余换行从控制台复制时容易带上尾部空白可以用echo -n对比长度。如果 Key 本身过期或被删去 API Keys 页面重新生成一个。local proxy failed / 连接失败。这类报错通常出现在客户端连不上 endpoint 时。先确认 URL 拼写本地是http://127.0.0.1:8000/sseTaoToken 是https://taotoken.net/api/sse注意本地用http、统一通道用https协议写错会直接连接失败。其次确认服务端确实在跑curl -N http://127.0.0.1:8000/sse能出事件流才算正常。如果本地能通、换成 TaoToken 就不通检查网络是否能访问taotoken.net以及有没有把端口写进 URL统一通道不需要带端口。reading choices 报错。这个一般出现在调用返回体解析阶段说明请求发出去了但返回结构不符合预期。常见原因是 Model ID 填错或没填客户端拿到的是错误响应而不是正常的 choices 结构。回到配置里确认model字段填的是控制台里真实存在的 Model ID。OAuth 相关报错。部分客户端在没配 Key 时会尝试走 OAuth 流程然后报 OAuth 失败。解决办法就是显式配好Authorizationheader让它走 Key 鉴权而不是 OAuth。配置里三件套写全这个报错基本不会出现。工具列表为空。客户端连上了、初始化也成功但list_tools返回空。九成是服务端include_tags和路由tags没对上。检查app.get(..., tags[mcp])和FastApiMCP(..., include_tags[mcp])里的字符串是否完全一致大小写、空格都算。另外确认operation_id没重复重复会导致工具注册异常。CC Switch / Cline MCP 配置不生效。如果你在 CC Switch 或 Cline 里配了 MCP 但没反应先确认配置文件路径对不对再确认 JSON 语法合法多余逗号会导致整个配置被忽略。三件套 Base URL、Key、Model ID 必须都在缺一个都可能静默失败。改完配置记得重启客户端很多客户端不会热加载。排查顺序建议固定成先 curl 验证 endpoint 可达再验证鉴权再看客户端日志。这样能把问题范围快速缩小到「网络层」还是「鉴权层」还是「配置层」。6. 把链路固定下来接入文档与后续动作链路跑通之后建议把配置固化下来别每次手动改。客户端里的 Base URL、Key、Model ID 三件套抽到环境变量或独立配置文件代码里只读不写。服务端这边operation_id和tags的约定写进 README团队里其他人加新工具时照着填避免工具列表莫名其妙变空。如果你要接更多客户端接入文档里有各客户端的配置示例入口在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content对照着改 Base URL 和 Key 就行。Key 的管理统一在 API Keys 页面入口是https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content需要轮换或新增时去那里操作。最后留一个我实际踩过的点SSE 连接是长连接客户端跑完记得正常退出否则服务端可能残留会话。在async with块里操作能保证连接被正确关闭别用裸sse_client不关。另外本地调试时端口被占用会报Address already in use换个端口或杀掉占用进程即可这个和 MCP 本身无关但第一次跑很容易卡在这。

相关新闻

【ue】UltraEdit使用技巧:把编辑器 settings 改到 TaoToken 的 API 通道

【ue】UltraEdit使用技巧:把编辑器 settings 改到 TaoToken 的 API 通道

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

2026/10/19 20:46:44 阅读更多 →
机器人焊接气体自适应调节:从固定参数到动态优化

机器人焊接气体自适应调节:从固定参数到动态优化

我第一次被焊接气路逼到想改行,是在调试一条汽车零部件产线的时候。同一条焊缝,上午参数还好好的,下午一开工飞溅大到防护面罩都看不清,熔池像开锅一样翻。带班师傅二话不说,把CO2流量从15调到20,没用&…

2026/10/19 20:45:27 阅读更多 →
工业+大模型落地指南:从知识问答到设备故障排查实操

工业+大模型落地指南:从知识问答到设备故障排查实操

我见过太多做工业智能的团队,折腾了好几年,上了一堆大屏和报表系统,最后真正被一线工人用起来的却没几个。但大模型是个例外——它是少数能让老师傅主动天天打开来问问题的AI技术。原因不复杂,因为它真的能“听懂人话”&#xff0…

2026/10/19 20:46:06 阅读更多 →

最新新闻

普朗克公式MATLAB实现:从热辐射原理到数值计算避坑指南

普朗克公式MATLAB实现:从热辐射原理到数值计算避坑指南

简介:这份资源面向从事红外仿真、物理模拟与科学计算的工程师及科研人员,聚焦如何用MATLAB实现普朗克公式的数值计算。普朗克公式是描述黑体辐射能量分布的基本定律,掌握其编程实现是红外仿真与辐射度分析的基础技能。资源包共5个文件&#x…

2026/10/20 5:09:59 阅读更多 →
Agent上下文管理五路线解析:从窗口瓶颈到记忆分层

Agent上下文管理五路线解析:从窗口瓶颈到记忆分层

做Agent的朋友最近应该都有同一种焦虑:上下文不够用了。单轮对话的任务还好,一旦进入多步规划、多工具调用、长对话连续执行,模型的输入窗口就成了瓶颈,而且这个瓶颈不只是“放不下”那么简单——放得下但不重要、放得下但太贵、放…

2026/10/20 5:09:59 阅读更多 →
AutoGen多智能体框架:工程化落地的开源底座

AutoGen多智能体框架:工程化落地的开源底座

1. 这不是又一个“AI Agent 框架”,而是让多智能体协作真正落地的工程化底座“微软 AutoGen:多智能体 AI 应用的开源框架”——这个标题里藏着三个被多数人忽略的关键定语:“微软”、“多智能体”、“工程化”。它不是在讲“怎么调用一个大模…

2026/10/20 5:09:59 阅读更多 →
基于YOLO的行人跌倒检测系统实战:数据、训练与部署优化

基于YOLO的行人跌倒检测系统实战:数据、训练与部署优化

最早接触行人跌倒检测,是帮朋友做一套家庭看护系统的原型。当时第一反应很简单:拿现成的目标检测模型,在视频流上框出人,再判断这个人是站着还是躺着,不就完了吗?真正跑起来才发现,这事和"…

2026/10/20 5:09:59 阅读更多 →
大模型量化部署全攻略:从显存优化到GPTQ/AWQ/GGUF实战

大模型量化部署全攻略:从显存优化到GPTQ/AWQ/GGUF实战

量化这事,做大模型部署的基本都绕不开。我去年底第一次想在本地把一个大模型跑起来的时候,一看权重文件动辄十几个GB,再看看手头显卡那点显存,瞬间理解了什么叫"看得见吃不着"。后来折腾了一遍量化,从4bit加…

2026/10/20 5:09:59 阅读更多 →
联想Y7000-I5装Ubuntu 22.04实战避坑指南

联想Y7000-I5装Ubuntu 22.04实战避坑指南

1. 项目概述:为什么一台游戏本装Linux需要专门写注意事项?“联想拯救者Y7000-I5装Ubuntu”这个标题背后,藏着的不是一句简单的“换系统”,而是一场硬件兼容性、驱动生态与用户预期之间的三方拉锯战。我从2018年起陆续帮二十多位朋…

2026/10/20 5:08:59 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/18 12:16:16 阅读更多 →