快速结论:这个报错通常出现在 MCP Python SDK 2.x 中,为资源模板(resource template)或提示(prompt)处理器标注了带参数的 Context[LifespanContextT] 时——服务器注入的 Context 被 Pydantic 重新构造,请求级私有状态丢失。优先排查处理器签名里 ctx 的类型注解是否为参数化泛型,以及是否读取了 ctx.request_context / ctx.session / ctx.request_id。
适用环境:MCP Python SDK 2.0.0 以及当时 main 分支(commit a4f4ccd091138771535e17191123f20b30fda68e);Python 3.12.13;Pydantic 2.12.5。Issue 未提供操作系统、CUDA 或显卡信息。
最快修复方案:Issue 讨论中没有给出可由用户自行执行的一步修复方案,最终由维护者在 PR #3624 中修复(ctx: Context[T] 在 prompt/resource template 中现在能拿到实时请求上下文)。建议升级到包含该修复的 SDK 版本。作为临时规避,可优先尝试把处理器签名中的 Context[LifespanContextT] 改为不带参数的 Context——Issue 明确指出未参数化的 Context 碰巧可以正常工作,但需注意这属于未在 Issue 中验证的规避手段。
注意事项:该行为在修复前被官方记录为已知限制(docs/handlers/lifespan.md、docs/migration.md),且 tests/docs_src/test_lifespan.py 当时断言参数化上下文在资源与提示中会失败——也就是说旧版本上的失败是“预期行为”而非偶发 bug。修复走的是“Context 将已有实例校验为自身”的路线,与社区此前提出的 SkipValidation PR 不同;使用方无需修改 prompt/template 代码。若仍复现,应开新 Issue。
问题场景
在 MCP Python SDK 中构建 MCPServer,并使用 lifespan 提供类型化的生命周期状态。处理器写法遵循文档中推荐的 Context[LifespanContextT] 泛型模式:
- 资源模板处理器:
@server.resource("probe://{name}"),签名为async def resource(name: str, ctx: Context[str]); - 提示处理器:
@server.prompt("probe"),签名为async def prompt(name: str, ctx: Context[str])。
当处理器内访问 ctx.request_context(进而读取 lifespan_context)时立即抛出 ValueError。而完全等价的工具(tool)处理器却可以正常工作,因此该问题专门影响动态资源与提示。
报错原文
ValueError: Context is not available outside of a request
原因分析
根因在 SDK 内部的对象重建:
ResourceTemplate.from_function与Prompt.from_function会正确地把检测到的Context参数从对外参数 schema 中排除,但随后用pydantic.validate_call包裹原始处理器。- 调用时 SDK 把实时的
Context注入被包裹的处理器,于是 Pydantic 又对它做了一次校验。 - 对于泛型注解,Pydantic 会把运行时未参数化的实例转换为
Context[str, Any],从而创建一个新的模型实例,且不会携带Context的私有属性_request_context、_mcp_server等。
Issue 中给出的对象身份对比很直观:
Context -> same object, request state present
Context[str] -> new object, request state absent
工具处理器不走这条路径,因为 FuncMetadata.call_fn_with_arg_validation 只校验客户端传入的参数,注入值直接交给原始处理器,所以不受影响。可优先尝试的方向是:让 SDK 注入的上下文绕过校验、保留对象身份,同时继续校验/强制转换客户端参数——这也是最终修复所坚持的边界。
环境排查
- 确认 MCP Python SDK 版本:2.0.0 或对应
maincommit 存在该问题;确认是否已升级到包含 PR #3624 的版本。 - Python 版本:Issue 环境为 3.12.13。
- Pydantic 版本:Issue 环境为 2.12.5,属于触发重建的关键依赖。
- 检查资源/提示处理器的
ctx注解:是Context[LifespanContextT](参数化,触发问题)还是未参数化的Context(在当时碰巧可用)。 - 检查处理器是否在调用链中读取了
ctx.request_context、ctx.session、ctx.request_id或 lifespan 状态;仅断言ctx非空的测试会掩盖该问题。 - Issue 未涉及操作系统、CUDA、显卡或其它依赖,无需在此范围内排查。
解决步骤
- 确认复现路径:用带
Context[str]注解的资源模板 + 提示处理器,并在其中读取ctx.request_context.lifespan_context,确认抛出ValueError: Context is not available outside of a request。 - 记录当前 SDK 版本与安装来源,确认其是否早于包含 PR #3624 的版本。
- 升级到包含修复的 SDK 版本(PR #3624 已合并,
ctx: Context[T]在 prompt 与 resource template 中会收到实时请求上下文,客户端参数的校验与强制转换行为保持不变)。升级后无需修改 prompt/template 代码。 - 若暂时无法升级,可优先尝试临时规避:将处理器签名中的参数化注解改为未参数化的
Context(Issue 记录该写法在当时碰巧可用)。这是规避手段而非官方修复,请在你的代码库中标注并在升级后还原为类型化写法。 - 如升级后仍在任何位置复现,按维护者要求另开新 Issue,而不是复用 #3235。
验证方法
- 运行 Issue 中的最小复现脚本:资源与提示两次调用都应返回形如
value:live-state的内容,而不是抛异常。 - 在处理器内验证注入对象为服务器创建的同一个上下文实例,而不仅仅是“能读到今天的 lifespan 值”——即
ctx保留请求级状态(request_context、session、request_id、lifespan 状态)。 - 确认客户端传入参数的校验与强制转换仍然生效(原本能通过的合法/非法参数用例行为不变)。
- 确认同步与异步处理器、以及使用
**kwargs的资源处理器均回归通过。
参考来源
modelcontextprotocol/python-sdk #3235(修复 PR:#3624;相关 PR:#3236)
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。
![[Bug] Client sends empty _meta:{} on every request; strict servers (Meta Ads MCP) reject with HTTP 400](https://www.chat-gpts.plus/wp-content/uploads/2026/10/3473-a9bea40e-768x403.jpg)
![[Bug]: s3_v2 async 500/503 retries are bypassed by HTTPStatusError](https://www.chat-gpts.plus/wp-content/uploads/2026/10/42868-cdeacc24-768x403.jpg)
![[Bug]: timestamp_granularities=["segment", "word"] only returns the last granularity for Whisper](https://www.chat-gpts.plus/wp-content/uploads/2026/10/35937-6543e9b1-768x403.jpg)