Skip to content

test: add end-to-end tests for Streamable HTTP Transport session ID and elicitation capabilities#300

Merged
frontegg-david merged 2 commits intorelease/1.0.xfrom
eliciation-improvemtns
Mar 19, 2026
Merged

test: add end-to-end tests for Streamable HTTP Transport session ID and elicitation capabilities#300
frontegg-david merged 2 commits intorelease/1.0.xfrom
eliciation-improvemtns

Conversation

@frontegg-david
Copy link
Copy Markdown
Contributor

@frontegg-david frontegg-david commented Mar 19, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Ensure session ID headers are consistently set for stateless streamable HTTP, improving compliance and session handling.
    • Refine stateless vs. streamable transport selection so elicitation and fallback behavior work reliably across client capability scenarios.
  • Tests

    • Added end-to-end test suite covering streamable HTTP: session header handling, elicitation flows, fallback for non-supporting clients, and capability persistence.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 19, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ad259d83-74bb-421a-9297-43bdfd62f3be

📥 Commits

Reviewing files that changed from the base of the PR and between e256477 and 8c51ecf.

📒 Files selected for processing (2)
  • libs/sdk/src/common/utils/decide-request-intent.utils.ts
  • libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts
✅ Files skipped from review due to trivial changes (1)
  • libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/sdk/src/common/utils/decide-request-intent.utils.ts

📝 Walkthrough

Walkthrough

Stateless HTTP transports now always provide a session-id generator returning '__stateless__' and use an explicit isStateless option to control per-request transport recreation. Request-intent rules were adjusted to exclude streamable-http when selecting stateless flows. New E2E tests validate elicitation and session behavior.

Changes

Cohort / File(s) Summary
Streamable / Stateless Transport
libs/sdk/src/transport/adapters/transport.streamable-http.adapter.ts, libs/sdk/src/transport/adapters/streamable-http-transport.ts
resolveSessionIdGenerator now returns () => '__stateless__' for stateless-http. Added isStateless?: boolean option and changed recreation logic to use this explicit flag rather than inferring statelessness from absence of a sessionIdGenerator.
Request Intent Rules
libs/sdk/src/common/utils/decide-request-intent.utils.ts
Updated rule masks so stateless POST→SSE/JSON branches explicitly require that streamable-http is NOT enabled (added B_STREAMABLE_EN to care masks and removed from match masks). Also tightened related branches by including B_STATELESS_EN in care masks.
Handlers — minor whitespace
libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts
Whitespace-only adjustment around sessionId declaration; no behavior changes.
Tests — unit & E2E
libs/sdk/src/transport/adapters/__tests__/transport.streamable-http.adapter.spec.ts, apps/e2e/demo-e2e-elicitation/e2e/streamable-http-transport.e2e.spec.ts
Unit test updated to expect a session-id generator for stateless transports and assert it returns '__stateless__'. Added comprehensive E2E tests for streamable HTTP elicitation in stateless mode, covering session-id header, elicitation flows, fallbacks, and capability persistence.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐇 A stateless hop, a header bright,
"stateless" tucked in the night,
Flags now say when to remake the stream,
Elicitation hums — a test-approved dream,
I nibble code and twitch with delight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 65.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary change: adding E2E tests for Streamable HTTP Transport focusing on session ID headers and elicitation capabilities, which is the most significant addition in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch eliciation-improvemtns
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
libs/sdk/src/common/utils/decide-request-intent.utils.ts (2)

354-356: ⚠️ Potential issue | 🟠 Major

Stateless SSE branch is shadowed and never selected when streamable is disabled.

At Line 354, the streamable disabled rule matches all CH_POST_SSE requests with B_STREAMABLE_EN=0, including stateless ones. That prevents the stateless branch at Line 364 from ever running.

🐛 Suggested fix
   {
-    care: CH_MASK | B_STREAMABLE_EN,
-    match: CH_POST_SSE /* streamable disabled */,
+    care: CH_MASK | B_STREAMABLE_EN | B_STATELESS_EN,
+    match: CH_POST_SSE /* streamable disabled + stateless disabled */,
     outcome: {
       intent: 'unknown',
       reason: 'Streamable HTTP disabled.',
       recommendation: { httpStatus: 405, message: 'Streamable HTTP disabled' },
     },
   },

Also applies to: 362-366

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@libs/sdk/src/common/utils/decide-request-intent.utils.ts` around lines 354 -
356, The branch matching CH_POST_SSE with B_STREAMABLE_EN=0 is currently too
broad and shadows the stateless SSE branch; either restrict that match to
exclude stateless requests by adding a CH_MASK condition (e.g., require CH_MASK
does not include the stateless flag) or reorder the rules so the stateless
outcome (the rule referencing the stateless branch) is evaluated before the
general CH_POST_SSE + B_STREAMABLE_EN=0 rule; update the match for the
streamable-disabled case or move the stateless rule accordingly so the stateless
outcome can ever be selected.

385-387: ⚠️ Potential issue | 🟠 Major

Stateless JSON branch is shadowed by the "JSON mode disabled" rule.

At Line 385, the rule does not account for B_STATELESS_EN, so it matches before the stateless JSON branch at Line 395 when stateful=false and streamable=false.

🐛 Suggested fix
   {
-    care: CH_MASK | B_STATEFUL_EN | B_STREAMABLE_EN,
-    match: CH_POST_JSON /* neither enabled */,
+    care: CH_MASK | B_STATEFUL_EN | B_STREAMABLE_EN | B_STATELESS_EN,
+    match: CH_POST_JSON /* stateful disabled + streamable disabled + stateless disabled */,
     outcome: {
       intent: 'unknown',
       reason: 'JSON mode disabled.',
       recommendation: { httpStatus: 405, message: 'JSON mode disabled' },
     },
   },

Also applies to: 393-397

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@libs/sdk/src/common/utils/decide-request-intent.utils.ts` around lines 385 -
387, The rule that disables JSON mode is shadowing the stateless JSON branch
because it doesn't check the B_STATELESS_EN flag; update the JSON-disabled rule
(the entry using CH_MASK | B_STATEFUL_EN | B_STREAMABLE_EN and match
CH_POST_JSON) to also care about B_STATELESS_EN and ensure the rule requires
B_STATELESS_EN to be absent (i.e., include B_STATELESS_EN in the care mask and
set its match bit to 0 or add an explicit check for !B_STATELESS_EN) so the
stateless JSON branch (which depends on B_STATELESS_EN) can match; apply the
same fix to the other identical rule block around the CH_POST_JSON branch at the
other location.
🧹 Nitpick comments (1)
libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts (1)

87-87: Remove unnecessary non-null assertions after the sessionId guard.

Lines 87 and 105 use sessionId! inside the if (sessionId) guard block (line 75), where type narrowing already ensures sessionId is truthy. Remove the ! operator to keep null-safety checks meaningful.

Suggested fix
-          scope.notifications.setClientCapabilities(sessionId!, clientCapabilities);
+          scope.notifications.setClientCapabilities(sessionId, clientCapabilities);
...
-          scope.notifications.setClientInfo(sessionId!, {
+          scope.notifications.setClientInfo(sessionId, {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts` at line
87, Remove the unnecessary non-null assertion usage for sessionId inside the
existing if (sessionId) guard: wherever sessionId is used within that guarded
block (e.g., the call scope.notifications.setClientCapabilities(sessionId!,
clientCapabilities) and the other occurrence at the same guarded scope), drop
the trailing "!" so the calls use sessionId directly; this preserves proper
type-narrowing and avoids redundant non-null assertions in
initialize-request.handler.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@libs/sdk/src/common/utils/decide-request-intent.utils.ts`:
- Around line 354-356: The branch matching CH_POST_SSE with B_STREAMABLE_EN=0 is
currently too broad and shadows the stateless SSE branch; either restrict that
match to exclude stateless requests by adding a CH_MASK condition (e.g., require
CH_MASK does not include the stateless flag) or reorder the rules so the
stateless outcome (the rule referencing the stateless branch) is evaluated
before the general CH_POST_SSE + B_STREAMABLE_EN=0 rule; update the match for
the streamable-disabled case or move the stateless rule accordingly so the
stateless outcome can ever be selected.
- Around line 385-387: The rule that disables JSON mode is shadowing the
stateless JSON branch because it doesn't check the B_STATELESS_EN flag; update
the JSON-disabled rule (the entry using CH_MASK | B_STATEFUL_EN |
B_STREAMABLE_EN and match CH_POST_JSON) to also care about B_STATELESS_EN and
ensure the rule requires B_STATELESS_EN to be absent (i.e., include
B_STATELESS_EN in the care mask and set its match bit to 0 or add an explicit
check for !B_STATELESS_EN) so the stateless JSON branch (which depends on
B_STATELESS_EN) can match; apply the same fix to the other identical rule block
around the CH_POST_JSON branch at the other location.

---

Nitpick comments:
In `@libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts`:
- Line 87: Remove the unnecessary non-null assertion usage for sessionId inside
the existing if (sessionId) guard: wherever sessionId is used within that
guarded block (e.g., the call
scope.notifications.setClientCapabilities(sessionId!, clientCapabilities) and
the other occurrence at the same guarded scope), drop the trailing "!" so the
calls use sessionId directly; this preserves proper type-narrowing and avoids
redundant non-null assertions in initialize-request.handler.ts.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4c322f8d-fed2-4cf2-aa44-fdb1e693d004

📥 Commits

Reviewing files that changed from the base of the PR and between 26fff24 and e256477.

📒 Files selected for processing (6)
  • apps/e2e/demo-e2e-elicitation/e2e/streamable-http-transport.e2e.spec.ts
  • libs/sdk/src/common/utils/decide-request-intent.utils.ts
  • libs/sdk/src/transport/adapters/__tests__/transport.streamable-http.adapter.spec.ts
  • libs/sdk/src/transport/adapters/streamable-http-transport.ts
  • libs/sdk/src/transport/adapters/transport.streamable-http.adapter.ts
  • libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 19, 2026

Performance Test Results

Status: ✅ All tests passed

Summary

Project Tests Passed Warnings Failed Leaks
✅ demo-e2e-agents 4 4 0 0 0
✅ demo-e2e-cache 11 11 0 0 0
✅ demo-e2e-codecall 4 4 0 0 0
✅ demo-e2e-config 4 4 0 0 0
✅ demo-e2e-direct 3 3 0 0 0
✅ demo-e2e-elicitation 1 1 0 0 0
✅ demo-e2e-errors 4 4 0 0 0
✅ demo-e2e-hooks 3 3 0 0 0
✅ demo-e2e-multiapp 4 4 0 0 0
✅ demo-e2e-notifications 3 3 0 0 0
✅ demo-e2e-openapi 2 2 0 0 0
✅ demo-e2e-providers 4 4 0 0 0
✅ demo-e2e-public 4 4 0 0 0
✅ demo-e2e-redis 14 14 0 0 0
✅ demo-e2e-remember 4 4 0 0 0
✅ demo-e2e-remote 5 5 0 0 0
✅ demo-e2e-serverless 2 2 0 0 0
✅ demo-e2e-skills 15 15 0 0 0
✅ demo-e2e-standalone 2 2 0 0 0
✅ demo-e2e-transport-recreation 3 3 0 0 0
✅ demo-e2e-ui 4 4 0 0 0

Total: 100 tests across 21 projects

📊 View full report in workflow run


Generated at: 2026-03-19T22:22:16.399Z
Commit: 533a8f6f

@frontegg-david frontegg-david merged commit 6f7b9bf into release/1.0.x Mar 19, 2026
63 checks passed
@frontegg-david frontegg-david deleted the eliciation-improvemtns branch March 19, 2026 22:45
github-actions Bot pushed a commit that referenced this pull request Mar 19, 2026
… session ID and elicitation capabilities

Cherry-picked from #300 (merged to release/1.0.x)
Original commit: 6f7b9bf

Co-Authored-By: frontegg-david <69419539+frontegg-david@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Cherry-pick Created

A cherry-pick PR to main has been automatically created.

Please review and merge if this change should also be in main.

If the cherry-pick is not needed, close the PR.

frontegg-david added a commit that referenced this pull request Mar 19, 2026
… session ID and elicitation capabilities (#301)

Cherry-picked from #300 (merged to release/1.0.x)
Original commit: 6f7b9bf

Co-authored-by: agentfront[bot] <agentfront[bot]@users.noreply.github.com>
Co-authored-by: frontegg-david <69419539+frontegg-david@users.noreply.github.com>
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.

1 participant