modelcontextprotocol/typescript-sdk

StdioClientTransport.close() doesn't terminate child processes, causing memory leaks

Closed this issue · 2 comments

The StdioClientTransport.close() method doesn't properly terminate spawned child processes, causing
memory leaks in applications that frequently connect/disconnect from STDIO MCP servers.

In client/stdio.js, the close() method only aborts the spawn signal and nullifies the process
reference, but doesn't actually kill the running child process:

async close() {
    this._abortController.abort();  // Only prevents new spawns
    this._process = undefined;      // Just removes reference
    this._readBuffer.clear();
}

To Reproduce

  FOR 1000 times:
      transport = new StdioClientTransport(server_command)
      client = new Client()

      client.connect(transport)  // spawns child process
      pid = transport.pid

      client.close()             // BUG: doesn't kill child process

      // Process with 'pid' is still running (memory leak)

  // Result: 1000 orphaned processes still running

Expected behavior
When close() is called, the spawned child process should be terminated to prevent resource leaks.

Thanks for raising this 🙏.

From my understanding, AbortController should terminate the spawned process, so I wasn’t able to reproduce the memory leak.

Could you please clarify how you verified that the child processes are still running after close()?

Maybe I’m missing a detail in your repro steps.

This is a false alarm, the memory leak actually came from the MCP server I'm testing against. Sorry about that.