Skip to content

[v1.x] fix(stdio): release consumed ReadBuffer storage - #2943

Open
sharifhsn wants to merge 1 commit into
modelcontextprotocol:v1.xfrom
sharifhsn:fix/v1-readbuffer-release-consumed-storage
Open

sharifhsn wants to merge 1 commit into
modelcontextprotocol:v1.xfrom
sharifhsn:fix/v1-readbuffer-release-consumed-storage

Conversation

@sharifhsn

@sharifhsn sharifhsn commented Oct 2, 2026 •

Copy link
Copy Markdown

A drained stdio reader retains the previous allocation through an empty buffer view. Clear that reference when no bytes remain so idle transports release the storage and the next append avoids Buffer.concat(). Non-empty remainders are preserved.

V1 counterpart to #2540, using its proposed empty-remainder handling.

Related to #2536.

Validation:

  • All nine CI checks pass, including the build, unit and end-to-end tests on Node 18 and 24, and client/server conformance.
  • Locally on Node 24.21.0, npm run check and npm run build pass; 1,855 unit tests pass with two workers.
  • The consumed-storage and next-chunk-copy regressions fail on base a8cf503 and pass here. The partial-message control passes on both.
  • All seven stdio end-to-end tests pass. With one worker, all 1,135 end-to-end assertions pass on both base and patch, but both commands exit nonzero with the same unhandled 200 ms protocol timeout. An initial two-worker run also hit an SSE max-total timing assertion.

AI-assisted with Codex.

@changeset-bot

changeset-bot Bot commented Oct 2, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 460ac99

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Oct 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@modelcontextprotocol/sdk@2943

commit: 460ac99

@sharifhsn
sharifhsn marked this pull request as ready for review October 2, 2026 20:03
@sharifhsn
sharifhsn requested a review from a team as a code owner October 2, 2026 20:03

Copy link
Copy Markdown

I found one remaining storage-retention case in this fix.

readMessage() now drops _buffer when the consumed line ends exactly at the buffer boundary, which fixes the fully-drained case. But when a large backing allocation contains a complete message followed by a tiny partial next message, this line still keeps a view into the original allocation:

const remainder = this._buffer.subarray(index + 1);
this._buffer = remainder.length === 0 ? undefined : remainder;

Because Buffer.subarray() shares the same ArrayBuffer, a few trailing bytes can pin the entire large allocation until more input arrives. The new partial-message test uses a normally-sized Buffer.from(...), so it doesn't exercise that retention case.

A regression test could allocate (for example) 64 KiB, place message + "\n" + partialNextMessage at the front, append a subarray of that allocation, consume the first message, and verify the retained remainder no longer shares/pins the 64 KiB backing store. One option is to compact/copy the remainder when the consumed prefix dominates the allocation, while keeping the zero-copy path for normal cases.

AI assistance was used to inspect the patch; this comment is scoped to the concrete backing-store retention behavior above.

@claude claude Bot added the v1 Issues / PRs related to v1.x label Oct 3, 2026

This branch has not been deployed

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

Labels

v1 Issues / PRs related to v1.x

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants