首页/新闻资讯/正文详情

MCP Python SDK 服务端 lifespan 全解:从连接池管理到生命周期验证实战

发布时间:2026/9/21 7:26:55 来源:云帆数科 栏目:资讯中心
MCP Python SDK 服务端 lifespan 全解:从连接池管理到生命周期验证实战
MCP Python SDK 服务端 lifespan 全解从连接池管理到生命周期验证实战【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/gh_mirrors/pythonsd/python-sdk导读本篇文章基于官方 Python SDK for Model Context Protocol仓库 pythonsd/python-sdk的文档展开系统讲解服务端lifespan生命周期机制的完整用法。真实 MCP 服务器几乎都需要在存活期间持有某个常驻资源——数据库连接池、HTTP 客户端、加载好的模型——你不希望每次请求都重新创建又希望在服务器退出时干净地关闭。lifespan 正是为此设计的官方机制。读完本文你将掌握如何用asynccontextmanager编写类型化 lifespan、如何让yield出的对象被所有 handler 共享、类型参数Context[AppContext]的威力与使用边界以及如何通过一个最小实验亲眼验证启动先于首请求、结束于 finally的生命周期时序。为什么需要 lifespan服务器级别的常驻资源绝大多数真实服务器都会持有某些存活期与服务器本身一致的资源数据库连接池、HTTP 客户端、加载到内存中的模型等。如果每次调用都新建性能与连接数都不可接受如果从不关闭又会泄漏连接与句柄。lifespan 解决的就是这个创建一次、干净关闭的问题。lifespan 的本质是一个asynccontextmanager异步上下文管理器它接收服务器实例yield出一个对象这个对象在服务器运行的整个期间对所有 handler 可见。yield之前的代码是启动逻辑yield之后的代码通常放在finally中是关闭逻辑。如果你写过 FastAPI 的lifespan这里的知识是相通的同一个装饰器、同一个yield、同一个finally。类型化 lifespan完整接线示例以下是最小但完整的示例完整源码见 docs_src/lifespan/tutorial001.py建议自下而上阅读from collections.abc import AsyncIterator from contextlib import asynccontextmanager from dataclasses import dataclass from mcp.server import MCPServer from mcp.server.mcpserver import Context class Database: classmethod async def connect(cls) - Database: return cls() async def disconnect(self) - None: ... def query(self) - int: return 3 dataclass class AppContext: db: Database asynccontextmanager async def app_lifespan(server: MCPServer) - AsyncIterator[AppContext]: db await Database.connect() try: yield AppContext(dbdb) finally: await db.disconnect() mcp MCPServer(Bookshop, lifespanapp_lifespan) mcp.tool() def count_books(genre: str, ctx: Context[AppContext]) - str: Count the books in a genre. db ctx.request_context.lifespan_context.db return f{db.query()} books in {genre!r}.逐层拆解这段代码app_lifespan是启动与关闭的全部yield之前连接Databaseyield之后在finally中断开连接。异步上下文管理器保证无论期间发生什么finally都会执行关闭逻辑绝不遗漏。AppContext是一个普通 dataclass它只是承载你设置好的一堆东西的容器。今天放一个字段db明天可以扩展成十个字段——工具函数依然只需要通过ctx.request_context.lifespan_context一处入口访问。MCPServer(Bookshop, lifespanapp_lifespan)就是全部接线工作把 lifespan 作为构造参数传入即可SDK 负责在正确时机进入和退出。工具内部通过ctx.request_context.lifespan_context拿到 yield 出的对象ctx是 SDK 注入的Context参数不参与工具的输入 schema。生命周期时序一次执行全程共享lifespan恰好执行一次服务器启动时在第一个请求之前进入服务器停止时退出。期间的所有请求共享同一个AppContext实例——这正是连接池/客户端/模型只建一次语义的来源。从源码可以印证这一点。在底层服务器实现中Server.run用async with self.lifespan(self) as lifespan_context:包裹整个消息循环见 src/mcp/server/lowlevel/server.py也就是说 lifespan 上下文以with方式包住整个连接生命周期yield 出的对象随后通过lifespan_state传递给每个请求src/mcp/server/lowlevel/server.py。如果你不传lifespanSDK 会使用默认实现——一个什么都不做、直接yield {}的异步上下文管理器见 src/mcp/server/lowlevel/server.py。这解释了文档中的关键保证lifespan 永远存在ctx.request_context.lifespan_context至少是{}绝不会是None。这也是为什么裸Context会把lifespan_context类型标注为dict[str, Any]。模型视角ctx 是 SDK 注入的不进 schema对调用方LLM来说lifespan 是完全透明的。ctx是一个Context 参数由 SDK 在调用时注入绝不会出现在工具的输入 schema 里。以count_books为例模型能看到的输入 schema 只有genre一个字段{ type: object, properties: { genre: {title: Genre, type: string} }, required: [genre], title: count_booksArguments }模型唯一能传的参数是genre。lifespan 是你的服务器内部事务与协议无关。这一点在 SDK 实现中同样成立Context.request_context属性在无活动请求时会直接抛出ValueError(Context is not available outside of a request)见 src/mcp/server/mcpserver/context.py而每个请求的request_context都携带lifespan_context字段定义见 src/mcp/server/context.py。mcp.resource()与mcp.prompt()函数同样可以接收ctx参数但它们应按下一节的原因写成不带类型参数的裸Context。ctx携带的全部内容可进一步查阅文档 Context。它真的是类型安全的Context[AppContext] 的威力再看一次注解ctx: Context[AppContext]。正是这一个类型参数让类型检查器如 mypy / pyright确信ctx.request_context.lifespan_context就是AppContext类型。于是.db能自动补全而敲出.dbb会在服务器运行之前就成为类型错误——IDE 里直接标红。反过来如果写成不带类型参数的裸Contextlifespan_context的类型就是dict[str, Any]类型检查器无法得知你的 lifespan yield 了什么。对象在运行时依然存在但你失去了编译期的全部帮助。从源码看这一设计的根基在于Context的泛型声明与LifespanContextT类型变量ServerRequestContext的lifespan_context字段是泛型的src/mcp/server/context.pyContext类自身也声明为Generic[LifespanT_co]且协变src/mcp/server/context.py因此Context[AppContext]可以安全地向下兼容为Context[object]等更宽类型。重要警告Context[AppContext] 是工具专用写法警告Context[AppContext]只适用于工具mcp.tool()函数。如果把它写到mcp.resource()或mcp.prompt()函数上该 handler 的每次调用都会失败。客户端会收到错误服务器日志中会显示原因Context is not available outside of a request在资源与提示词中请写成裸ctx: Context。你的 lifespan yield 出的对象在运行时仍然位于ctx.request_context.lifespan_context中——你放弃的只是类型参数不是对象本身。产生这一限制的原因与实现细节一致Context.request_context属性在请求上下文尚未建立时如资源/提示词 handler 的某些调用路径会抛出上述ValueError见 src/mcp/server/mcpserver/context.py。提示lifespan 永远存在lifespan永远存在。即使你不传lifespanSDK 的默认 lifespan 也会 yield 一个空dict因此ctx.request_context.lifespan_context是{}绝不会是None。裸Context将其类型标为dict[str, Any]正是因为这个默认值。你的代码可以放心地直接访问lifespan_context而无需判空——当然若你依赖自定义对象仍需通过类型参数来恢复精确类型。亲眼验证启动先于首请求关闭落于 finally启动代码在第一个请求之前运行这类论断不该靠直觉接受值得亲手验证。做法是把服务器精简到只剩生命周期本身给Database加一个connected布尔标志在connect()与disconnect()中翻转该标志添加一个报告该标志状态的工具。完整示例见 docs_src/lifespan/tutorial002.pyfrom collections.abc import AsyncIterator from contextlib import asynccontextmanager from dataclasses import dataclass from mcp.server import MCPServer from mcp.server.mcpserver import Context class Database: def __init__(self) - None: self.connected False async def connect(self) - None: self.connected True async def disconnect(self) - None: self.connected False dataclass class AppContext: db: Database database Database() asynccontextmanager async def app_lifespan(server: MCPServer) - AsyncIterator[AppContext]: await database.connect() try: yield AppContext(dbdatabase) finally: await database.disconnect() mcp MCPServer(Bookshop, lifespanapp_lifespan) mcp.tool() def database_status(ctx: Context[AppContext]) - str: Report whether the database connection is up. db ctx.request_context.lifespan_context.db return connected if db.connected else disconnected注意database放在模块级别唯一的原因是从服务器外部观察它——你可以在自己的测试或调试代码里直接读取database.connected而不需要穿过 MCP 协议。三个时间点三个值按文档的验证清单在三个时刻观察时刻database.connected说明服务器启动前False导入模块不会连接任何东西连接只发生在 lifespan 的yield之前服务器运行中True调用database_status返回connected启动代码已在首个请求之前执行完毕服务器停止后Falsefinally块运行disconnect()被调用结论很清晰工作恰好发生在你放置它的位置——yield的周围。既不在模块导入时也不在每个请求时。这正印证了 lifespan 与每次请求都初始化或导入时初始化两种模式的本质区别。总结lifespan 核心要点lifespan参数接收一个asynccontextmanager它接收服务器实例并yield出一个对象。yield之前的代码是启动其后的finally是关闭。它在服务器的整个生命周期内只执行一次而非每个请求一次。你 yield 出的对象在所有工具、资源与提示词中都可以通过ctx.request_context.lifespan_context访问。ctx: Context[AppContext]让工具中的该访问获得完整类型。资源与提示词请使用裸ContextContext[AppContext]写在资源/提示词上会导致每次调用失败。不传lifespan时默认值是一个空dict绝不会是None。接下来可以继续阅读在调用中途停下来向用户询问只有用户才知道的信息的 handler属于Elicitation询问机制参见文档 Elicitation。【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/gh_mirrors/pythonsd/python-sdk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

Vue Router 2 构造选项全解析:routes、mode、base 与 scrollBehavior 配置指南
Vue Router 2 构造选项全解析:routes、mode、base 与 scrollBehavior 配置指南

前端路由 【免费下载链接】vue-router 🚦 The official router for Vue 2 项目地址: https://gitcode.com/gh_mirrors/vu/vue-router 点击查看 免费下载 本篇技术指南以 Vue Router 2(本仓库 vu/vue-router)官方文档《Options de… · 2026/9/21 7:26:55

MATLAB 2022b 配置 IPOPT 与 OPTI 工具箱实战指南
MATLAB 2022b 配置 IPOPT 与 OPTI 工具箱实战指南

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

Android定位权限全链路实战:从分步申请到后台持续定位避坑指南
Android定位权限全链路实战:从分步申请到后台持续定位避坑指南

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

企业网站做电脑营销多少钱?揭秘防黑挂马的底层逻辑
企业网站做电脑营销多少钱?揭秘防黑挂马的底层逻辑

企业网站做电脑营销多少钱?揭秘防黑挂马的底层逻辑 网站突然被黑,首页挂满赌博广告,后台密码怎么改都没用,这种绝望感做过站的都懂。很多老板第一反应是问:“清理一次病毒多少钱?”或者“换个服务器多少钱?”但真相往往扎心:单纯清理病毒的费用可能只要几百块,但重建信任、修复SEO权重、补全安全漏洞的成本,往… · 2026/9/21 8:03:27

3步搞定做品管圈网站从零搭建到上线避坑指南
3步搞定做品管圈网站从零搭建到上线避坑指南

3步搞定做品管圈网站从零搭建到上线避坑指南 不会写代码,但想给团队搭个品管圈展示平台?别慌。 很多河南的创业老板都卡在这一步:手里有现成的QCC成果,想做个官网放上去,结果一搜全是“前端开发教程”,看得头大。 做品管圈网站 这事儿,真没你想的那么玄乎。只要路子对,零基础也能 从零搭建… · 2026/9/21 7:45:56

Voyager 資料夾管理指南:為 Gemini 與 AI Studio 的 AI 對話打造真正的「檔案系統」
Voyager 資料夾管理指南:為 Gemini 與 AI Studio 的 AI 對話打造真正的「檔案系統」

AI 应用前端 【免费下载链接】voyager Enhancement suite for Gemini, AI Studio, Claude & ChatGPT — plus a prompt manager for any websites, DeepSeek Harness included. / 面向 Gemini、AI Studio、Claude 与 ChatGPT 的增强套件;其中的提示词管理器可用… · 2026/9/21 7:41:58

gatsby-source-graphql 插件全解析:将任意第三方 GraphQL API 缝合进 Gatsby 数据层
gatsby-source-graphql 插件全解析:将任意第三方 GraphQL API 缝合进 Gatsby 数据层

前端静态站点Web框架 【免费下载链接】gatsby React-based framework with performance, scalability, and security built in. 项目地址: https://gitcode.com/gh_mirrors/ga/gatsby 点击查看 免费下载 本篇技术指南以 gatsby-source-graphql 插件的 CHANGELOG 版… · 2026/9/21 7:41:58

Lightweight Charts v3 到 v4 迁移指南:破坏性变更逐项分析与实战改造方案
Lightweight Charts v3 到 v4 迁移指南:破坏性变更逐项分析与实战改造方案

Lightweight Charts v3 到 v4 迁移指南:破坏性变更逐项分析与实战改造方案 【免费下载链接】lightweight-charts Performant financial charts built with HTML5 canvas 项目地址: https://gitcode.com/gh_mirrors/li/lightweight-charts 本指南以 Lightweig… · 2026/9/21 7:41:58

FoundationDB 存储基准测试上 RAM Disk:mako_storage_bench.sh 在 okteto 开发 Pod 上的 tmpfs 实践指南
FoundationDB 存储基准测试上 RAM Disk:mako_storage_bench.sh 在 okteto 开发 Pod 上的 tmpfs 实践指南

分布式数据库KV存储数据库后端 【免费下载链接】foundationdb FoundationDB - the open source, distributed, transactional key-value store 项目地址: https://gitcode.com/gh_mirrors/fo/foundationdb 点击查看 免费下载 mako_storage_bench.sh 是 FoundationD… · 2026/9/21 7:41:58

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化
Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡… · 2026/9/21 0:02:39

Word表格编号全攻略:从列表编号到题注交叉引用
Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技… · 2026/9/21 0:02:39

从第一个站到第二个站:独立开发者的静态网站选型与落地实践
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&… · 2026/9/20 0:00:41

Claude Code 按智谱AI指南装完,ANTHROPIC_BASE_URL 改走 TaoToken 兼容通道行不行
Claude Code 按智谱AI指南装完,ANTHROPIC_BASE_URL 改走 TaoToken 兼容通道行不行

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

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程
agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and … · 2026/9/21 0:00:18

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,… · 2026/9/21 0:00:18

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码