Description
Expected Behavior
The McpSchema.Tool
record should be able to represent the full structure of a JSON Schema provided for inputSchema
, including top-level definitions specified using the $defs
(or older definitions
) keyword. This would allow server implementers to define complex, reusable types within the schema itself and use $ref
within the properties
to refer to them.
Ideally, the McpSchema.JsonSchema
record would be enhanced, or an alternative mechanism provided, to retain this information.
Example of desired outcome:
// Hypothetical enhanced JsonSchema record
public record JsonSchema(
@JsonProperty("type") String type,
@JsonProperty("properties") Map<String, Object> properties,
@JsonProperty("required") List<String> required,
@JsonProperty("additionalProperties") Boolean additionalProperties,
@JsonProperty("$defs") Map<String, Object> defs // Added field for definitions
) { }
// Or potentially keep JsonSchema simple and parse into a more generic Map
// Tool constructor might change:
public Tool(String name, String description, Map<String, Object> fullInputSchema) {
// ... internal handling ...
}
// Example usage when creating a Tool:
String complexSchemaJson = """
{
"type": "object",
"$defs": {
"Address": {
"type": "object",
"properties": {
"street": {"type": "string"},
"city": {"type": "string"}
},
"required": ["street", "city"]
}
},
"properties": {
"name": {"type": "string"},
"shippingAddress": {"$ref": "#/$defs/Address"}
},
"required": ["name", "shippingAddress"]
}
""";
// Current SDK constructor loses $defs:
// McpSchema.Tool tool = new McpSchema.Tool("addressTool", "Handles addresses", complexSchemaJson);
// tool.inputSchema() would NOT contain the $defs section.
// Desired behavior:
// Somehow create a Tool object where the full structure, including $defs, is preserved
// and potentially accessible, allowing for more robust schema validation or generation
// on the client or server side based on the full definition.
Current Behavior
Currently, the McpSchema.JsonSchema
record only defines fields for type
, properties
, required
, and additionalProperties
.
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record JsonSchema(
@JsonProperty("type") String type,
@JsonProperty("properties") Map<String, Object> properties,
@JsonProperty("required") List<String> required,
@JsonProperty("additionalProperties") Boolean additionalProperties
) { }
When a JSON schema string is provided to the McpSchema.Tool(String name, String description, String schema)
constructor, the internal parseSchema
method deserializes this string directly into the McpSchema.JsonSchema
record using Jackson (OBJECT_MAPPER.readValue(schema, JsonSchema.class)
).
Due to the limited fields in the JsonSchema
record and the @JsonIgnoreProperties(ignoreUnknown = true)
annotation, any top-level properties in the JSON string that do not match the record's fields, specifically $defs
(or definitions
), are ignored and discarded during deserialization.
As a result, it's impossible to represent or convey tool input schemas that rely on internal definitions using $defs
through the current McpSchema.Tool
structure. The structural information about reusable types defined in $defs
is lost.
Context
We are developing an MCP server using the Java SDK where our tools accept complex input structures. To promote consistency and avoid repetition, we want to define reusable data types within the tool's inputSchema
using the standard JSON Schema $defs
keyword and reference them using $ref
within the properties
.
The current limitation prevents us from accurately representing these schemas within the McpSchema.Tool
object. This hinders:
- Client-side Validation: Clients receiving the
Tool
definition cannot perform complete validation if the schema relies on$defs
that are missing. - Schema Clarity: The schema conveyed via MCP doesn't fully represent the intended structure.
- Code Generation: Tooling that might generate client-side code or documentation based on the
inputSchema
will lack the necessary definitions.
Alternatives Considered:
- External References: Using
$ref
to point to external URIs where the full schema (including definitions) is hosted. This adds complexity (hosting schemas) and potential latency. - Inlining Definitions: Repeating the full definition of a reusable type everywhere it's used within the
properties
. This violates the DRY principle and makes schemas verbose and hard to maintain. - Flattening Schemas: Pre-processing schemas to resolve all
$ref
s and remove$defs
before passing the string to theTool
constructor. This requires an external JSON Schema processing library and adds build complexity.
Workarounds:
- The primary workaround is schema flattening/pre-processing before creating the
Tool
object, which is cumbersome.
Adding support for $defs
directly within the SDK's schema representation would significantly improve the ability to define and communicate complex tool interfaces according to standard JSON Schema practices.