Make MCP client initialization timeout configurable via ToolOptions#212
Make MCP client initialization timeout configurable via ToolOptions#212matiazo wants to merge 2 commits intomicrosoft:mainfrom
Conversation
Add nullable McpClientInitializationTimeoutSeconds property to ToolOptions so consumers can override the MCP client initialization timeout. When null (default), the MCP SDK default is used. When set, both McpClientOptions and HttpClient.Timeout are configured to match. Co-Authored-By: Claude Code <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds an opt-in configuration surface to the Tooling layer so SDK consumers can override the MCP client initialization timeout (handshake/connection setup) via ToolOptions, helping environments where MCP initialization regularly exceeds the SDK default.
Changes:
- Added
ToolOptions.McpClientInitializationTimeoutSeconds(nullable) to allow overriding MCP initialization timeout. - When set, applies the timeout to both
HttpClient.TimeoutandMcpClientOptions.InitializationTimeoutduring MCP client creation.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/Tooling/Core/Models/ToolOptions.cs | Introduces a new nullable option to configure MCP client initialization timeout (in seconds). |
| src/Tooling/Core/Services/McpToolServerConfigurationService.cs | Applies the configured timeout when creating the HTTP client and MCP client options for MCP client initialization. |
| // Apply custom timeout only when explicitly configured | ||
| if (toolOptions.McpClientInitializationTimeoutSeconds.HasValue) | ||
| { | ||
| httpClient.Timeout = TimeSpan.FromSeconds(toolOptions.McpClientInitializationTimeoutSeconds.Value); | ||
| } |
There was a problem hiding this comment.
McpClientInitializationTimeoutSeconds is used directly to set HttpClient.Timeout and McpClientOptions.InitializationTimeout. If a consumer sets this to 0, a negative value, or a very large value, TimeSpan.FromSeconds(...) / HttpClient.Timeout can throw (or effectively make requests immediately time out). Consider validating the value (e.g., > 0 and within TimeSpan/HttpClient supported bounds) and throwing an ArgumentOutOfRangeException with a clear message.
| var clientOptions = toolOptions.McpClientInitializationTimeoutSeconds.HasValue | ||
| ? new McpClientOptions | ||
| { | ||
| InitializationTimeout = TimeSpan.FromSeconds(toolOptions.McpClientInitializationTimeoutSeconds.Value), | ||
| } | ||
| : new McpClientOptions(); | ||
|
|
||
| return await McpClientFactory.CreateAsync(clientTransport, clientOptions, loggerFactory: this._loggerFactory); |
There was a problem hiding this comment.
When McpClientInitializationTimeoutSeconds is null, this now still constructs and passes new McpClientOptions() and uses a different CreateAsync overload than before (previously the options argument was omitted/left null). If the MCP SDK treats “null options” differently from “default options instance”, this could be a behavioral change despite the PR’s stated intent. To preserve existing behavior, consider only creating/passing McpClientOptions when the timeout is explicitly set, and otherwise call the original overload (or pass null for options).
| /// Gets or sets the timeout in seconds for MCP client initialization. | ||
| /// This includes the time for the MCP protocol handshake (initialize/initialized exchange) | ||
| /// and the underlying HTTP connection. Increase this value if the MCP server performs | ||
| /// slow operations during initialization (e.g., token exchanges in test environments). | ||
| /// When null, the MCP SDK default timeout is used. |
There was a problem hiding this comment.
The new McpClientInitializationTimeoutSeconds property doesn’t document or enforce an allowed range. Since invalid values (<= 0, extremely large) can cause runtime exceptions when converted to a TimeSpan or applied to HttpClient.Timeout, it would help to document the expected bounds here (and ideally validate it at the call site).
| // Apply custom timeout only when explicitly configured | ||
| if (toolOptions.McpClientInitializationTimeoutSeconds.HasValue) | ||
| { | ||
| httpClient.Timeout = TimeSpan.FromSeconds(toolOptions.McpClientInitializationTimeoutSeconds.Value); | ||
| } | ||
|
|
||
| var clientTransport = new SseClientTransport(options, httpClient); | ||
|
|
||
| try | ||
| { | ||
| return await McpClientFactory.CreateAsync(clientTransport, loggerFactory: this._loggerFactory); | ||
| var clientOptions = toolOptions.McpClientInitializationTimeoutSeconds.HasValue | ||
| ? new McpClientOptions | ||
| { | ||
| InitializationTimeout = TimeSpan.FromSeconds(toolOptions.McpClientInitializationTimeoutSeconds.Value), | ||
| } | ||
| : new McpClientOptions(); | ||
|
|
||
| return await McpClientFactory.CreateAsync(clientTransport, clientOptions, loggerFactory: this._loggerFactory); |
There was a problem hiding this comment.
This change adds a new timeout behavior but there are no unit tests asserting the configured timeout is applied (and that the default/null path preserves existing behavior). Given there are existing tests around ToolOptions usage for MCP tooling services, please add coverage for the new option to prevent regressions.
- Add input validation (1-600s range) with ArgumentOutOfRangeException - Document valid range in ToolOptions XML docs - Preserve original SDK behavior when timeout is null: call McpClientFactory.CreateAsync without McpClientOptions instead of passing a default instance - Add 13 unit tests covering: null default, valid/invalid values, ArgumentOutOfRangeException for out-of-bounds inputs Co-Authored-By: Claude Code <noreply@anthropic.com>
Summary
McpClientInitializationTimeoutSecondsproperty toToolOptionsso consumers can override the MCP client initialization timeoutnull), the MCP SDK default (60s) is used — no behavioral change for existing consumersMcpClientOptions.InitializationTimeoutandHttpClient.Timeoutare configured to matchMotivation
Consumers connecting to the MCP platform may experience
OperationCanceledExceptionwhen downstream dependencies are slow. The MCP SDK's default 60-second initialization timeout is not configurable throughToolOptions, leaving no way for consumers to adjust it for their agents.Usage
Changes
src/Tooling/Core/Models/ToolOptions.cs— Addint? McpClientInitializationTimeoutSecondspropertysrc/Tooling/Core/Services/McpToolServerConfigurationService.cs— Apply timeout only when explicitly setTest plan
null) uses MCP SDK default timeoutMcpClientOptions.InitializationTimeoutandHttpClient.TimeoutGenerated with Claude Code