Review-feedback round on the conformance burn-down:
- Cancelled requests no longer leave the legacy streamable-HTTP POST
hanging. The dispatcher emits a RequestSettled marker when a handler is
cancelled without producing a response; the transport consumes it by
closing the per-request stream, so the POST's SSE stream terminates
without a response frame and JSON-response mode completes with 204 No
Content (the client treats 202/204 alike). Per-request streams are
released instead of leaking until session teardown, and a handler that
survives the cancellation still delivers its normal response. The
marker is type-visible on the dispatcher write stream and is stripped
by every serializing transport, so it can never appear on a wire.
- A bearer token whose audience cannot be canonicalized (out-of-range or
non-numeric port) is now rejected with the standard 401 invalid_token
instead of raising through the auth middleware as a 500.
- The bundled authorization server's /register now accepts only https
redirect URIs or http on a loopback host; other schemes on loopback
hosts (ftp, ws, javascript, custom) are rejected.
- OAuth client scope selection falls back to the caller-configured
OAuthClientMetadata.scope when neither the WWW-Authenticate challenge
nor protected-resource metadata names scopes, matching the TypeScript
SDK, so the documented migration path works as written.
- The cross-dispatcher contract that handler-raised MCPError subclasses
surface to callers as plain MCPError is now pinned by an explicit test
and documented; rehydrate with from_error when the subclass matters.
- Docs: migration notes for the bearer-challenge wire-shape changes and
the cancellation wire spellings; story READMEs updated to the landed
error contract; strict-capabilities doc corrected to state that
resources/unsubscribe is gated by the base resources capability only.
Client(..., strict_capabilities=True) rejects, before any request reaches
the transport, a call to a method whose required server capability the
connected server did not advertise -- for example list_resources() against
a server that only advertised tools, or subscribe_resource() when the
server's resources capability does not set subscribe. The rejection is an
MCPError with code -32601 (METHOD_NOT_FOUND) and data set to the method,
the same shape a compliant server returns for an unadvertised capability,
so opting in changes where the rejection happens, not what callers catch.
The default is False and unchanged: every request is sent and the server's
answer is surfaced. This mirrors the TypeScript SDK's
enforceStrictCapabilities option (also default-off). The same keyword-only
parameter exists on ClientSession for low-level users; Client forwards it.
The method-to-capability table lives in
mcp_types.methods.SERVER_CAPABILITY_REQUIREMENTS next to the other
per-method maps, with missing_server_capability() as its only evaluator,
so the check in ClientSession.send_request is a single data-driven gate
rather than a per-method condition, and the relationship is the same at
every protocol version. Because the gate reads server_capabilities, a bare
version pin (mode="2026-07-28" with no prior_discover=) would reject every
gated method; that combination is refused at Client construction with a
ValueError that names the fix.
The interaction-requirements entry for the lifecycle capability rule is no
longer marked untested: the new tests pin both the opt-in pre-wire
rejection and the default send-and-surface behaviour.
A client constructed without an elicitation_callback or
list_roots_callback still answers the server's request, via a default
callback that returns a JSON-RPC error. Both defaults used -32600
(invalid request). The spec assigns a specific code to each case:
- elicitation/create: -32602 (invalid params). A client with no
callback declares no elicitation modes, so every incoming request
names an undeclared mode, which clients MUST answer with -32602.
- roots/list: -32601 (method not found), the code clients SHOULD use
when they do not support roots.
The default sampling callback keeps -32600: the spec assigns no code
to a client that does not support sampling. Error messages are
unchanged.
Update the affected tests and the interaction-requirement entries that
recorded the old codes, fix the code named in the client callbacks doc
page, and add a migration note.