refactor(mcp): remove redundant type field from Content implementations (#27)

- The type field and associated methods were redundant in Content implementations (TextContent, ImageContent, EmbeddedResource)
  as the type information is already handled by Jackson's polymorphic type handling via @JsonSubTypes annotation.
- Add default implementation that returns the appropriate type string based on the implementing class (text, image, or resource)
- Added comprehensive unit tests for McpSchema to validate serialization/deserialization behavior of all schema components.
- Add deserialization tests for all content types
- Add json-unit-assertj for flexible JSON testing -  ignores array order and extra array items, reducing test brittleness while
maintaining functional validation.

Resolves #26
Resolve https://github.com/spring-projects/spring-ai/issues/2350

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
Christian Tzolov 2025-03-03 13:57:41 +01:00 • committed by GitHub
commit 1bee8d4744
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 619 additions and 33 deletions

View file

@ -11,7 +11,7 @@
<artifactId>mcp</artifactId>
<packaging>jar</packaging>
<name>Java MCP SDK</name>
<description>Java SDK implementation of the Model Context Protocol, enabling seamless integration with language models and AI tools</description>
<description>Java SDK implementation of the Model Context Protocol, enabling seamless integration with language models and AI tools</description>
<url>https://github.com/modelcontextprotocol/java-sdk</url>
<scm>
@ -51,7 +51,7 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
@ -158,12 +158,20 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit-assertj</artifactId>
<version>${json-unit-assertj.version}</version>
<scope>test</scope>
</dependency>
<!-- Used by the HttpServletSseServerTransport -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>${jakarta.servlet.version}</version>
<scope>provided</scope>
<scope>provided</scope>
</dependency>
<!-- Tomcat dependencies for testing -->
@ -183,4 +191,4 @@
</dependencies>
</project>
</project>

View file

@ -964,7 +964,18 @@ public final class McpSchema {
@JsonSubTypes.Type(value = EmbeddedResource.class, name = "resource") })
public sealed interface Content permits TextContent, ImageContent, EmbeddedResource {
String type();
default String type() {
if (this instanceof TextContent) {
return "text";
}
else if (this instanceof ImageContent) {
return "image";
}
else if (this instanceof EmbeddedResource) {
return "resource";
}
throw new IllegalArgumentException("Unknown content type: " + this);
}
}
@ -972,19 +983,10 @@ public final class McpSchema {
public record TextContent( // @formatter:off
@JsonProperty("audience") List<Role> audience,
@JsonProperty("priority") Double priority,
@JsonProperty("type") String type,
@JsonProperty("text") String text) implements Content { // @formatter:on
public TextContent {
type = "text";
}
public String type() {
return type;
}
public TextContent(String content) {
this(null, null, "text", content);
this(null, null, content);
}
}
@ -992,33 +994,15 @@ public final class McpSchema {
public record ImageContent( // @formatter:off
@JsonProperty("audience") List<Role> audience,
@JsonProperty("priority") Double priority,
@JsonProperty("type") String type,
@JsonProperty("data") String data,
@JsonProperty("mimeType") String mimeType) implements Content { // @formatter:on
public ImageContent {
type = "image";
}
public String type() {
return type;
}
}
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public record EmbeddedResource( // @formatter:off
@JsonProperty("audience") List<Role> audience,
@JsonProperty("priority") Double priority,
@JsonProperty("type") String type,
@JsonProperty("resource") ResourceContents resource) implements Content { // @formatter:on
public EmbeddedResource {
type = "resource";
}
public String type() {
return type;
}
}
// ---------------------------

View file

@ -0,0 +1,592 @@
/*
* Copyright 2025 - 2025 the original author or authors.
*/
package io.modelcontextprotocol.spec;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
import io.modelcontextprotocol.spec.McpSchema.TextResourceContents;
import net.javacrumbs.jsonunit.core.Option;
import org.junit.jupiter.api.Test;
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.json;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* @author Christian Tzolov
*/
public class McpSchemaTests {
ObjectMapper mapper = new ObjectMapper();
// Content Types Tests
@Test
void testTextContent() throws Exception {
McpSchema.TextContent test = new McpSchema.TextContent("XXX");
String value = mapper.writeValueAsString(test);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(json("""
{"type":"text","text":"XXX"}"""));
}
@Test
void testTextContentDeserialization() throws Exception {
McpSchema.TextContent textContent = mapper.readValue("""
{"type":"text","text":"XXX"}""", McpSchema.TextContent.class);
assertThat(textContent).isNotNull();
assertThat(textContent.type()).isEqualTo("text");
assertThat(textContent.text()).isEqualTo("XXX");
}
@Test
void testContentDeserializationWrongType() throws Exception {
assertThatThrownBy(() -> mapper.readValue("""
{"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]");
}
@Test
void testImageContent() throws Exception {
McpSchema.ImageContent test = new McpSchema.ImageContent(null, null, "base64encodeddata", "image/png");
String value = mapper.writeValueAsString(test);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(json("""
{"type":"image","data":"base64encodeddata","mimeType":"image/png"}"""));
}
@Test
void testImageContentDeserialization() throws Exception {
McpSchema.ImageContent imageContent = mapper.readValue("""
{"type":"image","data":"base64encodeddata","mimeType":"image/png"}""", McpSchema.ImageContent.class);
assertThat(imageContent).isNotNull();
assertThat(imageContent.type()).isEqualTo("image");
assertThat(imageContent.data()).isEqualTo("base64encodeddata");
assertThat(imageContent.mimeType()).isEqualTo("image/png");
}
@Test
void testEmbeddedResource() throws Exception {
McpSchema.TextResourceContents resourceContents = new McpSchema.TextResourceContents("resource://test",
"text/plain", "Sample resource content");
McpSchema.EmbeddedResource test = new McpSchema.EmbeddedResource(null, null, resourceContents);
String value = mapper.writeValueAsString(test);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"type":"resource","resource":{"uri":"resource://test","mimeType":"text/plain","text":"Sample resource content"}}"""));
}
@Test
void testEmbeddedResourceDeserialization() throws Exception {
McpSchema.EmbeddedResource embeddedResource = mapper.readValue(
"""
{"type":"resource","resource":{"uri":"resource://test","mimeType":"text/plain","text":"Sample resource content"}}""",
McpSchema.EmbeddedResource.class);
assertThat(embeddedResource).isNotNull();
assertThat(embeddedResource.type()).isEqualTo("resource");
assertThat(embeddedResource.resource()).isNotNull();
assertThat(embeddedResource.resource().uri()).isEqualTo("resource://test");
assertThat(embeddedResource.resource().mimeType()).isEqualTo("text/plain");
assertThat(((TextResourceContents) embeddedResource.resource()).text()).isEqualTo("Sample resource content");
}
@Test
void testEmbeddedResourceWithBlobContents() throws Exception {
McpSchema.BlobResourceContents resourceContents = new McpSchema.BlobResourceContents("resource://test",
"application/octet-stream", "base64encodedblob");
McpSchema.EmbeddedResource test = new McpSchema.EmbeddedResource(null, null, resourceContents);
String value = mapper.writeValueAsString(test);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"type":"resource","resource":{"uri":"resource://test","mimeType":"application/octet-stream","blob":"base64encodedblob"}}"""));
}
@Test
void testEmbeddedResourceWithBlobContentsDeserialization() throws Exception {
McpSchema.EmbeddedResource embeddedResource = mapper.readValue(
"""
{"type":"resource","resource":{"uri":"resource://test","mimeType":"application/octet-stream","blob":"base64encodedblob"}}""",
McpSchema.EmbeddedResource.class);
assertThat(embeddedResource).isNotNull();
assertThat(embeddedResource.type()).isEqualTo("resource");
assertThat(embeddedResource.resource()).isNotNull();
assertThat(embeddedResource.resource().uri()).isEqualTo("resource://test");
assertThat(embeddedResource.resource().mimeType()).isEqualTo("application/octet-stream");
assertThat(((McpSchema.BlobResourceContents) embeddedResource.resource()).blob())
.isEqualTo("base64encodedblob");
}
// JSON-RPC Message Types Tests
@Test
void testJSONRPCRequest() throws Exception {
Map<String, Object> params = new HashMap<>();
params.put("key", "value");
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, "method_name", 1,
params);
String value = mapper.writeValueAsString(request);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(json("""
{"jsonrpc":"2.0","method":"method_name","id":1,"params":{"key":"value"}}"""));
}
@Test
void testJSONRPCNotification() throws Exception {
Map<String, Object> params = new HashMap<>();
params.put("key", "value");
McpSchema.JSONRPCNotification notification = new McpSchema.JSONRPCNotification(McpSchema.JSONRPC_VERSION,
"notification_method", params);
String value = mapper.writeValueAsString(notification);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(json("""
{"jsonrpc":"2.0","method":"notification_method","params":{"key":"value"}}"""));
}
@Test
void testJSONRPCResponse() throws Exception {
Map<String, Object> result = new HashMap<>();
result.put("result_key", "result_value");
McpSchema.JSONRPCResponse response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, 1, result, null);
String value = mapper.writeValueAsString(response);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(json("""
{"jsonrpc":"2.0","id":1,"result":{"result_key":"result_value"}}"""));
}
@Test
void testJSONRPCResponseWithError() throws Exception {
McpSchema.JSONRPCResponse.JSONRPCError error = new McpSchema.JSONRPCResponse.JSONRPCError(
McpSchema.ErrorCodes.INVALID_REQUEST, "Invalid request", null);
McpSchema.JSONRPCResponse response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, 1, null, error);
String value = mapper.writeValueAsString(response);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(json("""
{"jsonrpc":"2.0","id":1,"error":{"code":-32600,"message":"Invalid request"}}"""));
}
// Initialization Tests
@Test
void testInitializeRequest() throws Exception {
McpSchema.ClientCapabilities capabilities = McpSchema.ClientCapabilities.builder()
.roots(true)
.sampling()
.build();
McpSchema.Implementation clientInfo = new McpSchema.Implementation("test-client", "1.0.0");
McpSchema.InitializeRequest request = new McpSchema.InitializeRequest("2024-11-05", capabilities, clientInfo);
String value = mapper.writeValueAsString(request);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"protocolVersion":"2024-11-05","capabilities":{"roots":{"listChanged":true},"sampling":{}},"clientInfo":{"name":"test-client","version":"1.0.0"}}"""));
}
@Test
void testInitializeResult() throws Exception {
McpSchema.ServerCapabilities capabilities = McpSchema.ServerCapabilities.builder()
.logging()
.prompts(true)
.resources(true, true)
.tools(true)
.build();
McpSchema.Implementation serverInfo = new McpSchema.Implementation("test-server", "1.0.0");
McpSchema.InitializeResult result = new McpSchema.InitializeResult("2024-11-05", capabilities, serverInfo,
"Server initialized successfully");
String value = mapper.writeValueAsString(result);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"protocolVersion":"2024-11-05","capabilities":{"logging":{},"prompts":{"listChanged":true},"resources":{"subscribe":true,"listChanged":true},"tools":{"listChanged":true}},"serverInfo":{"name":"test-server","version":"1.0.0"},"instructions":"Server initialized successfully"}"""));
}
// Resource Tests
@Test
void testResource() throws Exception {
McpSchema.Annotations annotations = new McpSchema.Annotations(
Arrays.asList(McpSchema.Role.USER, McpSchema.Role.ASSISTANT), 0.8);
McpSchema.Resource resource = new McpSchema.Resource("resource://test", "Test Resource", "A test resource",
"text/plain", annotations);
String value = mapper.writeValueAsString(resource);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"uri":"resource://test","name":"Test Resource","description":"A test resource","mimeType":"text/plain","annotations":{"audience":["user","assistant"],"priority":0.8}}"""));
}
@Test
void testResourceTemplate() throws Exception {
McpSchema.Annotations annotations = new McpSchema.Annotations(Arrays.asList(McpSchema.Role.USER), 0.5);
McpSchema.ResourceTemplate template = new McpSchema.ResourceTemplate("resource://{param}/test", "Test Template",
"A test resource template", "text/plain", annotations);
String value = mapper.writeValueAsString(template);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"uriTemplate":"resource://{param}/test","name":"Test Template","description":"A test resource template","mimeType":"text/plain","annotations":{"audience":["user"],"priority":0.5}}"""));
}
@Test
void testListResourcesResult() throws Exception {
McpSchema.Resource resource1 = new McpSchema.Resource("resource://test1", "Test Resource 1",
"First test resource", "text/plain", null);
McpSchema.Resource resource2 = new McpSchema.Resource("resource://test2", "Test Resource 2",
"Second test resource", "application/json", null);
McpSchema.ListResourcesResult result = new McpSchema.ListResourcesResult(Arrays.asList(resource1, resource2),
"next-cursor");
String value = mapper.writeValueAsString(result);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"resources":[{"uri":"resource://test1","name":"Test Resource 1","description":"First test resource","mimeType":"text/plain"},{"uri":"resource://test2","name":"Test Resource 2","description":"Second test resource","mimeType":"application/json"}],"nextCursor":"next-cursor"}"""));
}
@Test
void testListResourceTemplatesResult() throws Exception {
McpSchema.ResourceTemplate template1 = new McpSchema.ResourceTemplate("resource://{param}/test1",
"Test Template 1", "First test template", "text/plain", null);
McpSchema.ResourceTemplate template2 = new McpSchema.ResourceTemplate("resource://{param}/test2",
"Test Template 2", "Second test template", "application/json", null);
McpSchema.ListResourceTemplatesResult result = new McpSchema.ListResourceTemplatesResult(
Arrays.asList(template1, template2), "next-cursor");
String value = mapper.writeValueAsString(result);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"resourceTemplates":[{"uriTemplate":"resource://{param}/test1","name":"Test Template 1","description":"First test template","mimeType":"text/plain"},{"uriTemplate":"resource://{param}/test2","name":"Test Template 2","description":"Second test template","mimeType":"application/json"}],"nextCursor":"next-cursor"}"""));
}
@Test
void testReadResourceRequest() throws Exception {
McpSchema.ReadResourceRequest request = new McpSchema.ReadResourceRequest("resource://test");
String value = mapper.writeValueAsString(request);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(json("""
{"uri":"resource://test"}"""));
}
@Test
void testReadResourceResult() throws Exception {
McpSchema.TextResourceContents contents1 = new McpSchema.TextResourceContents("resource://test1", "text/plain",
"Sample text content");
McpSchema.BlobResourceContents contents2 = new McpSchema.BlobResourceContents("resource://test2",
"application/octet-stream", "base64encodedblob");
McpSchema.ReadResourceResult result = new McpSchema.ReadResourceResult(Arrays.asList(contents1, contents2));
String value = mapper.writeValueAsString(result);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"contents":[{"uri":"resource://test1","mimeType":"text/plain","text":"Sample text content"},{"uri":"resource://test2","mimeType":"application/octet-stream","blob":"base64encodedblob"}]}"""));
}
// Prompt Tests
@Test
void testPrompt() throws Exception {
McpSchema.PromptArgument arg1 = new McpSchema.PromptArgument("arg1", "First argument", true);
McpSchema.PromptArgument arg2 = new McpSchema.PromptArgument("arg2", "Second argument", false);
McpSchema.Prompt prompt = new McpSchema.Prompt("test-prompt", "A test prompt", Arrays.asList(arg1, arg2));
String value = mapper.writeValueAsString(prompt);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"name":"test-prompt","description":"A test prompt","arguments":[{"name":"arg1","description":"First argument","required":true},{"name":"arg2","description":"Second argument","required":false}]}"""));
}
@Test
void testPromptMessage() throws Exception {
McpSchema.TextContent content = new McpSchema.TextContent("Hello, world!");
McpSchema.PromptMessage message = new McpSchema.PromptMessage(McpSchema.Role.USER, content);
String value = mapper.writeValueAsString(message);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(json("""
{"role":"user","content":{"type":"text","text":"Hello, world!"}}"""));
}
@Test
void testListPromptsResult() throws Exception {
McpSchema.PromptArgument arg = new McpSchema.PromptArgument("arg", "An argument", true);
McpSchema.Prompt prompt1 = new McpSchema.Prompt("prompt1", "First prompt", Collections.singletonList(arg));
McpSchema.Prompt prompt2 = new McpSchema.Prompt("prompt2", "Second prompt", Collections.emptyList());
McpSchema.ListPromptsResult result = new McpSchema.ListPromptsResult(Arrays.asList(prompt1, prompt2),
"next-cursor");
String value = mapper.writeValueAsString(result);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"prompts":[{"name":"prompt1","description":"First prompt","arguments":[{"name":"arg","description":"An argument","required":true}]},{"name":"prompt2","description":"Second prompt","arguments":[]}],"nextCursor":"next-cursor"}"""));
}
@Test
void testGetPromptRequest() throws Exception {
Map<String, Object> arguments = new HashMap<>();
arguments.put("arg1", "value1");
arguments.put("arg2", 42);
McpSchema.GetPromptRequest request = new McpSchema.GetPromptRequest("test-prompt", arguments);
assertThat(mapper.readValue("""
{"name":"test-prompt","arguments":{"arg1":"value1","arg2":42}}""", McpSchema.GetPromptRequest.class))
.isEqualTo(request);
}
@Test
void testGetPromptResult() throws Exception {
McpSchema.TextContent content1 = new McpSchema.TextContent("System message");
McpSchema.TextContent content2 = new McpSchema.TextContent("User message");
McpSchema.PromptMessage message1 = new McpSchema.PromptMessage(McpSchema.Role.ASSISTANT, content1);
McpSchema.PromptMessage message2 = new McpSchema.PromptMessage(McpSchema.Role.USER, content2);
McpSchema.GetPromptResult result = new McpSchema.GetPromptResult("A test prompt result",
Arrays.asList(message1, message2));
String value = mapper.writeValueAsString(result);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"description":"A test prompt result","messages":[{"role":"assistant","content":{"type":"text","text":"System message"}},{"role":"user","content":{"type":"text","text":"User message"}}]}"""));
}
// Tool Tests
@Test
void testTool() throws Exception {
String schemaJson = """
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"value": {
"type": "number"
}
},
"required": ["name"]
}
""";
McpSchema.Tool tool = new McpSchema.Tool("test-tool", "A test tool", schemaJson);
String value = mapper.writeValueAsString(tool);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"name":"test-tool","description":"A test tool","inputSchema":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"number"}},"required":["name"]}}"""));
}
@Test
void testCallToolRequest() throws Exception {
Map<String, Object> arguments = new HashMap<>();
arguments.put("name", "test");
arguments.put("value", 42);
McpSchema.CallToolRequest request = new McpSchema.CallToolRequest("test-tool", arguments);
String value = mapper.writeValueAsString(request);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(json("""
{"name":"test-tool","arguments":{"name":"test","value":42}}"""));
}
@Test
void testCallToolResult() throws Exception {
McpSchema.TextContent content = new McpSchema.TextContent("Tool execution result");
McpSchema.CallToolResult result = new McpSchema.CallToolResult(Collections.singletonList(content), false);
String value = mapper.writeValueAsString(result);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(json("""
{"content":[{"type":"text","text":"Tool execution result"}],"isError":false}"""));
}
// Sampling Tests
@Test
void testCreateMessageRequest() throws Exception {
McpSchema.TextContent content = new McpSchema.TextContent("User message");
McpSchema.SamplingMessage message = new McpSchema.SamplingMessage(McpSchema.Role.USER, content);
McpSchema.ModelHint hint = new McpSchema.ModelHint("gpt-4");
McpSchema.ModelPreferences preferences = new McpSchema.ModelPreferences(Collections.singletonList(hint), 0.3,
0.7, 0.9);
Map<String, Object> metadata = new HashMap<>();
metadata.put("session", "test-session");
McpSchema.CreateMessageRequest request = new McpSchema.CreateMessageRequest(Collections.singletonList(message),
preferences, "You are a helpful assistant",
McpSchema.CreateMessageRequest.ContextInclusionStrategy.THIS_SERVER, 0.7, 1000,
Arrays.asList("STOP", "END"), metadata);
String value = mapper.writeValueAsString(request);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"messages":[{"role":"user","content":{"type":"text","text":"User message"}}],"modelPreferences":{"hints":[{"name":"gpt-4"}],"costPriority":0.3,"speedPriority":0.7,"intelligencePriority":0.9},"systemPrompt":"You are a helpful assistant","includeContext":"this_server","temperature":0.7,"maxTokens":1000,"stopSequences":["STOP","END"],"metadata":{"session":"test-session"}}"""));
}
@Test
void testCreateMessageResult() throws Exception {
McpSchema.TextContent content = new McpSchema.TextContent("Assistant response");
McpSchema.CreateMessageResult result = new McpSchema.CreateMessageResult(McpSchema.Role.ASSISTANT, content,
"gpt-4", McpSchema.CreateMessageResult.StopReason.END_TURN);
String value = mapper.writeValueAsString(result);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"role":"assistant","content":{"type":"text","text":"Assistant response"},"model":"gpt-4","stopReason":"end_turn"}"""));
}
// Roots Tests
@Test
void testRoot() throws Exception {
McpSchema.Root root = new McpSchema.Root("file:///path/to/root", "Test Root");
String value = mapper.writeValueAsString(root);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(json("""
{"uri":"file:///path/to/root","name":"Test Root"}"""));
}
@Test
void testListRootsResult() throws Exception {
McpSchema.Root root1 = new McpSchema.Root("file:///path/to/root1", "First Root");
McpSchema.Root root2 = new McpSchema.Root("file:///path/to/root2", "Second Root");
McpSchema.ListRootsResult result = new McpSchema.ListRootsResult(Arrays.asList(root1, root2));
String value = mapper.writeValueAsString(result);
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
.isObject()
.isEqualTo(
json("""
{"roots":[{"uri":"file:///path/to/root1","name":"First Root"},{"uri":"file:///path/to/root2","name":"Second Root"}]}"""));
}
}

View file

@ -92,6 +92,8 @@
<jakarta.servlet.version>6.1.0</jakarta.servlet.version>
<awaitility.version>4.2.0</awaitility.version>
<bnd-maven-plugin.version>7.1.0</bnd-maven-plugin.version>
<json-unit-assertj.version>4.1.0</json-unit-assertj.version>
</properties>
<modules>