Skip to content

Fix stdio frame interleaving under backpressure - #266

Draft
rohitsalla wants to merge 1 commit into
modelcontextprotocol:mainfrom
rohitsalla:fix/stdio-send-serialization
Draft

Fix stdio frame interleaving under backpressure#266
rohitsalla wants to merge 1 commit into
modelcontextprotocol:mainfrom
rohitsalla:fix/stdio-send-serialization

Conversation

@rohitsalla

Copy link
Copy Markdown

Fixes #263

Summary

  • Serialize StdioTransport.send() calls in FIFO order.
  • Keep the existing nonblocking partial-write and EAGAIN retry behavior.
  • Add a regression test that forces pipe backpressure and verifies concurrent sends preserve newline-delimited frame boundaries.

Root cause

StdioTransport is an actor, but its write loop suspends while retrying EAGAIN. Actor reentrancy allowed a second send() call to write while the first frame was only partially written, splicing one JSON-RPC frame into another.

Each send now waits for the previously enqueued send to complete before entering the write loop. A failed send does not prevent later queued sends from running.

Verification

  • Real nonblocking-pipe reproduction before the change: ordered=false, with the second frame's newline inside the first payload.
  • The same reproduction after the change: ordered=true, first newline at the expected 524288-byte boundary.
  • The production module compiled successfully through the reproduction executable.
  • git diff --check passes.

The full swift test target could not run locally because the installed macOS Command Line Tools lack the repository's existing Testing module and have a Swift compiler/SDK patch mismatch. The pull request CI matrix provides the required Swift 6.1 macOS and Linux coverage.

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.

StdioTransport.send() still interleaves concurrent sends under EAGAIN backpressure — #252 was closed without a merged fix

1 participant