Skip to content

feat: add distributed Streamable HTTP event store#1024

Open
DaleSeo wants to merge 1 commit into
mainfrom
agent/distributed-event-store
Open

feat: add distributed Streamable HTTP event store#1024
DaleSeo wants to merge 1 commit into
mainfrom
agent/distributed-event-store

Conversation

@DaleSeo

@DaleSeo DaleSeo commented Jul 22, 2026

Copy link
Copy Markdown
Member

Closes #330

Motivation and Context

The load-balancing problem described in #330 has largely been addressed by stateless operation, the removal of sessions from the latest protocol lifecycle, and SessionStore-based restoration for legacy sessions. Stateless operation removes most cross-instance session routing, but it does not preserve an in-flight SSE response when the original connection or server instance disappears.

This PR closes that remaining gap with a shared EventStore. Event IDs are globally unique and identify their stream without a session ID, so another server instance can replay missed events from Last-Event-ID. Stateless handlers continue writing their response to the shared store after the original HTTP connection is dropped, and the client can reconnect without Mcp-Session-Id. Legacy session-based replay continues to use the same event-store contract.

How Has This Been Tested?

  • Added a cross-instance legacy-session replay test.
  • Added a stateless test that disconnects after a progress event, lets the original handler finish into the shared store, shuts down that instance, and replays the final response from another instance.
  • Added client tests for sessionless reconnect and for refusing to reconnect before an event ID exists.
  • Ran the Streamable HTTP disconnect, JSON response, priming, stale-session, event-store, unit, and doctest suites locally.

Breaking Changes

  • StreamableHttpClient::get_stream and get_stream_with_max_sse_event_size now receive Option<Arc<str>> for the session ID. Custom HTTP client implementations must handle None for stateless replay.
  • LocalSessionManager and NeverSessionManager no longer implement UnwindSafe or RefUnwindSafe because they contain an optional Arc<dyn EventStore>. Code that captures either manager across std::panic::catch_unwind must provide its own assertion or avoid that boundary.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@github-actions github-actions Bot added T-documentation Documentation improvements T-dependencies Dependencies related changes T-test Testing related changes T-config Configuration file changes T-core Core library changes T-transport Transport layer changes and removed T-documentation Documentation improvements labels Jul 22, 2026
@DaleSeo
DaleSeo force-pushed the agent/distributed-event-store branch 2 times, most recently from bde88eb to 4321381 Compare July 22, 2026 17:57
@DaleSeo DaleSeo self-assigned this Jul 22, 2026
@DaleSeo
DaleSeo marked this pull request as ready for review July 22, 2026 18:26
@DaleSeo
DaleSeo requested a review from a team as a code owner July 22, 2026 18:26
@DaleSeo
DaleSeo force-pushed the agent/distributed-event-store branch from 4321381 to 0a103b4 Compare July 22, 2026 22:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-config Configuration file changes T-core Core library changes T-dependencies Dependencies related changes T-test Testing related changes T-transport Transport layer changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HTTP 401 Unauthorized errors and connection drops when running MCP server behind Azure Load Balancer

1 participant