【MCP实践】Python构建MCP应用全攻略:从STDIO到Streamable HTTP的TaoToken接入
发布时间:2026/10/2 16:00:52来源:尧图网络
1. 为什么你的 MCP 服务总是连不上模型很多人第一次接触 MCPModel Context Protocol时会把它想得很玄乎其实它解决的是一个非常朴素的问题让模型能调用你写的函数。你有一个查天气的 Python 脚本、一个查数据库的工具、一个内部工单系统模型本身碰不到它们MCP 就是中间那层标准化的“插座”。你按协议把函数暴露出去模型侧按协议来调用双方不用互相认识。但真正动手时坑往往不在协议本身而在“链路怎么接”。我见过太多人卡在同一个地方本地用 STDIO 跑得好好的一改成 Streamable HTTP 就报连接失败或者服务端明明起来了客户端list_tools却返回空再或者工具能列出来一call_tool就抛参数错误。这些问题的根源八成不是 fastmcp 写错了而是传输方式选错、endpoint 配错、或者 Key 通道没打通。这篇就按“从零到跑通”的顺序来先用 fastmcp 写一个最小可用的 MCP 服务把 STDIO 和 Streamable HTTP 两种传输方式都跑一遍然后把服务的 endpoint 统一改到 TaoToken 的 Key/API 通道上最后用一段完整的客户端代码做一次真实调用验证。适合谁适合已经会写 Python 函数、想让模型调用自己工具、但被 MCP 的传输和鉴权绕晕的开发者。读完你能拿到三样东西可复制的服务端配置、可复制的客户端连接代码、一次能跑出结果的验证动作。先说清楚一个概念避免后面混淆。MCP 服务里有三个核心角色Tool工具负责执行具体动作比如算折扣、查数据Prompt提示负责生成给模型的指导消息Resource资源负责提供可复用的静态或动态数据。三者用不同的装饰器暴露mcp.tool()、mcp.prompt()、mcp.resource()。新手最容易只写 Tool然后以为 MCP 就这点东西其实 Prompt 和 Resource 才是让服务“像个产品”的关键。下面我会以 Tool 为主线跑通链路中间穿插 Prompt 和 Resource 的写法。2. TaoToken 前置把 MCP endpoint 接到统一 Key 通道在写代码之前先把“通道”这件事定下来。MCP 服务本身不负责模型推理它只负责暴露工具真正去调模型、做推理的是客户端那一侧。所以当你想让 MCP 服务被一个统一的模型通道调用时需要把 endpoint 指向 TaoToken 的 API 地址用统一的 Key 来鉴权。这样做的好处是你本地写的工具、云端部署的服务、不同客户端都走同一个入口不用每个工具单独配一套鉴权。TaoToken 的官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 这个不加 UTM。你需要先在控制台创建一个 API Key然后把它作为环境变量注入到你的 MCP 客户端或服务端配置里。注意Key 不要硬编码进代码提交到仓库用环境变量或者.env文件管理。这里有个关键认知MCP 的传输层和模型的鉴权层是两件事。STDIO 模式下服务端和客户端在同一台机器上通过标准输入输出通信不涉及网络鉴权Streamable HTTP 模式下服务端监听一个 HTTP 端口客户端通过 URL 连接这时候才需要把 endpoint 和 Key 配好。很多人把这两层混在一起导致“本地能跑、远程报 401”。正确的做法是先用 STDIO 验证工具逻辑没问题再切到 Streamable HTTP 验证网络链路最后把 endpoint 换成 TaoToken 的通道做统一鉴权。如果你用的是 Claude Code 这类工具它支持通过配置文件接入 MCP 服务。配置里通常需要三件套Base URL、API Key、Model ID。Base URL 填 TaoToken 的 API 地址Key 填你在控制台创建的 KeyModel ID 填你要调用的模型标识。这三样配齐Claude Code 才能既连上模型、又连上你的 MCP 服务。下面第三节我会给出具体的 JSON 配置片段路径和字段名都按实际可用的来写。还有一个容易忽略的点TaoToken 的 API Key 是有权限范围的。如果你只是做本地测试创建一个测试用的 Key 就够了如果要部署到生产建议单独建一个 Key 并限制调用范围。控制台里可以管理多个 Key按项目或环境区分这样出问题的时候能快速定位是哪个环节的 Key 失效了。API Keys 的管理入口在控制台里创建后记得复制保存页面刷新后就看不到了。3. 可复制配置fastmcp 服务端 客户端 settings 片段这一节是全文的核心所有代码都可以直接复制运行。先装依赖pip install fastmcp然后写服务端。下面这个文件我命名为mcp_server.py包含一个 Tool、一个 Prompt、一个 Resource并且支持通过环境变量切换传输模式import os from fastmcp import FastMCP mcp FastMCP(demo.mcp) mcp.tool() def greet(name: str) - str: 根据名字返回问候语 return fHello, {name} mcp.tool() def calculate_discount(price: float, discount: float) - float: 计算商品折扣价discount 为百分比 return price * (1 - discount / 100) mcp.prompt() def generate_interview_questions(position: str, level: str) - str: 生成职位面试问题 return f作为资深{position}面试官请生成5个适合{level}级候选人的技术问题 要求 1. 包含代码题和理论题 2. 难度递增 3. 标注考察点 mcp.resource(uriresource://greeting/{name}, namegreeting, description演示用资源) def get_greeting(name: str) - str: return fHello from {name} Resources! mcp.resource(resource://config) def get_config() - dict: return { theme: dark, version: 1.2.0, features: [tools, resources], } def run_server(): mode os.getenv(MCP_MODE, ).lower() if mode sse: mcp.run(transportsse, port8000, path/sse) elif mode streamable-http: mcp.run(transportstreamable-http, port8000, path/mcp) else: mcp.run() # 默认 STDIO if __name__ __main__: run_server()STDIO 模式直接python mcp_server.py就行它不监听端口靠标准输入输出通信。Streamable HTTP 模式这样启动MCP_MODEstreamable-http python mcp_server.py启动后服务监听http://localhost:8000/mcp。注意路径是/mcp客户端连接时要带上这个路径少一个斜杠都可能 404。接下来是客户端。先做本地自测不经过网络直接连内存里的服务实例import asyncio from fastmcp import Client from mcp_server import mcp async def main(): client Client(mcp) async with client: tools await client.list_tools() print(可用工具:, [t.name for t in tools]) result await client.call_tool(greet, {name: 技术爱好者}) print(调用结果:, result[0].text) asyncio.run(main())这段跑通说明你的工具逻辑没问题。然后测 Streamable HTTP 远程连接import asyncio from fastmcp.client import Client async def main(): async with Client(http://localhost:8000/mcp/) as client: tools await client.list_tools() print(f可用工具: {[t.name for t in tools]}) result await client.call_tool(greet, {name: Python开发者}) print(f返回结果: {result[0].text}) asyncio.run(main())预期输出可用工具: [greet, calculate_discount] 返回结果: Hello, Python开发者现在把 endpoint 换成 TaoToken 通道。如果你用 Claude Code配置文件里需要写全三件套。下面是一个settings.json片段路径按实际配置位置来{ mcpServers: { demo-mcp: { url: https://taotoken.net/api/mcp, headers: { Authorization: Bearer ${TAOTOKEN_API_KEY} } } }, model: { baseUrl: https://taotoken.net/api, apiKey: ${TAOTOKEN_API_KEY}, modelId: your-model-id } }注意${TAOTOKEN_API_KEY}是环境变量引用实际运行时会被替换。Base URL 用https://taotoken.net/api不要加 UTM 参数。Model ID 填你在控制台看到的模型标识。这样配完Claude Code 既走 TaoToken 的模型通道又能连上你的 MCP 服务。如果你用 Cline 或类似的编辑器插件配置逻辑一样Base URL、Key、Model ID 三件套缺一不可。Cline 的 MCP 配置通常在插件设置里填 server 名称、URL、headers。Codex 的话auth.json里需要写 API Key 和 base URL。不管哪个客户端核心都是把 endpoint 指向 TaoToken 的 API 地址用统一 Key 鉴权。4. 验证请求一次完整的调用与结果确认配置写完不算完必须做一次真实调用验证。验证分三步先确认服务端起来了再确认工具列表能拉到最后确认工具能调用并返回正确结果。第一步启动 Streamable HTTP 服务MCP_MODEstreamable-http python mcp_server.py看到类似Uvicorn running on http://0.0.0.0:8000的输出说明服务起来了。如果端口被占用换一个端口比如port8001客户端连接时同步改。第二步用 curl 探一下 endpoint 是否可达curl -i http://localhost:8000/mcp/如果返回 200 或 405取决于方法说明路径对。返回 404 就是路径写错了检查是不是漏了/mcp。第三步跑客户端验证脚本。把上面的远程连接代码保存为client_test.py运行python client_test.py预期看到工具列表和调用结果。如果list_tools返回空列表先检查服务端有没有正确注册工具再检查客户端连的 URL 是不是服务端实际监听的地址。如果call_tool报参数错误检查字典的 key 是否和函数参数名完全一致——greet的参数是name你就必须传{name: xxx}传{username: xxx}会直接报错。再验证一下 Prompt 和 Resource。Prompt 的调用方式prompt_result await client.get_prompt(generate_interview_questions, {position: 后端, level: 高级}) print(prompt_result)Resource 的读取resource_result await client.read_resource(resource://config) print(resource_result)这两个能跑通说明你的 MCP 服务是完整的不只是个工具集合。最后做一次端到端验证把客户端连到 TaoToken 通道确认鉴权通过。如果你在 Claude Code 里配好了直接在对话里让模型调用greet工具看它能不能返回问候语。这一步跑通整条链路就通了模型 → TaoToken 通道 → MCP 服务 → 你的 Python 函数。5. 本篇常见错排查401、local proxy failed、reading choices这一节按真实报错来。我把踩过的坑列出来你对照着查。401 Unauthorized。这个最常见出现在 Streamable HTTP 模式连 TaoToken 通道时。原因通常是 Key 没传、传错、或者环境变量没生效。检查三处配置文件里Authorization头的格式是不是Bearer ${TAOTOKEN_API_KEY}环境变量TAOTOKEN_API_KEY有没有在当前 shell 里 exportKey 本身有没有过期或被删。如果用的是 Claude Code确认settings.json里的apiKey字段引用的环境变量名和实际 export 的一致。local proxy failed。这个报错通常出现在客户端试图连接一个不可达的地址时。检查服务端是不是真的在监听那个端口netstat -an | grep 8000看一下。如果服务端在容器里客户端在宿主机localhost是不通的要用容器 IP 或host.docker.internal。另外检查防火墙有没有拦。reading choices 相关报错。这个一般出现在模型返回格式不符合预期时比如你期望的是工具调用但模型返回了纯文本。检查 Model ID 是否填对有些模型不支持工具调用换一个支持 function calling 的模型。另外确认请求体里的tools字段格式正确MCP 客户端一般会帮你封装但如果你手动构造请求要按 OpenAI 兼容格式来。OAuth 相关报错。如果你在配置里看到了 OAuth 字样说明客户端在尝试走 OAuth 流程但你的配置是 API Key 模式。检查配置文件里有没有多余的 OAuth 字段删掉只保留Authorization头。TaoToken 的 API 通道用 Key 鉴权不需要 OAuth。工具列表为空。服务端起来了但list_tools返回空。检查装饰器有没有写错mcp.tool()必须紧贴函数定义中间不能有空行或其他装饰器。另外确认你连的是正确的服务实例STDIO 模式下客户端和服务端必须在同一进程或通过管道连接不能跨进程。参数名不匹配。call_tool的字典 key 必须和函数参数名完全一致。def greet(name: str)就只能传{name: ...}。这个错误报得很直接看到unexpected keyword argument就回去对参数名。端口冲突。多个 MCP 服务同时跑默认都抢 8000。给每个服务分配不同端口mcp.run(port8001)客户端连接时同步改 URL。异步陷阱。fastmcp 的工具函数可以是同步的但客户端调用是异步的。如果你在同步代码里调call_tool会报coroutine was never awaited。用asyncio.run()包起来或者用await。6. 语义一致 CTA把链路跑通之后链路跑通之后你手里就有了一套可复用的 MCP 开发模板服务端用 fastmcp 写工具、提示、资源传输层按场景选 STDIO 或 Streamable HTTP鉴权层统一走 TaoToken 的 Key 通道。接下来可以做的事很多把内部 API 封装成 Tool 让模型调用把常用提示词做成 Prompt 集中管理把配置数据做成 Resource 动态供给。如果你在排障或接入阶段卡住了建议先看接入文档对照配置检查 Base URL、Key、Model ID 三件套。文档里有各客户端的配置示例路径和字段名都写得很清楚。需要创建或管理 Key 的话去 API Keys 页面操作按环境分 Key 是个好习惯。想先验证模型通道是否正常可以用模型对话页面发一条测试消息确认 Key 和 Base URL 没问题再回来调 MCP 工具。如果你打算长期做编码类或 Agent 类的工作Coding Plan 更适合它针对长时间、多轮次的编码场景做了优化不用每次单独配 Key。最后给一个实用建议MCP 服务开发时先用 STDIO 模式把工具逻辑跑通再切 Streamable HTTP 验证网络链路最后接 TaoToken 通道做统一鉴权。这个顺序能帮你快速定位问题出在哪一层而不是一上来就全配好然后对着一个报错发呆。工具函数写完后先本地自测list_tools和call_tool确认参数名和返回格式没问题再往外暴露。这样每一步都有明确的验证点出问题也知道回退到哪一步。
网站建设高端定制企业官网