22
33import inspect
44from collections .abc import Callable
5- from typing import TYPE_CHECKING , Any
5+ from typing import TYPE_CHECKING , Any , get_type_hints
66
77from pydantic import BaseModel , Field
88
1515 from mcp .shared .context import LifespanContextT
1616
1717
18+ def _is_context_type (annotation : type [Any ]) -> bool :
19+ from mcp .server .fastmcp import Context
20+
21+ if annotation is Context :
22+ return True
23+ if (
24+ generic_metadata := getattr (annotation , "__pydantic_generic_metadata__" , None )
25+ ) is not None :
26+ return _is_context_type (generic_metadata ["origin" ])
27+ return False
28+
29+
1830class Tool (BaseModel ):
1931 """Internal tool registration info."""
2032
@@ -40,8 +52,6 @@ def from_function(
4052 context_kwarg : str | None = None ,
4153 ) -> Tool :
4254 """Create a Tool from a function."""
43- from mcp .server .fastmcp import Context
44-
4555 func_name = name or fn .__name__
4656
4757 if func_name == "<lambda>" :
@@ -51,9 +61,11 @@ def from_function(
5161 is_async = inspect .iscoroutinefunction (fn )
5262
5363 if context_kwarg is None :
54- sig = inspect .signature (fn )
55- for param_name , param in sig .parameters .items ():
56- if param .annotation is Context :
64+ type_hints = get_type_hints (fn )
65+ for param_name , param_type in type_hints .items ():
66+ if param_name == "return" :
67+ continue
68+ if _is_context_type (param_type ):
5769 context_kwarg = param_name
5870 break
5971
0 commit comments