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.

@github-actions

Copy link
Copy Markdown
Contributor

This pull request is included in pre-release v2.0.0a3

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