Skip to content

test(mcp-test): deflake streamable HTTP version-negotiation integration test - #1113

Open
slachiewicz wants to merge 2 commits into
modelcontextprotocol:mainfrom
slachiewicz:test/negotiation-test-deflake
Open

test(mcp-test): deflake streamable HTTP version-negotiation integration test#1113
slachiewicz wants to merge 2 commits into
modelcontextprotocol:mainfrom
slachiewicz:test/negotiation-test-deflake

Conversation

@slachiewicz

Copy link
Copy Markdown
Contributor

Two independent timing hazards cause intermittent CI failures:

  1. contextExtractor NPE — Map.of rejects null values while MCP-Protocol-Version is legitimately absent on initialize requests
  2. GET /mcp stream opens asynchronously post-initialize; immediate assertion raced it ('Expected size: 3 but was: 2', e.g. actions/run/33069467622 Jackson 2 job)

Change: null-safe extractor (Objects.requireNonNullElse) + Awaitility guard for the recorded GET.
Tested: ./mvnw -pl mcp-test -am test -Dtest=HttpClientStreamableHttpVersionNegotiationIntegrationTests → 2/2 green; no production code touched.

@Kehrlann Kehrlann 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.

Thanks for your contribution, please review.

Comment on lines +43 to +46
// The MCP-Protocol-Version header may legitimately be absent on initialize
// requests, so a missing header must not break context extraction.
.contextExtractor(req -> McpTransportContext
.create(Map.of("protocol-version", Objects.requireNonNullElse(req.getHeader("MCP-protocol-version"), ""))))

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.

I may be absent, but is it, given the clients we use in this test? If not, leave as-is.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correct — the client always sends it on initialize with these clients, so it is never absent here. Reverted to the original extractor in 8fccf33.

This comment was created with AI assistance.

Comment on lines +80 to +85
// The GET /mcp stream is opened asynchronously once the initialize response
// creates the session, so wait for it to be recorded before asserting.
await().atMost(Duration.ofSeconds(5))
.untilAsserted(() -> assertThat(requestRecordingFilter.getCalls()).filteredOn(c -> "GET".equals(c.method()))
.hasSize(1));

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.

Wrap the whole assertion below (calls = ... + assertThat(calls)) in the await(), and include your comment there.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 8fccf33 — the whole assertion now runs inside await(), comment moved with it.

This comment was created with AI assistance.

@Kehrlann Kehrlann self-assigned this Aug 28, 2026
@Kehrlann Kehrlann added the build Build and CI related issues label Aug 28, 2026
@slachiewicz

Copy link
Copy Markdown
Contributor Author

The Jackson 2 job on 8fccf33 failed in HttpServletStreamableIntegrationTests.testRootsSuccess with -32603 "Stream unavailable for session" (run 33192309921). That is the server-initiated push race tracked in #1114 and fixed by #1115, not this diff — #1115 should land first. Merged main in to retrigger.

This comment was created with AI assistance.

…on test

- tolerate an absent MCP-Protocol-Version header in the context extractor: Map.of rejects null values while spec-correct clients legitimately omit the header on initialize requests

- await the asynchronously opened GET /mcp stream before asserting recorded calls; observed intermittently in CI as AssertionError Expected size: 3 but was: 2 (evidence: actions/run/33069467622 Jackson 2 Integration Tests)
…actor

Review follow-up: the header is never absent with the clients used here,
so the contextExtractor stays as on main; the whole size-3 assertion now
runs inside await() so a late POST is covered as well as the async GET.

Claude-Session: https://claude.ai/code/session_01WtjUifqJuzJdfxc1zjcZrL
@slachiewicz
slachiewicz force-pushed the test/negotiation-test-deflake branch from 926b8c1 to d77e9f7 Compare August 28, 2026 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Build and CI related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants