Skip to content

server: support distributed sessions #232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

jba
Copy link
Contributor

@jba jba commented Aug 4, 2025

  • SessionState holds the state of a ServerSession.

  • SessionStore allows arbitrary storage for SessionState.

  • ServerSession.InitSession provides a session ID, store and state to a ServerSession.

For #148

@joshwlewis
Copy link

This looks right to me -- session state is the correct thing to store rather than a transport.

Should this be implemented for the SSE transport as well?

BC-ACherednichenko pushed a commit to BC-ACherednichenko/go-sdk that referenced this pull request Aug 5, 2025
Copy link

@BC-ACherednichenko BC-ACherednichenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Session change LGTM, just one minor question about NewStreamableServerTransport

jba added 3 commits August 9, 2025 12:43
- SessionState holds the state of a ServerSession.

- SessionStore allows arbitrary storage for SessionState.

- ServerSession.InitSession provides a session ID, store and state
  to a ServerSession.
findleyr added a commit to findleyr/go-sdk that referenced this pull request Aug 9, 2025
Support stateless streamable sessions by adding a GetSessionID function
to StreamableHTTPOptions. If GetSessionID returns "", the session is
stateless, and no validation is performed. This is implemented by
providing the session a trivial initialization state.

To implement this, some parts of modelcontextprotocol#232 (distributed sessions) are copied
over, since they add an API for creating an already-initialized session.

In total, the following new API is added:
- StreamableHTTPOptions.GetSessionID
- ServerSessionOptions (a new parameter to Server.Connect)
- ServerSessionState
- ClientSessionOptions (a new parameter to Client.Connect, for symmetry)

For modelcontextprotocol#10
findleyr added a commit to findleyr/go-sdk that referenced this pull request Aug 9, 2025
Support stateless streamable sessions by adding a GetSessionID function
to StreamableHTTPOptions. If GetSessionID returns "", the session is
stateless, and no validation is performed. This is implemented by
providing the session a trivial initialization state.

To implement this, some parts of modelcontextprotocol#232 (distributed sessions) are copied
over, since they add an API for creating an already-initialized session.

In total, the following new API is added:
- StreamableHTTPOptions.GetSessionID
- ServerSessionOptions (a new parameter to Server.Connect)
- ServerSessionState
- ClientSessionOptions (a new parameter to Client.Connect, for symmetry)

For modelcontextprotocol#10

Co-Authored-By: 36760115+ln-12@users.noreply.github.com
findleyr added a commit to findleyr/go-sdk that referenced this pull request Aug 9, 2025
Support stateless streamable sessions by adding a GetSessionID function
to StreamableHTTPOptions. If GetSessionID returns "", the session is
stateless, and no validation is performed. This is implemented by
providing the session a trivial initialization state.

To implement this, some parts of modelcontextprotocol#232 (distributed sessions) are copied
over, since they add an API for creating an already-initialized session.

In total, the following new API is added:
- StreamableHTTPOptions.GetSessionID
- ServerSessionOptions (a new parameter to Server.Connect)
- ServerSessionState
- ClientSessionOptions (a new parameter to Client.Connect, for symmetry)

For modelcontextprotocol#10

Co-Authored-By: 36760115+ln-12@users.noreply.github.com
@jba jba marked this pull request as draft August 11, 2025 16:41
@jba
Copy link
Contributor Author

jba commented Aug 11, 2025

I've converted this to draft status. I don't think we fully understand what it means to have a distributed server.

For example, if a server receives a request and then sends a nested request back, how can we be sure that the same server process will receive the reply? I don't think having a session store helps with that problem. So we're going to wait until this gets resolved in the specification.

@BC-ACherednichenko
Copy link

BC-ACherednichenko commented Aug 11, 2025

@jba what do you mean by sends nested request back? my understanding of the spec is that it is potentially possible to operate in both streamable and simple request/response modes, as long as session is distributed and transport does not assume streams only that should be compatible, right?

@jba
Copy link
Contributor Author

jba commented Aug 11, 2025

what do you mean by sends nested request back?

  1. client -> CallTool -> server (a POST)
  2. server -> Sampling -> client (via the SSE stream that's part of the POST connection)
  3. client -> Sampling response -> server (separate POST)

What if the server in step 1 is in a different process from the server in step 3?

@BC-ACherednichenko
Copy link

server -> Sampling -> client (via the SSE stream that's part of the POST connection)

I think these are essentially two different modes, stremableHTTP and stremableHTTP + SSE, SSE is optional according to the spec, hence, the concrete servers using SDK which dont utilise SSE may omit that part completely.

when it comes to the stremableHTTP + SSE and the provided use-case, regardless of session storage there is also resumability aspect, hence the server needs to have the ability to replay messages based on "Last-event-id" when resume request from the client arrives, as the result in multi container server setup (where is more than one instance of MCP server in a cluster), I think we will need to provide an interface or a fallback so it is possible to replay these messages, something like RMQ.

The protocol itself omits the details on mechanism for message replay, but on the interface level they assume resumability to be functional if I read it correctly, expecting the request to land on the same server limits the implemtation options to sticky session on the edge.

findleyr added a commit to findleyr/go-sdk that referenced this pull request Aug 11, 2025
Support stateless streamable sessions by adding a GetSessionID function
to StreamableHTTPOptions. If GetSessionID returns "", the session is
stateless, and no validation is performed. This is implemented by
providing the session a trivial initialization state.

To implement this, some parts of modelcontextprotocol#232 (distributed sessions) are copied
over, since they add an API for creating an already-initialized session.

In total, the following new API is added:
- StreamableHTTPOptions.GetSessionID
- ServerSessionOptions (a new parameter to Server.Connect)
- ServerSessionState
- ClientSessionOptions (a new parameter to Client.Connect, for symmetry)

For modelcontextprotocol#10

Co-Authored-By: 36760115+ln-12@users.noreply.github.com
Copy link

@BC-ACherednichenko BC-ACherednichenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI I checked most recent updates on the branch - it looks fully functional now 👍

@6juara9
Copy link

6juara9 commented Aug 11, 2025

I'd like to include a small flow diagram as well, and I'm curious if you agree with its representation 🙂

image

cc: @jba

@jba
Copy link
Contributor Author

jba commented Aug 11, 2025

server -> Sampling -> client (via the SSE stream that's part of the POST connection)

I think these are essentially two different modes, stremableHTTP and stremableHTTP + SSE, SSE is optional according to the spec, hence, the concrete servers using SDK which dont utilise SSE may omit that part completely.

You could say that distributed servers must not initiate SSE streams, but then they couldn't even send things like progress notifications and log messages. So you'd have to say that they don't send nested requests. That seems like a very strange restriction, and I'm not sure how you'd enforce it.

All the discussion about resumability is irrelevant to this point. There may be separate issues there, but I think this one is enough of a concern that I'd like to wait for clarity in the specification before pursuing this.

@jba
Copy link
Contributor Author

jba commented Aug 11, 2025

See #148.

@findleyr
Copy link
Contributor

See also my comment here: #148 (comment)

(Sorry that the conversation is split between that issue and this PR).

jba pushed a commit that referenced this pull request Aug 11, 2025
Support stateless streamable sessions by adding a GetSessionID function
to StreamableHTTPOptions. If GetSessionID returns "", the session is
stateless, and no validation is performed. This is implemented by
providing the session a trivial initialization state.

To implement this, some parts of #232 (distributed sessions) are copied
over, since they add an API for creating an already-initialized session.

In total, the following new API is added:
- StreamableHTTPOptions.GetSessionID
- ServerSessionOptions (a new parameter to Server.Connect)
- ServerSessionState
- ClientSessionOptions (a new parameter to Client.Connect, for symmetry)

For #10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants