fix(core): shorten MCP tools/list discovery timeout so it fails fast#28410
fix(core): shorten MCP tools/list discovery timeout so it fails fast#28410sahilempire wants to merge 1 commit into
Conversation
|
📊 PR Size: size/M
|
15f131c to
942de53
Compare
🛑 Action Required: Evaluation ApprovalSteering changes have been detected in this PR. To prevent regressions, a maintainer must approve the evaluation run before this PR can be merged. Maintainers:
Once approved, the evaluation results will be posted here automatically. |
Summary of ChangesHello, 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 Highlights
Using Gemini Code AssistThe 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
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 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
|
There was a problem hiding this comment.
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.
| ...(options ?? { | ||
| timeout: this.serverConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC, | ||
| timeout: this.serverConfig.timeout ?? MCP_DISCOVERY_TIMEOUT_MSEC, | ||
| }), |
There was a problem hiding this comment.
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,There was a problem hiding this comment.
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
942de53 to
3111616
Compare
Summary
The MCP
tools/listdiscovery request could silently freeze the CLI for 10minutes at startup when a server did not answer it (for example, replying with a
mismatched JSON-RPC id). This gives
tools/listdiscovery a short defaulttimeout so it fails fast.
Details
tools/listdiscovery reusedMCP_DEFAULT_TIMEOUT_MSEC(10 minutes), thedefault 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 thetools/listdiscovery calls (both the livediscoverIntopath and thestandalone
connectAndDiscoverpath). It is only a default: an explicitper-server
timeoutstill wins, so a deliberately slow server keeps itsconfigured 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/listdiscovery request, which is theone call that used the 10-minute default:
prompts/listandresources/listdo not pass this default; they already usethe MCP SDK default (60s), so they were never part of the 10-minute freeze.
connect/initialize) and the tool-invocationtimeout 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.
tools/listlegitimately takes longer than the default and hasno explicit
timeoutset will be skipped for that session. The escape hatchis the existing per-server
timeoutsetting, which still takes precedence.Related Issues
Fixes #28355
How to Validate
tools/list, or answers with amismatched JSON-RPC id.
surfaces the failure.
timeoutfor that server and confirm discovery honors it.Unit tests:
tools/listdiscovery uses the 10s default when no per-server timeout is settools/listdiscovery honors an explicit per-server timeoutPre-Merge Checklist
is no user-facing setting or docs change.
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.