diff --git a/homeassistant/components/mcp_server/server.py b/homeassistant/components/mcp_server/server.py index 2386ffa153db..dcb1fae80ae6 100644 --- a/homeassistant/components/mcp_server/server.py +++ b/homeassistant/components/mcp_server/server.py @@ -44,7 +44,9 @@ def _format_tool( ) -> types.Tool: """Format tool specification.""" input_schema = probatio.to_openapi( - tool.parameters, custom_serializer=custom_serializer + tool.parameters, + custom_serializer=custom_serializer, + openapi_version="3.1.0", ) mcp_schema: dict[str, Any] = { "type": "object", diff --git a/tests/components/mcp_server/test_http.py b/tests/components/mcp_server/test_http.py index ab0aa337b005..d764dc87f3fb 100644 --- a/tests/components/mcp_server/test_http.py +++ b/tests/components/mcp_server/test_http.py @@ -687,6 +687,51 @@ async def test_mcp_tools_list_required_parameters( assert tool.inputSchema.get("required") == expected_required +@pytest.mark.usefixtures("setup_integration") +@pytest.mark.parametrize("llm_hass_api", [TEST_LLM_API_ID]) +@pytest.mark.parametrize( + ("parameters", "expected_schema"), + [ + pytest.param( + probatio.Schema( + {probatio.Optional("value"): probatio.Range(min=0, min_included=False)} + ), + {"type": "number", "exclusiveMinimum": 0}, + id="exclusive-minimum", + ), + pytest.param( + probatio.Schema({probatio.Optional("value"): probatio.Maybe(str)}), + {"anyOf": [{"type": "null"}, {"type": "string"}]}, + id="nullable", + ), + ], +) +async def test_mcp_tools_list_json_schema( + hass: HomeAssistant, + mcp_url: str, + mcp_client: MCPClientFactory, + hass_supervisor_access_token: str, + parameters: probatio.Schema, + expected_schema: JsonObjectType, +) -> None: + """Test tool parameters use JSON Schema 2020-12 compatible representations.""" + llm.async_register_api( + hass, + MockLLMAPI( + hass=hass, + id=TEST_LLM_API_ID, + name="Test API", + tools=[_StubTool(parameters)], + ), + ) + + async with mcp_client(hass, mcp_url, hass_supervisor_access_token) as session: + result = await session.list_tools() + + tool = next(tool for tool in result.tools if tool.name == "test_tool") + assert tool.inputSchema["properties"]["value"] == expected_schema + + @pytest.mark.parametrize("llm_hass_api", [TEST_LLM_API_ID]) async def test_mcp_tools_list_metadata( hass: HomeAssistant,