-
Notifications
You must be signed in to change notification settings - Fork 241
feat(mcp): retain structured content in the AgentTool response #528
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat(mcp): retain structured content in the AgentTool response #528
Conversation
src/strands/tools/mcp/mcp_client.py
Outdated
@@ -252,6 +270,9 @@ def _handle_tool_result(self, tool_use_id: str, call_tool_result: MCPCallToolRes | |||
if (mapped_content := self._map_mcp_content_to_tool_result_content(content)) is not None | |||
] | |||
|
|||
if call_tool_result.structuredContent: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noting that the alternative to this is adding a new content type "structured". This is large decision point of this PR, should json be leveraged as an implied structured content or can json be different
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if there is an advantage to use "json" as an implied structure content field? If not, it may be more readable to add a new content type "structured" for readability
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, there is a third option too where we can do
ToolResult(
status:...
toolUseId:..
content: ...
structuredContent: ...
)
In this case structuredContent is not exposed to the Agent but is present to be usable by the tool caller
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comes down to if we view structuredContent as something that is just intended to be used by the user or not. The main concern is with the MCP spec
For backwards compatibility, a tool that returns structured content SHOULD also return the serialized JSON in a TextContent block.
meaning the content block may not be used. We could take the opinionated view that if a text block is not present we stringify the json and add it though.
After writing this I am leaning more toward the following but open to discussion
ToolResult(
status:...
toolUseId:..
content: ...
structuredContent: ...
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The above proposed approach sounds good to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We had a offline chat with @dbschmigelski about the ToolResult
object, I'd vote for content block with json
appended into results which follows existing patterns today.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chatted offline with a few folks on this as well.
I would like to avoid adding this to the tool result content array. MCP currently recommends that if a tool previously returned json in its result as serialized text, it SHOULD continue doing so. By appending the structuredContent to the content array, we are duplicating the number of tokens provided to the model.
Im thinking we extend the ToolResult
type with an MCPToolResult
, and when we call the bedrock model, we filter out only the required keys needed. This way we can include additional information like structuredContent
in the ToolResult, while also not impacting how the model uses it.
src/strands/tools/mcp/mcp_client.py
Outdated
expected by the agent framework. If structured content is available in the MCP tool result, | ||
it will be appended as the last item in the content array of the returned ToolResult. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will duplicate the response in content blocks, since both the structured and unstructured results are returned. Just a concern if it would break any existing implementations.
Description
This PR implements the retention of structured content in the AgentTool response when using the MCP client. When structured content is available from MCP tools, it will now be included as the last item in the content array of the returned ToolResult.
The changes include updating the MCP dependency to version 1.11.0, modifying the MCPClient class to handle structured content in both synchronous and asynchronous tool calls. The echo server in integration tests has been enhanced to include a new tool that returns structured content for testing purposes.
The implementation ensures backward compatibility while adding the ability to access structured data returned by MCP tools. This enhancement improves the flexibility of the SDK by allowing tools to return both unstructured and structured responses in a consistent format.
The changes have been tested with both unit tests and integration tests to verify proper handling of structured content in various scenarios.
Related to: https://modelcontextprotocol.io/specification/2025-06-18/server/tools#structured-content
Design Decision Discussion:
We faced two potential approaches for handling structured content:
Option A:
We could have mirrored the MCP Tool Response structure by having separate 'content' and 'structuredContent' fields in our AgentTool response. This would have introduced structured content support uniformly across all tools, not just MCP tools. However, this would require a more significant change to our existing tool response interface.
Option B (Chosen Approach):
We decided to leverage our existing 'json' content type capability, which already provides a mechanism for handling structured data. This approach maintains consistency with our current content type system while still allowing us to represent structured data.
A key design decision was whether to append the structured content to existing content items or replace them entirely. We chose to append the structured content as the last item in the content array for several reasons:
While appending was chosen, it's worth noting this wasn't a straightforward decision. Replacing existing content with structured content could have provided a cleaner, more direct approach to structured data handling, may result in existing applications breaking because an expected text block is no longer present.
Type of Change
New feature
Testing
How have you tested the change? Verify that the changes do not break functionality or introduce warnings in consuming repositories: agents-docs, agents-tools, agents-cli
hatch run prepare
Checklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.