From d4fc44feb423dc6e6b9d6ef24e4e8e87f960ea65 Mon Sep 17 00:00:00 2001 From: William Easton Date: Mon, 4 Aug 2025 08:41:05 -0500 Subject: [PATCH] Fix method-bound tools (#1360) --- src/fastmcp/utilities/types.py | 7 ++++++- tests/utilities/test_typeadapter.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/fastmcp/utilities/types.py b/src/fastmcp/utilities/types.py index 5b2d22fe1..246432ac6 100644 --- a/src/fastmcp/utilities/types.py +++ b/src/fastmcp/utilities/types.py @@ -101,7 +101,12 @@ def get_cached_typeadapter(cls: T) -> TypeAdapter[T]: new_func.__module__ = cls.__module__ new_func.__qualname__ = getattr(cls, "__qualname__", cls.__name__) new_func.__annotations__ = processed_hints - return TypeAdapter(new_func) + + if inspect.ismethod(cls): + new_method = types.MethodType(new_func, cls.__self__) + return TypeAdapter(new_method) + else: + return TypeAdapter(new_func) return TypeAdapter(cls) diff --git a/tests/utilities/test_typeadapter.py b/tests/utilities/test_typeadapter.py index a32d7fcb0..941cd1db9 100644 --- a/tests/utilities/test_typeadapter.py +++ b/tests/utilities/test_typeadapter.py @@ -37,6 +37,19 @@ class SomeComplexModel(BaseModel): y: dict[int, str] +class ClassWithMethods: + def do_something(self, x: int) -> int: + return x + + def do_something_annotated( + self, x: Annotated[int, Field(description="A description")] + ) -> int: + return x + + def do_something_return_none(self) -> None: + return None + + def complex_arguments_fn( an_int: int, must_be_none: None, @@ -242,3 +255,19 @@ def test_str_vs_int(): type_adapter = get_cached_typeadapter(func_with_str_and_int) result = type_adapter.validate_python({"a": "123", "b": 123}) assert result == "123" + + +def test_class_with_methods(): + """Test that class methods are not included in the schema""" + class_with_methods = ClassWithMethods() + type_adapter = get_cached_typeadapter(class_with_methods.do_something) + schema = type_adapter.json_schema() + assert "self" not in schema["properties"] + + type_adapter = get_cached_typeadapter(class_with_methods.do_something_annotated) + schema = type_adapter.json_schema() + assert "self" not in schema["properties"] + + type_adapter = get_cached_typeadapter(class_with_methods.do_something_return_none) + schema = type_adapter.json_schema() + assert "self" not in schema["properties"]