The server connects StdioServerTransport with no close/error handling, so when
the MCP client disconnects (session ends, or a client-side timeout tears down
the pipe) the Node process does not exit — it lingers, orphaned, holding a CDP
connection to Comet. These accumulate one per session/stall and are never
reaped.
Exit on transport close/error and on stdin end/close, with an idempotent
shutdown guard. Pure lifecycle change; no tool behavior is affected. In-flight
work is abandoned on client disconnect (correct: there is no client to return
it to). tsc is clean on this file (the two pre-existing cdp-client.ts errors
are unrelated and present on upstream main).
Problem
The server connects the stdio transport with no close/error handling:
When the MCP client disconnects — the session ends, or a long
comet_askbrowser-modal stall trips the client's timeout and it tears down the pipe — the stdio channel closes, but the Node process does not exit. It keeps running, orphaned and idle, holding a CDP connection to Comet.In practice these accumulate fast: on one machine, 7 → 34 orphaned
perplexity-comet-mcpprocesses were observed over three days, monotonically increasing, one per session/stall. They are never reaped, and the pileup correlates with mid-session connection drops (handle pressure).Root cause
A stdio MCP server's lifetime is bound to its stdin/stdout pipe to the client. When the client closes that pipe, the server should exit.
StdioServerTransportexposesonclose/onerror; this server wires neither, so a closed pipe is silently ignored and the event loop stays alive.Fix
Exit on transport close/error and on stdin end/close, with an idempotent guard:
Notes
tscis clean on this file. The two pre-existingcdp-client.tstype errors are unrelated and already present on upstreammain.Out of scope (happy to file separately)
The stalls themselves are triggered by
comet_askauto-rewriting prompts containing words likevisit/open/browse/page/.aiinto a "use your browser" form, which surfaces Perplexity's browser-control modal. This PR only stops the orphaned-process consequence so a stall can't leak a zombie.