diff --git a/homeassistant/components/mcp/coordinator.py b/homeassistant/components/mcp/coordinator.py index f3bea5f3d58e..fb099a800530 100644 --- a/homeassistant/components/mcp/coordinator.py +++ b/homeassistant/components/mcp/coordinator.py @@ -29,7 +29,6 @@ from homeassistant.exceptions import ( from homeassistant.helpers import llm from homeassistant.helpers.httpx_client import create_async_httpx_client from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from homeassistant.util.json import JsonObjectType from homeassistant.util.ssl import SSL_ALPN_HTTP11, SSLCipherList, client_context from .auth import AuthenticateHeader @@ -148,7 +147,7 @@ class ModelContextProtocolTool(llm.Tool): hass: HomeAssistant, tool_input: llm.ToolInput, llm_context: llm.LLMContext, - ) -> JsonObjectType: + ) -> llm.ToolResult: """Call the tool.""" try: async with asyncio.timeout(TIMEOUT): @@ -188,7 +187,10 @@ class ModelContextProtocolTool(llm.Tool): raise HomeAssistantError( f"Error communicating with MCP server when calling tool: {error}" ) from error - return result.model_dump(exclude_unset=True, exclude_none=True) + return llm.ToolResult( + data=result.model_dump(exclude_unset=True, exclude_none=True), + error=bool(result.isError), + ) class ModelContextProtocolCoordinator(DataUpdateCoordinator[list[llm.Tool]]): diff --git a/tests/components/mcp/test_init.py b/tests/components/mcp/test_init.py index a25005da4345..7e903e5066d2 100644 --- a/tests/components/mcp/test_init.py +++ b/tests/components/mcp/test_init.py @@ -317,8 +317,42 @@ async def test_llm_get_api_tools( } +@pytest.mark.parametrize( + ("call_tool_result", "expected_result"), + [ + pytest.param( + CallToolResult( + content=[TextContent(type="text", text="User was born in February")] + ), + llm.ToolResult( + data={ + "content": [{"text": "User was born in February", "type": "text"}] + } + ), + id="success", + ), + pytest.param( + CallToolResult( + content=[TextContent(type="text", text="Memory search failed")], + isError=True, + ), + llm.ToolResult( + data={ + "content": [{"text": "Memory search failed", "type": "text"}], + "isError": True, + }, + error=True, + ), + id="error", + ), + ], +) async def test_call_tool( - hass: HomeAssistant, config_entry: MockConfigEntry, mock_mcp_client: Mock + hass: HomeAssistant, + config_entry: MockConfigEntry, + mock_mcp_client: Mock, + call_tool_result: CallToolResult, + expected_result: llm.ToolResult, ) -> None: """Test calling an MCP Tool through the LLM API.""" mock_mcp_client.return_value.list_tools.return_value = ListToolsResult( @@ -337,9 +371,7 @@ async def test_call_tool( tool = api_instance.tools[0] assert tool.name == "search_memory" - mock_mcp_client.return_value.call_tool.return_value = CallToolResult( - content=[TextContent(type="text", text="User was born in February")] - ) + mock_mcp_client.return_value.call_tool.return_value = call_tool_result result = await tool.async_call( hass, llm.ToolInput( @@ -347,9 +379,7 @@ async def test_call_tool( ), create_llm_context(), ) - assert result == { - "content": [{"text": "User was born in February", "type": "text"}] - } + assert result == expected_result async def test_call_tool_fails(