modelcontextprotocol / modelcontextprotocol/java-sdk
McpClientSession/McpServerSession: pending response entries leak when a request times out or is cancelled
まだ誰も着手していません。
- 主要言語
- Java
- スター
- 3.7k
- フォーク
- 1.1k
- 平均マージ
- 1日 15時間
- マージ済み PR(30日)
- 9
説明
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.
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
まず McpClientSession.sendRequest と McpServerSession.sendRequest から始め、次に McpStreamableServerSession.McpStreamableServerSessionStream.sendRequest と比較します。指定された回帰テスト McpClientSessionTests を実行し、タイムアウトとキャンセルの経路について同等のカバレッジを追加します。どちらかの条件の後に pendingResponses が空であれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- java
- 領域
- api, backend, testing
- issue の種類
- バグ
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 活発さ
- 活発
- 明瞭さ
- 明確に書かれている
- 初心者へのやさしさ
- 35/100