Skip to content

fix(mcp): ensure MCP transport is closed to prevent memory leaks#18054

Merged
jackwotherspoon merged 5 commits intogoogle-gemini:mainfrom
cbcoutinho:fix/mcp-transport-memory-leak
Feb 4, 2026
Merged

fix(mcp): ensure MCP transport is closed to prevent memory leaks#18054
jackwotherspoon merged 5 commits intogoogle-gemini:mainfrom
cbcoutinho:fix/mcp-transport-memory-leak

Conversation

@cbcoutinho
Copy link
Contributor

Summary

Fixes a memory leak where MCP server transports were never closed on disconnection, leaving event listeners and buffers running indefinitely. This eventually causes "JavaScript heap out of memory" errors in long-running sessions.

Related:

Root Cause

When MCP servers disconnect or encounter errors, the transport (Stdio/SSE/HTTP) was not being closed because:

  1. connectToMcpServer() only returned the Client, not the transport
  2. The transport reference was created locally and lost after connection
  3. McpClient.transport was declared but never assigned (always undefined)

This meant disconnect() checks if (this.transport) but it's always falsy, so transport cleanup never happened.

Changes

connectToMcpServer() Return Type

  • Changed from Promise<Client> to Promise<{client: Client, transport: Transport}>
  • All return paths now include the transport reference

McpClient.connect()

  • Destructures result: const { client, transport } = await connectToMcpServer(...)
  • Stores transport reference: this.transport = transport
  • Error handler now closes transport to prevent leaks on connection errors

connectAndDiscover()

  • Updated to handle the new return type
  • Added transport cleanup in error handler

Helper Functions

  • connectWithSSETransport() now returns the transport
  • retryWithOAuth() now returns the transport for proper lifecycle management

Test Plan

  • All existing tests pass (updated assertions to match new return type)
  • Added close mock to transport mock in disconnect test
  • Manual testing: Verified transport.close() is called on disconnect

Impact

This is a focused bug fix that:

  • Fixes memory leaks in long-running CLI sessions
  • Does not change any user-facing behavior
  • Has minimal surface area (localized to MCP client connection logic)

This PR was generated with the help of AI, and reviewed by a Human

@cbcoutinho cbcoutinho requested a review from a team as a code owner February 1, 2026 11:29
@google-cla
Copy link

google-cla bot commented Feb 1, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @cbcoutinho, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a significant memory leak within the MCP client by ensuring that underlying communication transports are properly closed when connections are terminated or encounter errors. By modifying the connection establishment process to retain and manage transport references, the system can now correctly deallocate resources, thereby preventing indefinite memory consumption and improving the stability of long-running CLI sessions.

Highlights

  • Memory Leak Fix: Addressed a critical memory leak in MCP server transports where event listeners and buffers were not being released upon disconnection or errors, leading to 'JavaScript heap out of memory' issues in long-running sessions.
  • Return Type Modification for connectToMcpServer(): The connectToMcpServer() function now returns both the Client instance and the Transport instance, ensuring that the transport reference is available for proper cleanup.
  • Enhanced McpClient.connect(): The McpClient.connect() method now stores the transport reference and includes logic to explicitly close the transport when connection errors occur, preventing resource accumulation.
  • Updated connectAndDiscover() and Helper Functions: The connectAndDiscover() function and helper functions like connectWithSSETransport() and retryWithOAuth() have been updated to handle the new return type and incorporate transport cleanup in their error handling paths.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@cbcoutinho cbcoutinho force-pushed the fix/mcp-transport-memory-leak branch from 80601f5 to efca517 Compare February 1, 2026 11:30
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively addresses a memory leak in the MCP client by ensuring the transport layer is properly closed on disconnection or error. The changes are well-structured, propagating the transport object through the connection logic so it can be managed correctly. The test updates are also appropriate. I've found one area with a redundant call to close the transport, which could be simplified to improve code clarity and prevent potential issues if the close method isn't idempotent. Overall, this is a solid fix for a critical issue.

@gemini-cli gemini-cli bot added priority/p2 Important but can be addressed in a future release. area/core Issues related to User Interface, OS Support, Core Functionality area/extensions Issues related to Gemini CLI extensions capability labels Feb 1, 2026
@cbcoutinho cbcoutinho force-pushed the fix/mcp-transport-memory-leak branch from 06c89f7 to 3a3eba1 Compare February 2, 2026 06:30
Root cause: When MCP servers disconnect or encounter errors, the transport
(Stdio/SSE/HTTP) was not being closed because:
1. `connectToMcpServer()` only returned the Client, not the transport
2. The transport reference was created locally and lost after connection
3. `McpClient.transport` was declared but never assigned

This caused event listeners and buffers to run indefinitely, eventually
causing "JavaScript heap out of memory" errors in long-running sessions.

Changes:
- `connectToMcpServer()` now returns `{client, transport}` instead of just `Client`
- `McpClient.connect()` stores the transport reference
- `McpClient.disconnect()` now properly closes the transport before the client
- Error handlers in both `McpClient` and `connectAndDiscover` now close
  the transport to prevent leaks on connection errors
- Helper functions `connectWithSSETransport()` and `retryWithOAuth()` now
  return the transport for proper lifecycle management

Addresses the memory leak fix from PR google-gemini#12801.
The SDK's Client.close() method already calls transport.close() internally,
making the explicit transport.close() call redundant. This addresses the
reviewer feedback about potentially calling close() twice on the transport.
@cbcoutinho cbcoutinho force-pushed the fix/mcp-transport-memory-leak branch from 3a3eba1 to d3c5a88 Compare February 2, 2026 06:32
@cbcoutinho
Copy link
Contributor Author

Hi @iqbalbhatti49 thanks for the approval - it appears that if I update the branch from upstream/main it requires re-approval. How would you like for me to keep this branch up-to-date in prep for being merged?

@jackwotherspoon jackwotherspoon added this pull request to the merge queue Feb 4, 2026
Merged via the queue into google-gemini:main with commit 821355c Feb 4, 2026
26 checks passed
sidwan02 pushed a commit to sidwan02/gemini-cli-gemma that referenced this pull request Feb 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Issues related to User Interface, OS Support, Core Functionality area/extensions Issues related to Gemini CLI extensions capability priority/p2 Important but can be addressed in a future release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants