Skip to content

fix(core): shorten MCP tools/list discovery timeout so it fails fast#28410

Open
sahilempire wants to merge 1 commit into
google-gemini:mainfrom
sahilempire:fix/mcp-discovery-timeout
Open

fix(core): shorten MCP tools/list discovery timeout so it fails fast#28410
sahilempire wants to merge 1 commit into
google-gemini:mainfrom
sahilempire:fix/mcp-discovery-timeout

Conversation

@sahilempire

@sahilempire sahilempire commented Jul 15, 2026

Copy link
Copy Markdown

Summary

The MCP tools/list discovery request could silently freeze the CLI for 10
minutes at startup when a server did not answer it (for example, replying with a
mismatched JSON-RPC id). This gives tools/list discovery a short default
timeout so it fails fast.

Details

tools/list discovery reused MCP_DEFAULT_TIMEOUT_MSEC (10 minutes), the
default meant for long-running tool invocations. It was the only discovery call
that passed that 10-minute value. When a server's response is ignored per
JSON-RPC (mismatched id), the request stays pending for the full timeout with no
spinner or warning, then disconnects.

This adds MCP_DISCOVERY_TIMEOUT_MSEC (10s) and uses it as the default for the
tools/list discovery calls (both the live discoverInto path and the
standalone connectAndDiscover path). It is only a default: an explicit
per-server timeout still wins, so a deliberately slow server keeps its
configured value. The failure is reported through the existing MCP diagnostic
channel, which now fires within 10s instead of 10 minutes.

Scope and trade-offs

This is deliberately limited to the tools/list discovery request, which is the
one call that used the 10-minute default:

  • prompts/list and resources/list do not pass this default; they already use
    the MCP SDK default (60s), so they were never part of the 10-minute freeze.
  • The connection handshake (connect / initialize) and the tool-invocation
    timeout are intentionally unchanged. The handshake is a separate failure mode
    and touches the OAuth/SSE paths, so it is out of scope for this fix.
  • A server whose tools/list legitimately takes longer than the default and has
    no explicit timeout set will be skipped for that session. The escape hatch
    is the existing per-server timeout setting, which still takes precedence.

Related Issues

Fixes #28355

How to Validate

  1. Configure an MCP server that never answers tools/list, or answers with a
    mismatched JSON-RPC id.
  2. Start the CLI.
    • Before: discovery hangs about 10 minutes with no feedback.
    • After: discovery gives up in about 10 seconds and the MCP diagnostic
      surfaces the failure.
  3. Set an explicit timeout for that server and confirm discovery honors it.

Unit tests:

npm test -w @google/gemini-cli-core -- src/tools/mcp-client.test.ts
  • tools/list discovery uses the 10s default when no per-server timeout is set
  • tools/list discovery honors an explicit per-server timeout

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed). Not needed, there
    is no user-facing setting or docs change.
  • Added/updated tests
  • Noted breaking changes (none)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

Validated on macOS via the core unit test suite (the change is
platform-independent timeout logic). Not manually exercised on Windows, Linux,
or the container and sandbox launchers.

@github-actions github-actions Bot added the size/m A medium sized PR label Jul 15, 2026
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

📊 PR Size: size/M

  • Lines changed: 143
  • Additions: +138
  • Deletions: -5
  • Files changed: 2

@gemini-cli gemini-cli Bot added priority/p1 Important and should be addressed in the near term. area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality labels Jul 15, 2026
@sahilempire sahilempire force-pushed the fix/mcp-discovery-timeout branch from 15f131c to 942de53 Compare July 15, 2026 20:51
@sahilempire sahilempire changed the title fix(core): bound MCP tool discovery timeout so a stuck server fails fast fix(core): shorten MCP tools/list discovery timeout so it fails fast Jul 15, 2026
@sahilempire sahilempire marked this pull request as ready for review July 15, 2026 21:18
@sahilempire sahilempire requested a review from a team as a code owner July 15, 2026 21:18
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

🛑 Action Required: Evaluation Approval

Steering changes have been detected in this PR. To prevent regressions, a maintainer must approve the evaluation run before this PR can be merged.

Maintainers:

  1. Go to the Workflow Run Summary.
  2. Click the yellow 'Review deployments' button.
  3. Select the 'eval-gate' environment and click 'Approve'.

Once approved, the evaluation results will be posted here automatically.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 addresses a performance issue where the MCP tools/list discovery process could cause the CLI to hang for up to 10 minutes when interacting with unresponsive servers. By implementing a shorter 10-second default timeout specifically for discovery, the system now fails fast while still allowing users to define longer timeouts for specific servers when necessary.

Highlights

  • Reduced Discovery Timeout: Introduced a new constant MCP_DISCOVERY_TIMEOUT_MSEC set to 10 seconds to replace the previous 10-minute default for tools/list discovery.
  • Improved Failure Handling: Ensures that unresponsive or misbehaving MCP servers fail fast during startup, preventing the CLI from freezing for extended periods.
  • Preserved Configuration Precedence: Maintained support for explicit per-server timeout configurations, ensuring that custom settings still override the new default.
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 the 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 counterproductive. 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.

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.

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

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.

Code Review

This pull request introduces a shorter default timeout (10 seconds) for Model Context Protocol (MCP) tools/list discovery requests to prevent slow or misbehaving servers from freezing the CLI, along with corresponding unit tests. A critical issue was identified where merging options using the nullish coalescing operator discards the timeout property entirely when other options are provided. It is recommended to define the default timeout first and spread the options over it to ensure proper fallback behavior.

Comment thread packages/core/src/tools/mcp-client.ts Outdated
Comment on lines 347 to 349
...(options ?? {
timeout: this.serverConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
timeout: this.serverConfig.timeout ?? MCP_DISCOVERY_TIMEOUT_MSEC,
}),

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.

high

When options is provided (e.g., in refreshTools where { signal: abortController.signal } is passed), the nullish coalescing operator options ?? { timeout: ... } evaluates to options. This completely discards the timeout property, meaning neither this.serverConfig.timeout nor MCP_DISCOVERY_TIMEOUT_MSEC will be applied, and it will fall back to the SDK's default timeout (60s).

To fix this, define the default timeout first and then spread options over it so that any explicitly provided timeout in options can still take precedence.

        timeout: this.serverConfig.timeout ?? MCP_DISCOVERY_TIMEOUT_MSEC,
        ...options,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 3111616. The discovery default is now set first and ...options is spread after it, so the timeout is forwarded on the refresh path (which passes an abort signal) instead of being dropped, while an explicit options.timeout still takes precedence. Added a regression assertion on the refresh test.

The tools/list discovery request reused MCP_DEFAULT_TIMEOUT_MSEC (10 minutes),
the default meant for long-running tool invocations. It was the only discovery
call that passed that 10-minute default: when a server answers tools/list with
a mismatched JSON-RPC id, the SDK ignores the response per spec, so the request
stays pending for the full 10 minutes with no visible feedback, freezing
startup discovery.

Add MCP_DISCOVERY_TIMEOUT_MSEC (10s) and apply it as the default for the
tools/list discovery request. The default is forwarded on every discovery call,
including the tool-refresh path that also passes an abort signal, and an
explicit per-server timeout still takes precedence. A server whose tools/list
has not answered within the timeout is skipped for that session, and the failure
is surfaced through the existing MCP diagnostic path within 10s instead of 10
minutes.

Scope is limited to the tools/list discovery request, which is the one call that
used the 10-minute default. prompts/list and resources/list already use the SDK
default (60s), and the connection handshake and tool-invocation timeouts are
intentionally unchanged.

Fixes google-gemini#28355
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality priority/p1 Important and should be addressed in the near term. size/m A medium sized PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP tool discovery silently blocks for 10 minutes when server returns a mismatched response id

1 participant