Skip to content

Fix flaky AddIncomingMessageFilter_Multiple_Filters_Execute_In_Order test#1627

Merged
tarekgh merged 1 commit into
modelcontextprotocol:mainfrom
tarekgh:fix-messagefilter-test-flakiness
Jun 4, 2026
Merged

Fix flaky AddIncomingMessageFilter_Multiple_Filters_Execute_In_Order test#1627
tarekgh merged 1 commit into
modelcontextprotocol:mainfrom
tarekgh:fix-messagefilter-test-flakiness

Conversation

@tarekgh
Copy link
Copy Markdown
Contributor

@tarekgh tarekgh commented Jun 4, 2026

Summary

Fixes a flaky test: McpServerBuilderExtensionsMessageFilterTests.AddIncomingMessageFilter_Multiple_Filters_Execute_In_Order. It intermittently fails on CI with Assert.Equal() Failure: Expected: 3, Actual: 2 (observed on the net8.0 leg, but the race is framework-independent).

Root cause

The test asserts each incoming message filter runs exactly three times, once per message: initialize, notifications/initialized, and tools/list.

  • initialize and tools/list are request/response exchanges, so awaiting the corresponding client calls guarantees their filter passes have completed.
  • notifications/initialized is sent fire-and-forget by the client. It has no synchronization point, so it can still be in flight when ListToolsAsync returns. When that happens the strict counts are only 2 and the test fails.

Fix

Add a TaskCompletionSource that the outermost filter completes once it has finished processing the initialized notification, and await it before snapshotting the log. This mirrors the existing TaskCompletionSource pattern already used elsewhere in this test file (AddOutgoingMessageFilter_Can_Send_Additional_Messages), keeps the strict count assertions intact, and introduces no timing-based delays.

Verification

  • Ran the affected test 8x in a row on net8.0: all pass.
  • Full McpServerBuilderExtensionsMessageFilterTests class passes on net8.0, net9.0, net10.0, and net472 (21/21 each).

…test

The test asserts each incoming message filter runs exactly three times, once
per message: initialize, notifications/initialized, and tools/list. The
initialize and tools/list exchanges are request/response, so awaiting the
client calls guarantees their filter passes have completed. The
notifications/initialized notification is sent fire-and-forget by the client,
so it has no synchronization point and may still be in flight when
ListToolsAsync returns, leaving the strict counts at two and failing the test.

Add a TaskCompletionSource that the outermost filter completes once it has
finished processing the initialized notification, and await it before
snapshotting the log. This follows the existing pattern used elsewhere in this
file and makes the test deterministic without weakening the strict count
assertions.
@tarekgh tarekgh requested a review from halter73 June 4, 2026 21:51
@tarekgh tarekgh merged commit 719eade into modelcontextprotocol:main Jun 4, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants