NotRequired TypedDict return annotation raises PydanticForbiddenQualifier at tool registration on Python 3.10

该报错发生在 Python 3.10 环境下,当 MCP 工具的返回值注解为包含 NotRequired 键的 TypedDict 时,工具注册阶段会触发 PydanticForbiddenQualifier 异常。优先排查是否使用了 typing.get_type_hints 而非 typing_

快速结论:该报错发生在 Python 3.10 环境下,当 MCP 工具的返回值注解为包含 NotRequired 键的 TypedDict 时,工具注册阶段会触发 PydanticForbiddenQualifier 异常。优先排查是否使用了 typing.get_type_hints 而非 typing_extensions.get_type_hints 来解析注解。

适用环境:MCP Python SDK 2.x(main 分支)、Python 3.10(3.11 及以上不受影响)、依赖 pydantic 与 typing_extensions。

最快修复方案:暂无确认的一步修复方案(补丁已提交但尚未合并)。若需自行修复,可尝试将 src/mcp/server/mcpserver/utilities/func_metadata.py 中的 get_type_hints 导入来源从 typing 改为 typing_extensions

注意事项:此修复方案来自 Issue 评论中的补丁确认,但尚未合并到主分支,使用时需自行评估风险并验证兼容性。

问题场景

在 Python 3.10 环境下使用 MCP Python SDK 注册工具,工具返回值注解为包含 NotRequired 键的 TypedDict 时触发。报错发生在 @mcp.tool() 装饰器执行阶段,导致工具在 import 时即注册失败,工具永远不会被创建。

报错原文

pydantic.errors.PydanticForbiddenQualifier: The annotation 'NotRequired[int]' contains the 'typing.NotRequired' type qualifier, which is invalid in the context it is defined.

原因分析

根因位于 src/mcp/server/mcpserver/utilities/func_metadata.py_create_model_from_typeddict 函数。该函数使用 typing.get_type_hints 解析 TypedDict 注解,并将结果直接传给 create_model。但 typing.get_type_hints 仅在 Python 3.11 及以上版本会剥离 Required/NotRequired 限定符;在 Python 3.10 上,field_type 仍是 NotRequired[int],pydantic 会拒绝 TypedDict 上下文之外的裸限定符。

观察到的差异:

python 3.10.19  typing.get_type_hints(Person) -> {'name': str, 'age': typing_extensions.NotRequired[int]}
python 3.13.12  typing.get_type_hints(Person) -> {'name': str, 'age': int}

typing_extensions.get_type_hints 在两个版本上都会返回剥离后的形式。

环境排查

  • 确认 Python 版本是否为 3.10(3.11 及以上不受影响)
  • 确认 MCP Python SDK 版本为 2.x(main 分支)
  • 确认 typing_extensions 已安装且版本支持 NotRequired
  • 检查返回值注解是否包含 NotRequired 键(而非 total=False 的 TypedDict)

解决步骤

  1. 定位文件 src/mcp/server/mcpserver/utilities/func_metadata.py,找到 _create_model_from_typeddict 函数。
  2. 将导入语句中的 get_type_hintstyping 改为 typing_extensions(该库已用于导入 is_typeddict)。
  3. (可选)在 tests/server/mcpserver/test_func_metadata.py 中添加包含 NotRequired 字段的测试用例,验证修复效果。
  4. 在 Python 3.10 环境中运行复现脚本,确认工具能够正常注册。

验证方法

在 Python 3.10 环境下运行 Issue 中的复现脚本,确认不再抛出 PydanticForbiddenQualifier 异常,且 get_person 工具能够成功注册。同时可在 Python 3.13 上运行同一脚本,确保行为一致。

参考来源

modelcontextprotocol/python-sdk #3227

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 19355

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注