feat(mcp): expose entity creation schemas on demand

Expose creation fields, constraints and examples for the 11 supported types without expanding startup tool schemas. Share the creation contract and constructor with execution to keep accepted inputs consistent.

Validation: MCP, contract/factory and entity creation regression tests.
This commit is contained in:
Karim Jerbi committed 2026-10-13 09:33:49 +01:00
1 parent a5435a6df6
commit 97afb57333
10 files changed
+1118 -488

No files matched your search

+42
View File
@@ -0,0 +1,42 @@
//! Offline validation of application-owned JSON Schema contracts.
use serde_json::Value;
/// Only application-owned schemas enter this cache; client payloads are instances,
/// never schemas. Disable JSON Schema HTTP/file resolution at the dependency level.
pub fn validate_shape(schema: &Value, value: &Value, path: &str) -> Result<(), String> {
use std::{
collections::HashMap,
sync::{Arc, Mutex, OnceLock},
};
static VALIDATORS: OnceLock<Mutex<HashMap<String, Arc<jsonschema::Validator>>>> =
OnceLock::new();
let key = schema.to_string();
let validator = {
let mut cache = VALIDATORS
.get_or_init(Default::default)
.lock()
.expect("schema cache poisoned");
if let Some(validator) = cache.get(&key) {
Arc::clone(validator)
} else {
let validator = Arc::new(
jsonschema::validator_for(schema).expect("application-owned schema must compile"),
);
cache.insert(key, Arc::clone(&validator));
validator
}
};
validator.validate(value).map_err(|error| {
let field = match error.kind() {
jsonschema::error::ValidationErrorKind::Required { property } => property.as_str(),
jsonschema::error::ValidationErrorKind::AdditionalProperties { unexpected } => {
unexpected.first().map(String::as_str)
}
_ => None,
};
let suffix = field
.map(|key| format!("/{}", key.replace('~', "~0").replace('/', "~1")))
.unwrap_or_default();
format!("{path}{}{suffix}: {error}", error.instance_path())
})
}