feat: relax outputSchema to accept non-object JSON Schema types (SEP-2106)#895
feat: relax outputSchema to accept non-object JSON Schema types (SEP-2106)#895branben wants to merge 5 commits into
Conversation
|
thanks @branben if you can run a fmt over this to get CI happy - I think this is then good to merge, thanks! |
just checked on this @michaelneale happy I could contribute! |
| assert!(tool.output_schema.is_some()); | ||
|
|
||
| let schema_str = serde_json::to_string(tool.output_schema.as_ref().unwrap()).unwrap(); | ||
| assert!(schema_str.contains("\"type\":\"integer\"")); |
There was a problem hiding this comment.
To prevent false positives
| assert!(schema_str.contains("\"type\":\"integer\"")); | |
| assert_eq!(schema.get("type"), Some(&serde_json::json!("integer"))); |
There was a problem hiding this comment.
@branben You marked this as resolved but it still doesn't seem to be fixed!
|
Thanks for the review @DaleSeo! All 4 comments addressed in the latest push:
The Please let me know where else I can make meaningful contributions if there's a specific pain point that's bugging the team! |
|
@branben You might've forgotten to push those fixes? I'm still seeing the original code. 😅 |
47e5d23 to
6588978
Compare
…urns Result - Add strip_output() that strips title/description without validating type (Dale modelcontextprotocol#1) - Change schema_for_output to return Arc<JsonObject> instead of Result (Dale modelcontextprotocol#2) - Cache only Arc<JsonObject> success values, not Result (Dale modelcontextprotocol#3) - Remove dead unwrap_or_else panic paths in with_output_schema, ToolBase, and macros - Tighten test assertions from contains to assert_eq on type field (Dale modelcontextprotocol#4) - Update test_schema_for_output_rejects_primitive to accept_primitive (SEP-2106) Co-authored-by: Orca <help@stably.ai>
Add tests verifying schema_for_output accepts non-object types: - test_tool_builder_methods: primitive (i32), array (Vec<String>), option - test_structured_output: tool returning Json<Vec<T>> and Json<i32> - test_json_schema_detection: Json<Vec<T>>, Result<Json<Vec<T>>,E>, Json<String> - tool_traits: ToolBase::output_schema with Vec<AddOutput> output type
Add tests identified during code review: - description stripping for primitive types - composition types (Option<String> with anyOf/oneOf/null) - cache correctness (Arc::ptr_eq for repeated calls) - schema_for_input rejecting array types (not just primitives) - schema_for_output accepting unit type ()
6588978 to
28c2bcc
Compare
| assert!(tool.output_schema.is_some()); | ||
|
|
||
| let schema_str = serde_json::to_string(tool.output_schema.as_ref().unwrap()).unwrap(); | ||
| assert!(schema_str.contains("\"type\":\"integer\"")); |
There was a problem hiding this comment.
@branben You marked this as resolved but it still doesn't seem to be fixed!
|
|
||
| /// Generate and strip a JSON schema for outputSchema (top-level "title" and | ||
| /// "description" are removed; output schemas are not restricted to root type "object"). | ||
| pub fn schema_for_output<T: JsonSchema + std::any::Any>() -> Arc<JsonObject> { |
There was a problem hiding this comment.
Public API Check is red in CI because the schema_for_output return-type change is a breaking change:
-pub fn ...::schema_for_output<...>() -> Result<Arc<JsonObject>, String>
+pub fn ...::schema_for_output<...>() -> Arc<JsonObject>
Error: The API diff is not allowed as per --deny: Changed items not allowed
That's expected and fine, and the plan is to batch all 2026-07-28 spec breaking changes into v3.0. So this SEP-2106 implementation belongs in that major.
We need to mark the introducing commit breaking though replacing feat: with feat!: so the CI gate computes major and Public API Check passes.
This introduces SEP-2106: schema_for_output no longer validates or returns Result. The public signature changed, so bump major.
…ArrayTool
- Replace loose schema_str.contains(...) assertions with direct
schema.get("type") equality checks in test_tool_builder_methods.rs
and test_structured_output.rs
- Remove redundant ArrayTool fixture and its round-trip
serde_json::from_str test from tool_traits.rs since schema is
already Arc<JsonObject>
- Drop dead schema_str variable in test_structured_output.rs
|
Hey again @DaleSeo ! context on this commit ended up getting malformed and rotted from a memory mcp tool as I was working on this, so I apologize for a bit of the run around! Let me know if I'm on the right path here! |
Thanks @DaleSeo you're the GOAT!, are there any other specific pain points I could contribute to that might make the next migration easier? |
Summary
Relax
schema_for_outputto accept any JSON Schema 2020-12 root type (arrays, primitives, compositions) foroutputSchema, while keepingschema_for_inputenforcingtype: "object". This implements SEP-2106, which was accepted May 18 2026.PR #860 (merged Jun 2 2026) added title/desc stripping and input validation. This PR covers the remaining work: decoupling the type gate so output schemas are no longer rejected for non-object types.
Changes
crates/rmcp/src/handler/server/common.rs: Splitvalidate_and_stripinto:validate_and_strip_input— keepstype: "object"check for inputSchemavalidate_and_strip_output— strips title/desc, no type check (accepts any JSON Schema root type)crates/rmcp/src/model/tool.rs: Updatedwith_output_schemadoc comment to remove incorrect "root type object" panic referenceOption<T>), unit type,Json<T>macro path,ToolBasetrait path, cache correctness, and negative tests for input rejectionBackward Compatibility
schema_for_outputreturn type unchanged (Result<Arc<JsonObject>, String>)Verification
cargo test -p rmcp --all-features: 424 passed, 0 failedcargo clippy --all-targets --all-features -- -D warnings: No issues found