-
Notifications
You must be signed in to change notification settings - Fork 442
Add support for Tool.outputSchema and CallToolResult.structuredContent
#316
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
Add support for Tool.outputSchema and CallToolResult.structuredContent
#316
Conversation
- Add optional output_schema field to Tool struct for defining tool output structure - Update Tool::new() to initialize output_schema as None
- Add optional structured_content field for JSON object results - Make content field optional to support either structured or unstructured results - Add CallToolResult::structured() and structured_error() constructor methods
…ontent - Add validate() method to ensure content and structured_content are mutually exclusive - Implement custom Deserialize to enforce validation during deserialization - Update documentation to clarify the mutual exclusivity requirement
- Add output_schema field to ToolAttribute and ResolvedToolAttribute structs - Implement automatic output schema generation from return types - Support explicit output_schema attribute for manual specification - Generate schemas for Result<T, E> where T is not CallToolResult - Update tool generation to include output_schema in Tool struct
- Add Structured<T> wrapper type for explicit structured content - Implement IntoCallToolResult for Structured<T> with JSON serialization - Add support for Result<Structured<T>, E> conversions - Enable tools to return structured content through the trait system
- Handle Option<Vec<Content>> in CallToolResult.content - Add proper unwrapping for the optional content field - Fix compilation error in chat.rs
- Add output_schema field to Tool initialization in sampling_stdio example - Update test_tool_macros tests to handle Option<Vec<Content>> - Use as_ref() before calling first() on optional content field
- Add validate_against_schema function for basic type validation - Add note that full JSON Schema validation requires dedicated library - Document that actual validation should happen in tool handler
d9b8bfc to
8769ec5
Compare
- Add output_schema field to Tool struct for defining output JSON schemas - Add structured_content field to CallToolResult (mutually exclusive with content) - Implement Structured<T> wrapper for type-safe structured outputs - Update #[tool] macro to automatically generate output schemas from return types - Add validation of structured outputs against their schemas - Update all examples and tests for breaking change (CallToolResult.content now Option) - Add comprehensive documentation and rustdoc - Add structured_output example demonstrating the feature BREAKING CHANGE: CallToolResult.content is now Option<Vec<Content>> instead of Vec<Content> Closes modelcontextprotocol#312
8769ec5 to
b174b63
Compare
|
|
The #[tool] macro requires Parameters<T> wrapper for tool inputs. This fixes the pre-existing broken doctest in the structured output documentation example.
|
Some doctest were apparently failing on |
| } | ||
| } | ||
| _ => None, | ||
| } |
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.
Is the complexity of the circle here a bit high?
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.
Simplify this please.
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.
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.
It seems that there are no modifications here
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.
@jokemanfire my bad! Sorry.
Done in 43f08bf
|
Back to draft to add validation improvements:
|
Key Benefits:
Validation Logic: if let Some(ref output_schema) = item.attr.output_schema {
// When output_schema is defined, structured_content is required
if result.structured_content.is_none() {
return Err(crate::ErrorData::invalid_params(
"Tool with output_schema must return structured_content",
None
));
}
// Ensure content is not used when output_schema is defined
if result.content.is_some() {
return Err(crate::ErrorData::invalid_params(
"Tool with output_schema cannot use content field",
None
));
}
// Validate the structured content against the schema
validate_against_schema(result.structured_content.as_ref().unwrap(), output_schema)?;
}The implementation successfully addresses the original issue and ensures that when a tool declares an output_schema, it must consistently return structured content, providing better type safety and |
This commit implements strict validation to ensure tools with output_schema consistently use structured_content for both success and error responses. Changes: - Enhanced ToolRouter::call() validation to require structured_content when output_schema is present - Added validation that tools with output_schema cannot use regular content field - Added comprehensive tests covering the new strict validation behavior - Created example demonstrating proper structured output usage - Updated TODO.md to track validation improvements This ensures consistent response format and better type safety for MCP clients.
TODO.md
Outdated
| @@ -0,0 +1,142 @@ | |||
| Add support for: | |||
|
|
|||
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 may should not contain this doc.
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.
@jokemanfire sorry about that! fixed in cf52be9
| } | ||
| } | ||
| _ => None, | ||
| } |
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.
It seems that there are no modifications here
- Extract complex nested logic into dedicated helper function - Replace deeply nested if-else chains with functional approach - Use early returns and ? operator for cleaner code flow - Reduce 46 lines to 7 lines in main logic while improving readability
After further testing with IMHO the MCP protocol documentation is misleading or Claude Code itself is not up to date for version 2025-06-18 (!):
https://modelcontextprotocol.io/specification/2025-06-18/server/tools#structured-content That "SHOULD" is actually a "MUST" for now in my experience (cf anthropics/claude-code#4427). So I propose to revert 767d3ae. |
Structured content is returned as a JSON object in the structuredContent field of a result.For backwards compatibility, a tool that returns structured content SHOULD also return the serialized JSON in a TextContent block. https://modelcontextprotocol.io/specification/2025-06-18/server/tools#structured-content Tools may also provide an output schema for validation of structured results. If an output schema is provided: - Servers MUST provide structured results that conform to this schema. - Clients SHOULD validate structured results against this schema. https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema
It turns out that
https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema So instead of reverting 767d3ae I made the implementation compliant in 906812e Update: tested and working with Claude Code and opencode via https://gitlab.com/lx-industries/rmcp-openapi/-/issues/37 |
|
Sorry for not reponde this last week, thanks for your work, I will have a good look this week. |
Add support for:
Tool.outputSchemaCallToolResult.structuredContentMotivation and Context
Implements #312
First step toward MCP 2025-06-18 support.
How Has This Been Tested?
Comprehensive unit tests for the new structured output features we implemented. The tests cover:
CallToolResult::structured()andCallToolResult::structured_error()methodsoutput_schemafield functionalityIntoCallToolResulttrait implementation forStructured<T>contentandstructured_contentThe tests are located in
tests/test_structured_output.rsand provide good coverage of the core functionality we added.Breaking Changes
Both
Tool.outputSchemaandCallToolResult.structuredContentare optional.The only breaking change being that
CallToolResult.contentis now optional to support mutual exclusivity withstructured_content.Types of changes
Checklist
Additional context
None for now.
Task List
Core Data Structures
output_schema: Option<Arc<JsonObject>>field to Tool structstructured_content: Option<Value>field to CallToolResult structCallToolResult::structured()constructor methodCallToolResult::structured_error()constructor methodMacro Support
output_schemaattribute for manual schema specificationType Conversion Infrastructure
Structured<T>wrapper type for structured resultsIntoCallToolResultforStructured<T>IntoCallToolResultfor types that should produce structured contentTool Handler Updates
Testing
Documentation and Examples
Validation Improvements
Technical Considerations
Backward Compatibility
Performance
Error Handling
Dependencies
Timeline Estimate
Total estimated time: 14-20 hours
References