You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When using local (stdio) MCP servers, Node.js emits the following warning:
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 drain listeners added to [WriteStream]. MaxListeners is 10. Use emitter.setMaxListeners() to increase limit
Root cause
In StdioClientTransport:
start() attaches permanent listeners to the stdio pipes:
this._process.stdin?.on("error", ...)this._process.stdout?.on("data", ...)this._process.stdout?.on("error", ...)this._process.stderr.pipe(this._stderrStream)// pipe() internally adds a "drain" listener
close() kills the process but doesn't remove any listeners:
asyncclose(){// ... kills the process ...// NO removeListener / off / unpipe here}
The pipe() call on stderr automatically adds a drain listener on the source stream to handle back-pressure. When the process is killed, this listener is orphaned.
Reproduction
Configure any local (stdio) MCP server that produces stderr output
Launch an MCP client (e.g., opencode TUI)
Observe the warning in stderr
Minimal MCP servers that don't produce stderr output don't trigger the warning. Real MCP servers (gitlab, google-workspace, etc.) that log to stderr do trigger it.
Cross-reference: see #780 for the same root cause reported from a different angle (JSON parse error after close). This issue documents the MaxListenersExceededWarning on drain listeners specifically.
I'll backport the fix to the v1.x line, mirroring the approach in #3073 (shared drain wait, settle-on-exit/close, close()-time listener detach and stderr unpipe). PR coming up against v1.x.
Update: the v1.x backport is ready (fix + six regression tests, ported from #3073's approach), but this repository allows contributors without write access only 1 open PR at a time and my #3091 is still open. I'll open the v1.x PR as soon as #3091 merges or closes; the branch is staged on my fork.
Activity
amd-clb commentedon Oct 22, 2026
Cross-reference: see #780 for the same root cause reported from a different angle (JSON parse error after close). This issue documents the
MaxListenersExceededWarningondrain listenersspecifically.fix(stdio): remove listeners in close() to prevent EventEmitter memor…
test(stdio): add regression test for listener cleanup in close()
fix(stdio): remove specific listeners in close(), keep no-op error ha…
test(stdio): fix regression tests to check correct stream and add loo…
suryakant-source commentedon Oct 24, 2026
I'll backport the fix to the v1.x line, mirroring the approach in #3073 (shared drain wait, settle-on-exit/close, close()-time listener detach and stderr unpipe). PR coming up against v1.x.
suryakant-source commentedon Oct 24, 2026
Update: the v1.x backport is ready (fix + six regression tests, ported from #3073's approach), but this repository allows contributors without write access only 1 open PR at a time and my #3091 is still open. I'll open the v1.x PR as soon as #3091 merges or closes; the branch is staged on my fork.