Fix a lifecycle bug with server-everything in stdio mode #2848
+7
−3
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.
In STDIO mode, the server-everything server has a lifecycle issue that causes non-standard behavior. When a client calls
close()
, the timeouts are not cleaned up and so the process never exits.Description
Server Details
@modelcontextprotocol/server-everything
, fix exit/cleanup lifecycle.Motivation and Context
You can repro this with a minimal client:
You'll see the client is closed, but the process remains running because the child process's interval handlers have not been removed (
cleanup()
).I tried various things to fix this, e.g. sending a SIGINT/SIGTERM/SIGKILL to the child. However, the PID you see in the transport is the NPX process, not it's child (the MCP server).
E.g. launching via NPX neither this, nor a using SIGKILL, works (the pipes remain open and your process never exits):
(Notable the above code does work if the transport is connecting to
node everything/index.js
).This is non-standard for STDIO servers, I think. E.g. the first example works with a litany of other servers (including other examples in this repo like
sequential-thinking
). Presumably in STDIO mode, the parent process is the client (or at least proxying pipes to client). In any case, the client callingclose()
should result in termination of the everything MCP.How Has This Been Tested?
I tested this using the first minimal example above. The first example worked properly with local (non-NPX) invocation of server-everything in my branch, (whereas it did not work in
main
).I also verified that (when doing a local
node
invocation) the behavior of SIGINT remained the same.Breaking Changes
No breaking changes.
Types of changes
Checklist
Additional context