Skip to content

SEP-2260 follow-up: skip session tracking and the standalone GET stream at protocol >= 2026-07-28 #1108

Open

Description

@gocamille

Follow-up to #1033 / PR #1055.

PR #1055 makes the client reject SEP-2260-restricted requests that arrive on the standalone GET stream: the streamable HTTP transport marks inbound requests with an InboundStreamOrigin, the service layer turns that into a PeerRequestAssociation, and RoleClient::enforce_peer_request_association answers -32602 for Unassociated.

Rejecting is the right behavior for a server that sends such a request. But at protocol 2026-07-28 the client shouldn't have the stream in the first place. SEP-2567 removes sessions and SEP-2575 removes the standalone GET endpoint at that version, so an Mcp-Session-Id and a GET stream are both artifacts of a pre-2026-07-28 server shape. Keeping them open at 2026-07-28 means maintaining an inbound path whose only purpose is to be refused.

The modern path already gets this right. A server/discover startup sets session_id to None unconditionally (streamable_http_client.rs, ~L892), and there's a debug_assert! that discover bootstrap creates no session state (~L1054). What's left is the legacy-shaped paths, where a session id survives regardless of the version that was ultimately negotiated. spawn_common_stream has three call sites and all three are guarded only by if let Some(session_id), never by negotiated_version:

  • Legacy startup (~L969). A server that answers legacy initialize with both a session id and protocolVersion: 2026-07-28 gets a GET stream. This is the shape the e2e test in feat: SEP-2260 stream-based enforcement of client receive-side request association #1055 scripts deliberately.
  • Fallback initialize after server/discover fails (~L1382, on the initialized notification). Same shape, reached through ClientLifecycleMode::Auto.
  • Session re-establishment after an expired-session 404 (~L1218). Re-spawns on the new session id without reconsulting the version.

Work: gate session tracking and spawn_common_stream on negotiated_version < ProtocolVersion::STANDARD_HEADERS, so that at 2026-07-28 and later no session id is retained and no GET stream is opened. PeerRequestAssociation::Unassociated then becomes unreachable over streamable HTTP rather than merely rejected, and the enforcement from #1055 stays as the defense for anything that still slips through.

Two open questions worth settling in the same change:

  • What to do when a server returns a session id and negotiates 2026-07-28. Dropping the id silently is the least disruptive, but the server plainly expects it echoed back, so failing startup may be more honest than half-speaking its dialect.
  • Whether session cleanup (SessionCleanupInfo, the DELETE on shutdown) should also be skipped, or kept so a session the server did create still gets torn down.

This also bears on #863 (expose the negotiated Mcp-Session-Id): if there is deliberately no session at 2026-07-28, the accessor is a legacy-only affordance, and that's probably worth saying there either way.

Not a conformance gap — the receive-side check is a SHOULD and #1055 covers the scenarios — so this is hardening rather than a fix.

Activity

  1. added
    enhancementNew feature or request
    P2Medium: important but non-blocking improvement
    T-transportTransport layer changes
    on Aug 7, 2026
  2. github-actions commented on Oct 7, 2026

    @github-actions
    Contributor

    This issue has had no activity for 60 days and is now marked as stale. It will be closed in 14 days if there is no further activity. Add the keep label to keep it open.

  3. gocamille commented on Oct 15, 2026

    @gocamille
    ContributorAuthor

    #1256 implements this and is in review. It's currently waiting on a rebase for the MSRV fix (#1316). Keeping this open until that lands.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    2026-07-28P2Medium: important but non-blocking improvementT-transportTransport layer changesenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions