Skip to content

unified-mcp-server: make the response sink per-request (AsyncLocalStorage) #409

Description

@jobordu

Part of #408.

Why

send() (bin/unified-mcp-server.mjs:110) writes every response to process.stdout. That is correct for stdio, where one process serves one client, and impossible for HTTP, where one process serves many clients concurrently and each response must go back down its own request.

This is the prerequisite for the HTTP transport — nothing user-visible changes.

What

Carry the response sink per-request with AsyncLocalStorage:

const responseSink = new AsyncLocalStorage();
function send(obj) {
  const sink = responseSink.getStore();
  if (sink) sink(obj);
  else process.stdout.write(JSON.stringify(obj) + '\n');
}

Chosen over threading a sink argument through handleRequest() because all 15 response call sites funnel through send/sendResult/sendError — the async-local approach leaves every one of them untouched, so the diff is three functions rather than fifteen call sites plus a signature change.

Acceptance

  • stdio path byte-identical in behaviour; existing tests unchanged and passing
  • send() falls back to stdout when no sink is set (i.e. stdio mode)
  • a unit test proves two concurrent handleRequest calls with different sinks do not cross responses

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions