Skip to content

Conversation

@mattzcarey
Copy link
Contributor

  • use TransportSendOptions as per the MCP SDK
  • send() method to prioritise relatedRequestId for routing
  • some tests

- Added support for TransportSendOptions to route server-to-client requests through the same stream as the originating client request
- Updated send() method to prioritize relatedRequestId for routing, with message.id override for responses/errors
- Added comprehensive test coverage for stream routing scenarios including multiple streams, error cases, and response handling
@changeset-bot
Copy link

changeset-bot bot commented Nov 17, 2025

🦋 Changeset detected

Latest commit: df0bc0d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agents Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 17, 2025

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/agents@654

commit: df0bc0d

@claude
Copy link

claude bot commented Nov 17, 2025

Claude Code Review

Summary

PR implements relatedRequestId routing to enable server-to-client requests (like elicitation) to use the same POST stream as the originating client request. Implementation is solid with comprehensive test coverage.

Issues

1. Type safety gap in storage mock (tests/mcp/transports/worker-transport.test.ts:665-668)

const mockStorage = {
  get: () => storedState,
  set: (state: TransportState) => {
    storedState = state;
  }
};

The get method should return TransportState | undefined | Promise<TransportState | undefined> to match the actual storage interface. Current signature returns TransportState | undefined synchronously while the real interface is async.

2. Whitebox testing accessing private fields (tests/mcp/transports/worker-transport.test.ts:1041-1050)

type TransportInternal = {
  streamMapping: Map<string, unknown>;
  requestToStreamMapping: Map<string | number, string>;
};

Tests access private streamMapping and requestToStreamMapping fields via type assertion. This couples tests to implementation details and will break if internals change. Consider:

  • Adding test-only public methods for setup
  • Using dependency injection for stream management
  • Or accepting this as pragmatic tradeoff (document why whitebox testing is needed)

3. Optional chaining inconsistency (worker-transport.ts:362-363)

if (
  \!acceptHeader?.includes("application/json") ||
  \!acceptHeader?.includes("text/event-stream")
) {

Both conditions use optional chaining, but if acceptHeader is null/undefined, the first check returns true (triggering error) before the second check runs. This is correct behavior but the pattern suggests both checks are symmetric when they're actually sequential short-circuit. No bug, just noting the pattern.

Strengths

  • Comprehensive test coverage including edge cases (concurrent requests, closed streams, missing mappings)
  • Clear documentation in comments explaining routing priority
  • Proper error handling for unmapped requests
  • Example updated to demonstrate usage

Minor

  • Line 89 in examples/mcp-elicitation/src/index.ts: minLength: 1 on a number type has no effect (minLength is for strings). Likely meant minimum: 1 or just remove it.

threepointone pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Nov 17, 2025
Add comprehensive documentation for the relatedRequestId routing feature
that enables proper server-to-client request routing in Streamable HTTP
transport. This feature is essential for bidirectional communication
patterns like elicitation where the server needs to send requests back
to the client while maintaining proper request-response pairing.

Related: cloudflare/agents#654

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@threepointone
Copy link
Contributor

Documentation sync PR created: cloudflare/cloudflare-docs#26562

This PR documents the relatedRequestId routing feature for bidirectional MCP streams, including:

  • How relatedRequestId routing works in Streamable HTTP transport
  • When to use relatedRequestId (elicitation, progress updates, callbacks)
  • Implementation details and code examples
  • Clarification that this is specific to Streamable HTTP transport

The documentation has been added to the transport.mdx page in the Model Context Protocol section.

threepointone pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Nov 17, 2025
Add documentation for bidirectional streaming with relatedRequestId in MCP transport. This explains how server-to-client requests (like elicitation) are routed through the same stream as the originating client request.

Related to cloudflare/agents#654
@threepointone
Copy link
Contributor

📚 Documentation Update

I've synced the documentation for this PR to the cloudflare-docs repository.

Documentation PR: cloudflare/cloudflare-docs#26562

What was documented:

  • Added a new section on Bidirectional streaming with relatedRequestId to the MCP Transport documentation
  • Explained how server-to-client requests (like elicitation) are routed through the same stream as the originating client request
  • Documented the message routing priority: responses → relatedRequestId → fallback to GET stream
  • Provided a practical elicitation example showing automatic relatedRequestId handling
  • Included advanced usage documentation for custom transport implementations using TransportSendOptions

The documentation helps developers understand when and how to use relatedRequestId for proper bidirectional communication in MCP servers.

@threepointone
Copy link
Contributor

Documentation has been synced to cloudflare-docs.

📚 Documentation PR: cloudflare/cloudflare-docs#26562

The following documentation updates have been made:

  • Added comprehensive guide on using relatedRequestId for bidirectional MCP communication
  • Documented how server-to-client requests (elicitation) are routed through POST streams
  • Included complete code example showing elicitInput() with relatedRequestId parameter
  • Explained technical details of request-to-stream mapping and hibernation support

Please review the documentation PR to ensure it accurately reflects the changes in this PR.

@mattzcarey mattzcarey force-pushed the fix-related-request-id branch from c365f76 to df0bc0d Compare November 18, 2025 12:06
"agents": patch
---

Use relatedRequestId in TransportOptions to send the response down a POST stream if supported
Copy link
Contributor

Choose a reason for hiding this comment

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

reference MCP here

@threepointone
Copy link
Contributor

📚 Documentation Updated

The documentation for this change has been synced to the cloudflare-docs repository:

Documentation PR: cloudflare/cloudflare-docs#26562

What was documented

Added a new section on Bidirectional stream routing in the MCP transport documentation that covers:

  • How the transport layer routes server-to-client requests through the correct HTTP stream using relatedRequestId
  • The routing priority (responses → related requests → standalone stream)
  • Practical example showing how to use relatedRequestId with elicitInput in tool handlers

This ensures developers understand how to properly implement elicitation and other bidirectional communication patterns when building MCP servers with the Agents SDK.

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