Skip to content

feat(mcp): Implement MCP sampling support with transport memory leak fix#12801

Closed
cbcoutinho wants to merge 13 commits intogoogle-gemini:mainfrom
cbcoutinho:fix/mcp-memory-leak-sampling-issues
Closed

feat(mcp): Implement MCP sampling support with transport memory leak fix#12801
cbcoutinho wants to merge 13 commits intogoogle-gemini:mainfrom
cbcoutinho:fix/mcp-memory-leak-sampling-issues

Conversation

@cbcoutinho
Copy link
Copy Markdown
Contributor

@cbcoutinho cbcoutinho commented Nov 9, 2025

Summary

  • Implements MCP sampling support with user approval dialog
  • Fixes memory leak from unclosed MCP server transports on disconnection
  • Adds integration test for MCP sampling flow

Addresses:

MCP Spec:

Changes

MCP Sampling Feature

Implements the Model Context Protocol sampling capability, allowing MCP servers to request LLM completions from the client with user approval (human-in-the-loop pattern).

Core Implementation (packages/core/src/tools/mcp-client.ts):

  • Advertises sampling: {} capability to MCP servers
  • Implements CreateMessageRequestSchema handler for sampling requests
  • Handles message content parsing (text/image/audio types per MCP spec)
  • Converts between MCP message format and Gemini API format
  • Maps Gemini response back to MCP format (role, content, model, stopReason)
  • Resolves model "auto" to concrete model name before API calls

UI Integration (packages/cli/src/ui):

  • New McpSamplingDialog component with RadioButtonSelect for approval
  • Event-driven architecture via CoreEvent.McpSamplingRequest
  • State management in AppContainer with wrapped callbacks
  • Dialog rendered through DialogManager
  • Properly coordinates with InputPrompt terminal state

Configuration:

  • Added --auto-confirm-mcp-sampling CLI flag for testing/automation
  • Config option autoConfirmMcpSampling to bypass user prompts

Memory Leak Fix

Root Cause: MCP server transports were never closed on disconnection, leaving event listeners and buffers running indefinitely, eventually causing "JavaScript heap out of memory" errors.

Fix (packages/core/src/tools/mcp-client.ts):

  • Changed connectToMcpServer() to return {client, transport} instead of just client
  • Store transport reference in McpClient class
  • Call transport.close() in disconnect() and error handlers
  • Updated all callers to destructure both client and transport

Test Updates

Integration Test (integration-tests/mcp-sampling.test.ts):

  • New test with mock MCP server that requests sampling
  • Validates request/response format per MCP spec
  • Uses --auto-confirm-mcp-sampling flag

Unit Tests (packages/core/src/tools/mcp-client.test.ts):

  • Updated transport mocks to include close() method

Events Tests (packages/core/src/utils/events.ts):

  • Fixed backlog FIFO logic to match upstream (shift oldest when at capacity)

Bug Fixes

  • Fixed FallbackModeChangedPayload to use isInFallbackMode property (matching upstream)
  • Fixed EventEmitter type overloads with explicit signatures
  • Removed invalid constructor listener that broke backlog tests

Test Plan

  • Build passes (npm run build)
  • All tests pass (npm run test:ci)
  • Integration test validates MCP sampling flow
  • Memory leak fixed (transports properly cleaned up on disconnect)
  • UI dialog properly coordinates with terminal input state
  • Manual testing: Connect MCP server with sampling, verify approval dialog works
  • Manual testing: Reject sampling request, verify server receives rejection
  • Manual testing: Disconnect MCP server, verify no memory leak over time

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 November 9, 2025 23:49
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Nov 9, 2025

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
Copy Markdown
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 introduces significant enhancements to the Model Context Protocol (MCP) integration by adding support for MCP sampling, which enables external MCP servers to request LLM completions from the client. A key aspect of this feature is the implementation of a user approval dialog, ensuring that users retain control over these requests. Concurrently, a critical memory leak related to unclosed MCP server transports has been addressed, improving the stability and performance of the system. These changes are supported by new configuration options, a dedicated UI component, and comprehensive integration tests.

Highlights

  • MCP Sampling Implementation: Added support for Model Context Protocol (MCP) sampling, allowing MCP servers to request LLM completions from the client with user approval (human-in-the-loop pattern).
  • Memory Leak Fix: Resolved a memory leak issue where unclosed MCP server transports were not properly disconnected, leading to resource exhaustion and 'JavaScript heap out of memory' errors.
  • User Approval Dialog: Introduced a new UI component (McpSamplingDialog) for user approval of sampling requests, ensuring human-in-the-loop interaction before LLM calls are made.
  • CLI Configuration for Sampling: Added a --auto-confirm-mcp-sampling CLI flag and corresponding configuration option to bypass user prompts for testing or automation purposes.
  • Integration Testing: Included a new integration test to validate the end-to-end MCP sampling flow, including the mock MCP server and client interaction.
  • Event System Enhancements: Updated the core event system to handle MCP sampling requests and fixed a bug in the feedback backlog FIFO logic, ensuring proper event handling and message delivery.
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.

Copy link
Copy Markdown
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 introduces MCP sampling support, a significant feature that allows MCP servers to request LLM completions from the client. The implementation is well-structured, including a user approval dialog in the CLI and a corresponding --auto-confirm-mcp-sampling flag for automated testing.

Crucially, this PR also addresses a critical memory leak by ensuring MCP server transports are properly closed on disconnection or error. The changes to return and manage the transport object from connectToMcpServer are clean and effectively solve the reported "JavaScript heap out of memory" issue.

The addition of an integration test for the new sampling flow is excellent and ensures the feature is robust.

My review has identified one high-severity issue related to duplicated code in the command-line argument parsing, which should be addressed.

Comment thread packages/cli/src/config/config.ts Outdated
@cbcoutinho cbcoutinho force-pushed the fix/mcp-memory-leak-sampling-issues branch 3 times, most recently from 1051c8b to 8790b2f Compare November 10, 2025 00:04
@cbcoutinho
Copy link
Copy Markdown
Contributor Author

Fixed the duplicate auto-confirm-mcp-sampling option definitions. The option was accidentally duplicated 7 times due to a copy-paste error during commit amendments. Removed 6 duplicate definitions, keeping only the first one.

@jackwotherspoon
Copy link
Copy Markdown
Collaborator

Thanks for this @cbcoutinho 👏

For changes this large we require an issue first to discuss best approach usually, is there an open issue or FR for MCP sampling that this PR links to?

Are you able to also to provide a screencast of this in action? Would be great to see how it works with an example 😄

@cbcoutinho
Copy link
Copy Markdown
Contributor Author

cbcoutinho commented Nov 10, 2025

Hi @jackwotherspoon ,

Thanks! I've now linked the relevant open issues for MCP sampling in the PR description. Since they were quiet, I took a shot at the implementation. Happy to move the technical discussion to whichever issue you'd like to consolidate on.

I'll add a screencast later this evening. My use case is an MCP server that supports sampling for RAG (summarizing results from a vector DB query), and the screencast will show gemini-cli handling the sampled prompt requests from it.

@cbcoutinho
Copy link
Copy Markdown
Contributor Author

cbcoutinho commented Nov 10, 2025

Howdy @jackwotherspoon, the attached link shows a screencast demonstrating the MCP sampling feature introduced by this PR. This enables MCP servers to leverage the existing LLM within gemini-cli to generate responses to user prompts without having to maintain a separate connection for generative tasks.

In the example asciinema recording, I have an MCP server that includes a vector database to support semantic queries, and pre-loaded it with some documents about the National Park Service and various National Parks in the US. The nc_semantic_search_answer tool takes a user query, generates the embedding associated with the query and does a similar search against the vector database to find related documents. Rather than returning the documents themselves and potentially filling up the context, the MCP server uses sampling to generate a summary of the documents using the MCP Client's LLM, returning a summary of the documents that addresses the user query.

https://asciinema.org/a/YlEZapOSLEV4RbHii9uyXLJ5E

Flow Overview

  1. Document Indexing: The MCP server has been pre-loaded with documents that are stored in a vector database

  2. Query Processing: A semantic search/answer tool accepts a user query and generates an embedding

  3. Vector Search: The embedding is used to search for related documents in the vector database, which returns ranked candidates based on semantic similarity

  4. MCP Sampling: The MCP server then samples (i.e., prompts) Gemini to synthesize and summarize the ranked candidates

  5. Sampling Consent: Gemini prompts the user with the sampling request, which the user can accept/reject.

  6. Enhanced Response: After accepting the sampling request and returning a summary, the MCP server returns the generated response in addition to the sources utilized when generating the summary.

This demonstrates how Gemini supports MCP sampling, enabling AI-powered synthesis of retrieved context, providing users with coherent answers rather than just document references.

sequenceDiagram
    participant Client as MCP Client<br/>(Gemini CLI)
    participant Server as MCP Server<br/>(Nextcloud)
    participant VectorDB as Vector DB<br/>(Qdrant)
    participant LLM as LLM<br/>(Gemini 2.5 Flash)

    Client->>Server: (1) nc_semantic_search_answer("What are my Q1 goals?")
    
    Server->>VectorDB: (2) Vector search for similar docs
    VectorDB-->>Server: (3) Top K docs<br/>[note, event, card, file]
    
    Server->>Client: (4) MCP Sampling Request<br/>create_message(messages=[{<br/>role: "user",<br/>content: "Query + Docs"<br/>}])
    
    Client->>LLM: (5) Forward prompt + docs to LLM
    
    Note over LLM: (6) Generate answer<br/>with citations
    
    LLM-->>Client: (7) Generated answer<br/>"Based on Doc 1 (note: Project)...<br/>Doc 2 (event)..."
    
    Client-->>Server: (8) Sampling Response<br/>(answer + model info)
    
    Server-->>Client: (9) Final Response<br/>{<br/>generated_answer,<br/>sources: [...],<br/>model_used<br/>}
Loading

Adds comprehensive support for MCP (Model Context Protocol) sampling,
allowing MCP servers to request LLM completions through Gemini CLI. This
enables MCP tools to leverage AI capabilities for processing and
analyzing data.

Key Features:
- Implement sampling request/response handling in MCP client
- Add McpSamplingDialog component for user consent and progress
- Integrate sampling workflow with event system and UI state management
- Add comprehensive integration tests for sampling scenarios

UI Improvements:
- Make consent screen scrollable for better UX with long prompts
- Fix MarkdownDisplay width to ensure proper text wrapping
- Implement proper cleanup of consent prompts on dialog close

Bug Fixes:
- Close sampling dialog properly on server timeout
- Fix build errors related to upstream merges
- Ensure proper event handler cleanup to prevent memory leaks

Technical Changes:
- Enhanced mcp-client.ts with sampling support and event emission
- Updated events.ts with new sampling-related event types
- Modified UIStateContext to manage sampling dialog state
- Added McpSamplingDialog component with progress indicators
- Created integration tests covering various sampling scenarios

Files Modified:
- packages/core/src/tools/mcp-client.ts (sampling logic)
- packages/core/src/utils/events.ts (event types)
- packages/cli/src/ui/components/McpSamplingDialog.tsx (new)
- integration-tests/mcp-sampling.test.ts (new)
- Various UI components for integration
@cbcoutinho cbcoutinho force-pushed the fix/mcp-memory-leak-sampling-issues branch from 9bb2577 to e971fdf Compare November 16, 2025 06:25
@cbcoutinho
Copy link
Copy Markdown
Contributor Author

Hi @jackwotherspoon, I've updated this branch to correctly handle large prompt requests and provide scrolling.

Screencast.From.2025-11-16.10-01-31.mp4

@cbcoutinho
Copy link
Copy Markdown
Contributor Author

Hi @jackwotherspoon - is there still interest in this feature? I'm trying to keep the branch up to date with upstream/main but there seems to be quite a bit of activity in the mcp-client.ts and events.ts files.

Any guidance about getting this merged into gemini-cli?

@jackwotherspoon
Copy link
Copy Markdown
Collaborator

Hey @cbcoutinho sorry for the delay here! Definitely still interested in this 👍

Been a busy couple weeks with most of the team working towards the Gemini 3 launch and now it being US thanksgiving week a lot of folks are on holidays.

I can take a quick look today or tomorrow and then can have an expert take a look next week 😄

@elliette
Copy link
Copy Markdown

elliette commented Dec 9, 2025

Hi! Wanted to chime in that over on Dart & Flutter DevTools we are eagerly watching this PR and hoping it lands. This would be very helpful for us to begin integrating AI assistance into DevTools that works with Gemini CLI. See flutter/devtools#9570 for details.

cbcoutinho and others added 3 commits December 13, 2025 14:00
# Conflicts:
#	packages/core/src/tools/mcp-client-manager.ts
#	packages/core/src/tools/mcp-client.test.ts
#	packages/core/src/tools/mcp-client.ts
#	packages/core/src/utils/events.ts
Merge upstream/main into MCP sampling branch
Add the 'type' field to SETTINGS_SCHEMA_DEFINITIONS for MCPServerConfig
to match the actual TypeScript type definition in core/config.ts.

This field was added to MCPServerConfig class in commit bdbbe92 but
was not included in the JSON schema definition. The field allows users
to specify transport type ('sse' or 'http') when using the 'url' field,
with auto-detection as fallback.
@cbcoutinho cbcoutinho force-pushed the fix/mcp-memory-leak-sampling-issues branch from 11d6c1c to e207c47 Compare December 13, 2025 13:36
@cbcoutinho
Copy link
Copy Markdown
Contributor Author

Hi @jackwotherspoon I've updated this branch based on upstream/main so it should be ready now for review. Looking forward to your feedback 🙏

cbcoutinho and others added 5 commits December 13, 2025 15:51
- Add 5-minute timeout to sampling consent promise to prevent memory leaks
  when dialog is closed without user response
- Improve McpSamplingDialog formatting to show messages with role labels
  instead of raw JSON
- Fix MCP role mapping: map 'assistant' to 'model' for Gemini compatibility
- Fix incomplete test mocks by adding required Config methods

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, the Scrollable component would auto-scroll to the bottom on
initial render due to the isAtBottom check triggering when size changed
from the initial zero values. This caused the MCP sampling dialog to show
the end of long prompts first, requiring users to scroll up.

Add hasInitializedRef to track first render and only maintain scroll
position at bottom after initial render. This allows dialogs to start
at the top so users can read prompts from the beginning and scroll down
as needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The register callback was creating a new Map on every call, even when
re-registering the same entry ID. This caused React to see a state
change and re-render all children, which in turn triggered more
register calls, creating an infinite re-render loop.

Fix by checking if the entry ID already exists - if so, update the
entry in-place without creating a new Map reference. This prevents
unnecessary state updates and stops the flickering.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Wrap mouse event handlers in useCallback to prevent constant
  re-subscription in useMouse hook, which was causing UI flickering
- Increase scroll step from 1 to 3 lines per scroll event for
  smoother trackpad and mouse wheel scrolling
- Update tests to account for the new scroll step

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@gemini-cli gemini-cli Bot added status/need-issue Pull requests that need to have an associated issue. and removed status/need-issue Pull requests that need to have an associated issue. labels Jan 7, 2026
@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 labels Jan 8, 2026
@bdmorgan
Copy link
Copy Markdown
Collaborator

Hi @cbcoutinho, thank you so much for your contribution to Gemini CLI! We really appreciate the time and effort you've put into this.

We're making some updates to our contribution process to improve how we track and review changes. Please take a moment to review our recent discussion post: Improving Our Contribution Process & Introducing New Guidelines.

Key Update: Starting January 26, 2026, the Gemini CLI project will require all pull requests to be associated with an existing issue. Any pull requests not linked to an issue by that date will be automatically closed.

Thank you for your understanding and for being a part of our community!

@cbcoutinho
Copy link
Copy Markdown
Contributor Author

cbcoutinho commented Jan 15, 2026

Hi @bdmorgan this PR is associated with an issue, but was closed by your bot a few days ago due to inactivity.

It's my understanding that this feature is generally desirable by both users and colleagues of yours.

Please confirm if this is still the case, otherwise I can close it

@jackwotherspoon
Copy link
Copy Markdown
Collaborator

@cbcoutinho Yes I am going to review again, we definitely want this 😄

Thanks for the patience.

Do you mind trying to fix the merge conflicts and sign the CLA?

Will take a look.

Resolve merge conflicts:
- packages/cli/src/config/config.ts: Keep auto-confirm-mcp-sampling option
- packages/cli/src/gemini.tsx: Use non-nullable settings access with type assertion
- packages/cli/src/ui/AppContainer.tsx: Keep MCP sampling handler
- packages/cli/src/ui/contexts/UIStateContext.tsx: Add AuthState and ActiveHook imports
- packages/core/src/tools/mcp-client.ts: Keep cliConfig parameter for sampling support
- packages/core/src/tools/mcp-client.test.ts: Add sanitizationConfig to mockConfig
- packages/cli/src/config/settingsSchema.ts: Remove duplicate 'type' key in MCP config

Co-Authored-By: Claude <noreply@anthropic.com>
@cbcoutinho cbcoutinho requested a review from a team as a code owner January 16, 2026 13:41
@bdmorgan bdmorgan linked an issue Jan 16, 2026 that may be closed by this pull request
cbcoutinho and others added 2 commits January 18, 2026 22:22
…th headers

Two fixes for MCP client:

1. Race condition fix: MCP servers start asynchronously during initialization
   and are not awaited. If tool discovery completes before geminiClient.initialize(),
   the setTools() call in the finally block is skipped because isInitialized()
   returns false. This causes MCP tools to be registered but never sent to the
   Gemini API. Fix by calling setTools() after geminiClient.initialize() completes.

2. Auth header precedence: When an Authorization header is explicitly configured
   (e.g., via --header flag), respect it instead of overwriting with stored OAuth
   tokens. This allows users to manually configure authentication for MCP servers
   that require custom auth mechanisms.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolved conflict in packages/core/src/config/config.ts:
- Kept autoConfirmMcpSampling feature from our branch
- Adopted upstream's refactored hooks handling that extracts the
  disabled property

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@cbcoutinho cbcoutinho force-pushed the fix/mcp-memory-leak-sampling-issues branch from d35d497 to b93e9c6 Compare January 19, 2026 07:18
@cbcoutinho
Copy link
Copy Markdown
Contributor Author

cbcoutinho commented Jan 19, 2026

Hi @jackwotherspoon the PR is merge-conflict free and ready for review.

The reason the CLA is failing is because the CI workflow is detecting Claude Code as a co-author. I will update the commits shortly so that they only contain my username, but in terms of content I consider this PR complete

cc @bdmorgan

Copy link
Copy Markdown
Collaborator

@jackwotherspoon jackwotherspoon left a comment

Choose a reason for hiding this comment

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

Alright I took a first pass here.

Thanks for this awesome PR @cbcoutinho 👍

Couple things of note:

  • Seems like a lot of changes to the scrollable UI components, are those necessary?
  • Can we extract the sampling logic from mcp-client.ts into its own named function so we don't bloat connectToMcpServer.
  • Not sure we want to be adding a top-level flag for auto approving sampling (i think we'd rather follow-up with integrating it into our policy engine or something of the like)

Comment thread package-lock.json
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can we remove the package-lock.json changes, they aren't needed

Comment on lines +252 to +256
})
.option('auto-confirm-mcp-sampling', {
type: 'boolean',
description: 'Automatically confirm all MCP sampling requests.',
hidden: true,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We try and keep our top level CLI flags clean.

I see this is hidden, yet I would still prefer we not add this.

I think ideally we find a way to add sampling to our policy engine for users to provide a way to blanket allow.

Probably a follow-up PR though. I would just remove flag from initial implementation unless you have reservations with doing so.

https://geminicli.com/docs/core/policy-engine/#special-syntax-for-mcp-tools

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is a good point regarding keeping top-level CLI flags clean, even if hidden. I agree that integrating sampling into the policy engine for blanket allowance is a more robust and scalable solution. I'll remove this flag for now and create a follow-up task to explore the policy engine integration. Thanks for the suggestion and the link to the policy engine documentation!

Suggested change
})
.option('auto-confirm-mcp-sampling', {
type: 'boolean',
description: 'Automatically confirm all MCP sampling requests.',
hidden: true,
})

incrementalRendering:
settings.merged.ui.incrementalRendering !== false && useAlternateBuffer,
},
} as RenderOptions & { incrementalRendering?: boolean },
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is this related to sample...?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

mind explaining the changes to this file?

maybe this was added as part of a merge conflict or is there reason for the scrollable?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

again this seems kind of odd to change in this PR...

});

// Timeout for sampling consent dialog (5 minutes)
const SAMPLING_CONSENT_TIMEOUT_MS = 5 * 60 * 1000;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe move this to top of file alongside MCP_DEFAULT_TIMEOUT_MSEC

clearTimeout(timeoutId);
resolve();
},
reject: (_reason?: unknown) => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Any reason for ignoring the outer reason here?

// Timeout for sampling consent dialog (5 minutes)
const SAMPLING_CONSENT_TIMEOUT_MS = 5 * 60 * 1000;

mcpClient.setRequestHandler(CreateMessageRequestSchema, async (req) => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we maybe move this to a named function so it keeps connectToMcpServer a little more lean?

That way we can test more easily in isolation.

Maybe something like:

  // At top of file or in a logical section
  async function handleSamplingRequest(
    req: CreateMessageRequest,
    serverName: string,
    cliConfig: Config,
  ): Promise<CreateMessageResult> {
    // All the sampling logic here
  }

@gemini-cli gemini-cli Bot added the area/extensions Issues related to Gemini CLI extensions capability label Jan 19, 2026
@bdmorgan
Copy link
Copy Markdown
Collaborator

Thank you for submission to the Gemini CLI project. At this time, we are closing this pull request in order to allow us to better triage and support more recent pull requests against the latest code changes. If you feel like this pull request is a critical contribution to the Gemini CLI project, please associate the pull request with an existing GitHub issue (instructions here: https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue) before reopening. After Monday January 26 2026, any pull requests submitted by contributors without an associated issue will be automatically closed (more information here: #16706). If you do choose to reopen and submit this pull request, please ensure you rebase your changes onto the current main branch before resubmitting. This will help avoid merge conflicts and ensure your contribution is compatible with the latest codebase.

@bdmorgan bdmorgan closed this Jan 23, 2026
cbcoutinho added a commit to cbcoutinho/gemini-cli that referenced this pull request Jan 24, 2026
- Remove --auto-confirm-mcp-sampling CLI flag (use env var for testing)
- Extract sampling handler to named function createSamplingRequestHandler()
- Move SAMPLING_CONSENT_TIMEOUT_MS constant to top of file
- Fix ignored reason parameter in reject callback
- Update integration test to use GEMINI_AUTO_CONFIRM_MCP_SAMPLING env var
- Remove autoConfirmMcpSampling from Config interface and implementation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
cbcoutinho added a commit to cbcoutinho/gemini-cli that referenced this pull request Feb 1, 2026
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.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
cbcoutinho added a commit to cbcoutinho/gemini-cli that referenced this pull request Feb 1, 2026
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.
cbcoutinho added a commit to cbcoutinho/gemini-cli that referenced this pull request Feb 2, 2026
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.
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.

Support MCP Sampling

4 participants