modelcontextprotocol / modelcontextprotocol/java-sdk

McpClientSession/McpServerSession: pending response entries leak when a request times out or is cancelled

Offen
#1,133 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

area/client area/server area/transport bug P2
Vorherrschende Sprache
Java
Sterne
3.7k
Forks
1.1k
Ø Merge
1 T. 15 Std.
Gemergte PRs (30 T.)
9

Beschreibung

Bug description

McpClientSession.sendRequest and McpServerSession.sendRequest put an entry into pendingResponses when a request is sent, but only remove it when a response arrives or the send itself fails. If the downstream .timeout(...) fires — or the caller cancels the Mono — no cleanup hook runs, so the entry stays in pendingResponses forever (request IDs are unique per request, so it is never overwritten).

The streamable variant already cleans up after its timeout (McpStreamableServerSession.McpStreamableServerSessionStream.sendRequest calls this.pendingResponses.remove(requestId) in a doOnError after .timeout(requestTimeout)), which suggests the legacy paths missing this is an oversight.

Amplifier

KeepAliveScheduler pings every session periodically via sendRequest(PING, ...). A dead or hung session therefore accumulates one leaked entry per ping interval on both the client and the server side; long-lived sessions grow unboundedly until close().

Suggested fix

Mirror the streamable pattern in both sendRequest methods:

.timeout(this.requestTimeout)
.doOnError(e -> this.pendingResponses.remove(requestId))
.doOnCancel(() -> this.pendingResponses.remove(requestId))
.handle(...)

Removal is idempotent, and the late-response path already tolerates a missing key.

I have the fix plus a regression test (testRequestTimeoutRemovesPendingResponse in McpClientSessionTests, asserting the map is empty after a timeout) ready and will open a PR referencing this issue.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit McpClientSession.sendRequest und McpServerSession.sendRequest und vergleiche sie anschließend mit McpStreamableServerSession.McpStreamableServerSessionStream.sendRequest. Führe den genannten Regressionstest McpClientSessionTests aus und füge eine gleichwertige Abdeckung für Timeout- und Abbruchpfade hinzu; abgeschlossen ist die Aufgabe, wenn pendingResponses nach einer der beiden Bedingungen leer ist.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
java
Bereich
api, backend, testing
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Aktiv
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.