From 9e858f1c525bf1203e9f8df0cd6a03c45d2f2239 Mon Sep 17 00:00:00 2001 From: jitokim Date: Wed, 23 Apr 2025 01:17:47 +0900 Subject: [PATCH] add AudioContent to McpSchema Signed-off-by: jitokim --- .../modelcontextprotocol/spec/McpSchema.java | 15 ++++++- .../spec/McpSchemaTests.java | 42 ++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java b/mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java index e77edb3b..6d05a94a 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java +++ b/mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java @@ -1254,8 +1254,9 @@ public record CompleteCompletion( @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = TextContent.class, name = "text"), @JsonSubTypes.Type(value = ImageContent.class, name = "image"), + @JsonSubTypes.Type(value = AudioContent.class, name = "audio"), @JsonSubTypes.Type(value = EmbeddedResource.class, name = "resource") }) - public sealed interface Content permits TextContent, ImageContent, EmbeddedResource { + public sealed interface Content permits TextContent, ImageContent, AudioContent, EmbeddedResource { default String type() { if (this instanceof TextContent) { @@ -1264,6 +1265,9 @@ default String type() { else if (this instanceof ImageContent) { return "image"; } + else if (this instanceof AudioContent) { + return "audio"; + } else if (this instanceof EmbeddedResource) { return "resource"; } @@ -1293,6 +1297,15 @@ public record ImageContent( // @formatter:off @JsonProperty("mimeType") String mimeType) implements Content { // @formatter:on } + @JsonInclude(JsonInclude.Include.NON_ABSENT) + @JsonIgnoreProperties(ignoreUnknown = true) + public record AudioContent( // @formatter:off + @JsonProperty("audience") List audience, + @JsonProperty("priority") Double priority, + @JsonProperty("data") String data, + @JsonProperty("mimeType") String mimeType) implements Content { // @formatter:on + } + @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonIgnoreProperties(ignoreUnknown = true) public record EmbeddedResource( // @formatter:off diff --git a/mcp/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java b/mcp/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java index a41fc095..732e95bf 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java @@ -58,7 +58,7 @@ void testContentDeserializationWrongType() throws Exception { {"type":"WRONG","text":"XXX"}""", McpSchema.TextContent.class)) .isInstanceOf(InvalidTypeIdException.class) .hasMessageContaining( - "Could not resolve type id 'WRONG' as a subtype of `io.modelcontextprotocol.spec.McpSchema$TextContent`: known type ids = [image, resource, text]"); + "Could not resolve type id 'WRONG' as a subtype of `io.modelcontextprotocol.spec.McpSchema$TextContent`: known type ids = [audio, image, resource, text]"); } @Test @@ -83,6 +83,46 @@ void testImageContentDeserialization() throws Exception { assertThat(imageContent.mimeType()).isEqualTo("image/png"); } + @Test + void testAudioContent() throws Exception { + McpSchema.AudioContent test = new McpSchema.AudioContent(List.of(McpSchema.Role.USER), 0.8, "base64audiodata", + "audio/mp3"); + + String value = mapper.writeValueAsString(test); + + assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER) + .when(Option.IGNORING_EXTRA_ARRAY_ITEMS) + .isObject() + .isEqualTo(json(""" + { + "type":"audio", + "audience": ["user"], + "priority": 0.8, + "data": "base64audiodata", + "mimeType": "audio/mp3" + }""")); + } + + @Test + void testAudioContentDeserialization() throws Exception { + String json = """ + { + "type":"audio", + "audience": ["user"], + "priority": 0.8, + "data": "base64audiodata", + "mimeType": "audio/mp3" + }"""; + + McpSchema.AudioContent audioContent = mapper.readValue(json, McpSchema.AudioContent.class); + + assertThat(audioContent).isNotNull(); + assertThat(audioContent.audience()).containsExactly(McpSchema.Role.USER); + assertThat(audioContent.priority()).isEqualTo(0.8); + assertThat(audioContent.data()).isEqualTo("base64audiodata"); + assertThat(audioContent.mimeType()).isEqualTo("audio/mp3"); + } + @Test void testEmbeddedResource() throws Exception { McpSchema.TextResourceContents resourceContents = new McpSchema.TextResourceContents("resource://test",