{{ message }}
Repository navigation
Conversation
jest-environment-node builds its own sandbox and does not forward Node's web-stream globals into it, so eventsource-parser -- which @eko-ai/eko pulls in -- threw "TransformStream is not defined" at import time. Every test in this package failed before its first line ran, including the existing test/mcp.test.ts. Install ReadableStream, TransformStream and WritableStream from node:stream/web in a setup file, leaving any real globals in place.
A stdout "data" event is a chunk of bytes, not a JSON-RPC message. SimpleStdioMcpClient read each chunk as exactly one message, so a response split across two chunks made JSON.parse throw out of the stream listener -- an uncaught exception, since no request promise is on that stack -- and a chunk carrying two messages, or a log line next to a message, lost the response entirely and left the caller hanging. Buffer the tail of an incomplete line and hand complete lines to one parser that skips non-JSON output and logs an unparseable line instead of throwing. An end-of-stream flush keeps a final message that a server wrote without a trailing newline, which the old per-chunk read handled by accident. Fixes FellouAI#276
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Fixes #276.
The bug
A stdout
dataevent is a chunk of bytes, not a JSON-RPC message.SimpleStdioMcpClientread each chunk as exactly one message:Three things go wrong with a real MCP server:
JSON.parsethrows on the first half. It throws inside a stream listener, where no request promise is on the stack, so it surfaces as an uncaught exception and takes the process down.sendMessagehanging forever.{, so the whole chunk is skipped and the answer is lost.Large responses and rapid-fire servers hit this routinely; on small, slow ones the chunks happen to line up and nothing looks wrong.
The fix
Buffer the tail of an incomplete line and hand only complete lines to one parser. That parser keeps the existing "ignore non-JSON output" rule per line, and logs an unparseable line instead of throwing, since a throw there has no caller to catch it.
One extra case: the old per-chunk read accepted a final message written without a trailing newline, because it never waited for a delimiter. A strict line reader would swallow it, so the end-of-stream handler flushes whatever is left. No behaviour a working server relied on is lost.
Tests
test/mcp-stdio-framing.test.tsspawns a small fixture server (test/fixtures/chunked-mcp-server.mjs) that answers over a real pipe with deliberately misaligned writes — one message torn in half, two messages in one write, a log line beside a message, a broken line beside a message, and an unterminated final message. No mocking; the failures are the real ones.Against
main's parser 4 of the 5 fail; the fifth is the unterminated-message case, which the old code passed by accident and the end-of-stream flush keeps passing. Each piece of the fix was also checked on its own: dropping the try/catch fails exactly the broken-line test, dropping the end-of-stream flush fails exactly the unterminated-message test, and reading only the first line of each chunk fails the three tests about batched chunks.Why the first commit is there
The package's tests could not run at all before this.
jest-environment-nodebuilds its own sandbox and does not forward Node's web-stream globals, soeventsource-parser— which@eko-ai/ekopulls in — threwReferenceError: TransformStream is not definedat import time, before the first line of any test. That hits the existingtest/mcp.test.tstoo. The setup file installsReadableStream,TransformStreamandWritableStreamfromnode:stream/weband leaves any real globals alone.npx tsc -p tsconfig.test.json --noEmitis clean. Tested on macOS, Node 24.