Python MCP SDK入门:FastMCP快速开发

发布时间:2026/9/30 14:05:43

Python MCP SDK入门:FastMCP快速开发 Python MCP SDK入门 FastMCP快速开发我第一次写 MCP 服务端用的是低级 API注册工具要写一堆装饰器初始化要手动拼 InitializationOptions跑起来还得自己管 stdio 流。后来换成 FastMCP同样的功能代码量少了七成。这篇把 FastMCP 的装饰器 API、生命周期管理、配置体系讲清楚再跟低级 API 做个对比最后给一个完整可运行的项目。FastMCP 是什么FastMCP 是 MCP Python SDK 提供的高层封装让你用装饰器把普通 Python 函数变成 MCP 工具、资源、提示。它自动处理协议握手、消息路由、参数校验和 schema 生成你只管写业务函数。它有两个来源容易搞混。一个是官方 mcp SDK 自带的mcp.server.fastmcp装pip install mcp就有导入写法是from mcp.server.fastmcp import FastMCP。另一个是社区演进的独立包fastmcpFastMCP v2装pip install fastmcp导入写法是from fastmcp import FastMCP功能更全多了标签过滤、服务端组合、代理、后台任务等能力。两者装饰器 API 基本一致本篇用官方自带的版本保证最低依赖。装饰器 API 三件套FastMCP 用三个装饰器对应 MCP 的三类原语。mcp.tool把函数变成工具模型可以调用它执行操作。函数名当工具名docstring 当描述类型注解自动生成参数 schema。返回值会被序列化成文本返回给模型。mcp.resource把函数变成资源模型读取它获取上下文数据。支持静态 URI 和带参数的模板 URI模板用花括号占位比如notes://{note_id}占位符会自动映射成函数参数。mcp.prompt把函数变成提示模板给模型提供结构化的交互起点。返回字符串或消息列表复杂场景可以返回多轮消息。生命周期管理服务端启动和关闭时常要做资源初始化和清理比如连数据库、建连接池。FastMCP 用 lifespan 机制处理传一个异步上下文管理器给FastMCP构造函数。lifespan 在服务端启动时进入yield 出来的对象会挂到请求上下文里工具函数通过ctx.request_context.lifespan_context取到。服务端关闭时执行 finally 里的清理逻辑。用 dataclass 定义上下文类型能让 IDE 自动补全这就是官方说的类型安全上下文。配置管理FastMCP 的配置分三层。构造函数参数管服务级行为比如 name、instructions、dependencies、lifespan。run 方法的参数管传输比如 transport、host、port、log_level。独立包 fastmcp 还支持全局配置通过FASTMCP_前缀的环境变量设置日志等级、错误脱敏、资源前缀格式等。几个常用配置点。instructions 是给客户端和模型看的服务端说明写清楚有哪些能力、怎么用很多人漏写导致模型瞎调工具。dependencies 声明部署时要装的第三方包配合mcp install自动安装。重复注册同名工具时on_duplicate_tools 控制是警告、报错还是覆盖生产环境建议设成 error 尽早发现问题。与低级 SDK API 的对比低级 API 在mcp.server.lowlevel里给你完全的协议控制权代价是要写更多样板代码。下面这张表对比两者。维度FastMCP 高层 API低级 SDK API工具注册mcp.tool一行搞定server.list_tools()加server.call_tool()分开写Schema 生成类型注解自动生成手动构造 types.Tool参数校验框架自动做自己解析校验生命周期lifespan 装饰器风格同样支持 lifespan但要手动拼 InitializationOptions传输启动mcp.run()一行手动 stdio_server 加 server.run 加 InitializationOptions协议控制框架托管定制有限完全可控能改任何细节适合场景业务功能开发协议研究、自定义扩展、特殊传输选型很简单。写业务服务端用 FastMCP几行代码跑起来。要做协议级定制或研究 MCP 内部机制再改用低级 API。两者也能混用FastMCP 内部就是基于低级 Server 实现的。完整代码先装依赖。pipinstallmcp[cli]完整项目note_server.py一个笔记服务包含工具、资源、提示和生命周期管理。# note_server.py# FastMCP 完整示例笔记服务演示工具/资源/提示/生命周期/配置fromcontextlibimportasynccontextmanagerfromcollections.abcimportAsyncIteratorfromdataclassesimportdataclass,fieldfrommcp.server.fastmcpimportFastMCP,Context# ---------- 生命周期上下文定义 ----------dataclassclassNoteStore:笔记存储演示 lifespan 管理的资源。 真实项目换成数据库连接或 ORM 会话。 notes:dict[str,str]field(default_factorydict)defadd(self,note_id:str,content:str)-None:添加一条笔记。self.notes[note_id]contentdefget(self,note_id:str)-str|None:按 id 取笔记不存在返回 None。returnself.notes.get(note_id)deflist_all(self)-list[str]:返回所有笔记 id。returnlist(self.notes.keys())# 类型安全的 lifespan 上下文IDE 能补全 db 字段dataclassclassAppContext:store:NoteStoreasynccontextmanagerasyncdefapp_lifespan(server:FastMCP)-AsyncIterator[AppContext]:服务端生命周期启动时建存储关闭时清理。 yield 出去的对象会挂到每个请求的上下文里 工具函数通过 ctx.request_context.lifespan_context 取用。 # 启动阶段初始化资源storeNoteStore()# 预置两条示例笔记方便验证store.add(1,学习 MCP 传输层)store.add(2,写完 FastMCP 示例)try:# 把资源交给请求处理阶段yieldAppContext(storestore)finally:# 关闭阶段清理资源这里存储在内存里无需特殊清理store.notes.clear()# ---------- 创建服务端 ----------# instructions 写清楚服务能力帮模型正确调用mcpFastMCP(NoteServer,instructions这是一个笔记服务可以添加、查询、列出笔记还能生成摘要提示。,lifespanapp_lifespan,)# ---------- 工具 ----------mcp.tool()defadd_note(note_id:str,content:str,ctx:Context)-str:添加一条笔记。 Args: note_id: 笔记唯一标识 content: 笔记内容 ctx: 框架注入的上下文 # 从 lifespan 上下文取存储对象store:NoteStorectx.request_context.lifespan_context.store store.add(note_id,content)returnf已添加笔记{note_id}mcp.tool()deflist_notes(ctx:Context)-str:列出所有笔记 id。store:NoteStorectx.request_context.lifespan_context.store idsstore.list_all()# 没有笔记时给个友好提示ifnotids:return当前没有笔记return笔记列表: , .join(ids)# ---------- 资源 ----------mcp.resource(notes://{note_id})defget_note(note_id:str,ctx:Context)-str:按 id 读取笔记内容URI 模板的占位符自动映射成参数。store:NoteStorectx.request_context.lifespan_context.store contentstore.get(note_id)# 笔记不存在时返回提示文本ifcontentisNone:returnf笔记{note_id}不存在returncontent# ---------- 提示 ----------mcp.tool()defsummarize_all_notes(ctx:Context)-str:汇总所有笔记内容供模型生成摘要。store:NoteStorectx.request_context.lifespan_context.store# 拼接所有笔记内容parts[f[{nid}]{store.get(nid)}fornidinstore.list_all()]ifnotparts:return没有笔记可汇总return\n.join(parts)mcp.prompt()defreview_notes()-str:生成一个提示让模型审查所有笔记并给出改进建议。return请读取所有笔记逐条审查内容给出简短改进建议。# ---------- 启动 ----------if__name____main__:# 默认 stdio 传输可被 Claude Desktop 等客户端接入# 想换远程传输改成 mcp.run(transportstreamable-http, port9000)mcp.run()客户端note_client.py连接服务端验证全部功能。# note_client.py# 笔记服务客户端验证工具/资源/提示都能用importasynciofrommcpimportClientSession,StdioServerParametersfrommcp.client.stdioimportstdio_clientasyncdefmain():# 配置 stdio 子进程参数paramsStdioServerParameters(commandpython,args[note_server.py],)# 拉起服务端子进程并建立会话asyncwithstdio_client(params)as(read,write):asyncwithClientSession(read,write)assession:# 初始化握手awaitsession.initialize()# 列出工具确认注册成功toolsawaitsession.list_tools()print(工具:,[t.namefortintools.tools])# 调用 list_notes 看预置数据r1awaitsession.call_tool(list_notes,{})print(初始笔记:,r1.content[0].text)# 添加一条新笔记r2awaitsession.call_tool(add_note,{note_id:3,content:测试新增笔记})print(r2.content[0].text)# 读取资源验证 URI 模板resawaitsession.read_resource(notes://3)print(读取 notes://3:,res.contents[0].text)# 调用汇总工具r3awaitsession.call_tool(summarize_all_notes,{})print(汇总:\n,r3.content[0].text)# 获取提示模板promptawaitsession.get_prompt(review_notes)print(提示:,prompt.messages[0].content.text)if__name____main__:asyncio.run(main())效果验证用 Inspector 快速可视化验证会打开调试界面。mcp dev note_server.py在 Inspector 里能看到 NoteServer 的工具、资源、提示三类内容。调用 add_note 添加笔记再读notes://3资源能看到刚写的内容说明 lifespan 上下文在请求间正确共享。跑客户端脚本验证端到端。python note_client.py输出会依次显示工具列表、初始笔记、新增结果、资源读取、汇总内容和提示模板证明工具、资源、提示、生命周期全部跑通。常见问题与避坑1. lifespan 上下文取不到。早期我以为直接ctx.lifespan_context就能取结果属性不存在。正确写法是ctx.request_context.lifespan_context取到的就是你 yield 出去的对象。如果你 yield 的是 dataclass用属性访问yield 的是 dict用键访问。两种别搞混。2. 同步工具阻塞事件循环的误判。FastMCP 默认把同步工具丢到线程池跑不会阻塞事件循环多个工具能并发。但如果你用了有线程亲和性的库比如 Windows 的 COM 组件线程池里跑会出错这时要传run_in_threadFalse让它在事件循环线程跑。这个参数只有独立包 fastmcp 支持。3. 装饰器加不加括号。新版mcp.tool和mcp.tool()都能用。但低级 API 里server.list_tools()必须加括号混用两套 API 时容易写错。统一加括号最保险。4. 重复注册工具名静默覆盖。默认重复注册同名工具只警告不报错线上可能悄悄用错了实现。生产环境把 on_duplicate_tools 设成 error注册阶段就拦住。5. instructions 漏写模型瞎调。instructions 是服务端的能力说明客户端会把它交给模型。不写的话模型只能靠工具描述猜经常调错。花两句话写清楚服务干什么、有哪些主要工具调用准确率明显提升。小结FastMCP 把 MCP 服务端开发做到装饰器级别工具资源提示各一个装饰器生命周期用 lifespan配置分构造参数和 run 参数三两下搞定。日常业务用高层 API协议级定制再回到低级 API。把 instructions 写好、lifespan 上下文取对、重复注册设成报错能避开大部分坑。这四篇连起来从通知机制、传输层、协议对比到 SDK 实操MCP 的核心链路就串完了。
延伸阅读

更多相关文章

2026/9/28 5:48:08

设计系统搭建与组件库自动化管理:接口设计的可验证边界

设计系统搭建与组件库自动化管理:接口设计的可验证边界说明:本文以常见接口边界问题为例。文中阈值和改造收益不是通用结论;应根据组件的调用方式、错误模型和可访问性要求验收。1. 上午11点的前端群争吵:12个业务团队都在投诉 Mo…

2026/9/26 22:15:21

计算机专业学习规划:从基础到实践,打造工程能力与职业竞争力

1. 先看清现状:计算机专业不等于“高薪铁饭碗”如果你现在考虑报计算机专业,脑子里想的是毕业就能进大厂、拿高薪、工作稳定,那我劝你先冷静。这个专业早就不是十年前那个“学了就能找到好工作”的黄金赛道了。现在的现状是:入门门…

2026/9/28 18:35:38

AR/VR多人手势协同:解决全息协作中的冲突问题

1. 项目概述:全息协作中的手势冲突痛点去年参与某跨国汽车设计项目时,我们团队首次尝试用全息协作平台进行3D模型评审。当德国工程师伸手旋转引擎部件时,我的虚拟手掌恰好从同一位置穿过,系统瞬间将两个手势识别为"捏合"…

2026/9/30 14:03:26

嵌入式驱动开发:从能跑到会崩的量产工程化鸿沟

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

2026/9/30 14:03:26

MFC TCP网络通信实战:心跳保活、粘包处理与断线续传

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

2026/9/30 14:03:26

使用Filler4提取微信小程序视频:手把手实操与原理剖析

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

2026/9/30 14:03:26

昇思 MindSpore 大模型单卡微调推理:自助搭建流程

一、摘要基于昇思 MindSpore 在单张昇腾 NPU(310P/910B)完成大模型微调 推理是轻量化落地常用方案。单卡流程包含:环境准备、权重加载、数据集构建、LoRA 微调、模型保存、离线推理全链路。相比于全参数微调,LoRA 低秩适配极大降…

2026/9/30 13:58:25

方差、标准差、MSE与RMSE:数据工程师的指标选择实战指南

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

2026/9/29 11:07:23

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/29 21:48:03

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/29 7:00:49

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/30 0:01:22

MATLAB+Yalmip+CPLEX实战:综合能源系统优化调度全流程解析

做综合能源系统优化调度这活儿,最痛苦的不是建模本身,而是模型写完之后不知道该怎么求解。看论文里轻飘飘一句“采用Yalmip调用CPLEX求解”,自己上手时却往往卡在环境配置、变量声明、约束写法和求解状态判读上,一耗就是两三天。这…

2026/9/30 0:01:22

I3C比I2C快10倍?RK3576实战:速率、DTS配置与混合总线避坑指南

I3C 比 I2C 快 10 倍?这句话在嵌入式群里传了很久,每次都能吵出一堆截图。前段时间我正好在 RK3576 上调板级 I3C 接口,从控制器寄存器一路摸到 Linux DTS 配置,踩了不少坑,也把这笔速度账彻底算明白了。本文就用 RK35…

2026/9/30 0:01:22

字符串转对象:JSON.parse、new Function与URLSearchParams

“字符串转对象”这几个字,我在技术群里见过的问法至少有十几种:有人拿着一串{a:1,b:2}说 JSON.parse 直接报错,有人要从 URL 里抠出参数,还有人只是想把abc变成能挂属性的东西。js 这门语言里,字符串和对象之间的转换…

2026/9/29 3:53:39

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/29 9:46:12

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/30 10:28:53

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑