Add a Ping section to the README covering both directions of the
utility: constructing and sending a PingRequest via send_request, and
the automatic default handler response (with an override example for
custom liveness logic). Links to the MCP ping spec.
Ping was the only non-experimental feature lacking user-facing
documentation and an example.
* fix(model): decode metadata-bearing input-required results
The draft permits every Result, including InputRequiredResult, to carry
_meta and recommends that servers include
io.modelcontextprotocol/serverInfo on every response. It also requires
an InputRequiredResult to contain inputRequests or requestState so the
client knows what to provide or how to resume the request.
ServerResult uses untagged deserialization and attempts CallToolResult
before InputRequiredResult. Because CallToolResult accepts _meta and
defaults missing content to an empty list, it consumed valid
input_required results carrying metadata. Unknown inputRequests and
requestState fields were then discarded, leaving clients without the
information needed to continue.
Reject resultType input_required when deserializing CallToolResult so
Serde proceeds to the InputRequiredResult variant. Add regression
coverage proving that inputRequests, requestState, and serverInfo
metadata are preserved.
Spec:
41d9e938e9/schema/draft/schema.ts (L137-L151)41d9e938e9/schema/draft/schema.ts (L198-L224)41d9e938e9/schema/draft/schema.ts (L541-L565)
Signed-off-by: Filinto Duran <1373693+filintod@users.noreply.github.com>
* incorporate feedback - close gap in inputrequired not properly checking that at least one of inputRequest or requestState is present
Signed-off-by: Filinto Duran <1373693+filintod@users.noreply.github.com>
---------
Signed-off-by: Filinto Duran <1373693+filintod@users.noreply.github.com>
* refactor(service): express SEP-2260 receive-side association as an enum
Replaces the has_pending_outbound_request bool on
enforce_peer_request_association with PeerRequestAssociation, so a
stream-separating transport can report per-request association (#1033).
Behavior-preserving: the event loop still passes the coarse signal as
Unknown.
* feat(transport): record inbound stream origin on streamable HTTP client (#1033)
The worker attaches an InboundStreamOrigin extension to each inbound
server request: Unassociated for the standalone GET stream,
OutboundRequest(id) for a POST's SSE stream. Mirror of the
OriginatingRequestId marker used by the server side.
* feat(service): enforce SEP-2260 client receive-side check per stream origin (#1033)
The event loop maps InboundStreamOrigin plus the in-flight responder
pool to PeerRequestAssociation: restricted requests arriving on the
standalone GET stream are now rejected with -32602 even while unrelated
outbound requests are in flight.
* test: end-to-end SEP-2260 stream-based enforcement over streamable HTTP (#1033)
* docs: cross-link SEP-2260 stream markers
* test: origin marker survives SSE resumption per SEP-2260 (#1033)
A POST SSE stream resumed via GET + Last-Event-ID (SEP-1699) reconnects
beneath execute_sse_stream, so requests replayed after a resume keep
their OutboundRequest origin. Pins the layering invariant: hoisting
reconnection above the marker attach point would wrongly reject
associated requests with -32602.
* docs: trim SEP-2260 comments to spec rationale
* docs: align SEP-2577 expect reason with sibling suppressions
* test: harden SEP-2260 stream-enforcement e2e (#1033)
Detect handler invocation via a channel asserted empty instead of a
panic in a spawned task (swallowed, cannot fail the test); surface
scripted-server misuse as transport errors rather than panics in the
transport task; bound the tail awaits with 5s timeouts. Correct the
header comment: a 2026-07-28 server minting a session id is not
spec-legal (SEP-2567 removes sessions and the GET endpoint) — the
scripted server is deliberately non-conforming, which is the point of
receive-side enforcement.
* test: adapt SEP-2260 association tests to ServerPeerInfo
Rebase onto 3.0.0: RoleClient::PeerInfo is now ServerPeerInfo (#1065)
and its constructor takes the protocol version directly.
* chore: add 'Copy' macro to new PeerRequestAssociation
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
---------
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
* fix: stamp server info on graceful subscription results
* fix: expose subscription server info metadata
---------
Co-authored-by: mrcs64 <9069178+mrcs64@users.noreply.github.com>
* fix(auth): preserve OAuth discovery transport errors
* refactor!: expose domain-specific boxed OAuth HTTP errors
Let custom OAuth HTTP clients preserve native error types and source chains
while keeping the type-erased boundary explicit in the public API.
BREAKING CHANGE: OAuthHttpClientError is now a boxed error alias; custom
clients should return native errors with .into() or box them directly.
---------
Co-authored-by: Theodore Ni <3806110+tjni@users.noreply.github.com>
* refactor!: refactor OAuth client authorization api
`OAuthState::start_authorization` now accepts a declarative `AuthorizationRequest`
describing the client's available identity material and selects the highest-priority
mechanism the server supports: pre-registered client information → Client ID
Metadata Documents (SEP-991) → Dynamic Client Registration.
This replaces the three mechanism-specific entry points (`start_authorization`,
`start_authorization_with_metadata_url`, `start_authorization_with_preregistered_client`),
where callers previously had to know which mechanism to pick. `AuthorizationSession::new`
is consolidated the same way, and the failure-recovery pattern from #994 (returning the
manager alongside the error so `OAuthState` recovers to `Unauthorized` on transient failures)
is now applied across all registration paths. Includes new `RecordingOAuthHttpClient`-based
tests covering the priority matrix and recovery semantics, plus updated docs, examples, and
conformance client.
* fix: dcr registration uses requested application type
* fix: error for invalid combination
* feat: implement SEP-2260 require server requests to associate with client requests
* feat(service): attach originating request id to in-handler outbound requests (SEP-2260)
Reuses the ORIGINATING_REQUEST task-local from #1027; the marker rides
the request's non-serialized Extensions so the streamable HTTP server
can route associated requests to the originating SSE stream.
* feat(transport): route associated server requests to originating SSE stream (SEP-2260)
* test: end-to-end SEP-2260 stream routing over streamable HTTP
* test: register SEP-2260 routing test with required-features; drop dead list_tools
* docs: document SEP-2260 association requirement and stream routing
* docs: fix redundant explicit link on OriginatingRequestId
* docs: note marker is role-agnostic; add reason to deprecated expect
Review follow-ups: the OriginatingRequestId rustdoc now states the marker
is attached for both roles with only the server transport reading it, and
the test's deprecation suppression carries a reason per house style.
* docs: condense inline comments to repo convention
Trims multi-line inline comments added in this branch down to the terse
one-to-two-line style used elsewhere in the codebase, keeping only the
non-obvious rationale (spec references, fallback invariant, version choice).
* docs: condense SEP-2260 rustdoc sections
Tightens the duplicated per-method association section from eleven lines
to five, and trims the marker and SessionManager docs to the same
information in fewer words.
* docs: single-source SEP-2260 caller requirements on OriginatingRequestId
* feat(service): reject unassociated server-to-client requests on the client (SEP-2260)
Implements the client receive-side of SEP-2260: restricted server
requests (sampling/createMessage, roots/list, elicitation/create)
received while the client has no outbound request in flight are
answered with -32602 invalid params instead of being dispatched to the
handler. Gated on negotiated protocol >= 2026-07-28; ping is exempt.
With a request in flight we cannot tell which one the server request
belongs to (SEP-2260 defines no wire field), so this is a deliberate
under-approximation of the spec's SHOULD; exact stream-based
enforcement for streamable HTTP needs receive-side provenance plumbing
and is left as a follow-up.
---------
Co-authored-by: Alex Hancock <alexhancock@block.xyz>