Return METHOD_NOT_FOUND for unsupported MCP methods in mcp_server (#183350)

This commit is contained in:
Allen Porter
2026-09-30 06:58:34 +02:00
committed by GitHub
parent 9213cba499
commit 0efa3eabc5
2 changed files with 65 additions and 0 deletions
@@ -33,6 +33,7 @@ from contextlib import asynccontextmanager
from dataclasses import dataclass
from http import HTTPStatus
import logging
from typing import get_args
from aiohttp import web
from aiohttp.web_exceptions import HTTPBadRequest, HTTPNotFound
@@ -61,6 +62,12 @@ _LOGGER = logging.getLogger(__name__)
STREAMABLE_API = "/api/mcp"
TIMEOUT = 60 # Seconds
KNOWN_MCP_METHODS: frozenset[str] = frozenset(
req_cls.model_fields["method"].default
for req_cls in get_args(types.ClientRequestType)
if "method" in req_cls.model_fields
)
# Legacy SSE endpoint
SSE_API = f"/{DOMAIN}/sse"
MESSAGES_API = f"/{DOMAIN}/messages/{{session_id}}"
@@ -286,6 +293,20 @@ async def _async_handle_streamable_message(
_LOGGER.debug("Notification or response received, returning 202")
return web.Response(status=HTTPStatus.ACCEPTED)
if message.root.method not in KNOWN_MCP_METHODS:
error_response = types.JSONRPCError(
jsonrpc="2.0",
id=message.root.id,
error=types.ErrorData(
code=types.METHOD_NOT_FOUND,
message="Method not found",
data=message.root.method,
),
)
return web.json_response(
data=error_response.model_dump(by_alias=True, exclude_none=True),
)
# The MCP server runs as a background task for the duration of the
# request. We open a buffered stream pair to communicate with it. The
# request is sent to the MCP server and we wait for a single response
+44
View File
@@ -1217,3 +1217,47 @@ async def test_require_admin_allows_admin(
headers={"accept": CONTENT_TYPE_JSON},
)
assert response.status == HTTPStatus.OK
@pytest.mark.parametrize(
"method",
[
pytest.param("server/discover", id="server_discover"),
pytest.param("no/such-method", id="unknown_method"),
],
)
@pytest.mark.usefixtures("setup_integration")
async def test_unsupported_method_returns_method_not_found(
hass_client: ClientSessionGenerator,
caplog: pytest.LogCaptureFixture,
method: str,
) -> None:
"""Test that unsupported methods return JSON-RPC METHOD_NOT_FOUND without log warnings."""
client = await hass_client()
response = await client.post(
STREAMABLE_API,
json={
"jsonrpc": "2.0",
"id": "request-123",
"method": method,
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
}
},
},
headers={"accept": CONTENT_TYPE_JSON},
)
assert response.status == HTTPStatus.OK
data = await response.json()
assert data == {
"jsonrpc": "2.0",
"id": "request-123",
"error": {
"code": -32601,
"message": "Method not found",
"data": method,
},
}
assert "Failed to validate request" not in caplog.text