新闻详情

新闻详情

首页 / 资讯中心 / 详情

构建你的第一个MCP服务器:用Python+FastMCP从零实现stdio与JSON-RPC

发布时间:2026/10/2 16:38:09来源:尧图网络
构建你的第一个MCP服务器:用Python+FastMCP从零实现stdio与JSON-RPC
1. 从零理解 MCP 服务器到底在做什么如果你最近在折腾 AI 工具链大概率听过 MCP 服务器这个词。它的全称是 Model Context Protocol说白了就是给大模型和外部世界之间定了一套“普通话”。模型本身只会生成文本它没法直接读你硬盘上的文件、查你的数据库、调你的内部接口。MCP 就是那个中间层模型通过标准协议告诉服务器“我要读这个文件”服务器执行完把结果按标准格式返回模型再拿结果继续推理。这套协议底层用的是 JSON-RPC 2.0传输层可以走 stdio标准输入输出也可以走 HTTP。对本地开发来说stdio 是最省事的服务器进程启动后从 stdin 读 JSON-RPC 请求往 stdout 写 JSON-RPC 响应不需要开端口、不需要处理网络。你写完代码直接跑客户端一发请求就能看到结果。这篇文章面向的是想动手写第一个 MCP 服务器的 Python 开发者。我会用 FastMCP 这个官方 SDK带你搭一个最小可用的文件系统服务器暴露两个能力列目录和读文件。整个过程包括项目结构、依赖安装、服务端代码、客户端调用脚本以及本地启动后一次完整请求响应的验证。你跟着敲一遍就能理解 stdio 传输和 JSON-RPC 消息格式到底长什么样。适合谁看会一点 Python、用过 pip 或 uv、想搞清楚 MCP 服务器内部机制的人。不需要你之前写过任何 MCP 相关代码。我试过把整个流程压缩到 30 分钟内跑通关键是把每一步的“为什么”讲清楚而不是复制粘贴一堆看不懂的装饰器。先明确一个概念MCP 服务器里通常有三类东西——资源Resources、提示Prompts、工具Tools。资源偏向“读数据”比如列文件、查表工具偏向“执行动作”比如读文件内容、调 API提示是模板化的消息。我们这个最小服务器会各用一个资源负责列目录工具负责读文件。这样你能同时看到两种注册方式的区别。2. TaoToken 前置准备把模型侧和服务器侧接起来写 MCP 服务器本身不需要任何外部服务Python 装好就能跑。但服务器写完之后你总得有个“主机”来调用它否则只能自己手写 JSON-RPC 请求测试。实际开发中这个主机可能是 Claude Desktop、Cline、或者你自己写的 Agent。如果你想让模型真正用上你写的工具就需要一个能访问模型的入口。这里我用 TaoToken 作为模型接入层来说明。它的作用是提供统一的 API 入口让你在客户端配置里填一个 Base URL 和 Key就能调用模型对话能力。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。注意 API 地址后面不加 UTM 参数直接用它作为 Base URL。为什么要在 MCP 教程里提这个因为很多人卡在“服务器写好了但不知道怎么让模型调用”。你需要三样东西对齐Base URL、API Key、Model ID。这三件套在配置任何 MCP 主机时都会出现。比如你在 Cline 或 Claude Code 里配置模型填的就是这三个值。MCP 服务器负责提供工具模型负责决定什么时候调工具两者通过主机进程串起来。获取 Key 的路径是先注册登录然后进控制台创建 API Key。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 创建 Key 的页面在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。拿到 Key 之后先存好后面配置客户端要用。如果你只是想先验证 MCP 服务器能不能跑不接模型也行直接用我后面给的客户端脚本发 JSON-RPC 请求。但如果你想体验“模型自动调用我写的工具”那就需要把模型侧配好。模型对话入口在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 可以先用它确认 Key 能用。长期做编码和 Agent 的话Coding Plan 页面在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。这里要强调一点MCP 服务器和模型接入是两件事。服务器是你自己写的 Python 进程模型接入是客户端配置。不要混在一起。先把服务器跑通再去配客户端。顺序反了容易懵。3. 可复制配置项目结构、依赖与 FastMCP 服务端代码这一节是核心所有代码都可以直接复制。先建项目目录我习惯用 uv 管理依赖因为它比 pip 快很多而且虚拟环境管理更干净。如果你还没装 uv先执行pip install uv uv --version然后创建项目mkdir mcp_filesystem_server cd mcp_filesystem_server uv init uv venv source .venv/bin/activateWindows 下激活命令换成.venv\Scripts\activate。接着安装 MCP SDKuv add mcp[cli]装完之后验证 CLI 可用mcp --version项目结构最终长这样mcp_filesystem_server/ ├── .venv/ ├── filesystem_server.py ├── client_test.py ├── requirements.txt └── README.mdrequirements.txt里写一行就行mcp[cli]下面是filesystem_server.py的完整代码。我加了详细注释重点看mcp.resource和mcp.tool两个装饰器的用法以及最后mcp.run(transportstdio)这一行from mcp.server.fastmcp import FastMCP import os from pydantic import Field # 初始化 MCP 服务器实例名字会出现在客户端工具列表里 mcp FastMCP(filesystem_server) mcp.resource(file://list/{directory}) def list_files(directory: str Field(description要列出文件的目录路径)) - list: 列出指定目录中的文件和子目录。 try: return os.listdir(directory) except Exception as e: return [f错误: {str(e)}] mcp.tool() def read_file(path: str Field(description要读取的文件的路径)) - str: 读取指定路径的文件内容。 try: with open(path, r, encodingutf-8) as file: return file.read() except Exception as e: return f错误: {str(e)} if __name__ __main__: mcp.run(transportstdio)注意几个细节。第一FastMCP的导入路径是mcp.server.fastmcp不是直接from mcp import FastMCP不同版本可能有差异以你安装的版本为准。第二mcp.resource需要给一个 URI 模板我这里用file://list/{directory}客户端调用时会替换{directory}。第三mcp.tool()括号不能省它是装饰器工厂。第四Field用来给参数加描述模型看到描述才知道这个参数填什么。如果你想让服务器同时支持 HTTP 传输把最后一行改成mcp.run(transporthttp)但本地开发用 stdio 就够了。stdio 的好处是零网络配置进程间直接通信。再给一个客户端测试脚本client_test.py用来手动发 JSON-RPC 请求验证服务器import subprocess import json # 启动服务器进程走 stdio proc subprocess.Popen( [python, filesystem_server.py], stdinsubprocess.PIPE, stdoutsubprocess.PIPE, stderrsubprocess.PIPE, textTrue, ) # 构造 JSON-RPC 2.0 请求初始化 init_request { jsonrpc: 2.0, id: 1, method: initialize, params: { protocolVersion: 2024-11-05, capabilities: {}, clientInfo: {name: test-client, version: 1.0}, }, } proc.stdin.write(json.dumps(init_request) \n) proc.stdin.flush() response proc.stdout.readline() print(初始化响应:, response) # 构造工具调用请求 call_request { jsonrpc: 2.0, id: 2, method: tools/call, params: { name: read_file, arguments: {path: requirements.txt}, }, } proc.stdin.write(json.dumps(call_request) \n) proc.stdin.flush() response proc.stdout.readline() print(工具调用响应:, response) proc.terminate()这个脚本直接操作子进程的 stdin/stdout你能亲眼看到 JSON-RPC 消息长什么样。运行它之前确保当前目录下有requirements.txt否则读文件会返回错误信息。4. 验证请求本地启动与一次完整请求响应先把服务器单独跑起来确认不报错python filesystem_server.py如果没有任何输出说明服务器在等待 stdin 输入这是正常的。stdio 模式下服务器不会主动打印东西它只响应请求。按 CtrlC 退出。然后运行客户端脚本python client_test.py你会看到类似这样的输出初始化响应: {jsonrpc:2.0,id:1,result:{protocolVersion:2024-11-05,capabilities:{resources:{},tools:{}},serverInfo:{name:filesystem_server,version:...}}} 工具调用响应: {jsonrpc:2.0,id:2,result:{content:[{type:text,text:mcp[cli]\n}]}}第一条是初始化响应服务器返回了协议版本、能力列表和服务器信息。第二条是工具调用响应content数组里就是requirements.txt的内容。看到这个说明你的 MCP 服务器已经能正常处理 JSON-RPC 请求了。这里解释一下 JSON-RPC 2.0 的消息格式。请求必须有jsonrpc、method、id三个字段params可选。响应里id和请求对应result是成功结果error是失败信息。MCP 在 JSON-RPC 基础上定义了自己的方法名比如initialize、tools/call、resources/read。你不需要手写这些方法名FastMCP 会根据你注册的工具和资源自动生成。再验证一下资源读取。把客户端脚本里的call_request换成call_request { jsonrpc: 2.0, id: 3, method: resources/read, params: { uri: file://list/., }, }重新运行你会看到当前目录的文件列表。注意 URI 里的{directory}被替换成了.服务器返回的是os.listdir(.)的结果。如果你想把服务器接到真实模型上需要在客户端配置里填三件套。以 Cline 为例配置片段大概是这样{ mcpServers: { filesystem: { command: python, args: [/absolute/path/to/filesystem_server.py] } } }模型侧的配置则是 Base URL 填https://taotoken.net/apiAPI Key 填你创建的那个Model ID 按文档填。这样模型就能在对话中自动调用read_file工具了。Claude Code 的接入方式类似具体看接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。5. 本篇常见错排查401、local proxy failed 与 reading choices写 MCP 服务器时最容易遇到的不是代码逻辑错误而是配置和协议层面的问题。我按真实报错整理几个高频场景。第一个是401 Unauthorized。这个通常出现在模型侧配置不是 MCP 服务器本身。原因是你填的 API Key 不对或者 Base URL 写错了。检查两点Base URL 是不是https://taotoken.net/apiKey 是不是从 API Keys 页面复制的完整字符串。注意不要多复制空格。如果用的是 Coding Plan确认套餐状态正常。第二个是local proxy failed或连接被拒绝。这个多半是客户端配置里的command路径不对。MCP 主机启动服务器时用的是绝对路径你写相对路径它会找不到。把args里的脚本路径改成绝对路径比如/Users/yourname/mcp_filesystem_server/filesystem_server.py。另外确认 Python 解释器路径正确虚拟环境没激活的话python可能指向系统 Python缺少mcp库。第三个是reading choices相关报错。这个一般出现在模型返回格式不符合预期时客户端解析失败。如果你在工具调用后看到类似错误先检查工具返回的内容是不是合法 JSON。FastMCP 会自动包装返回值但如果你在工具里返回了不可序列化的对象就会出问题。确保返回str、list、dict这类基础类型。第四个是 OAuth 相关报错。MCP 协议支持 OAuth 认证但我们的最小服务器没启用。如果你在客户端看到 OAuth 错误说明客户端配置里开了认证选项关掉即可。本地 stdio 传输不需要认证。第五个是服务器启动后立刻退出。检查mcp.run(transportstdio)是不是在if __name__ __main__:里面。如果不在导入时就会执行可能导致异常退出。另外确认没有在服务器代码里写print语句stdio 模式下 stdout 被 JSON-RPC 占用任何额外输出都会破坏协议。第六个是工具注册了但客户端看不到。FastMCP 要求工具函数有类型注解和文档字符串否则可能被忽略。确保path: str这样的注解存在Field描述也加上。资源 URI 模板要符合规范file://list/{directory}这种格式是对的。排查顺序建议先单独跑服务器确认不报错再用客户端脚本发原始 JSON-RPC 确认协议层通最后才接模型。这样能把问题范围缩小。6. 语义一致 CTA把服务器接上模型继续跑服务器跑通之后下一步就是让它真正被模型用起来。你可以先用模型对话入口 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 确认 Key 和模型可用然后在 Cline 或 Claude Code 里配置 MCP 服务器路径和模型三件套。配置完成后在对话里说“帮我读一下 requirements.txt”模型应该会自动调用你写的read_file工具。如果你打算长期做编码和 Agent 开发Coding Plan 页面 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 有更完整的方案说明。接入过程中遇到配置问题先看接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 大部分报错都有对应说明。需要新建或管理 Key 就去 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。最后给一个实用建议把你写的 MCP 服务器当成一个独立的小服务来维护工具函数尽量单一职责参数描述写清楚异常处理返回可读的错误信息。这样模型调用时成功率更高你自己调试也更快。等你把文件系统这个跑顺了可以试着加数据库查询工具或者 HTTP 请求工具套路完全一样。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

从零搭建AI工程能力:告别调包侠,掌握底层原理与实战 2026/10/2 17:31:08

从零搭建AI工程能力:告别调包侠,掌握底层原理与实战

1. 从零搭建AI工程能力:为什么我劝你别再当“调包侠”“ai-engineering-from-scratch”这个标题,第一次看到的时候我愣了一下。不是因为它有多花哨,恰恰相反,它朴素得有点不像现在这个时代的项目名。现在满大街都是“大模型实战”…

阅读更多 →
【题解-Acwing】9. 分组背包问题 2026/10/2 17:31:08

【题解-Acwing】9. 分组背包问题

题目:9. 分组背包问题 题目描述 有 NNN 组物品和一个容量是 VVV 的背包。 每组物品有若干个,同一组内的物品最多只能选一个。 每件物品的体积是 vijv_{ij}vij​,价值是 wijw_{ij}wij​,其中 iii 是组号,jjj 是组内编…

阅读更多 →
VSCode+Claude真香,TaoToken统一Key后Cursor优势还剩几何? 2026/10/2 17:30:56

VSCode+Claude真香,TaoToken统一Key后Cursor优势还剩几何?

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

阅读更多 →
【2026 AI 提效】别再手敲代码了!Cursor + DeepSeek 终极实战:小白 1 小时上线全栈项目(TaoToken 统一 Key 版) 2026/10/2 17:30:55

【2026 AI 提效】别再手敲代码了!Cursor + DeepSeek 终极实战:小白 1 小时上线全栈项目(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/2 17:30:55

零碳园区从政策到落地:能源管理与碳核算关键点全解析

1. 零碳园区:一个被政策和指标推着跑的赛道做园区能源管理这些年,我有一个很直观的感受:零碳园区真正开始大面积落地,并不是因为某个技术突然成熟了,而是因为政策链条把"零碳"从一句口号译成了园区必须面对的…

阅读更多 →
从石龟护甲到 ABAP 的业务防线,让并发、异常和重复请求伤不到关键数据 2026/10/2 17:30:48

从石龟护甲到 ABAP 的业务防线,让并发、异常和重复请求伤不到关键数据

一张采购订单正在审批,后台接口又收到一条修改金额的请求。请求里的数据格式完全正确,数据库也能够执行更新,但这笔修改究竟该不该发生,不能只靠一条 UPDATE 判断。订单是否已经批准,提交者是否有修改权限,页面上的金额是不是旧版本,重复发送的请求是否已经处理过,这些…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉