Summary
The validate method of JsonSchemaValidator treats a String structuredContent argument as a serialized JSON document to parse before validation. It does not treat the argument as a literal JSON string value.
This behavior is intentional and consistent across both JSON modules, but it is undocumented, which makes the API easy to misuse when you validate schemas whose document root is a scalar.
Steps to reproduce
Suppose you validate a root-level string against an enum schema:
var validator = new DefaultJsonSchemaValidator();
var schema = Map.<String, Object>of("enum", List.of("red", "green"));
var response = validator.validate(schema, "red");
The validation fails even though red is a member of the enumeration:
Error parsing tool JSON Schema: Unrecognized token 'red': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
Two things confuse readers here:
- The failure comes from JSON parsing, not from the
enum keyword. NetworkNT evaluates root-level enums correctly when the instance reaches it as a parsed node.
- The message says "tool JSON Schema", although the schema parses fine and the content is what fails to parse.
Passing quoted JSON text produces the expected results:
validator.validate(schema, "\"red\""); // valid=true
validator.validate(schema, "\"blue\""); // valid=false
Non-string instances follow the other path. The following call validates
correctly because Jackson converts the value through valueToTree:
var numericSchema = Map.<String, Object>of("enum", List.of(1, 2));
validator.validate(numericSchema, 1); // valid=true
Current implementation
Both default validators contain the same special case:
mcp-json-jackson2: io.modelcontextprotocol.json.schema.jackson2.DefaultJsonSchemaValidator,
the instanceof String branch at line 70
mcp-json-jackson3: io.modelcontextprotocol.json.schema.jackson3.DefaultJsonSchemaValidator,
the instanceof String branch at line 69
When the argument is a String, the validator calls jsonMapper.readTree on
it; otherwise it calls jsonMapper.valueToTree.
Suggested resolution
This is a documentation gap, not a behavioral bug. Add the contract to the
JsonSchemaValidator#validate Javadoc: if structuredContent is a String,
the method parses it as serialized JSON; quote embedded strings accordingly
(for example, "\"red\"" represents the JSON string value red). Any other
type is converted to its JSON representation directly.
A companion pull request with that Javadoc addition is ready if maintainers
want it; say so here and I will open it.
Context
Found during an audit of tool output-schema validation coverage against
SEP-2106 (#1000). Existing tests cover enum values nested inside object
properties; root-level scalar documents were the untested corner where the
undocumented contract surfaced.
Summary
The
validatemethod ofJsonSchemaValidatortreats aStringstructuredContentargument as a serialized JSON document to parse before validation. It does not treat the argument as a literal JSON string value.This behavior is intentional and consistent across both JSON modules, but it is undocumented, which makes the API easy to misuse when you validate schemas whose document root is a scalar.
Steps to reproduce
Suppose you validate a root-level string against an
enumschema:The validation fails even though
redis a member of the enumeration:Two things confuse readers here:
enumkeyword. NetworkNT evaluates root-level enums correctly when the instance reaches it as a parsed node.Passing quoted JSON text produces the expected results:
Non-string instances follow the other path. The following call validates
correctly because Jackson converts the value through
valueToTree:Current implementation
Both default validators contain the same special case:
mcp-json-jackson2:io.modelcontextprotocol.json.schema.jackson2.DefaultJsonSchemaValidator,the
instanceof Stringbranch at line 70mcp-json-jackson3:io.modelcontextprotocol.json.schema.jackson3.DefaultJsonSchemaValidator,the
instanceof Stringbranch at line 69When the argument is a
String, the validator callsjsonMapper.readTreeonit; otherwise it calls
jsonMapper.valueToTree.Suggested resolution
This is a documentation gap, not a behavioral bug. Add the contract to the
JsonSchemaValidator#validateJavadoc: ifstructuredContentis aString,the method parses it as serialized JSON; quote embedded strings accordingly
(for example,
"\"red\""represents the JSON string valuered). Any othertype is converted to its JSON representation directly.
A companion pull request with that Javadoc addition is ready if maintainers
want it; say so here and I will open it.
Context
Found during an audit of tool output-schema validation coverage against
SEP-2106 (#1000). Existing tests cover enum values nested inside object
properties; root-level scalar documents were the untested corner where the
undocumented contract surfaced.