feat(mcp): relax MCP Schema JSON deserialization constraints (#37)

* feat(mcp):  relax MCP Schema JSON deserialization constraints

- Add @JsonIgnoreProperties(ignoreUnknown = true) annotation to all record
classes in McpSchema to make JSON deserialization more robust by ignoring
unknown properties.
- Make the JsonSchema record public

Resolves #36

This improves compatibility with third-party implementations like Cursor that are not MCP Schema compliant.

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
Christian Tzolov 2025-03-10 12:36:54 +01:00 • committed by GitHub
commit 4eff00c8da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -176,6 +176,7 @@ public final class McpSchema {
} }
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record JSONRPCRequest( // @formatter:off public record JSONRPCRequest( // @formatter:off
@JsonProperty("jsonrpc") String jsonrpc, @JsonProperty("jsonrpc") String jsonrpc,
@JsonProperty("method") String method, @JsonProperty("method") String method,
@ -184,6 +185,7 @@ public final class McpSchema {
} // @formatter:on } // @formatter:on
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record JSONRPCNotification( // @formatter:off public record JSONRPCNotification( // @formatter:off
@JsonProperty("jsonrpc") String jsonrpc, @JsonProperty("jsonrpc") String jsonrpc,
@JsonProperty("method") String method, @JsonProperty("method") String method,
@ -191,6 +193,7 @@ public final class McpSchema {
} // @formatter:on } // @formatter:on
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record JSONRPCResponse( // @formatter:off public record JSONRPCResponse( // @formatter:off
@JsonProperty("jsonrpc") String jsonrpc, @JsonProperty("jsonrpc") String jsonrpc,
@JsonProperty("id") Object id, @JsonProperty("id") Object id,
@ -198,6 +201,7 @@ public final class McpSchema {
@JsonProperty("error") JSONRPCError error) implements JSONRPCMessage { @JsonProperty("error") JSONRPCError error) implements JSONRPCMessage {
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record JSONRPCError( public record JSONRPCError(
@JsonProperty("code") int code, @JsonProperty("code") int code,
@JsonProperty("message") String message, @JsonProperty("message") String message,
@ -209,6 +213,7 @@ public final class McpSchema {
// Initialization // Initialization
// --------------------------- // ---------------------------
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record InitializeRequest( // @formatter:off public record InitializeRequest( // @formatter:off
@JsonProperty("protocolVersion") String protocolVersion, @JsonProperty("protocolVersion") String protocolVersion,
@JsonProperty("capabilities") ClientCapabilities capabilities, @JsonProperty("capabilities") ClientCapabilities capabilities,
@ -239,6 +244,7 @@ public final class McpSchema {
* *
*/ */
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ClientCapabilities( // @formatter:off public record ClientCapabilities( // @formatter:off
@JsonProperty("experimental") Map<String, Object> experimental, @JsonProperty("experimental") Map<String, Object> experimental,
@JsonProperty("roots") RootCapabilities roots, @JsonProperty("roots") RootCapabilities roots,
@ -254,6 +260,7 @@ public final class McpSchema {
* has changed since the last time the server checked. * has changed since the last time the server checked.
*/ */
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record RootCapabilities( public record RootCapabilities(
@JsonProperty("listChanged") Boolean listChanged) { @JsonProperty("listChanged") Boolean listChanged) {
} }
@ -303,6 +310,7 @@ public final class McpSchema {
}// @formatter:on }// @formatter:on
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ServerCapabilities( // @formatter:off public record ServerCapabilities( // @formatter:off
@JsonProperty("experimental") Map<String, Object> experimental, @JsonProperty("experimental") Map<String, Object> experimental,
@JsonProperty("logging") LoggingCapabilities logging, @JsonProperty("logging") LoggingCapabilities logging,
@ -375,6 +383,7 @@ public final class McpSchema {
} // @formatter:on } // @formatter:on
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record Implementation(// @formatter:off public record Implementation(// @formatter:off
@JsonProperty("name") String name, @JsonProperty("name") String name,
@JsonProperty("version") String version) { @JsonProperty("version") String version) {
@ -413,6 +422,7 @@ public final class McpSchema {
* optional. It is a number between 0 and 1. * optional. It is a number between 0 and 1.
*/ */
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record Annotations( // @formatter:off public record Annotations( // @formatter:off
@JsonProperty("audience") List<Role> audience, @JsonProperty("audience") List<Role> audience,
@JsonProperty("priority") Double priority) { @JsonProperty("priority") Double priority) {
@ -458,6 +468,7 @@ public final class McpSchema {
* @see <a href="https://datatracker.ietf.org/doc/html/rfc6570">RFC 6570</a> * @see <a href="https://datatracker.ietf.org/doc/html/rfc6570">RFC 6570</a>
*/ */
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ResourceTemplate( // @formatter:off public record ResourceTemplate( // @formatter:off
@JsonProperty("uriTemplate") String uriTemplate, @JsonProperty("uriTemplate") String uriTemplate,
@JsonProperty("name") String name, @JsonProperty("name") String name,
@ -481,6 +492,7 @@ public final class McpSchema {
} // @formatter:on } // @formatter:on
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ReadResourceRequest( // @formatter:off public record ReadResourceRequest( // @formatter:off
@JsonProperty("uri") String uri){ @JsonProperty("uri") String uri){
} // @formatter:on } // @formatter:on
@ -499,11 +511,13 @@ public final class McpSchema {
* it is up to the server how to interpret it. * it is up to the server how to interpret it.
*/ */
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record SubscribeRequest( // @formatter:off public record SubscribeRequest( // @formatter:off
@JsonProperty("uri") String uri){ @JsonProperty("uri") String uri){
} // @formatter:on } // @formatter:on
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record UnsubscribeRequest( // @formatter:off public record UnsubscribeRequest( // @formatter:off
@JsonProperty("uri") String uri){ @JsonProperty("uri") String uri){
} // @formatter:on } // @formatter:on
@ -574,6 +588,7 @@ public final class McpSchema {
* @param arguments A list of arguments to use for templating the prompt. * @param arguments A list of arguments to use for templating the prompt.
*/ */
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record Prompt( // @formatter:off public record Prompt( // @formatter:off
@JsonProperty("name") String name, @JsonProperty("name") String name,
@JsonProperty("description") String description, @JsonProperty("description") String description,
@ -588,6 +603,7 @@ public final class McpSchema {
* @param required Whether this argument must be provided. * @param required Whether this argument must be provided.
*/ */
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record PromptArgument( // @formatter:off public record PromptArgument( // @formatter:off
@JsonProperty("name") String name, @JsonProperty("name") String name,
@JsonProperty("description") String description, @JsonProperty("description") String description,
@ -604,6 +620,7 @@ public final class McpSchema {
* @param content The content of the message of type {@link Content}. * @param content The content of the message of type {@link Content}.
*/ */
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record PromptMessage( // @formatter:off public record PromptMessage( // @formatter:off
@JsonProperty("role") Role role, @JsonProperty("role") Role role,
@JsonProperty("content") Content content) { @JsonProperty("content") Content content) {
@ -630,6 +647,7 @@ public final class McpSchema {
* @param arguments Arguments to use for templating the prompt. * @param arguments Arguments to use for templating the prompt.
*/ */
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record GetPromptRequest(// @formatter:off public record GetPromptRequest(// @formatter:off
@JsonProperty("name") String name, @JsonProperty("name") String name,
@JsonProperty("arguments") Map<String, Object> arguments) implements Request { @JsonProperty("arguments") Map<String, Object> arguments) implements Request {
@ -667,7 +685,7 @@ public final class McpSchema {
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
record JsonSchema( // @formatter:off public record JsonSchema( // @formatter:off
@JsonProperty("type") String type, @JsonProperty("type") String type,
@JsonProperty("properties") Map<String, Object> properties, @JsonProperty("properties") Map<String, Object> properties,
@JsonProperty("required") List<String> required, @JsonProperty("required") List<String> required,
@ -688,6 +706,7 @@ public final class McpSchema {
* arguments before sending them to the server. * arguments before sending them to the server.
*/ */
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record Tool( // @formatter:off public record Tool( // @formatter:off
@JsonProperty("name") String name, @JsonProperty("name") String name,
@JsonProperty("description") String description, @JsonProperty("description") String description,
@ -742,6 +761,7 @@ public final class McpSchema {
// Sampling Interfaces // Sampling Interfaces
// --------------------------- // ---------------------------
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ModelPreferences(// @formatter:off public record ModelPreferences(// @formatter:off
@JsonProperty("hints") List<ModelHint> hints, @JsonProperty("hints") List<ModelHint> hints,
@JsonProperty("costPriority") Double costPriority, @JsonProperty("costPriority") Double costPriority,
@ -750,10 +770,12 @@ public final class McpSchema {
} // @formatter:on } // @formatter:on
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ModelHint(@JsonProperty("name") String name) { public record ModelHint(@JsonProperty("name") String name) {
} }
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record SamplingMessage(// @formatter:off public record SamplingMessage(// @formatter:off
@JsonProperty("role") Role role, @JsonProperty("role") Role role,
@JsonProperty("content") Content content) { @JsonProperty("content") Content content) {
@ -761,6 +783,7 @@ public final class McpSchema {
// Sampling and Message Creation // Sampling and Message Creation
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record CreateMessageRequest(// @formatter:off public record CreateMessageRequest(// @formatter:off
@JsonProperty("messages") List<SamplingMessage> messages, @JsonProperty("messages") List<SamplingMessage> messages,
@JsonProperty("modelPreferences") ModelPreferences modelPreferences, @JsonProperty("modelPreferences") ModelPreferences modelPreferences,
@ -837,6 +860,7 @@ public final class McpSchema {
// Pagination Interfaces // Pagination Interfaces
// --------------------------- // ---------------------------
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record PaginatedRequest(@JsonProperty("cursor") String cursor) { public record PaginatedRequest(@JsonProperty("cursor") String cursor) {
} }
@ -848,6 +872,7 @@ public final class McpSchema {
// --------------------------- // ---------------------------
// Progress and Logging // Progress and Logging
// --------------------------- // ---------------------------
@JsonIgnoreProperties(ignoreUnknown = true)
public record ProgressNotification(// @formatter:off public record ProgressNotification(// @formatter:off
@JsonProperty("progressToken") String progressToken, @JsonProperty("progressToken") String progressToken,
@JsonProperty("progress") double progress, @JsonProperty("progress") double progress,
@ -864,6 +889,7 @@ public final class McpSchema {
* @param logger The logger that generated the message. * @param logger The logger that generated the message.
* @param data JSON-serializable logging data. * @param data JSON-serializable logging data.
*/ */
@JsonIgnoreProperties(ignoreUnknown = true)
public record LoggingMessageNotification(// @formatter:off public record LoggingMessageNotification(// @formatter:off
@JsonProperty("level") LoggingLevel level, @JsonProperty("level") LoggingLevel level,
@JsonProperty("logger") String logger, @JsonProperty("logger") String logger,
@ -980,6 +1006,7 @@ public final class McpSchema {
} }
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record TextContent( // @formatter:off public record TextContent( // @formatter:off
@JsonProperty("audience") List<Role> audience, @JsonProperty("audience") List<Role> audience,
@JsonProperty("priority") Double priority, @JsonProperty("priority") Double priority,
@ -991,6 +1018,7 @@ public final class McpSchema {
} }
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ImageContent( // @formatter:off public record ImageContent( // @formatter:off
@JsonProperty("audience") List<Role> audience, @JsonProperty("audience") List<Role> audience,
@JsonProperty("priority") Double priority, @JsonProperty("priority") Double priority,
@ -999,6 +1027,7 @@ public final class McpSchema {
} }
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record EmbeddedResource( // @formatter:off public record EmbeddedResource( // @formatter:off
@JsonProperty("audience") List<Role> audience, @JsonProperty("audience") List<Role> audience,
@JsonProperty("priority") Double priority, @JsonProperty("priority") Double priority,
@ -1019,6 +1048,7 @@ public final class McpSchema {
* for referencing the root in other parts of the application. * for referencing the root in other parts of the application.
*/ */
@JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record Root( // @formatter:off public record Root( // @formatter:off
@JsonProperty("uri") String uri, @JsonProperty("uri") String uri,
@JsonProperty("name") String name) { @JsonProperty("name") String name) {