Skip to content

SSEClientTransport doesn't re-establish lifecycle state on disconnect/reconnect #510

@BobDickinson

Description

@BobDickinson

I am writing an SSE proxy (using this library, including the SSEServerTransport) and struggling with what I assess as some bad client behavior caused by the standard libraries (including SSEClientTransport).

A client will connect and initialize, and send some number of requests receiving responses (notifications, etc). All great so far. When that connection goes away (long timeout, server restart, etc), the EventSource used by the SSE client re-establishes a new session with the server via the event source fetch method (calling the SSE url endpoint, typically /sse, and getting a new /messages endpoint for a new session). The problem is that the client does not then re-initialize to establish proper lifecycle state - it assumes the server somehow understands that it has already initialized and just starts blasting requests, which fail (the server requires an initialize message exchange to initialize the new session before it can accept requests).

I'm going by the lifecycle documentation provided here: https://modelcontextprotocol.io/specification/2025-03-26/basic/lifecycle

My reading of that and my understanding of how the MCP SSE protocol works indicate that if you make a new SSE endpoint request (/sse), that starts a new session, and you need to start the protocol again (initialize) with the /messages endpoint you get back (which is associated with that new session). I see no other way that multiple clients (or even multiple client connection instances from a single client) could use the same SSE server endpoint. In terms of trying to work around this on my server/proxy, I also see no reliable way to associate a client on a new connection with a previous session (especially while avoiding punishing a client who behaved correctly and re-initialized the new connection).

If my assessment is correct, and essentially all SSE clients in the wild do not correctly re-establish sessions on reconnect, then I'm not sure how a multi-user or multi-client SSE server can be made to work, at least if it implements the protocol lifecycle properly.

The fix to the client library for this is pretty straightforward, but it doesn't address the fact that all clients currently in the wild (many of which won't update anytime soon) aren't going to work in some common scenarios using SSE servers.

If anyone is curious, this is the basic new connection logic (more or less as advised):

app.get('/sse', async (req: Request, res: Response) => {
  const transport = new SSEServerTransport('/messages', res);
  activeSessions.set(transport.sessionId, transport);
  // This will  return the new endpoint with the new session id
  await transport.start(); 
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions