Skip to content

lowlevel Server: widen on_* return types for InputRequiredResult; add subscriptions/listen slot#2967

Merged
maxisbey merged 2 commits into
mainfrom
lowlevel-server-2026-handlers
Jun 25, 2026
Merged

lowlevel Server: widen on_* return types for InputRequiredResult; add subscriptions/listen slot#2967
maxisbey merged 2 commits into
mainfrom
lowlevel-server-2026-handlers

Conversation

@maxisbey

Copy link
Copy Markdown
Contributor

Type-only changes to the lowlevel Server constructor for the 2026-07-28 protocol revision.

Changes

Return-type widening — three on_* handlers can now return InputRequiredResult in addition to their concrete result type, matching MONOLITH_RESULTS in src/mcp/types/methods.py:

  • on_call_toolCallToolResult | InputRequiredResult
  • on_get_promptGetPromptResult | InputRequiredResult
  • on_read_resourceReadResourceResult | InputRequiredResult

These are the three methods whose request params extend InputResponseRequestParams. Widening is covariant, so existing handlers typed -> CallToolResult etc. still type-check unchanged.

New dispatch sloton_subscriptions_listen kwarg + _spec_requests row, so subscriptions/listen (the one new-in-2026 client→server request method) reaches a registered handler instead of METHOD_NOT_FOUND.

InputRequiredResult validatormodel_validator(mode="after") enforcing the spec's at-least-one-of input_requests / request_state requirement (matches the typescript-sdk and csharp-sdk behaviour).

Not in this PR

  • tasks/* — moved to the io.modelcontextprotocol/tasks extension; not core 2026-07-28.
  • on_discover override — server/discover stays the auto-derived built-in.
  • get_capabilities()ServerCapabilities has no subscriptions field; nothing to set.

Part of #2891.

AI Disclaimer

… subscriptions/listen slot

- on_call_tool / on_get_prompt / on_read_resource return types widened to
  include InputRequiredResult, matching MONOLITH_RESULTS in types/methods.py.
  Covariant widening; existing handlers returning the concrete type still
  type-check.
- on_subscriptions_listen kwarg + _spec_requests row added so the 2026
  subscriptions/listen method has a dispatch slot.
- InputRequiredResult: model_validator enforces at-least-one of
  input_requests / request_state (spec MUST).
@maxisbey maxisbey added the spec-2026-07-28 2026-07-28 MCP spec release work label Jun 25, 2026
@maxisbey maxisbey marked this pull request as ready for review June 25, 2026 12:00
…locate validator test

The discriminator-dump test was building a bare InputRequiredResult(), which
the at-least-one-of validator now (correctly) rejects. Construct the minimal
valid instance instead. Move the validator test alongside it in
tests/test_types.py and drop the separate file.
Comment thread src/mcp/types/_types.py
@maxisbey maxisbey merged commit ae13ede into main Jun 25, 2026
34 checks passed
@maxisbey maxisbey deleted the lowlevel-server-2026-handlers branch June 25, 2026 12:20

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good — the test conflict from my earlier comment is resolved, and the typing changes line up with MONOLITH_RESULTS.

Extended reasoning...

Overview

This PR is a small, type-focused change for the 2026-07-28 protocol revision: it widens three on_* handler return annotations in the lowlevel Server constructor to admit InputRequiredResult, adds an on_subscriptions_listen constructor kwarg plus its _spec_requests dispatch row, and adds a model_validator on InputRequiredResult enforcing the spec's at-least-one-of input_requests/request_state requirement, with accompanying tests in tests/test_types.py.

Consistency checks

The widened return types (tools/call, prompts/get, resources/read) match the unions already declared in MONOLITH_RESULTS in src/mcp/types/methods.py, and the new subscriptions/listen slot's EmptyResult return matches the surface and monolith result maps for that method. The widening is covariant, so existing handlers typed with the narrower result still type-check. I also checked for other call sites constructing a bare InputRequiredResult() that the new validator would break — the only one was the old discriminator test, which this revision updates (the issue I flagged in my earlier review), and tests/types/test_wire_frames.py constructs the model with both fields so it remains valid.

Security risks

None identified. The change does not touch auth, transport security, or input handling beyond adding a stricter validation rule on an outbound result model; it adds no new code paths that process untrusted data.

Level of scrutiny

Moderate. Constructor signatures and a dispatch-table row in the lowlevel server are visible API surface, but the changes are mechanical, follow the existing row/kwarg pattern exactly, and are runtime-inert except for the validator, which is spec-mandated and matches the typescript/csharp SDK behaviour. The previously broken test is now fixed and a new validator test is co-located alongside it. I could not execute the test suite in this environment (no project venv available), but the test changes are simple enough to verify by inspection.

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

Labels

spec-2026-07-28 2026-07-28 MCP spec release work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants