From c8e5340962014cfa09b59b32363e673f6d5552a7 Mon Sep 17 00:00:00 2001 From: Vishwa Murugan Date: Tue, 28 Oct 2025 23:03:08 -0700 Subject: [PATCH] fix: Propagate MCP tools output schema to FunctionDeclaration PiperOrigin-RevId: 825380145 --- src/google/adk/tools/mcp_tool/mcp_tool.py | 11 +++-- .../unittests/tools/mcp_tool/test_mcp_tool.py | 46 +++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/google/adk/tools/mcp_tool/mcp_tool.py b/src/google/adk/tools/mcp_tool/mcp_tool.py index 09737f09..82c09eb6 100644 --- a/src/google/adk/tools/mcp_tool/mcp_tool.py +++ b/src/google/adk/tools/mcp_tool/mcp_tool.py @@ -119,10 +119,15 @@ class McpTool(BaseAuthenticatedTool): Returns: FunctionDeclaration: The Gemini function declaration for the tool. """ - schema_dict = self._mcp_tool.inputSchema - parameters = _to_gemini_schema(schema_dict) + input_schema = self._mcp_tool.inputSchema + parameters = _to_gemini_schema(input_schema) + output_schema = self._mcp_tool.outputSchema + response = _to_gemini_schema(output_schema) function_decl = FunctionDeclaration( - name=self.name, description=self.description, parameters=parameters + name=self.name, + description=self.description, + parameters=parameters, + response=response, ) return function_decl diff --git a/tests/unittests/tools/mcp_tool/test_mcp_tool.py b/tests/unittests/tools/mcp_tool/test_mcp_tool.py index 3408bfa3..482f6a8a 100644 --- a/tests/unittests/tools/mcp_tool/test_mcp_tool.py +++ b/tests/unittests/tools/mcp_tool/test_mcp_tool.py @@ -36,6 +36,7 @@ try: from google.adk.tools.mcp_tool.mcp_tool import MCPTool from google.adk.tools.tool_context import ToolContext from google.genai.types import FunctionDeclaration + from google.genai.types import Type from mcp.types import CallToolResult from mcp.types import TextContent except ImportError as e: @@ -49,6 +50,7 @@ except ImportError as e: MCPTool = DummyClass ToolContext = DummyClass FunctionDeclaration = DummyClass + Type = DummyClass CallToolResult = DummyClass TextContent = DummyClass else: @@ -70,6 +72,7 @@ class MockMCPTool: }, "required": ["param1"], } + self.outputSchema = None class TestMCPTool: @@ -145,6 +148,49 @@ class TestMCPTool: assert declaration.name == "test_tool" assert declaration.description == "Test tool description" assert declaration.parameters is not None + assert declaration.response is None + + def test_get_declaration_with_output_schema(self): + """Test function declaration generation with an output schema.""" + self.mock_mcp_tool.outputSchema = { + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "The status of the operation", + }, + }, + } + tool = MCPTool( + mcp_tool=self.mock_mcp_tool, + mcp_session_manager=self.mock_session_manager, + ) + + declaration = tool._get_declaration() + + assert isinstance(declaration, FunctionDeclaration) + assert declaration.response is not None + assert declaration.response.type == Type.OBJECT + assert "status" in declaration.response.properties + assert declaration.response.properties["status"].type == Type.STRING + assert ( + declaration.response.properties["status"].description + == "The status of the operation" + ) + + def test_get_declaration_with_empty_output_schema(self): + """Test function declaration with an empty output schema.""" + self.mock_mcp_tool.outputSchema = {} + tool = MCPTool( + mcp_tool=self.mock_mcp_tool, + mcp_session_manager=self.mock_session_manager, + ) + + declaration = tool._get_declaration() + + assert declaration.response is not None + assert declaration.response.type == Type.OBJECT + assert declaration.response.properties is None @pytest.mark.asyncio async def test_run_async_impl_no_auth(self):