Skip to content

DefaultMcpTransportSession#closeGracefully leaks resources on incomplete DELETE response #547

Description

@1256064203

Bug description
When the MCP server is abnormal, the statement this.onClose.apply(this.sessionId.get()) in the closeGracefully method of DefaultMcpTransportSession.java throws an exception, so this.openConnections::dispose is never executed and may leak resources.

Environment
Java version: 21
mcp-bom: 0.11.3

Steps to reproduce
1、Create an McpSyncClient.
2、Execute client.initialize(); client.listTools();
3、Suspend the debugger at client.closeGracefully();
4、Make the MCP server unavailable.
5、Resume execution of client.closeGracefully();

Expected behavior
this.openConnections::dispose should always be executed.

Minimal Complete Reproducible example
McpSyncClient client = McpClient.sync(transport)
.requestTimeout(Duration.ofSeconds(10))
.build();

// Initialize connection
client.initialize();

// List available tools
ListToolsResult tools = client.listTools();

// Close client
client.closeGracefully();

Activity

  1. JunJieLiu51520 commented on Sep 22, 2025

    @JunJieLiu51520
    Contributor

    Can you take a screenshot of the leaked stack trace? from this code, i think it won't be happed

    Image
  2. CnLight commented on Sep 27, 2025

    @CnLight

    Image this worker will be close but selector always running, the way of close can not shutdown the httpclient

  3. chemicL commented on Feb 20, 2026

    @chemicL
    Member

    Is this perhaps related to the inability to close the HttpClient properly in Java 17?

  4. chemicL commented on Feb 20, 2026

    @chemicL
    Member

    An estensive analysis was published in the duplicate issue: #620 (comment)

  5. added
    bugSomething isn't working
    P2Moderate issues affecting some users, edge cases, potentially valuable feature
    and removed
    bugSomething isn't working
    waiting for userWaiting for user feedback or more details
    on Feb 20, 2026
  6. added theissue type on Feb 20, 2026
  7. andersenleo commented on Aug 24, 2026

    @andersenleo

    #566 covers the case where the DELETE fails. It does not cover the case where the DELETE never answers, and that is the one that leaks.

    closeGracefully() is:

    return Mono.from(this.onClose.apply(this.sessionId.get()))
        .then(Mono.fromRunnable(this.openConnections::dispose));

    #566 wraps the first stage in onErrorResume and keeps the .then(...). A DELETE that hangs signals no error, so dispose() is never reached.

    There is no second chance either. HttpClientStreamableHttpTransport.closeGracefully() replaces activeSession with a closed session before it awaits the close, so once the close stops progressing, the session holding the Disposable is unreachable. Each occurrence strands one SSE subscription and its socket. On one of our production pods that came to roughly 1,400 stranded outbound sockets over a business day.

    Easy to reproduce: point the transport at a stub that returns the DELETE response headers and never completes the body. closeGracefully() does not return and openConnections is never disposed.

    Two ways to fix it, as far as I can see: a timeout on the onClose publisher plus an unconditional dispose, or dispose before attempting the DELETE. We run the first against 1.1.0, with dispose on success, error, timeout and cancellation.

    If you take the timeout route, cancelling that Mono does not leave the exchange running: reactor's MonoCompletionStage calls future.cancel(true) and the JDK forwards it to the exchange, which closes the connection. Two things that tripped us up while verifying that. isCancelled() stays false afterwards, because what gets stored is a CompletionException wrapping the cancellation. And fromFuture versus fromCompletionStage makes no difference here, both pass suppressCancellation=false in reactor-core 3.8.4.

    Happy to send the test, either as a PR here or into #566.

  8. changed the title [-]DefaultMcpTransportSession.java closeGracefully may leak resources[/-] [+]DefaultMcpTransportSession#closeGracefully leaks resources on incomplete DELETE[/+] on Aug 27, 2026
  9. changed the title [-]DefaultMcpTransportSession#closeGracefully leaks resources on incomplete DELETE[/-] [+]DefaultMcpTransportSession#closeGracefully leaks resources on incomplete DELETE response[/+] on Aug 27, 2026
  10. self-assigned this
    on Aug 27, 2026
  11. added this to the 2.1.0 Planning milestone on Aug 27, 2026
  12. Kehrlann commented on Aug 27, 2026

    @Kehrlann
    Contributor

    Hey @andersenleo thanks for the extra info (great writeup!)

    Please shared the test as a snippet directly in this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Moderate issues affecting some users, edge cases, potentially valuable featurebugSomething isn't working

Type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions