Skip to content

GH-4542: Collect all Flux elements in async MCP tool callbacks#6158

Open
suryateja-g13 wants to merge 2 commits into
spring-projects:mainfrom
suryateja-g13:gh-4542-async-tool-flux-all-elements
Open

GH-4542: Collect all Flux elements in async MCP tool callbacks#6158
suryateja-g13 wants to merge 2 commits into
spring-projects:mainfrom
suryateja-g13:gh-4542-async-tool-flux-all-elements

Conversation

@suryateja-g13
Copy link
Copy Markdown
Contributor

Summary

  • Fixes AbstractAsyncMcpToolMethodCallback.convertToCallToolResult() which was calling .next() on Flux return types, silently discarding all elements except the first
  • When an async MCP tool method returns Flux<T>, all emitted elements are now collected and returned as separate CallToolResult content entries
  • This affects both AsyncMcpToolMethodCallback (stateful) and AsyncStatelessMcpToolMethodCallback (stateless) because both extend AbstractAsyncMcpToolMethodCallback
  • Updated existing tests that asserted the broken one-element behavior to verify all elements are returned

Before: Flux.just("a", "b", "c")CallToolResult with 1 content item ("a")
After: Flux.just("a", "b", "c")CallToolResult with 3 content items ("a", "b", "c")

Fixes: #4542

Test plan

  • ./mvnw -pl mcp/mcp-annotations test — all 1349 tests pass
  • testMultipleFluxTool now asserts 3 content items instead of 1
  • testGetToolSpecificationsWithFluxHandling now asserts 3 content items in both AsyncMcpToolProviderTests and AsyncStatelessMcpToolProviderTests
  • testToolWithFluxReturnType in AsyncMcpToolProviderTests now asserts all 3 items

…Max APIs

Adds the missing `REQUIRED` tool_choice constant that forces the model to call
at least one tool without specifying which one, aligning with the OpenAI spec.

Fixes: spring-projects#6120

Signed-off-by: Gorre Surya <suryateja.g13@gmail.com>
AsyncMcpToolMethodCallback and AsyncStatelessMcpToolMethodCallback
previously called .next() on Flux return types, discarding all but the
first emitted element. Tools returning Flux<T> now have all items
collected and returned as separate CallToolResult content entries.

Fixes: spring-projects#4542

Signed-off-by: Gorre Surya <suryateja.g13@gmail.com>
@suryateja-g13
Copy link
Copy Markdown
Contributor Author

The failing "MCP transport integration tests" check is unrelated to this PR's changes. The failures are in WebClientStreamableHttpTransportIT.testCloseInitialized and testCloseUninitialized within the mcp/mcp-transport-webflux module — a module this PR does not modify.

This PR only changes files in mcp/mcp-annotations. The same "MCP transport integration tests" workflow passed successfully on main a few hours ago (run 26394342907), so this appears to be a pre-existing intermittent failure in the transport layer.

@suryateja-g13
Copy link
Copy Markdown
Contributor Author

Thank you for taking the time to migrate and build on this — really appreciate it!

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.

Stateless Async MCP Server with streamable-http returns only the first element from tools with a Flux return

1 participant