modelcontextprotocol / modelcontextprotocol/java-sdk
McpClientSession/McpServerSession: pending response entries leak when a request times out or is cancelled
Nessuno ha ancora preso questa issue.
- Lingua principale
- Java
- Stelle
- 3.7k
- Fork
- 1.1k
- Merge medio
- 1g 15h
- PR unite (30g)
- 9
Descrizione
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.
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia con McpClientSession.sendRequest e McpServerSession.sendRequest, quindi confrontali con McpStreamableServerSession.McpStreamableServerSessionStream.sendRequest. Esegui il test di regressione McpClientSessionTests indicato e aggiungi una copertura equivalente per i percorsi di timeout e cancellazione; il lavoro è completato quando pendingResponses è vuoto dopo una delle due condizioni.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- java
- Ambito
- api, backend, testing
- Tipo di issue
- Bug
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Stato di attività
- Attiva
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 35/100