Skip to content

fix(core): avoid quadratic copying and scanning in ReadBuffer (#2961) - #2965

Open
SuparvaCode wants to merge 1 commit into
modelcontextprotocol:mainfrom
SuparvaCode:fix/readbuffer-linear-append
Open

SuparvaCode wants to merge 1 commit into
modelcontextprotocol:mainfrom
SuparvaCode:fix/readbuffer-linear-append

Conversation

@SuparvaCode

@SuparvaCode SuparvaCode commented Oct 6, 2026 •

Copy link
Copy Markdown

Summary

Fixes #2961

ReadBuffer previously spent time quadratic in single message size when receiving large messages delivered across chunks:

  1. append(chunk) – repeatedly invoked Buffer.concat([this._buffer, chunk]), copying the entire accumulated buffer on every incoming chunk.
  2. readMessage() – repeatedly scanned from byte 0 with this._buffer.indexOf('\n') on every iteration before a complete delimiter was received.

For a 100 MB message in 64 KiB chunks, this resulted in ~80 GB of intermediate copying and hundreds of millions of redundant byte comparisons, taking ~38s on the event loop (and timing out clients in production).

Changes

  • Retain incoming chunks in an array (_chunks: Buffer[]) without intermediate copying.
  • Scan for delimiter (6x0a) only within newly appended chunks as they arrive.
  • Slice and concatenate only once when a complete newline-delimited message is ready to be deserialized.
  • Keep remaining bytes and subsequent chunks for following messages, continuing without rescanning.
  • Retain existing maxBufferSize guard and bounds checking behavior.
  • Add regression tests in packages/core-internal/test/shared/stdio.test.ts covering:
    • Streaming large messages delivered across thousands of small chunks without quadratic overhead.
    • Multiple complete messages delivered within a single chunk.
    • Consecutive messages split unevenly across arbitrary chunk boundaries.
    • Zero-length chunk handling.
  • Include patch changeset for @modelcontextprotocol/core-internal.

Verification

  • Ran @modelcontextprotocol/core-internal unit test suite (71 test files, 1,529 tests passed).
  • Built @mcp-examples/server-quickstart (tsc) with strict noUncheckedIndexedAccess.
  • Verified linear time benchmark: reading a 20 MB payload in 64 KiB chunks improved from 1,537 ms to 35 ms (~43x speedup).

…ontextprotocol#2961)

- Buffer chunks in an array instead of copying the whole accumulated buffer with Buffer.concat on every append.
- Inspect newly appended chunks for delimiters instead of repeatedly rescanning the entire buffer from offset 0.
- Slice and concatenate only when a complete newline-delimited message is ready.
- Add regression tests covering chunked message streaming, multi-message chunks, and uneven split boundaries.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Suparva <suparva@outlook.in>
@SuparvaCode
SuparvaCode requested a review from a team as a code owner October 6, 2026 10:57
@changeset-bot

changeset-bot Bot commented Oct 6, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ec31eab

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@modelcontextprotocol/core-internal Patch

Not sure what this means? Click here to learn what changesets are.

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

@pkg-pr-new

pkg-pr-new Bot commented Oct 6, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@2965

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@2965

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@2965

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@2965

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@2965

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@2965

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@2965

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@2965

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@2965

commit: ec31eab

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ReadBuffer: reading a single large stdio message takes time quadratic in its size

1 participant