Skip to content

Improve handling non-compliant Notification responses  #586

Closed

Description

@hbsjz-swl

Bug description
Line 505 of io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport. If the result of responseEvent conversion is as follows: AggregateResponseEvent[responseInfo=jdk.internal.net.http.ResponseInfoImpl@67d15067, data=], the obtained data is an empty string. The Utils.hasText method does not recognize empty strings, resulting in an error:

io.modelcontextprotocol.spec.McpTransportException: Error deserializing JSON-RPC message: AggregateResponseEvent[responseInfo=jdk.internal.net.http.ResponseInfoImpl@5e431139, data=]
	at io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport.lambda$sendMessage$27(HttpClientStreamableHttpTransport.java:515) ~[mcp-core-0.13.1.jar:0.13.1]
	at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:388) ~[reactor-core-3.7.9.jar:3.7.9]
	at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:251) ~[reactor-core-3.7.9.jar:3.7.9]
	at reactor.core.publisher.FluxCreate$BufferAsyncSink.drain(FluxCreate.java:880) ~[reactor-core-3.7.9.jar:3.7.9]
	at reactor.core.publisher.FluxCreate$BufferAsyncSink.next(FluxCreate.java:805) ~[reactor-core-3.7.9.jar:3.7.9]
	at reactor.core.publisher.FluxCreate$SerializedFluxSink.next(FluxCreate.java:163) ~[reactor-core-3.7.9.jar:3.7.9]
	at io.modelcontextprotocol.client.transport.ResponseSubscribers$AggregateSubscriber.hookOnComplete(ResponseSubscribers.java:263) ~[mcp-core-0.13.1.jar:0.13.1]
	at reactor.core.publisher.BaseSubscriber.onComplete(BaseSubscriber.java:197) ~[reactor-core-3.7.9.jar:3.7.9]

Environment
Mcp Client: SpringBoot 3.5.5 SpringAI 1.1.0-M2
Mcp Java SDK: 0.13.1
Mcp Server: Python FastMCP

Expected behavior
Hopefully, the Utils.hasText() method can be used to recognize empty strings and return Mono.empty() to avoid errors.

Image

Activity

  1. tzolov commented on Oct 1, 2025

    @tzolov
    Contributor

    @hbsjz-swl I'm not sure that this is the real issue because we have tests for the Utils.hasText() to validate correct behavior for empty strings.

    Can you try to reproduce this issue with a test please?

  2. hbsjz-swl commented on Oct 1, 2025

    @hbsjz-swl
    ContributorAuthor

    @hbsjz-swl I'm not sure that this is the real issue because we have tests for the Utils.hasText() to validate correct behavior for empty strings.

    Can you try to reproduce this issue with a test please?

    Hi @tzolov ,
    My apologies for the confusion in my initial report. Thank you for your patience. I've pinpointed the exact issue, and it's a logic bug, not a problem with Utils.hasText().
    The problem is located in HttpClientStreamableHttpTransport.java at line 506:
    code

    if (sentMessage instanceof McpSchema.JSONRPCNotification && Utils.hasText(data)) {
        logger.warn("Notification: {} received non-compliant response: {}", sentMessage, data);
        return Mono.empty();
    }
    

    This code correctly handles non-compliant responses for a Notification only if the response has text.
    However, in my case, the server sends back an empty string "" as the response. For an empty string, Utils.hasText(data) returns false, causing the entire if condition to fail. The code then proceeds to the next line, passing the empty string to the JSON parser, which results in a JsonParseException.
    According to the JSON-RPC specification, a Notification should not receive a response at all. Therefore, any response, including an empty one, should be treated as non-compliant and handled gracefully.
    The fix would be to remove the && Utils.hasText(data) check, so that any response to a Notification is caught.
    Suggested Fix:
    code

    // Before

    if (sentMessage instanceof McpSchema.JSONRPCNotification && Utils.hasText(data)) {
    

    // After

    if (sentMessage instanceof McpSchema.JSONRPCNotification) {
    

    or

    if (sentMessage instanceof McpSchema.JSONRPCNotification && (Utils.hasText(data) || data.isBlank())) {
    

    This change would ensure that both non-empty and empty responses to a Notification are correctly handled by returning Mono.empty(), preventing the crash.
    Could you please take a look at this specific logic? Thanks!

  3. self-assigned this
    on Oct 1, 2025
  4. added this to the 0.14.0 milestone on Oct 1, 2025
  5. changed the title [-]The hasText method in the io.modelcontextprotocol.util.Utils tool cannot recognize empty strings[/-] [+]Improve handling non-compliant Notification responses [/+] on Oct 1, 2025
  6. tzolov commented on Oct 1, 2025

    @tzolov
    Contributor

    @hbsjz-swl I've updated the title to better reflect the issue you are describing.
    Also I would call it a bug as this is a non-compliant Notification responses that the server shouldn't have sent.
    Anyway I believe we can improve the condition to tolerate such server discrepancy.

  7. added a commit that references this issue on Oct 1, 2025
    82be0e1
  8. added a commit that references this issue on Oct 1, 2025
    3f7578b
  9. hbsjz-swl commented on Oct 2, 2025

    @hbsjz-swl
    ContributorAuthor

    @tzolov,
    Thank you for your quick follow-up and fix! Your description is correct. I've seen the relevant commit and PR (#589). Thank you for taking the suggestion and improving the SDK to better handle these noncompliant server responses. I look forward to the new version release!

  10. added a commit that references this issue on Jun 25, 2026
    7f007e3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions