Skip to content

Commit

Permalink
refactor(mcp): remove redundant type field from Content implementatio…
Browse files Browse the repository at this point in the history
…ns (#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 spring-projects/spring-ai#2350

Signed-off-by: Christian Tzolov <[email protected]>
  • Loading branch information
tzolov authored Mar 3, 2025
1 parent b2c62d5 commit 1bee8d4
Show file tree
Hide file tree
Showing 4 changed files with 619 additions and 33 deletions.
16 changes: 12 additions & 4 deletions mcp/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -51,7 +51,7 @@
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
Expand Down Expand Up @@ -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 -->
Expand All @@ -183,4 +191,4 @@
</dependencies>


</project>
</project>
42 changes: 13 additions & 29 deletions mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -964,61 +964,45 @@ public record CompleteCompletion(// @formatter:off
@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);
}

}

@JsonInclude(JsonInclude.Include.NON_ABSENT)
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);
}
}

@JsonInclude(JsonInclude.Include.NON_ABSENT)
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;
}
}

// ---------------------------
Expand Down
Loading

0 comments on commit 1bee8d4

Please sign in to comment.