Extend server/discover probe timeout in in-memory tests to fix flaky Windows Debug CI hang (#1701)#1702
Merged
jeffhandley merged 3 commits intoJul 24, 2026
Conversation
PranavSenthilnathan
marked this pull request as draft
July 14, 2026 01:21
halter73
reviewed
Jul 14, 2026
On slow Windows Debug CI, the default 5s DiscoverProbeTimeout can be spuriously exceeded when a July2026-capable client probes server/discover over the in-memory pipe. The client then falls back to the initialize handshake and negotiates an older protocol, dropping tasks-extension negotiation. For TaskCancellationIntegrationTests, whose tool runs Task.Delay(Timeout.Infinite), the fallback makes the server run the tool inline instead of as a background task, so the tools/call never returns and the test host hangs until the blame timeout. Force DiscoverProbeTimeout = Timeout.InfiniteTimeSpan in ClientServerTestBase.CreateMcpClientForServer. The in-memory pipe server always answers server/discover immediately, so the probe never legitimately needs to time out. This is applied even when a caller supplies its own options so no test can reintroduce the flake. Tests that intentionally exercise the probe-timeout fallback (July2026ProtocolFallbackTests) build their own transport and bypass this helper, so they are unaffected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PranavSenthilnathan
force-pushed
the
pranavsenthilnathan/fix-task-cancellation-test-hang
branch
from
July 16, 2026 00:47
42a99f0 to
0726434
Compare
PranavSenthilnathan
marked this pull request as ready for review
July 16, 2026 01:09
halter73
reviewed
Jul 16, 2026
Co-authored-by: Stephen Halter <halter73@gmail.com>
jeffhandley
approved these changes
Jul 24, 2026
jeffhandley
deleted the
pranavsenthilnathan/fix-task-cancellation-test-hang
branch
July 24, 2026 23:46
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the flaky Windows Debug CI test-host hang tracked in #1701, which surfaced most often as
TaskCancellationIntegrationTests.TaskTool_CancellationToken_GetTaskShowsWorkingBeforeCancel.The fix is a test-only change:
ClientServerTestBase.CreateMcpClientForServernow setsDiscoverProbeTimeout = TestConstants.DefaultTimeoutfor the in-memory client. This extends the production default from 5 seconds to the shared 60-second test timeout, giving slow or overloaded CI agents enough time to complete the probe while preserving a bounded failure mode. Previously, the default timeout could be spuriously exceeded, triggering a protocol-fallback cascade that ends in a hang (details below).Root cause
A July2026-capable client (the default) does not use the initialize handshake. Instead it calls
server/discoverto learn the server's capabilities, and only falls back to the legacyinitializehandshake if the probe fails or times out. That probe is bounded byMcpClientOptions.DiscoverProbeTimeout(default 5s).On a slow CI agent, the in-memory
server/discoverround-trip could occasionally take longer than 5s. When that happened:initializehandshake, negotiating an older protocol version.TaskCancellationIntegrationTestsregisters a tool whose body isTask.Delay(Timeout.Infinite, cancellationToken). Without the tasks extension, the server ran that tool inline on thetools/callrequest instead of dispatching it as a cancellable background task.tools/callresponse, and the client'sawait CallToolRawAsync(...)blocks forever.Because the trigger is purely environmental timing, the failure was intermittent and Windows-Debug-CI-specific.
How it was diagnosed (hang dump)
The blame-timeout hang dump was the key. Walking the managed thread stacks:
CallToolRawAsync→SendRequestAsync, awaiting the JSON-RPC response fortools/call— i.e. the client had sent the request and was waiting for a reply that never came.Task.Delay(Timeout.Infinite, …)synchronously on the request-handling path — proving the tool was running inline rather than as a background task.That pairing (client awaiting a
tools/callresponse while the server is blocked inside the tool on the same call) is only possible when the tasks extension was not negotiated. Confirming the negotiated protocol version was older than July2026 pointed directly at aserver/discover→initializefallback, and the only thing that forces that fallback in the in-memory harness is the probe timeout expiring — i.e. CI slowness tripping the 5sDiscoverProbeTimeout.The fix
Within
ClientServerTestBase, the shared 60-second test timeout gives slow or overloaded CI agents substantially more time than the production 5-second default to complete the in-memoryserver/discoverprobe, while keeping the operation bounded. Applying it in the helper avoids per-caller churn and ensures callers that supply other client options receive the same protection, with no production code change.Tests that intentionally exercise the probe-timeout fallback (
July2026ProtocolFallbackTests) build their own transport and callMcpClient.CreateAsyncdirectly, so they bypass this helper and are unaffected.Testing
dotnet build— clean (0 warnings / 0 errors).TestServer.exePATH issue unrelated to this change; they build and run in CI.)