Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {

// The spec mentions only ACCEPTED, but the existing SDKs can return
// 200 OK for notifications
if (response.statusCode().is2xxSuccessful()) {
if (is2xx(response)) {
Optional<MediaType> contentType = response.headers().contentType();
long contentLength = response.headers().contentLength().orElse(-1);
// Existing SDKs consume notifications with no response body nor
Expand Down Expand Up @@ -384,14 +384,15 @@ private Flux<McpSchema.JSONRPCMessage> extractError(ClientResponse response, Str
}
catch (IOException ex) {
toPropagate = new McpTransportException("Sending request failed, " + e.getMessage(), e);
logger.debug("Received content together with {} HTTP code response: {}", response.statusCode(), body);
logger.debug("Received content together with {} HTTP code response: {}", response.rawStatusCode(),
body);
}

// Some implementations can return 400 when presented with a
// session id that it doesn't know about, so we will
// invalidate the session
// https://github.com/modelcontextprotocol/typescript-sdk/issues/389
if (responseException.getStatusCode().isSameCodeAs(HttpStatus.BAD_REQUEST)) {
if (isBadRequest(responseException)) {
if (!sessionRepresentation.equals(MISSING_SESSION_ID)) {
return Mono.error(new McpTransportSessionNotFoundException(sessionRepresentation, toPropagate));
}
Expand All @@ -411,16 +412,8 @@ private Flux<McpSchema.JSONRPCMessage> eventStream(McpTransportStream<Disposable
return Flux.from(sessionStream.consumeSseStream(idWithMessages));
}

private static boolean isNotFound(ClientResponse response) {
return response.statusCode().isSameCodeAs(HttpStatus.NOT_FOUND);
}

private static boolean isNotAllowed(ClientResponse response) {
return response.statusCode().isSameCodeAs(HttpStatus.METHOD_NOT_ALLOWED);
}

private static boolean isEventStream(ClientResponse response) {
return response.statusCode().is2xxSuccessful() && response.headers().contentType().isPresent()
return is2xx(response) && response.headers().contentType().isPresent()
&& response.headers().contentType().get().isCompatibleWith(MediaType.TEXT_EVENT_STREAM);
}

Expand Down Expand Up @@ -572,4 +565,32 @@ public WebClientStreamableHttpTransport build() {

}

/**
* Needed for Spring 5 compatibility
*/
private static boolean isBadRequest(final WebClientResponseException responseException) {
return responseException.getRawStatusCode() == HttpStatus.BAD_REQUEST.value();
}

/**
* Needed for Spring 5 compatibility
*/
private static boolean isNotFound(ClientResponse response) {
return response.rawStatusCode() == HttpStatus.NOT_FOUND.value();
}

/**
* Needed for Spring 5 compatibility
*/
private static boolean isNotAllowed(ClientResponse response) {
return response.rawStatusCode() == HttpStatus.METHOD_NOT_ALLOWED.value();
}

/**
* Needed for Spring 5 compatibility
*/
private static boolean is2xx(final ClientResponse response) {
return response.rawStatusCode() >= 200 && response.rawStatusCode() < 300;
}

}