MCP协议服务端创建实战:用FastMCP从零跑通stdio通信
1. 为什么我要用 FastMCP 写一个 stdio 服务端MCP 协议服务端创建这件事说穿了就是让大模型能调用你自己写的函数。你写一个 Python 函数用mcp.tool()装饰一下大模型就能在对话里看到这个工具并在需要时调用它。听起来很玄实际跑一遍你会发现核心代码不到 50 行。MCPModel Context Protocol是给大模型提供上下文和能力的标准协议。一个 MCP 服务端可以暴露三类东西Resources资源类似文件数据供客户端读取、Tools工具LLM 可调用的函数、Prompts提示模板。对初次接触的开发者来说Tools 是最直观的切入点——你写一个查天气的函数模型就能帮你查天气。stdio 通信是 MCP 最基础的传输方式服务端通过标准输入接收 JSON-RPC 消息通过标准输出返回结果。不需要开端口、不需要网络配置客户端启动一个子进程就能通信。这也是为什么我建议从 stdio 入手——它把协议和网络两件事拆开了你只需要关心协议本身。这篇文章面向的是第一次接触 MCP 协议的开发者。我会带你从零搭一个可被大模型调用的 stdio 服务端给出完整可复制的代码、依赖安装命令、本地联调验证步骤最后说明如何通过 TaoToken 统一 Key/API 通道接入模型完成端到端调用测试。你不需要事先了解 JSON-RPC也不需要懂异步编程的细节跟着敲一遍就能跑通。我试过用最朴素的方式手写 JSON-RPC 消息去理解 MCP结果被消息格式和握手流程绕晕了。FastMCP 把这个过程封装成了装饰器你只需要关注业务逻辑。实测下来从装环境到看到工具被调用大概 20 分钟。2. 环境准备与 TaoToken 前置配置2.1 依赖安装Python 3.10 与 uvMCP Python SDK 要求 Python 3.10 或更高版本。先确认版本python3 --version # 期望输出Python 3.10.x 或更高如果版本不够建议用 uv 管理 Python 版本它比手动装省事。安装 uvcurl -LsSf https://astral.sh/uv/install.sh | sh安装完成后重新加载 shell 配置然后验证uv --version # 期望输出uv 0.x.x2.2 创建项目并安装 MCP SDKuv init weather-mcp cd weather-mcp uv venv source .venv/bin/activate uv add mcp[cli] httpx touch weather.pymcp[cli]会装上 MCP SDK 和命令行工具httpx用来发异步 HTTP 请求。装完后可以用uv run mcp version确认 SDK 版本建议 1.2.0 以上。2.3 通过 TaoToken 统一 Key/API 通道接入模型服务端写完后你需要一个能调用 MCP 工具的模型客户端来做端到端测试。这里用 TaoToken 的统一 API 通道好处是一个 Key 能对接多种模型不用为每个模型单独配环境。先在 TaoToken 控制台创建 API Key访问 API Keys 管理页新建一个 Key 并复制保存。然后记下两个地址Base URLhttps://taotoken.net/apiAPI Key你刚创建的那串如果你打算长期做编码类 Agent 开发可以了解下 Coding Plan它针对高频调用场景做了额度优化。只是想先验证模型能不能调通工具用按量计费的 Key 就够了。模型 ID 方面TaoToken 支持多种主流模型具体可用列表在 模型对话页 能看到。选一个支持 function calling 的模型即可比如claude-sonnet-4-20250514或gpt-4o。3. 可复制的 FastMCP 服务端配置与代码3.1 服务端完整代码把下面内容写入weather.py。这段代码定义了两个工具get_alerts查美国某州的天气预警get_forecast查某经纬度的天气预报。from typing import Any import httpx from mcp.server.fastmcp import FastMCP # 初始化 FastMCP 服务端名字叫 weather mcp FastMCP(weather) NWS_API_BASE https://api.weather.gov USER_AGENT weather-app/1.0 async def make_nws_request(url: str) - dict[str, Any] | None: 请求 NWS API带错误处理。 headers { User-Agent: USER_AGENT, Accept: application/geojson, } async with httpx.AsyncClient() as client: try: response await client.get(url, headersheaders, timeout30.0) response.raise_for_status() return response.json() except Exception: return None def format_alert(feature: dict) - str: 把预警数据格式化成可读字符串。 props feature[properties] return f Event: {props.get(event, Unknown)} Area: {props.get(areaDesc, Unknown)} Severity: {props.get(severity, Unknown)} Description: {props.get(description, No description available)} Instructions: {props.get(instruction, No specific instructions provided)} mcp.tool() async def get_alerts(state: str) - str: 获取美国某州的天气预警。 Args: state: 两个字母的州代码例如 CA、NY url f{NWS_API_BASE}/alerts/active/area/{state} data await make_nws_request(url) if not data or features not in data: return 无法获取预警数据。 if not data[features]: return 该州当前没有活跃预警。 alerts [format_alert(feature) for feature in data[features]] return \n---\n.join(alerts) mcp.tool() async def get_forecast(latitude: float, longitude: float) - str: 获取某经纬度的天气预报。 Args: latitude: 纬度 longitude: 经度 points_url f{NWS_API_BASE}/points/{latitude},{longitude} points_data await make_nws_request(points_url) if not points_data: return 无法获取该位置的预报数据。 forecast_url points_data[properties][forecast] forecast_data await make_nws_request(forecast_url) if not forecast_data: return 无法获取详细预报。 periods forecast_data[properties][periods] forecasts [] for period in periods[:5]: forecast f {period[name]}: Temperature: {period[temperature]}°{period[temperatureUnit]} Wind: {period[windSpeed]} {period[windDirection]} Forecast: {period[detailedForecast]} forecasts.append(forecast) return \n---\n.join(forecasts) if __name__ __main__: mcp.run(transportstdio)3.2 关键点解析mcp.tool() 装饰器做了什么mcp.tool()是 FastMCP 的核心。它把普通 Python 函数注册成 MCP 工具并自动从类型提示和 docstring 生成工具的输入 schema。也就是说你写的state: str和那段 docstring会被转成模型能理解的参数说明。装饰器内部逻辑大致是接收函数调用self.add_tool(fn, namename, descriptiondescription)注册然后返回原函数。注意它必须写成mcp.tool()带括号的形式直接写mcp.tool会抛TypeError因为装饰器需要先被调用一次。3.3 客户端配置让模型客户端启动这个服务端stdio 服务端不是常驻进程它由客户端按需启动。以 Claude Desktop 为例配置文件路径macOS~/Library/Application Support/Claude/claude_desktop_config.jsonWindows%APPDATA%\Claude\claude_desktop_config.json写入以下 JSON把路径换成你自己的绝对路径{ mcpServers: { weather: { command: uv, args: [ --directory, /ABSOLUTE/PATH/TO/weather-mcp, run, weather.py ] } } }这段配置告诉客户端有一个叫weather的 MCP 服务端通过uv --directory ... run weather.py启动它。改完配置要重启客户端。如果你用的是支持 OpenAI 兼容接口的客户端比如 Cline、Continue 等配置里需要同时填三件套{ mcpServers: { weather: { command: uv, args: [--directory, /ABSOLUTE/PATH/TO/weather-mcp, run, weather.py] } }, llm: { baseUrl: https://taotoken.net/api, apiKey: 你的 TaoToken Key, modelId: claude-sonnet-4-20250514 } }Base URL、Key、Model ID 三者缺一不可。Base URL 固定为https://taotoken.net/api不要加 UTM 参数。4. 验证请求与成功结果4.1 本地 stdio 联调用 mcp dev 检查工具注册在启动客户端之前先用 SDK 自带的调试工具确认服务端能正常握手uv run mcp dev weather.py这会启动一个本地调试界面列出服务端注册的所有工具。如果看到get_alerts和get_forecast两个工具说明服务端代码没问题。这一步能提前排掉大部分语法和注册错误。4.2 直接跑服务端看 stdio 输出也可以直接运行观察它是否在等待 stdinuv run weather.py正常情况下进程会挂起等待标准输入。此时它已经准备好接收 JSON-RPC 消息了。按 CtrlC 退出。4.3 端到端调用让模型调用工具重启客户端后在对话里输入帮我查一下加州现在的天气预警模型会分析可用工具选择get_alerts传入stateCA。客户端通过 stdio 把调用请求发给服务端服务端请求 NWS API 拿到数据格式化后返回。整个链路是客户端把问题发给模型模型决定调用get_alerts生成参数客户端通过 stdio 把工具调用发给服务端服务端执行函数返回结果客户端把结果回传给模型模型组织自然语言回复如果模型回复里包含具体的预警事件和区域描述说明端到端跑通了。第一次调用时客户端通常会弹窗询问是否授权点允许即可。5. 本篇常见错误排查5.1 401 UnauthorizedKey 或 Base URL 配错报错长这样Error: 401 Unauthorized - invalid api key原因通常是三件套里某一项写错。检查顺序Base URL 必须是https://taotoken.net/api结尾不要多斜杠API Key 复制时别带空格Model ID 要和 TaoToken 支持的模型名完全一致。如果用的是 Claude Desktop 这类不直接暴露 LLM 配置的客户端401 一般来自它自己的账号体系和 MCP 服务端无关。5.2 local proxy failed / connection refusedMCP error: local proxy failed to connect这通常是客户端启动服务端子进程失败。检查 JSON 配置里的--directory路径是不是绝对路径Windows 下要用双反斜杠或正斜杠。另外确认uv在 PATH 里客户端可能读不到你 shell 里的环境变量必要时把command写成uv的绝对路径。5.3 reading choices 报错响应结构不符TypeError: Cannot read properties of undefined (reading choices)这个报错说明客户端拿到的响应不是标准 OpenAI 格式。常见原因是 Base URL 填成了网页地址而不是 API 地址。确认填的是https://taotoken.net/api不是带/chat的页面地址。如果客户端要求填完整 endpoint用https://taotoken.net/api/v1/chat/completions。5.4 OAuth 相关报错OAuth error: invalid_client部分客户端默认走 OAuth 流程但 TaoToken 用的是 API Key 鉴权。在客户端设置里把认证方式从 OAuth 改成 API Key填入你的 Key 即可。如果客户端没有这个选项检查是不是选错了接入模式。5.5 工具注册了但模型不调用服务端日志显示工具已注册但模型就是不调用。先确认模型本身支持 function calling部分轻量模型不支持。其次检查 docstring 是否清晰——模型靠 docstring 判断什么时候用这个工具。把获取美国某州的天气预警。写得更具体比如加上当用户询问某地天气状况或预警时使用命中率会明显提升。6. 继续往下走从 stdio 到更完整的接入跑通 stdio 之后你已经掌握了 MCP 服务端的核心用 FastMCP 注册工具、用 stdio 传输、用客户端联调。接下来可以做的事把服务端换成你自己的业务逻辑比如查数据库、调内部 API、读本地文件。工具函数的写法完全一样只是把make_nws_request换成你的请求逻辑。如果你想让服务端被更多客户端复用可以了解 streamable HTTP 传输方式它适合部署成常驻服务。但 stdio 依然是本地开发调试最快的路径。端到端测试时如果遇到模型侧的问题可以到 模型对话页 直接验证 Key 和模型是否正常排除掉 MCP 服务端的干扰。接入细节和参数说明在 接入文档 里有完整对照表。最后一个实用技巧调试 stdio 服务端时不要用print()输出日志因为 stdout 被 JSON-RPC 占用了任何多余输出都会破坏协议。要打日志就写到 stderr或者用logging模块配置到文件。这个坑我第一次写的时候踩过服务端看起来在跑但客户端一直握手失败排查了半天才发现是一行 print。

相关新闻

【信道估计】基于matlab毫米波MIMO系统LS、OMP和SBL UPA远场信道估计(NMSE性能评估)【含Matlab源码 16091期】

【信道估计】基于matlab毫米波MIMO系统LS、OMP和SBL UPA远场信道估计(NMSE性能评估)【含Matlab源码 16091期】

💥💥💥💥💥💥💞💞💞💞💞💞💞💞欢迎来到海神之光博客之家💞💞💞&#x1f49…

2026/10/18 16:20:30 阅读更多 →
SpringBoot电商项目核心设计:订单、库存与支付幂等的工程实践

SpringBoot电商项目核心设计:订单、库存与支付幂等的工程实践

简介:基于SpringBoot的电商平台设计与实现资料包,围绕毕业设计场景展开,面向计算机相关专业学生及初级开发者,解决传统商品交易信息管理效率低、易出错等问题。项目采用Java语言、MySQL数据库与Spring Boot框架,涵盖商…

2026/10/18 16:20:30 阅读更多 →
AI辅助编码质量治理:工程规范、代码评审与风险驱动测试实战

AI辅助编码质量治理:工程规范、代码评审与风险驱动测试实战

1. 当AI开始写代码,质量治理为什么成了新命题过去一年,我参与过三个不同规模的研发团队做AI辅助编码的落地,从十几个人的创业小队到上百人的中台部门都有。一个非常一致的观察是:AI写代码的速度远超团队消化它的速度。以前一个需求…

2026/10/18 16:20:30 阅读更多 →

最新新闻

ROS2小车网页遥控:WebSocket桥接实现低延迟物理控制

ROS2小车网页遥控:WebSocket桥接实现低延迟物理控制

/* 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 17:03:56 阅读更多 →
STSPIN32G4高集成方案:FOC电机控制从选型到调试全实践

STSPIN32G4高集成方案:FOC电机控制从选型到调试全实践

/* 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 17:03:56 阅读更多 →
树莓派自动温控风扇:DS18B20与PWM调速实战

树莓派自动温控风扇:DS18B20与PWM调速实战

/* 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 17:03:56 阅读更多 →
传感器数据跳变排查指南:从硬件到软件的实战解决方案

传感器数据跳变排查指南:从硬件到软件的实战解决方案

/* 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 17:03:56 阅读更多 →
STM32F407的Modbus RTU主机代码详解:CRC16校验与RS485收发切换

STM32F407的Modbus RTU主机代码详解:CRC16校验与RS485收发切换

简介:基于STM32F407的Modbus RTU主机通信工程,实现RS485总线上完整的主站收发流程,适合嵌入式开发者及工业自动化技术人员在设备数据采集、从站轮询控制等场景中直接参考。工程基于STM32标准外设库编写,核心代码涵盖USART串口参数…

2026/10/18 17:03:56 阅读更多 →
帆软FR中JS实现分类汇总:完整思路、性能优化与避坑指南

帆软FR中JS实现分类汇总:完整思路、性能优化与避坑指南

做报表开发久了,你会发现一个奇怪的现象:SQL里一个GROUP BY就能搞定的分类汇总,到了帆软FR(FineReport)里,偏偏要用JS去实现。最开始我也觉得这是脱裤子放屁,直到遇到一个真实业务:某…

2026/10/18 17:02:55 阅读更多 →

日新闻

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

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

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

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

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

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

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

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

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

2026/10/18 0:00:55 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 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/18 0:55:02 阅读更多 →
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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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 阅读更多 →