
wrapped tools using annotations fail
快速结论:当你使用装饰器(如 @logfire.instrument)包装一个函数,并且该函数所在模块使用了 from __future__ import annotations 时,MCP FastMCP 在注册工具时可能抛出 InvalidSignature 异常。优先排查你的 MCP Python SDK 版本是否已更新至包含修复的版本(PR #1496 已修复此问题)。
问题场景
用户在 MCP Python SDK 中使用 @logfire.instrument 等装饰器包装一个工具函数,且该函数所在模块开启了 from __future__ import annotations。当通过 Tool.from_function() 注册该工具时,触发 InvalidSignature 异常。
报错原文
mcp.server.fastmcp.exceptions.InvalidSignature: Unable to evaluate type annotation ForwardRef("Literal['literal'] | None")
完整 Traceback 中包含以下关键路径:
File ".../mcp/server/fastmcp/utilities/func_metadata.py", line 466, in _get_typed_annotation
raise InvalidSignature(f"Unable to evaluate type annotation {annotation}")
原因分析
当工具函数被包装(如使用 @logfire.instrument)且模块使用了 from __future__ import annotations 时,函数注解会以字符串形式(ForwardRef)存储。MCP 的 func_metadata 在解析这些字符串注解时,错误地使用了包装器(wrapper)的 __globals__ 命名空间,而非原始函数的命名空间。由于包装器命名空间中不包含 Literal 等类型定义,导致注解无法被正确求值,从而抛出 InvalidSignature。
环境排查
- MCP Python SDK 版本:确认是否已更新至包含修复的最新版本。Issue 中提及 PR #1496 已修复此问题,该 PR 将
func_metadata切换为使用inspect.signature(func, eval_str=True)。 - Python 版本:Issue 中测试环境为 Python 3.11 和 3.13,理论上该问题与 Python 版本无直接关联。
- 相关依赖版本:确认
logfire或其他装饰器库的版本,但问题根源在于 MCP SDK 对包装函数的注解解析逻辑。
解决步骤
- 更新 MCP Python SDK:将 MCP Python SDK 更新到包含 PR #1496 修复的版本(该 PR 通过
inspect.signature(func, eval_str=True)正确解析字符串注解,并感知__wrapped__属性)。 - 验证修复:如果无法立即更新,可优先尝试将
from __future__ import annotations移除,或手动在包装器命名空间中注入所需类型(不推荐长期方案)。 - 检查装饰器兼容性:确认你的装饰器(如
@logfire.instrument)是否正确设置了__wrapped__属性,以支持inspect.signature的回溯。MCP SDK 修复依赖于该属性。
验证方法
运行以下测试代码(基于 Issue 中的最小复现示例):
from __future__ import annotations
from typing import Literal
from mcp.server.fastmcp.tools import Tool
import logfire
@logfire.instrument
def test_tool(location_type: Literal["literal"] | None = None) -> str:
"""Test tool."""
return f"a is {location_type}"
Tool.from_function(test_tool)
如果不再抛出 InvalidSignature 异常,说明问题已修复。你也可以通过 func_metadata(test_tool) 检查返回的签名中 location_type 的类型是否正确解析为 Optional[Literal['literal']]。
参考来源
modelcontextprotocol/python-sdk #1391 — Issue 讨论链包含完整的复现代码、原因分析和修复确认。修复 PR #1496 的链接:#1496。



