diff --git a/src/fastmcp/tools/tool.py b/src/fastmcp/tools/tool.py index 4fb6b7eb4..7f122c290 100644 --- a/src/fastmcp/tools/tool.py +++ b/src/fastmcp/tools/tool.py @@ -192,7 +192,7 @@ def _convert_to_content( other_content.append(item) if other_content: other_content = _convert_to_content( - other_content, _process_as_single_item=True + other_content, serializer=serializer, _process_as_single_item=True ) return other_content + mcp_types diff --git a/tests/tools/test_tool_manager.py b/tests/tools/test_tool_manager.py index 4d2bc2711..a777b755e 100644 --- a/tests/tools/test_tool_manager.py +++ b/tests/tools/test_tool_manager.py @@ -443,6 +443,34 @@ class TestCallTools: assert isinstance(result[0], TextContent) assert result[0].text == 'CUSTOM:{"key": "value", "number": 123}' + async def test_call_tool_with_list_result_custom_serializer(self): + """Test that a custom serializer provided to FastMCP is used by tools that return lists.""" + + def custom_serializer(data: Any) -> str: + if isinstance(data, list): + return f"CUSTOM:{json.dumps(data)}" + return json.dumps(data) + + mcp = FastMCP(tool_serializer=custom_serializer) + manager = mcp._tool_manager + + def get_data() -> list[dict]: + return [ + {"key": "value", "number": 123}, + {"key": "value2", "number": 456}, + ] + + manager.add_tool_from_fn(get_data) + + result = await manager.call_tool("get_data", {}) + assert isinstance(result, list) + assert len(result) == 1 + assert isinstance(result[0], TextContent) + assert ( + result[0].text + == 'CUSTOM:[{"key": "value", "number": 123}, {"key": "value2", "number": 456}]' + ) + async def test_custom_serializer_fallback_on_error(self): """Test that a broken custom serializer gracefully falls back."""