-
Notifications
You must be signed in to change notification settings - Fork 45
feat: Add structured output support to SmolAgentsAdapter (#62) #63
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
Conversation
Structured output was added in MCP spec 2025-06-18+
- Introduced structured output features, allowing conversion of MCP tools to SmolAgents tools with outputSchema support. - Added validation for output against schema with warnings for non-strict checks. - Implemented a two-level parameter system for structured output handling, ensuring backwards compatibility. - Updated example usage and documentation to reflect new capabilities and usage patterns.
- Introduced a new test file to validate structured output handling in SmolAgentsAdapter. - Implemented tests for various scenarios including weather synchronization, validation of unparseable JSON, and list outputs. - Ensured that tools return expected structured outputs and that appropriate warnings are logged for invalid outputs. - Verified schema structures for tools returning lists and simple text outputs, enhancing overall test coverage for the adapter's capabilities.
- Test same tools with both structured_output=False and True - Verify legacy mode (raw strings/JSON) vs enhanced mode (wrapped objects) - Ensure existing code compatibility when upgrading adapter settings
7c42963
to
6fb1d0e
Compare
I have merged the latest updates from main and keep all structured output functionality working. All tests are passing and backwards compatibility works with structured_output=False as default. I would be very happy about feedback and thank you very much! |
- Updated output type strategy to consistently use "object" for maximum flexibility, allowing runtime type detection for text, image, and audio content. - Removed validation against schema as it is no longer necessary with the new output type approach. - Adjusted tests to reflect changes in output type expectations, ensuring compatibility with legacy and enhanced modes.
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.
Check my previous message. I think we can just check for structureContent
in TextContent
based on the backward compatibility note in the specification.
Thank you very much @HSGamer for your support! I really appreciate your help as I am new to mcpadapt and smolagents. I have some concerns about parsing Here are some tool examples from the Python implementation of the Model Context Protocol (MCP): The following tools show how TextContent and structuredContent are handled very differently. The output schema would not match the returned content if we rely on the TextContent. Note: The RAW Response examples below are actual outputs generated by the official Python MCP SDK reference implementation. Example 1: List @mcp.tool()
def list_cities() -> list[str]:
"""Get a list of cities"""
return ["London", "Paris", "Tokyo"]
# Returns: {"result": ["London", "Paris", "Tokyo"]} Output Schema: {
"type": "object",
"properties": {
"result": {
"items": {
"type": "string"
},
"title": "Result",
"type": "array"
}
},
"required": [
"result"
],
"title": "list_citiesOutput"
} RAW Response: {
"content": [
{
"type": "text",
"text": "London"
},
{
"type": "text",
"text": "Paris"
},
{
"type": "text",
"text": "Tokyo"
}
],
"structuredContent": {
"result": [
"London",
"Paris",
"Tokyo"
]
},
"isError": false
} Example 2: Number @mcp.tool()
def get_temperature(city: str) -> float:
"""Get temperature as a simple float"""
return 22.5
# Returns: {"result": 22.5} Output Schema: {
"type": "object",
"properties": {
"result": {
"title": "Result",
"type": "number"
}
},
"required": [
"result"
],
"title": "get_temperatureOutput"
} RAW Response: {
"content": [
{
"type": "text",
"text": "22.5"
}
],
"structuredContent": {
"result": 22.5
},
"isError": false
} Why This MattersProblem 1: Lists break apart
Problem 2: Data types are lost
Problem 3: Schema mismatch
My QuestionSince the MCP spec says tools SHOULD provide both formats for backwards compatibility, shouldn't we:
This approach would...
With this strategy, would we still need something like What do you think? Thank you again for your help! |
You can always prefer |
Thank you @HSGamer! I'm happy that this make sense to you. But I worry about backward compatibility without a solution like If we always use Here's what happens:The latest releases of MCP Python SDK wrap return values in a What This Means for UsersSmolagents and our tests in Example: tool in @mcp.tool()
def echo_tool(text: str) -> str:
"""Echo the input text"""
return f"Echo: {text}"
Existing code, and our test expects the simple string Possible solution:What if we use This gives us:
Usage in smolagents: with MCPClient(server_parameters, structured_output=True) as tools:
# True is passed into MCPAdapt(server_parameters, SmolAgentsAdapter(structured_output=structured_output))
# smolagents gets structured output + output schema
# and can render the schema in the CodeAgent system prompt Advantages:
What do you think? Is it worth adding a flag to avoid breaking existing code? Thank you for helping with these design decisions! |
Now you mention it, it seems like the |
If that's the case we can always patch the fastMCP implementation :) |
Either ways, I think keeping the flag is fine for now. We can remove it later when we figure out a way to patch FastMCP that makes sense. |
I totally agree with you @grll and @HSGamer! The MCP specification is not clearly describing all relevant cases. The specification may be intentionally leaving room for interpretation? I do understand the reasoning behind FastMCP wrapping everything in When primitive and generic types are wrapped inside the I think they are aware of the compatibility issues as they provide a related flag to ours: There are two notes in the FastAPI / Python SDK documentation:
I think it makes sense to keep the flag in MCPAdapt to be independent of the tool and to be able to decide what we get on the agent side. @grll I fixed the linter issue with the last commit. Sorry for missing that! Thanks a lot! |
- Update docstring to indicate JSON parsing happens when structured_output=True, not just when outputSchema exists - Clarify that JSON parsing always attempts when structuredContent is absent - No functional changes, documentation only
83dff8b
to
74d45be
Compare
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.
Thank a lot for bringing this feature into mcpadapt! and sorry for the delay in reviewing the work. I have added a few points here and there.
Focus on type correctness, warning cases, and backwards compatibility.
…put coverage - Add comprehensive tests for structured output type handling - Add test for warning if tool returns unparseable JSON
…f format recommendation)
I added the ruff format recommendations in my last commit (612ea05). |
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.
Thanks a lot @grll for your support and feedback on this PR!
Based on your suggestions I've made the following updates with my latest commits:
- Kept docstring minimal and informative
- Used
structured_output
parameter consistently - Refactored tests to focus on types and warnings, tests now validate:
- Different return types (dict, list, string) are handled with proper schemas
- Warning messages are properly logged when tools return unparseable JSON
- Consolidated structured output tests, moved all structured output-related tests to
tests/test_smolagents_adapter.py
Hey hey thanks for your patience and sorry again for the time it took to review. I have just added a demo script that showcases the benefits of using structured output it's crazy how much it improves! |
@chahn let me know what you think, we should be good to merge |
@grll Great example, thank you for adding! If everything looks good on your side, feel free to merge. I’ve already prepared a PR for smolagents to use this new feature. Once this is merged, I’ll open it there and would love your feedback. Thanks a lot for your support! |
Thanks again @chahn really impactful change for CodeAgents! |
Good work |
Thanks again for all your help, @grll and @HSGamer. I’d really appreciate your feedback when you have a moment. |
…rll#63) * Update mcp dependency version to 1.10.1 in pyproject.toml Structured output was added in MCP spec 2025-06-18+ * Enhance SmolAgentsAdapter with structured output support - Introduced structured output features, allowing conversion of MCP tools to SmolAgents tools with outputSchema support. - Added validation for output against schema with warnings for non-strict checks. - Implemented a two-level parameter system for structured output handling, ensuring backwards compatibility. - Updated example usage and documentation to reflect new capabilities and usage patterns. * Add tests for SmolAgentsAdapter structured output functionality - Introduced a new test file to validate structured output handling in SmolAgentsAdapter. - Implemented tests for various scenarios including weather synchronization, validation of unparseable JSON, and list outputs. - Ensured that tools return expected structured outputs and that appropriate warnings are logged for invalid outputs. - Verified schema structures for tools returning lists and simple text outputs, enhancing overall test coverage for the adapter's capabilities. * Add docstring to test_weather_sync for clarity * Fix: Merge image/audio support with structured output features * Update uv.lock for MCP dependency version 1.10.1 * Add backwards compatibility test for structured output - Test same tools with both structured_output=False and True - Verify legacy mode (raw strings/JSON) vs enhanced mode (wrapped objects) - Ensure existing code compatibility when upgrading adapter settings * Refactor SmolAgentsAdapter to always use "object" output type - Updated output type strategy to consistently use "object" for maximum flexibility, allowing runtime type detection for text, image, and audio content. - Removed validation against schema as it is no longer necessary with the new output type approach. - Adjusted tests to reflect changes in output type expectations, ensuring compatibility with legacy and enhanced modes. * Remove unused pytest import from structured output test file * docs: Clarify JSON parsing behavior in structured output mode - Update docstring to indicate JSON parsing happens when structured_output=True, not just when outputSchema exists - Clarify that JSON parsing always attempts when structuredContent is absent - No functional changes, documentation only * refactor: Rename use_structured_features to structured_output in SmolAgentsAdapter * docs: Update docstring in SmolAgentsAdapter to clarify structured output usage * refactor: streamline structured output tests for key behaviors Focus on type correctness, warning cases, and backwards compatibility. * refactor(tests): enhance smolagents adapter tests with structured output coverage - Add comprehensive tests for structured output type handling - Add test for warning if tool returns unparseable JSON * refactor: improve readability and structure in SmolAgentsAdapter (ruff format recommendation) * example structured vs not structured output --------- Co-authored-by: Guillaume Raille <[email protected]>
Summary
This PR implements structured output support for the SmolAgentsAdapter as described in issue #62. The adapter now handles MCP tools with
outputSchema
definitions.Motivation
The latest MCP specifications (2025-06-18+) include support for
outputSchema
, which enables tools to return structured data with defined schemas.It would be great to take advantage of the structured output capabilities that MCP now offers. This enhancement would allow smolagents to use tools that return complex data structures, JSON objects, and other structured formats.
With this feature the agent's LLMs can "see" the structure of the tool output before calling a tool.
Implementation Details
I tried to add following:
outputSchema
from MCP tools and passes it to smolagents for inclusion in system promptsoutputSchema
and setsoutput_type="object"
accordinglystructuredContent
from MCP responses when availablestructured_output=False
(default)I implemented a two-level parameter system:
structured_output
(adapter-level): User-facing flag to enable/disable structured featuresuse_structured_features
(tool-level): Internal flag controlling individual tool behaviorUsage
Testing
I added comprehensive tests in
tests/test_smolagents_adapter_structured_output.py
covering:All existing tests continue to pass, ensuring no breaking changes.
Demo
I prepared a PR for smolagents that is using the structured output feature of SmolAgentsAdaper.
With our changes, smolagents receives the output schema and includes it in the system prompt, enabling the LLM to understand tool output structure. This results in smolagents needing only one step to respond with an answer:
In this example smolgents is using an extended system prompt showing the LLM the output schema of the tool.
Backwards Compatibility
This implementation maintains 100% backwards compatibility:
structured_output=False
)Request for Feedback
This is my first contribution to mcpadapt, so I welcome any suggestions for improvements or alternative approaches!
Fixes #62