-
Notifications
You must be signed in to change notification settings - Fork 497
Adding StreamableHttpServerTransportProvider class and unit tests #290
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
base: main
Are you sure you want to change the base?
Adding StreamableHttpServerTransportProvider class and unit tests #290
Conversation
...ain/java/io/modelcontextprotocol/server/transport/StreamableHttpServerTransportProvider.java
Outdated
Show resolved
Hide resolved
...ain/java/io/modelcontextprotocol/server/transport/StreamableHttpServerTransportProvider.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey 👋 Thanks for a comprehensive PR! I did my first round focusing on the main themes. Happy to offer guidance to cover the essential aspects (simple/stateful servers, multiple streams per session, lifecycle) if you'd like to push this forward.
...ain/java/io/modelcontextprotocol/server/transport/StreamableHttpServerTransportProvider.java
Outdated
Show resolved
Hide resolved
...ain/java/io/modelcontextprotocol/server/transport/StreamableHttpServerTransportProvider.java
Outdated
Show resolved
Hide resolved
...ain/java/io/modelcontextprotocol/server/transport/StreamableHttpServerTransportProvider.java
Outdated
Show resolved
Hide resolved
...ain/java/io/modelcontextprotocol/server/transport/StreamableHttpServerTransportProvider.java
Show resolved
Hide resolved
...ain/java/io/modelcontextprotocol/server/transport/StreamableHttpServerTransportProvider.java
Outdated
Show resolved
Hide resolved
...ain/java/io/modelcontextprotocol/server/transport/StreamableHttpServerTransportProvider.java
Outdated
Show resolved
Hide resolved
...ain/java/io/modelcontextprotocol/server/transport/StreamableHttpServerTransportProvider.java
Outdated
Show resolved
Hide resolved
AsyncContext asyncContext = request.startAsync(); | ||
asyncContext.setTimeout(0); // No timeout | ||
|
||
StreamableHttpSseStream sseStream = getOrCreateSseStream(sessionId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here the spec is being slightly violated IMO. We should aim to respect the MAY keyword to the best of our ability. The responses should go on a dedicated SSE stream if a stream is to be used, not the one opened initially with GET. The free hanging GET stream is meant for notifications or requests from the server. The SSE events that deal with the originating request should be sent over the stream associated with this request.
Here's some explanation from the specification on POST:
If the server initiates an SSE stream:
...
The server MAY send JSON-RPC requests and notifications before sending a JSON-RPC response.
These messages SHOULD relate to the originating client request.
These requests and notifications MAY be [batched](https://www.jsonrpc.org/specification#batch).
The server SHOULD NOT close the SSE stream before sending a JSON-RPC response
per each received JSON-RPC request, unless the [session](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#session-management) expires
and for GET:
If the server initiates an SSE stream:
The server MAY send JSON-RPC requests and notifications on the stream.
These requests and notifications MAY be [batched](https://www.jsonrpc.org/specification#batch).
These messages SHOULD be unrelated to any concurrently-running JSON-RPC request from the client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment:
We can probably just add a single stream session for GET requests into the StreamableHttpSession class. I can add that to my list today.
// Create or get SSE stream for this session | ||
StreamableHttpSseStream sseStream = getOrCreateSseStream(sessionId); | ||
if (lastEventId != null) { | ||
sseStream.replayEventsAfter(lastEventId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I understand it, in case of resumption, once the final response is streamed, the SSE stream should be closed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either client or server can close it at any time. Should we add a timer of sorts to hold the stream open and have it default to end right after stream completes?
...ain/java/io/modelcontextprotocol/server/transport/StreamableHttpServerTransportProvider.java
Outdated
Show resolved
Hide resolved
String lastEventId = request.getHeader(LAST_EVENT_ID_HEADER); | ||
|
||
// Create or get SSE stream for this session | ||
StreamableHttpSseStream sseStream = getOrCreateSseStream(sessionId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resumption needs to happen on a brand new SSE stream, otherwise the client is unable to distinguish between different streams.
...ain/java/io/modelcontextprotocol/server/transport/StreamableHttpServerTransportProvider.java
Outdated
Show resolved
Hide resolved
Thank you very much for all of the input @chemicL! I will begin making changes accordingly this afternoon. |
…b.com/ZachGerman/mcp-java-sdk into StreamableHttpServerTransportProvider
…b.com/ZachGerman/mcp-java-sdk into StreamableHttpServerTransportProvider
Today I'm targeting origin header validation and moving the dedicated GET stream to the StreamableHttpSession class, then adding an integ test for GET on /mcp to start the listening stream. |
Hi @ZachGerman I tried using your StreamableHttpServerTransportProvider.java file + java MCP SDK 0.10.0. My backend server is Jetty 12. The request from MCP Interceptor hangs in the below call. return streamSession.handle(message).then(Mono.just(responseType)).onErrorReturn(ResponseType.IMMEDIATE); This is the actuall line which gets blocked Can you please check this? |
@ZachGerman what do you mean by |
Still missing:
Motivation and Context
Trying to reach spec parity with TS and Python for Java. Will continue working on other aspects of this.
How Has This Been Tested?
Unit tests and integ tests using a partially-complete sHTTP client transport class, but I didn't include the integ test file as the client isn't complete.
Breaking Changes
N/A
Types of changes
Checklist
Additional context
This is part of a larger commit seen here: #289