◐ Shell
clean mode source ↗

Protocol types for 2026-07-28: superset monolith, committed per-version packages, and wire-method maps by maxisbey · Pull Request #2849 · modelcontextprotocol/python-sdk

@maxisbey mentioned this pull request

Jun 12, 2026

9 tasks

@maxisbey maxisbey changed the title Two-surface protocol types: validated model packages (candidate 1/2) Protocol types for 2026-07-28: superset monolith, committed per-version packages, and wire-method maps

Jun 12, 2026

maxisbey

maxisbey

…s, and wire-method maps

One public type set (mcp.types) covering every protocol revision through
2026-07-28; two per-version model packages that act as the schema-exact
validating layer; and plain (method, version) maps with two-step parse
functions. Version gating is data: key absence is the gate. Outbound
serialization is the model dump, with the new 2026-07-28 result fields
as ordinary serialized defaults.

Includes a surface-to-monolith field-parity test that asserts every wire
alias in either per-version package is carried by the monolith.
Vendor schema/2025-11-25.json and schema/2026-07-28.json (pinned to spec
SHA 6d441518), restore scripts/gen_surface_types.py to regenerate both
src/mcp/types/v* packages from them, and run --check in CI so the
committed files cannot drift from the schemas.
… generated-file pyright suppression
- Add validate_client_request/notification, validate_server_result to
  types.methods (surface-only siblings of the parse_* functions)
- ServerRunner validates inbound requests/notifications against the
  negotiated version's surface schema; custom methods fall through to
  the registered params_type as before
- Handler results are validated against the surface schema after dump;
  a spec-invalid result is logged and returns INTERNAL_ERROR to the client
- Map JSON-Schema format byte/uri/uri-template to plain str in codegen
  (Base64Str and AnyUrl over-assert on annotation-only formats);
  regenerate both surface packages
- Fix two test fixtures that built Tool(input_schema={}) without the
  spec-required type field
- Document handler-result validation in migration.md

@maxisbey maxisbey marked this pull request as ready for review

June 15, 2026 20:53
Generated surface types switch to extra="ignore" (with a per-version
allow-list for spec-declared open types: Result, _meta, GetTaskPayloadResult,
Tool input/output schemas, URLElicitationRequiredError data). The runner now
serializes spec-method results by dumping the monolith model and re-dumping
through the negotiated version's surface row, so 2026-only fields (resultType,
ttlMs, cacheScope) never reach the wire on a pre-2026 session.

- Monolith ttl_ms/cache_scope default to None; the SDK does not stamp a
  caching policy. EmptyResult.result_type stays None (deployed peer servers
  strict-validate ping responses).
- Spec methods absent at the negotiated version reject with METHOD_NOT_FOUND
  even if a handler is registered; custom methods fall through unchanged.
- Version fallback for pre-handshake/stateless is the literal 2025-11-25,
  not LATEST_PROTOCOL_VERSION.
- Add serialize_server_result to types.methods; codegen drift-guard asserts
  the open-class substitution count.
- Docstrings now say method-gating per version, shape per schema era.

Kludex

…uest

ServerSession.send_request and Connection.send_request now run the
client's response through validate_client_result before parsing into the
caller's result_type. KeyError (spec method without a row at the
negotiated version, or a non-spec method on Connection) is tolerated and
the existing model_validate proceeds; ValidationError propagates as today.

Adds validate_client_result to types.methods and refactors
parse_client_result to delegate its surface step to it.
…eration

ClientSession now uses parse_server_request/notification for inbound
dispatch (KeyError -> METHOD_NOT_FOUND), validates callback results
against the surface schema before sending (ValidationError ->
INTERNAL_ERROR), and gates server results through validate_server_result
before parsing. Adds a protocol_version property.

Surface codegen: SCHEMA_PATCHES targets ["integer", "number"] instead
of bare "number" so generated types use int | float (pydantic
smart-union preserves int through the sieve; previously coerced 37 ->
37.0). Regenerated both packages.

elicitation.py: Optional[T] fields now emit {"type": ...} with the
field omitted from required (was non-spec anyOf). Gate tightened to
reject list[...] and multi-primitive unions; only T or T | None
accepted. The interaction-suite divergence for nested requestedSchema is
flipped (client now rejects with INVALID_PARAMS).

Documented the elicit gate change in migration.md.
- Runner discriminator uses direction-specific SPEC_CLIENT_METHODS so
  server-direction methods (roots/list, sampling/createMessage,
  elicitation/create) registered via add_request_handler reach their
  handler instead of METHOD_NOT_FOUND
- Elicit gate now validates the rendered schema property-by-property
  against PrimitiveSchemaDefinition (restores list[str] + json_schema_extra
  multi-select; bare list[str] without enum still rejected; Literal[...]
  now supported)
- gen_surface_types.py always invokes datamodel-codegen via uv (the
  shutil.which() shortcut defeated the version pin)
- RequestedSchema.properties relaxed to dict[str, Any] in the generated
  surfaces (older python-sdk releases emit anyOf for Optional fields);
  ElicitResult.content value union gains a null arm (monolith superset
  leniency)
- Client _on_notify logs version-absent notifications at debug,
  malformed at warning (mirrors runner)
- migration.md: fix the input_schema={} example; document client-side
  surface validation; correct the elicit-gate section
- JSONValue: the spec includes null but the ts-to-json render dropped it
  alongside number; the existing patch restored number only. Now restores
  both, with a post-process step to strip the redundant forward-ref | None
  codegen emits in the recursive definitions.
- Tasks types: the 12 Tasks capability classes were defined in _types but
  not re-exported. Now in __all__, with a parity test that every public
  _types model is exported.

felixweinberger

@maxisbey maxisbey deleted the maxisbey/types-two-surface-packages branch

June 16, 2026 16:40

This was referenced

Jun 16, 2026

This was referenced

Jun 16, 2026