fix(shemars): use JSON Schema 2020-12 as Default Dialect (#549)
TODO: Not fully compatible with 2020-12 yet.
This commit is contained in:
parent
1d38d68709
commit
76cdf48b68
4 changed files with 57 additions and 21 deletions
|
|
@ -28,7 +28,8 @@ rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk", branch = "mai
|
||||||
Basic dependencies:
|
Basic dependencies:
|
||||||
- [tokio required](https://github.com/tokio-rs/tokio)
|
- [tokio required](https://github.com/tokio-rs/tokio)
|
||||||
- [serde required](https://github.com/serde-rs/serde)
|
- [serde required](https://github.com/serde-rs/serde)
|
||||||
|
Json Schema generation(Must follow the 2020-12 version):
|
||||||
|
- [shemars required](https://github.com/GREsau/schemars)
|
||||||
|
|
||||||
|
|
||||||
### Build a Client
|
### Build a Client
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ schemars = ["dep:schemars"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
schemars = { version = "1.0", features = ["chrono04"] }
|
schemars = { version = "1.1.0", features = ["chrono04"] }
|
||||||
|
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
tracing-subscriber = { version = "0.3", features = [
|
tracing-subscriber = { version = "0.3", features = [
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,8 @@ use crate::{
|
||||||
/// A shortcut for generating a JSON schema for a type.
|
/// A shortcut for generating a JSON schema for a type.
|
||||||
pub fn schema_for_type<T: JsonSchema>() -> JsonObject {
|
pub fn schema_for_type<T: JsonSchema>() -> JsonObject {
|
||||||
// explicitly to align json schema version to official specifications.
|
// explicitly to align json schema version to official specifications.
|
||||||
// https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/2025-03-26/schema.json
|
// refer to https://github.com/modelcontextprotocol/modelcontextprotocol/pull/655 for details.
|
||||||
// TODO: update to 2020-12 waiting for the mcp spec update
|
let mut settings = SchemaSettings::draft2020_12();
|
||||||
let mut settings = SchemaSettings::draft07();
|
|
||||||
settings.transforms = vec![Box::new(schemars::transform::AddNullable::default())];
|
settings.transforms = vec![Box::new(schemars::transform::AddNullable::default())];
|
||||||
let generator = settings.into_generator();
|
let generator = settings.into_generator();
|
||||||
let schema = generator.into_root_schema_for::<T>();
|
let schema = generator.into_root_schema_for::<T>();
|
||||||
|
|
|
||||||
|
|
@ -43,24 +43,60 @@ impl Demo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expected_schema() -> serde_json::Value {
|
||||||
|
serde_json::json!({
|
||||||
|
"$defs": {
|
||||||
|
"ChatMessage": {
|
||||||
|
"properties": {
|
||||||
|
"content": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"$ref": "#/$defs/ChatRole"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"role",
|
||||||
|
"content"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"ChatRole": {
|
||||||
|
"enum": [
|
||||||
|
"System",
|
||||||
|
"User",
|
||||||
|
"Assistant",
|
||||||
|
"Tool"
|
||||||
|
],
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"properties": {
|
||||||
|
"messages": {
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/ChatMessage"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"system": {
|
||||||
|
"nullable": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"messages"
|
||||||
|
],
|
||||||
|
"title": "ChatRequest",
|
||||||
|
"type": "object"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_complex_schema() {
|
fn test_complex_schema() {
|
||||||
let attr = Demo::chat_tool_attr();
|
let attr = Demo::chat_tool_attr();
|
||||||
let input_schema = attr.input_schema;
|
let input_schema = attr.input_schema;
|
||||||
let enum_number = input_schema
|
let expected = expected_schema();
|
||||||
.get("definitions")
|
let produced = serde_json::Value::Object(input_schema.as_ref().clone());
|
||||||
.unwrap()
|
assert_eq!(produced, expected, "schema mismatch");
|
||||||
.as_object()
|
|
||||||
.unwrap()
|
|
||||||
.get("ChatRole")
|
|
||||||
.unwrap()
|
|
||||||
.as_object()
|
|
||||||
.unwrap()
|
|
||||||
.get("enum")
|
|
||||||
.unwrap()
|
|
||||||
.as_array()
|
|
||||||
.unwrap()
|
|
||||||
.len();
|
|
||||||
assert_eq!(enum_number, 4);
|
|
||||||
println!("{}", serde_json::to_string_pretty(&input_schema).unwrap());
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue