-
Notifications
You must be signed in to change notification settings - Fork 518
Description
Problem Statement
According to #543 and the follow-up PRs (#788 and #773), Strands now supports true Python tool streaming where tool yield events (from an AsyncGenerator) appear inside the agent’s event stream via Agent.stream_async().
This works correctly for Strands-native Python tools, as documented here:
https://strandsagents.com/latest/documentation/docs/user-guide/concepts/tools/python-tools/#tool-streaming
However, when using MCP tools (via MCPClient), streaming events from the server are not surfaced to the agent. Instead:
- The MCP Python SDK successfully receives all tool chunks (verified with logging).
- The Strands MCP integration consumes those streaming chunks internally.
- Only the final MCP tool result is exposed to the LLM / agent.
- Intermediate streamed chunks are not emitted as AgentEvents and do not show up in
Agent.stream_async().
Expected Behavior
When an MCP tool returns an AsyncGenerator and streams multiple chunks:
- Each chunk should appear as a tool streaming event in
Agent.stream_async()(similar to the behavior of native Python tools after feat: Implement async generator tools #788). - The LLM should be able to observe partial tool output in real time.
Actual Behavior
- MCP tool streams are fully consumed internally.
- No intermediate chunks are surfaced.
- The agent only receives the final tool result.
- The LLM sometimes comments that "the tool is returning an async generator which means it's designed to stream the story content as it's being created. The actual story content would typically be streamed in real-time, but I'm not able to display the streaming output directly in this interface,” reflecting the missing event propagation.
Reproduction
Server-side (FastMCP)
from fastmcp import FastMCP
from typing import AsyncGenerator
mcp = FastMCP("Sample App")
@mcp.tool()
async def story(...) -> AsyncGenerator[dict]:
yield {"msg": "chunk 1"}
yield {"msg": "chunk 2"}
yield {"msg": "chunk 3"}
return {"msg": "final"}
# Run mcp server
mcp.run_async(transport="http", host="localhost", port=8005)Client-side (Strands)
from strands import Agent
from strands.tools.mcp.mcp_client import MCPClient
from mcp.client.streamable_http import streamablehttp_client
mcp_client = MCPClient(lambda: streamablehttp_client("http://localhost:8005/mcp"))
with mcp_client as mcp:
agent = Agent(model=..., tools=[client.list_tools_sync()])
async for event in agent.stream_async("Generate a story"):
print(event)Environment
- Strands SDK: 1.18.0
- FastMCP: 2.13.1
- Transport: streamable-http (SSE event stream)
Request
Could MCP tool streams be forwarded into Agent.stream_async() the same way Python tool streams are handled after PR #788?
This would allow MCP tools to benefit from the new streaming tool infrastructure and unlock real-time tool output for remote/HTTP-based tools.
Proposed Solution
- Surface MCP tool stream events as AgentEvents
- When
MCPClient/MCPAgentToolreceives a streaming chunk from the MCP Python SDK (viacall_tool_async): - Wrap each chunk in the same event type used by native Python tool streaming (ToolStreamEvent introduced in feat: Implement async generator tools #788), or an equivalent adapter event.
- Forward it to the agent’s callback handlers and
Agent.stream_async()generator.
This would mirror the behavior implemented for Python tools and enable tool streaming parity.
-
Preserve the existing final result behavior - with the final AgentEvent and structured output (if applicable)
-
Do not require MCP protocol changes - streamable-http transport already supports streaming these events - they just have to be forwarded to the Strands client-side agents.
Use Case
This would allow MCP tools to benefit from the new streaming tool infrastructure and unlock real-time tool output for remote/HTTP-based tools.
If a long-running MCP tool streams in-progress events, Strands on the client-side would be able to emit that progress to the user, rather than waiting for the final tool result.
Alternatives Solutions
- Using Strands-native tools - doesn't work if MCP architecture required
- Simply returning a final result object from the MCP tool, rather than streaming - but that simply avoids the problem
Additional Context
No response