diff --git a/fastmcp_slim/fastmcp/contrib/mcp_mixin/mcp_mixin.py b/fastmcp_slim/fastmcp/contrib/mcp_mixin/mcp_mixin.py index f783f7748..350359630 100644 --- a/fastmcp_slim/fastmcp/contrib/mcp_mixin/mcp_mixin.py +++ b/fastmcp_slim/fastmcp/contrib/mcp_mixin/mcp_mixin.py @@ -1,12 +1,9 @@ """Provides a base mixin class and decorators for easy registration of class methods with FastMCP.""" import inspect -import warnings from collections.abc import Callable from typing import TYPE_CHECKING, Any -import fastmcp -from fastmcp.exceptions import FastMCPDeprecationWarning from fastmcp.prompts.base import Prompt from fastmcp.resources.base import Resource from fastmcp.tools.base import Tool @@ -73,15 +70,6 @@ def mcp_tool( f"Valid keyword arguments are: {sorted(_TOOL_VALID_KWARGS)}" ) - if "serializer" in kwargs and fastmcp.settings.deprecation_warnings: - warnings.warn( - "The `serializer` parameter is deprecated. " - "Return ToolResult from your tools for full control over serialization. " - "See https://gofastmcp.com/servers/tools#custom-serialization for migration examples.", - FastMCPDeprecationWarning, - stacklevel=2, - ) - def decorator(func: Callable[..., Any]) -> Callable[..., Any]: call_args: dict[str, Any] = {"name": name or get_fn_name(func), **kwargs} if enabled is not None: diff --git a/fastmcp_slim/fastmcp/server/providers/filesystem_discovery.py b/fastmcp_slim/fastmcp/server/providers/filesystem_discovery.py index 8e4929ba9..fbebe9562 100644 --- a/fastmcp_slim/fastmcp/server/providers/filesystem_discovery.py +++ b/fastmcp_slim/fastmcp/server/providers/filesystem_discovery.py @@ -344,7 +344,6 @@ def extract_components(module: ModuleType) -> list[FastMCPComponent]: meta=meta.meta, task=resolved_task, exclude_args=meta.exclude_args, - serializer=meta.serializer, timeout=meta.timeout, auth=meta.auth, run_in_thread=meta.run_in_thread, diff --git a/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py b/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py index 1f685dd02..ba08f5a0a 100644 --- a/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py +++ b/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py @@ -8,7 +8,6 @@ from __future__ import annotations import inspect import types -import warnings from collections.abc import Callable from functools import partial from typing import ( @@ -27,7 +26,6 @@ import mcp_types from mcp_types import ToolAnnotations import fastmcp -from fastmcp.exceptions import FastMCPDeprecationWarning from fastmcp.server.auth.authorization import AuthCheck from fastmcp.server.tasks.config import TaskConfig from fastmcp.tools.base import Tool @@ -44,7 +42,6 @@ except ImportError: if TYPE_CHECKING: from fastmcp.server.providers.local_provider import LocalProvider - from fastmcp.tools.base import ToolResultSerializerType F = TypeVar("F", bound=Callable[..., Any]) @@ -162,7 +159,6 @@ class ToolDecoratorMixin: meta=tool_meta, task=resolved_task, exclude_args=fmeta.exclude_args, - serializer=fmeta.serializer, timeout=fmeta.timeout, auth=fmeta.auth, run_in_thread=fmeta.run_in_thread, @@ -192,7 +188,6 @@ class ToolDecoratorMixin: meta: dict[str, Any] | None = None, enabled: bool = True, task: bool | TaskConfig | None = None, - serializer: ToolResultSerializerType | None = None, # Deprecated timeout: float | None = None, auth: AuthCheck | list[AuthCheck] | None = None, run_in_thread: bool = True, @@ -215,14 +210,13 @@ class ToolDecoratorMixin: meta: dict[str, Any] | None = None, enabled: bool = True, task: bool | TaskConfig | None = None, - serializer: ToolResultSerializerType | None = None, # Deprecated timeout: float | None = None, auth: AuthCheck | list[AuthCheck] | None = None, run_in_thread: bool = True, ) -> Callable[[F], F]: ... # NOTE: This method mirrors fastmcp.tools.tool() but adds registration, - # the `enabled` param, and supports deprecated params (serializer, exclude_args). + # the `enabled` param, and supports the deprecated `exclude_args` param. # When deprecated params are removed, this should delegate to the standalone # decorator to reduce duplication. def tool( @@ -241,7 +235,6 @@ class ToolDecoratorMixin: meta: dict[str, Any] | None = None, enabled: bool = True, task: bool | TaskConfig | None = None, - serializer: ToolResultSerializerType | None = None, # Deprecated timeout: float | None = None, auth: AuthCheck | list[AuthCheck] | None = None, run_in_thread: bool = True, @@ -272,7 +265,6 @@ class ToolDecoratorMixin: meta: Optional meta information about the tool enabled: Whether the tool is enabled (default True). If False, adds to blocklist. task: Optional task configuration for background execution - serializer: Deprecated. Return ToolResult from your tools for full control over serialization. Returns: The registered FunctionTool or a decorator function. @@ -290,14 +282,6 @@ class ToolDecoratorMixin: return str(x) ``` """ - if serializer is not None and fastmcp.settings.deprecation_warnings: - warnings.warn( - "The `serializer` parameter is deprecated. " - "Return ToolResult from your tools for full control over serialization. " - "See https://gofastmcp.com/servers/tools#custom-serialization for migration examples.", - FastMCPDeprecationWarning, - stacklevel=2, - ) if isinstance(annotations, dict): annotations = ToolAnnotations(**annotations) @@ -345,7 +329,6 @@ class ToolDecoratorMixin: annotations=annotations, exclude_args=exclude_args, meta=meta, - serializer=serializer, task=resolved_task, timeout=timeout, auth=auth, @@ -371,7 +354,6 @@ class ToolDecoratorMixin: meta=meta, task=task, exclude_args=exclude_args, - serializer=serializer, timeout=timeout, auth=auth, enabled=enabled, @@ -416,7 +398,6 @@ class ToolDecoratorMixin: meta=meta, enabled=enabled, task=task, - serializer=serializer, timeout=timeout, auth=auth, run_in_thread=run_in_thread, diff --git a/fastmcp_slim/fastmcp/server/providers/openapi/components.py b/fastmcp_slim/fastmcp/server/providers/openapi/components.py index a6f0a505f..45b493ce8 100644 --- a/fastmcp_slim/fastmcp/server/providers/openapi/components.py +++ b/fastmcp_slim/fastmcp/server/providers/openapi/components.py @@ -4,16 +4,12 @@ from __future__ import annotations import json import re -import warnings -from collections.abc import Callable from typing import TYPE_CHECKING, Any import httpx from mcp_types import ToolAnnotations from pydantic.networks import AnyUrl -import fastmcp -from fastmcp.exceptions import FastMCPDeprecationWarning from fastmcp.resources import ( Resource, ResourceContent, @@ -151,16 +147,7 @@ class OpenAPITool(Tool): output_schema: dict[str, Any] | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, - serializer: Callable[[Any], str] | None = None, # Deprecated ): - if serializer is not None and fastmcp.settings.deprecation_warnings: - warnings.warn( - "The `serializer` parameter is deprecated. " - "Return ToolResult from your tools for full control over serialization. " - "See https://gofastmcp.com/servers/tools#custom-serialization for migration examples.", - FastMCPDeprecationWarning, - stacklevel=2, - ) super().__init__( name=name, description=description, @@ -168,7 +155,6 @@ class OpenAPITool(Tool): output_schema=output_schema, tags=tags or set(), annotations=annotations, - serializer=serializer, ) self._client = client self._route = route diff --git a/fastmcp_slim/fastmcp/tools/base.py b/fastmcp_slim/fastmcp/tools/base.py index 879a5050f..2620816cb 100644 --- a/fastmcp_slim/fastmcp/tools/base.py +++ b/fastmcp_slim/fastmcp/tools/base.py @@ -7,7 +7,6 @@ from typing import ( Annotated, Any, ClassVar, - TypeAlias, overload, ) @@ -59,9 +58,6 @@ if TYPE_CHECKING: logger = get_logger(__name__) -ToolResultSerializerType: TypeAlias = Callable[[Any], str] - - def resolve_serialize_by_alias(value: Any) -> bool: """Resolve the effective ``by_alias`` setting for serializing *value*. @@ -196,12 +192,6 @@ class Tool(FastMCPComponent): ToolExecution | None, Field(description="Task execution configuration (SEP-1686)"), ] = None - serializer: Annotated[ - SkipJsonSchema[ToolResultSerializerType | None], - Field( - description="Deprecated. Return ToolResult from your tools for full control over serialization." - ), - ] = None auth: Annotated[ SkipJsonSchema[AuthCheck | list[AuthCheck] | None], Field(description="Authorization checks for this tool", exclude=True), @@ -268,7 +258,6 @@ class Tool(FastMCPComponent): annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | NotSetT | None = NotSet, - serializer: ToolResultSerializerType | None = None, # Deprecated meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None, timeout: float | None = None, @@ -289,7 +278,6 @@ class Tool(FastMCPComponent): annotations=annotations, exclude_args=exclude_args, output_schema=output_schema, - serializer=serializer, meta=meta, task=task, timeout=timeout, @@ -313,7 +301,7 @@ class Tool(FastMCPComponent): """Convert a raw result to ToolResult. Handles ToolResult passthrough and converts raw values using the tool's - attributes (serializer, output_schema) for proper conversion. + attributes (output_schema) for proper conversion. """ if isinstance(raw_value, ToolResult): return raw_value @@ -330,7 +318,7 @@ class Tool(FastMCPComponent): fastmcp_app_name=_get_fastmcp_app_name(self), ) - content = _convert_to_content(raw_value, serializer=self.serializer) + content = _convert_to_content(raw_value) # Bytes can't be represented as structured JSON content if isinstance(raw_value, bytes): @@ -460,7 +448,6 @@ class Tool(FastMCPComponent): tags: set[str] | None = None, annotations: ToolAnnotations | NotSetT | None = NotSet, output_schema: dict[str, Any] | NotSetT | None = NotSet, - serializer: ToolResultSerializerType | None = None, # Deprecated meta: dict[str, Any] | NotSetT | None = NotSet, transform_args: dict[str, ArgTransform] | None = None, transform_fn: Callable[..., Any] | None = None, @@ -479,7 +466,6 @@ class Tool(FastMCPComponent): tags=tags, annotations=annotations, output_schema=output_schema, - serializer=serializer, meta=meta, ) @@ -505,25 +491,8 @@ class Tool(FastMCPComponent): } -def _serialize_with_fallback( - result: Any, serializer: ToolResultSerializerType | None = None -) -> str: - if serializer is not None: - try: - return serializer(result) - except Exception as e: - logger.warning( - "Error serializing tool result: %s", - e, - exc_info=True, - ) - - return default_serializer(result) - - def _convert_to_single_content_block( item: Any, - serializer: ToolResultSerializerType | None = None, ) -> ContentBlock: if isinstance(item, ContentBlock): return item @@ -548,7 +517,7 @@ def _convert_to_single_content_block( return TextContent(type="text", text=base64.b64encode(item).decode("ascii")) - return TextContent(type="text", text=_serialize_with_fallback(item, serializer)) + return TextContent(type="text", text=default_serializer(item)) _PREFAB_TEXT_FALLBACK = "[Rendered Prefab UI]" @@ -599,7 +568,6 @@ def _prefab_to_tool_result(app: Any, fastmcp_app_name: str | None = None) -> Too def _convert_to_content( result: Any, - serializer: ToolResultSerializerType | None = None, ) -> list[ContentBlock]: """Convert a result to a sequence of content objects.""" @@ -607,7 +575,7 @@ def _convert_to_content( return [] if not isinstance(result, (list | tuple)): - return [_convert_to_single_content_block(result, serializer)] + return [_convert_to_single_content_block(result)] # If all items are ContentBlocks, return them as is if all(isinstance(item, ContentBlock) for item in result): @@ -617,13 +585,13 @@ def _convert_to_content( # without aggregating them if any(isinstance(item, ContentBlock | Image | Audio | File) for item in result): return [ - _convert_to_single_content_block(item, serializer) + _convert_to_single_content_block(item) if not isinstance(item, ContentBlock) else item for item in result ] # If none of the items are ContentBlocks, aggregate all items into a single TextContent - return [TextContent(type="text", text=_serialize_with_fallback(result, serializer))] + return [TextContent(type="text", text=default_serializer(result))] __all__ = ["Tool", "ToolResult"] diff --git a/fastmcp_slim/fastmcp/tools/function_tool.py b/fastmcp_slim/fastmcp/tools/function_tool.py index e83fd1791..3473032d8 100644 --- a/fastmcp_slim/fastmcp/tools/function_tool.py +++ b/fastmcp_slim/fastmcp/tools/function_tool.py @@ -36,7 +36,6 @@ from fastmcp.exceptions import FastMCPDeprecationWarning, ValidationError from fastmcp.tools.base import ( Tool, ToolResult, - ToolResultSerializerType, ) from fastmcp.tools.function_parsing import ParsedFunction, _is_object_schema from fastmcp.utilities.async_utils import ( @@ -171,7 +170,6 @@ class ToolMeta: app: Any = None task: bool | TaskConfig | None = None exclude_args: list[str] | None = None - serializer: Any | None = None timeout: float | None = None auth: AuthCheck | list[AuthCheck] | None = None enabled: bool = True @@ -238,7 +236,6 @@ class FunctionTool(Tool): annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | NotSetT | None = NotSet, - serializer: ToolResultSerializerType | None = None, meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None, timeout: float | None = None, @@ -268,7 +265,6 @@ class FunctionTool(Tool): annotations, meta, task, - serializer, timeout, auth, run_in_thread, @@ -303,20 +299,11 @@ class FunctionTool(Tool): meta=meta, task=task, exclude_args=exclude_args, - serializer=serializer, timeout=timeout, auth=auth, run_in_thread=True if run_in_thread is None else run_in_thread, ) - if metadata.serializer is not None and fastmcp.settings.deprecation_warnings: - warnings.warn( - "The `serializer` parameter is deprecated. " - "Return ToolResult from your tools for full control over serialization. " - "See https://gofastmcp.com/servers/tools#custom-serialization for migration examples.", - FastMCPDeprecationWarning, - stacklevel=2, - ) if metadata.exclude_args and fastmcp.settings.deprecation_warnings: warnings.warn( "The `exclude_args` parameter is deprecated as of FastMCP 2.14. " @@ -389,7 +376,6 @@ class FunctionTool(Tool): output_schema=final_output_schema, annotations=metadata.annotations, tags=metadata.tags or set(), - serializer=metadata.serializer, meta=metadata.meta, task_config=task_config, timeout=metadata.timeout, @@ -606,7 +592,6 @@ def tool( meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None, exclude_args: list[str] | None = None, - serializer: Any | None = None, timeout: float | None = None, auth: AuthCheck | list[AuthCheck] | None = None, run_in_thread: bool = True, @@ -626,7 +611,6 @@ def tool( meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None, exclude_args: list[str] | None = None, - serializer: Any | None = None, timeout: float | None = None, auth: AuthCheck | list[AuthCheck] | None = None, run_in_thread: bool = True, @@ -647,7 +631,6 @@ def tool( meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None, exclude_args: list[str] | None = None, - serializer: Any | None = None, timeout: float | None = None, auth: AuthCheck | list[AuthCheck] | None = None, run_in_thread: bool = True, @@ -690,7 +673,6 @@ def tool( meta=meta, task=resolve_task_config(task), exclude_args=exclude_args, - serializer=serializer, timeout=timeout, auth=auth, run_in_thread=run_in_thread, @@ -710,7 +692,6 @@ def tool( meta=meta, task=task, exclude_args=exclude_args, - serializer=serializer, timeout=timeout, auth=auth, run_in_thread=run_in_thread, diff --git a/fastmcp_slim/fastmcp/tools/tool_transform.py b/fastmcp_slim/fastmcp/tools/tool_transform.py index d43365dc2..425a970b3 100644 --- a/fastmcp_slim/fastmcp/tools/tool_transform.py +++ b/fastmcp_slim/fastmcp/tools/tool_transform.py @@ -1,7 +1,6 @@ from __future__ import annotations import inspect -import warnings from collections.abc import Callable from contextvars import ContextVar from copy import deepcopy @@ -15,8 +14,6 @@ from pydantic.fields import Field from pydantic.functional_validators import BeforeValidator from pydantic.json_schema import SkipJsonSchema -import fastmcp -from fastmcp.exceptions import FastMCPDeprecationWarning from fastmcp.tools.base import ( Tool, ToolResult, @@ -343,9 +340,7 @@ class TransformedTool(Tool): # Otherwise convert to content and create ToolResult with proper structured content - unstructured_result = _convert_to_content( - result, serializer=self.serializer - ) + unstructured_result = _convert_to_content(result) structured_output = None # First handle structured content based on output schema, if any @@ -393,7 +388,6 @@ class TransformedTool(Tool): transform_args: dict[str, ArgTransform] | None = None, annotations: ToolAnnotations | NotSetT | None = NotSet, output_schema: dict[str, Any] | NotSetT | None = NotSet, - serializer: Callable[[Any], str] | NotSetT | None = NotSet, # Deprecated meta: dict[str, Any] | NotSetT | None = NotSet, ) -> TransformedTool: """Create a transformed tool from a parent tool. @@ -415,7 +409,6 @@ class TransformedTool(Tool): output_schema: Control output schema for structured outputs: - None (default): Inherit from transform_fn if available, then parent tool - dict: Use custom output schema - serializer: Deprecated. Return ToolResult from your tools for full control over serialization. meta: Control meta information: - NotSet (default): Inherit from parent tool - dict: Use custom meta information @@ -470,18 +463,6 @@ class TransformedTool(Tool): """ tool = Tool._ensure_tool(tool) - if ( - serializer is not NotSet - and serializer is not None - and fastmcp.settings.deprecation_warnings - ): - warnings.warn( - "The `serializer` parameter is deprecated. " - "Return ToolResult from your tools for full control over serialization. " - "See https://gofastmcp.com/servers/tools#custom-serialization for migration examples.", - FastMCPDeprecationWarning, - stacklevel=2, - ) transform_args = transform_args or {} if transform_fn is not None: @@ -601,9 +582,6 @@ class TransformedTool(Tool): final_annotations = ( annotations if not isinstance(annotations, NotSetT) else tool.annotations ) - final_serializer = ( - serializer if not isinstance(serializer, NotSetT) else tool.serializer - ) transformed_tool = cls( fn=final_fn, @@ -617,7 +595,6 @@ class TransformedTool(Tool): output_schema=final_output_schema, tags=tags or tool.tags, annotations=final_annotations, - serializer=final_serializer, meta=final_meta, transform_args=transform_args, auth=tool.auth, diff --git a/tests/deprecated/test_tool_serializer.py b/tests/deprecated/test_tool_serializer.py deleted file mode 100644 index cccc95665..000000000 --- a/tests/deprecated/test_tool_serializer.py +++ /dev/null @@ -1,178 +0,0 @@ -"""Tests for deprecated tool serializer functionality. - -These tests verify that serializer parameters still work but are deprecated. -All serializer-related tests should be moved here. -""" - -import warnings - -import pytest -from inline_snapshot import snapshot -from mcp_types import TextContent - -from fastmcp import FastMCP -from fastmcp.contrib.mcp_mixin import mcp_tool -from fastmcp.server.providers import LocalProvider -from fastmcp.tools.base import Tool, _convert_to_content -from fastmcp.tools.tool_transform import TransformedTool -from fastmcp.utilities.tests import temporary_settings - - -class TestToolSerializerDeprecated: - """Tests for deprecated serializer functionality.""" - - async def test_tool_serializer(self): - """Test that a tool's serializer is used to serialize the result.""" - - def custom_serializer(data) -> str: - return f"Custom serializer: {data}" - - def process_list(items: list[int]) -> int: - return sum(items) - - tool = Tool.from_function(process_list, serializer=custom_serializer) - - result = await tool.run(arguments={"items": [1, 2, 3, 4, 5]}) - # Custom serializer affects unstructured content - assert isinstance(result.content[0], TextContent) - assert result.content[0].text == "Custom serializer: 15" - # Structured output should have the raw value - assert result.structured_content == {"result": 15} - - def test_custom_serializer(self): - """Test that a custom serializer is used for non-MCP types.""" - - def custom_serializer(data): - return f"Serialized: {data}" - - result = _convert_to_content({"a": 1}, serializer=custom_serializer) - - assert result == snapshot( - [TextContent(type="text", text="Serialized: {'a': 1}")] - ) - - def test_custom_serializer_error_fallback(self, caplog): - """Test that if a custom serializer fails, it falls back to the default.""" - - def custom_serializer_that_fails(data): - raise ValueError("Serialization failed") - - result = _convert_to_content({"a": 1}, serializer=custom_serializer_that_fails) - - assert isinstance(result, list) - assert result == snapshot([TextContent(type="text", text='{"a":1}')]) - - assert "Error serializing tool result" in caplog.text - - -class TestSerializerDeprecationWarnings: - """Tests that deprecation warnings are raised when serializer is used.""" - - def test_tool_from_function_serializer_warning(self): - """Test that Tool.from_function warns when serializer is provided.""" - - def custom_serializer(data) -> str: - return f"Custom: {data}" - - def my_tool(x: int) -> int: - return x * 2 - - with temporary_settings(deprecation_warnings=True): - with pytest.warns(DeprecationWarning, match="serializer.*deprecated"): - Tool.from_function(my_tool, serializer=custom_serializer) - - def test_tool_from_function_serializer_no_warning_when_disabled(self): - """Test that no warning is raised when deprecation_warnings is False.""" - - def custom_serializer(data) -> str: - return f"Custom: {data}" - - def my_tool(x: int) -> int: - return x * 2 - - with temporary_settings(deprecation_warnings=False): - with warnings.catch_warnings(): - warnings.simplefilter("error") - # Should not raise - Tool.from_function(my_tool, serializer=custom_serializer) - - def test_local_provider_tool_serializer_warning(self): - """Test that LocalProvider.tool warns when serializer is provided.""" - provider = LocalProvider() - - def custom_serializer(data) -> str: - return f"Custom: {data}" - - def my_tool(x: int) -> int: - return x * 2 - - with temporary_settings(deprecation_warnings=True): - with pytest.warns(DeprecationWarning, match="serializer.*deprecated"): - provider.tool(my_tool, serializer=custom_serializer) - - def test_local_provider_tool_decorator_serializer_warning(self): - """Test that LocalProvider.tool decorator warns when serializer is provided.""" - provider = LocalProvider() - - def custom_serializer(data) -> str: - return f"Custom: {data}" - - with temporary_settings(deprecation_warnings=True): - with pytest.warns(DeprecationWarning, match="serializer.*deprecated"): - - @provider.tool(serializer=custom_serializer) - def my_tool(x: int) -> int: - return x * 2 - - def test_fastmcp_tool_serializer_warning(self): - """Test that FastMCP.tool warns when serializer is provided via LocalProvider.""" - - def custom_serializer(data) -> str: - return f"Custom: {data}" - - def my_tool(x: int) -> int: - return x * 2 - - # FastMCP.tool doesn't accept serializer directly, it goes through LocalProvider - # So we test LocalProvider.tool which is what FastMCP uses internally - provider = LocalProvider() - with temporary_settings(deprecation_warnings=True): - with pytest.warns(DeprecationWarning, match="serializer.*deprecated"): - provider.tool(my_tool, serializer=custom_serializer) - - def test_fastmcp_tool_serializer_parameter_raises_type_error(self): - """Test that FastMCP tool_serializer parameter raises TypeError.""" - - def custom_serializer(data) -> str: - return f"Custom: {data}" - - with pytest.raises(TypeError, match="no longer accepts `tool_serializer`"): - FastMCP("TestServer", tool_serializer=custom_serializer) - - def test_transformed_tool_from_tool_serializer_warning(self): - """Test that TransformedTool.from_tool warns when serializer is provided.""" - - def custom_serializer(data) -> str: - return f"Custom: {data}" - - def my_tool(x: int) -> int: - return x * 2 - - parent_tool = Tool.from_function(my_tool) - - with temporary_settings(deprecation_warnings=True): - with pytest.warns(DeprecationWarning, match="serializer.*deprecated"): - TransformedTool.from_tool(parent_tool, serializer=custom_serializer) - - def test_mcp_mixin_tool_serializer_warning(self): - """Test that mcp_tool decorator warns when serializer is provided.""" - - def custom_serializer(data) -> str: - return f"Custom: {data}" - - with temporary_settings(deprecation_warnings=True): - with pytest.warns(DeprecationWarning, match="serializer.*deprecated"): - - @mcp_tool(serializer=custom_serializer) - def my_tool(x: int) -> int: - return x * 2