diff --git a/src/integration-tests/process-cleanup.test.ts b/src/integration-tests/process-cleanup.test.ts new file mode 100644 index 00000000..0dd7861a --- /dev/null +++ b/src/integration-tests/process-cleanup.test.ts @@ -0,0 +1,28 @@ +import { Server } from "../server/index.js"; +import { StdioServerTransport } from "../server/stdio.js"; + +describe("Process cleanup", () => { + jest.setTimeout(5000); // 5 second timeout + + it("should exit cleanly after closing transport", async () => { + const server = new Server( + { + name: "test-server", + version: "1.0.0", + }, + { + capabilities: {}, + } + ); + + const transport = new StdioServerTransport(); + await server.connect(transport); + + // Close the transport + await transport.close(); + + // If we reach here without hanging, the test passes + // The test runner will fail if the process hangs + expect(true).toBe(true); + }); +}); \ No newline at end of file diff --git a/src/server/stdio.ts b/src/server/stdio.ts index f0eff82c..30c80012 100644 --- a/src/server/stdio.ts +++ b/src/server/stdio.ts @@ -62,8 +62,19 @@ export class StdioServerTransport implements Transport { } async close(): Promise { + // Remove our event listeners first this._stdin.off("data", this._ondata); this._stdin.off("error", this._onerror); + + // Check if we were the only data listener + const remainingDataListeners = this._stdin.listenerCount('data'); + if (remainingDataListeners === 0) { + // Only pause stdin if we were the only listener + // This prevents interfering with other parts of the application that might be using stdin + this._stdin.pause(); + } + + // Clear the buffer and notify closure this._readBuffer.clear(); this.onclose?.(); }