Skip to content

fix(session): return METHOD_NOT_FOUND for unknown request methods - #3210

Open
Ranga-Prasath-22 wants to merge 4 commits into
modelcontextprotocol:v1.xfrom
Ranga-Prasath-22:fix/v1-unknown-method-error-code
Open

fix(session): return METHOD_NOT_FOUND for unknown request methods#3210
Ranga-Prasath-22 wants to merge 4 commits into
modelcontextprotocol:v1.xfrom
Ranga-Prasath-22:fix/v1-unknown-method-error-code

Conversation

@Ranga-Prasath-22

@Ranga-Prasath-22 Ranga-Prasath-22 commented Jul 29, 2026

Copy link
Copy Markdown

Summary

Return JSON-RPC -32601 METHOD_NOT_FOUND for request methods that are not part of the session's request schema, while preserving -32602 INVALID_PARAMS for known methods with invalid parameters. Error responses echo the request id unchanged.

Why

BaseSession previously mapped every request-model validation failure to -32602. That made an unsupported method indistinguishable from a malformed call and caused clients to retry requests that could never succeed.

Implementation

  • Derive the supported request-method set from the configured Pydantic request type once per session.
  • Apply the distinction centrally in BaseSession, covering both client and server sessions and custom request unions.
  • Fail closed if schema introspection cannot produce a method set.

Behavior note

Validation-error responses no longer include the empty data="" field (-32602 and the new -32601 paths both omit it). This is spec-legal — the JSON-RPC data member is optional and its type is implementation-defined — and matches the TypeScript SDK, but clients inspecting error.data may notice the change.

Tests

  • Symmetric regression coverage for unknown methods and malformed known methods on both client and server sessions.
  • Unknown notifications are verified to produce no response, per JSON-RPC requirements.
  • Direct assertion that _extract_known_request_methods extracts the full expected method set for ClientRequest/ServerRequest, plus fallback behavior for non-string defaults and introspection failures.

Validation

  • Focused session tests pass (tests/shared/test_session.py, tests/server/test_session.py).
  • Ruff format and Ruff lint pass.
  • Behavior verified against the earlier review comments on this PR.

Fixes #3193
Resolves #1561

@Ranga-Prasath-22 Ranga-Prasath-22 changed the title fix(session): return -32601 METHOD_NOT_FOUND on unknown request methods fix(session): return METHOD_NOT_FOUND for unknown request methods Jul 29, 2026
@Ranga-Prasath-22

Copy link
Copy Markdown
Author

Just a quiet follow-up with some verification evidence, no rush -- I know the queue is deep.

Status: this PR makes the session return JSON-RPC -32601 (METHOD_NOT_FOUND) for unknown request methods instead of -32602 (INVALID_PARAMS).

Repro (stdlib + SDK only, anyio memory streams against ServerSession):

# send an unknown-method request to a ServerSession
await client_to_server_send.send(SessionMessage(types.JSONRPCMessage(
    types.JSONRPCRequest(jsonrpc="2.0", id=1, method="totally/bogus", params={}))))
resp = await server_to_client_receive.receive()
print(resp.message.root.error.code, resp.message.root.error.message)

Observed (same script, pip install -e ., one checkout per branch):

checkout error code message
v1.x (98b7159) -32602 Invalid request parameters
PR head (9936777) -32601 Method not found

Also checked for regressions: a known method with malformed params (initialize with protocolVersion: 12345) still returns -32602 on the PR head, so classification only affects unknown methods.

Happy to add docs or adjust the error message wording if that's the blocker -- could I get a review pass?

t is typed Any, so t.model_fields["method"].default is already Any; the
cast(Any, ...) was redundant and tripped pyright's reportUnnecessaryCast, which
fails the pre-commit hook. Drop the cast and the now-unused import.
@Ranga-Prasath-22

Copy link
Copy Markdown
Author

Follow-up: fix the pre-commit (pyright) failure

Root cause. checks / pre-commit failed because pyright reported reportUnnecessaryCast at src/mcp/shared/session.py:178: cast(Any, t.model_fields["method"].default) is redundant — t is typed Any, so .default is already Any, making the cast(Any, …) a no-op that pyright flags.

Fix. Drop the cast(Any, …) and the now-unused cast import.

Verification.

  • pre-commit run --all-files (local): end-of-file-fixer, prettier, markdownlint, ruff-format, and ruff all pass; pyright now reports 0 errors on the PR's files. (The remaining local pyright noise is Windows-only analysis of the posix/win32 mcp.os modules in untouched files, which does not occur on the ubuntu CI runner.)
  • ruff format/check on session.py: clean.
  • pytest tests/server/test_session.py tests/shared/test_session.py -q: 19 passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant