Skip to content

Commit 274581e

Browse files
committed
Return method-not-found for unknown request methods
1 parent fb2276b commit 274581e

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

src/mcp/server/session.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ async def handle_list_prompts(ctx: RequestContext, params) -> ListPromptsResult:
2929
"""
3030

3131
from enum import Enum
32-
from typing import Any, TypeVar, overload
32+
from typing import Any, TypeVar, get_args, overload
3333

3434
import anyio
3535
import anyio.lowlevel
@@ -63,6 +63,12 @@ class InitializationState(Enum):
6363
RequestResponder[types.ClientRequest, types.ServerResult] | types.ClientNotification | Exception
6464
)
6565

66+
_KNOWN_CLIENT_REQUEST_METHODS = frozenset(
67+
method
68+
for request_type in get_args(types.ClientRequest)
69+
if isinstance(method := request_type.model_fields["method"].default, str)
70+
)
71+
6672

6773
class ServerSession(
6874
BaseSession[
@@ -104,6 +110,11 @@ def _receive_request_adapter(self) -> TypeAdapter[types.ClientRequest]:
104110
def _receive_notification_adapter(self) -> TypeAdapter[types.ClientNotification]:
105111
return types.client_notification_adapter
106112

113+
def _get_request_validation_error(self, request: types.JSONRPCRequest) -> types.ErrorData:
114+
if request.method not in _KNOWN_CLIENT_REQUEST_METHODS:
115+
return types.ErrorData(code=types.METHOD_NOT_FOUND, message="Method not found")
116+
return super()._get_request_validation_error(request)
117+
107118
@property
108119
def client_params(self) -> types.InitializeRequestParams | None:
109120
return self._client_params

src/mcp/shared/session.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,9 @@ def _receive_request_adapter(self) -> TypeAdapter[ReceiveRequestT]:
330330
def _receive_notification_adapter(self) -> TypeAdapter[ReceiveNotificationT]:
331331
raise NotImplementedError
332332

333+
def _get_request_validation_error(self, request: JSONRPCRequest) -> ErrorData:
334+
return ErrorData(code=INVALID_PARAMS, message="Invalid request parameters", data="")
335+
333336
async def _receive_loop(self) -> None:
334337
async with self._read_stream, self._write_stream:
335338
try:
@@ -363,7 +366,7 @@ async def _receive_loop(self) -> None:
363366
error_response = JSONRPCError(
364367
jsonrpc="2.0",
365368
id=message.message.id,
366-
error=ErrorData(code=INVALID_PARAMS, message="Invalid request parameters", data=""),
369+
error=self._get_request_validation_error(message.message),
367370
)
368371
session_message = SessionMessage(message=error_response)
369372
await self._write_stream.send(session_message)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import anyio
2+
import pytest
3+
4+
from mcp.server.models import InitializationOptions
5+
from mcp.server.session import ServerSession
6+
from mcp.shared.message import SessionMessage
7+
from mcp.types import INVALID_PARAMS, METHOD_NOT_FOUND, JSONRPCError, JSONRPCRequest, ServerCapabilities
8+
9+
10+
@pytest.mark.anyio
11+
async def test_invalid_method_names_return_method_not_found() -> None:
12+
read_send_stream, read_receive_stream = anyio.create_memory_object_stream[SessionMessage | Exception](10)
13+
write_send_stream, write_receive_stream = anyio.create_memory_object_stream[SessionMessage](10)
14+
15+
try:
16+
async with ServerSession(
17+
read_stream=read_receive_stream,
18+
write_stream=write_send_stream,
19+
init_options=InitializationOptions(
20+
server_name="test_server",
21+
server_version="1.0.0",
22+
capabilities=ServerCapabilities(),
23+
),
24+
):
25+
await read_send_stream.send(
26+
SessionMessage(
27+
message=JSONRPCRequest(jsonrpc="2.0", id=1, method="invalid/method", params={})
28+
)
29+
)
30+
31+
invalid_method_response = (await write_receive_stream.receive()).message
32+
33+
assert isinstance(invalid_method_response, JSONRPCError)
34+
assert invalid_method_response.id == 1
35+
assert invalid_method_response.error.code == METHOD_NOT_FOUND
36+
assert invalid_method_response.error.message == "Method not found"
37+
38+
await read_send_stream.send(
39+
SessionMessage(
40+
message=JSONRPCRequest(jsonrpc="2.0", id=2, method="initialize")
41+
)
42+
)
43+
44+
malformed_known_method_response = (await write_receive_stream.receive()).message
45+
46+
assert isinstance(malformed_known_method_response, JSONRPCError)
47+
assert malformed_known_method_response.id == 2
48+
assert malformed_known_method_response.error.code == INVALID_PARAMS
49+
assert malformed_known_method_response.error.message == "Invalid request parameters"
50+
finally: # pragma: lax no cover
51+
await read_send_stream.aclose()
52+
await write_send_stream.aclose()
53+
await read_receive_stream.aclose()
54+
await write_receive_stream.aclose()

0 commit comments

Comments
 (0)