Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import io.modelcontextprotocol.spec.McpSchema.EmbeddedResource;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
import io.modelcontextprotocol.spec.McpSchema.ImageContent;
import io.modelcontextprotocol.spec.McpSchema.JsonSchema;
import io.modelcontextprotocol.spec.McpSchema.LoggingLevel;
import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification;
import io.modelcontextprotocol.spec.McpSchema.ProgressNotification;
Expand Down Expand Up @@ -51,8 +50,8 @@ public class ConformanceServlet {

private static final String MCP_ENDPOINT = "/mcp";

private static final JsonSchema EMPTY_JSON_SCHEMA = new JsonSchema("object", Collections.emptyMap(), null, null,
null, null);
private static final Map<String, Object> EMPTY_JSON_SCHEMA = Map.of("type", "object", "properties",
Collections.emptyMap());

// Minimal 1x1 red pixel PNG (base64 encoded)
private static final String RED_PIXEL_PNG = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==";
Expand Down Expand Up @@ -326,10 +325,10 @@ private static List<McpServerFeatures.SyncToolSpecification> createToolSpecs() {
.tool(Tool.builder()
.name("test_sampling")
.description("Tool that requests LLM sampling from client")
.inputSchema(new JsonSchema("object",
.inputSchema(Map.of("type", "object", "properties",
Map.of("prompt",
Map.of("type", "string", "description", "The prompt to send to the LLM")),
List.of("prompt"), null, null, null))
"required", List.of("prompt")))
.build())
.callHandler((exchange, request) -> {
logger.info("Tool 'test_sampling' called");
Expand All @@ -355,10 +354,10 @@ private static List<McpServerFeatures.SyncToolSpecification> createToolSpecs() {
.tool(Tool.builder()
.name("test_elicitation")
.description("Tool that requests user input from client")
.inputSchema(new JsonSchema("object",
.inputSchema(Map.of("type", "object", "properties",
Map.of("message",
Map.of("type", "string", "description", "The message to show the user")),
List.of("message"), null, null, null))
"required", List.of("message")))
.build())
.callHandler((exchange, request) -> {
logger.info("Tool 'test_elicitation' called");
Expand Down
38 changes: 4 additions & 34 deletions mcp-core/src/main/java/io/modelcontextprotocol/spec/McpSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -1298,27 +1298,6 @@ public ListToolsResult(List<Tool> tools, String nextCursor) {
}
}

/**
* A JSON Schema object that describes the expected structure of arguments or output.
*
* @param type The type of the schema (e.g., "object")
* @param properties The properties of the schema object
* @param required List of required property names
* @param additionalProperties Whether additional properties are allowed
* @param defs Schema definitions using the newer $defs keyword
* @param definitions Schema definitions using the legacy definitions keyword
*/
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@JsonIgnoreProperties(ignoreUnknown = true)
public record JsonSchema( // @formatter:off
@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,
@JsonProperty("definitions") Map<String, Object> definitions) { // @formatter:on
}

/**
* Additional properties describing a Tool to clients.
*
Expand Down Expand Up @@ -1363,7 +1342,7 @@ public record Tool( // @formatter:off
@JsonProperty("name") String name,
@JsonProperty("title") String title,
@JsonProperty("description") String description,
@JsonProperty("inputSchema") JsonSchema inputSchema,
@JsonProperty("inputSchema") Map<String, Object> inputSchema,
@JsonProperty("outputSchema") Map<String, Object> outputSchema,
@JsonProperty("annotations") ToolAnnotations annotations,
@JsonProperty("_meta") Map<String, Object> meta) { // @formatter:on
Expand All @@ -1380,7 +1359,7 @@ public static class Builder {

private String description;

private JsonSchema inputSchema;
private Map<String, Object> inputSchema;

private Map<String, Object> outputSchema;

Expand All @@ -1403,13 +1382,13 @@ public Builder description(String description) {
return this;
}

public Builder inputSchema(JsonSchema inputSchema) {
public Builder inputSchema(Map<String, Object> inputSchema) {
this.inputSchema = inputSchema;
return this;
}

public Builder inputSchema(McpJsonMapper jsonMapper, String inputSchema) {
this.inputSchema = parseSchema(jsonMapper, inputSchema);
this.inputSchema = schemaToMap(jsonMapper, inputSchema);
return this;
}

Expand Down Expand Up @@ -1450,15 +1429,6 @@ private static Map<String, Object> schemaToMap(McpJsonMapper jsonMapper, String
}
}

private static JsonSchema parseSchema(McpJsonMapper jsonMapper, String schema) {
try {
return jsonMapper.readValue(schema, JsonSchema.class);
}
catch (IOException e) {
throw new IllegalArgumentException("Invalid schema: " + schema, e);
}
}

/**
* Used by the client to call a tool provided by the server.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

import static io.modelcontextprotocol.util.ToolsUtils.EMPTY_JSON_SCHEMA;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
Expand All @@ -41,11 +40,7 @@ class AsyncToolSpecificationBuilderTest {
@Test
void builderShouldCreateValidAsyncToolSpecification() {

Tool tool = McpSchema.Tool.builder()
.name("test-tool")
.title("A test tool")
.inputSchema(EMPTY_JSON_SCHEMA)
.build();
Tool tool = McpSchema.Tool.builder().name("test-tool").title("A test tool").inputSchema(Map.of()).build();

McpServerFeatures.AsyncToolSpecification specification = McpServerFeatures.AsyncToolSpecification.builder()
.tool(tool)
Expand All @@ -68,11 +63,7 @@ void builderShouldThrowExceptionWhenToolIsNull() {

@Test
void builderShouldThrowExceptionWhenCallToolIsNull() {
Tool tool = McpSchema.Tool.builder()
.name("test-tool")
.title("A test tool")
.inputSchema(EMPTY_JSON_SCHEMA)
.build();
Tool tool = McpSchema.Tool.builder().name("test-tool").title("A test tool").inputSchema(Map.of()).build();

assertThatThrownBy(() -> McpServerFeatures.AsyncToolSpecification.builder().tool(tool).build())
.isInstanceOf(IllegalArgumentException.class)
Expand All @@ -81,11 +72,7 @@ void builderShouldThrowExceptionWhenCallToolIsNull() {

@Test
void builderShouldAllowMethodChaining() {
Tool tool = McpSchema.Tool.builder()
.name("test-tool")
.title("A test tool")
.inputSchema(EMPTY_JSON_SCHEMA)
.build();
Tool tool = McpSchema.Tool.builder().name("test-tool").title("A test tool").inputSchema(Map.of()).build();
McpServerFeatures.AsyncToolSpecification.Builder builder = McpServerFeatures.AsyncToolSpecification.builder();

// Then - verify method chaining returns the same builder instance
Expand All @@ -100,7 +87,7 @@ void builtSpecificationShouldExecuteCallToolCorrectly() {
Tool tool = McpSchema.Tool.builder()
.name("calculator")
.title("Simple calculator")
.inputSchema(EMPTY_JSON_SCHEMA)
.inputSchema(Map.of())
.build();
String expectedResult = "42";

Expand All @@ -124,11 +111,7 @@ void builtSpecificationShouldExecuteCallToolCorrectly() {

@Test
void fromSyncShouldConvertSyncToolSpecificationCorrectly() {
Tool tool = McpSchema.Tool.builder()
.name("sync-tool")
.title("A sync tool")
.inputSchema(EMPTY_JSON_SCHEMA)
.build();
Tool tool = McpSchema.Tool.builder().name("sync-tool").title("A sync tool").inputSchema(Map.of()).build();
String expectedResult = "sync result";

// Create a sync tool specification
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import org.junit.jupiter.api.Test;
import org.slf4j.LoggerFactory;

import static io.modelcontextprotocol.util.ToolsUtils.EMPTY_JSON_SCHEMA;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
Expand All @@ -38,7 +37,7 @@ class SyncToolSpecificationBuilderTest {
@Test
void builderShouldCreateValidSyncToolSpecification() {

Tool tool = Tool.builder().name("test-tool").title("A test tool").inputSchema(EMPTY_JSON_SCHEMA).build();
Tool tool = Tool.builder().name("test-tool").title("A test tool").inputSchema(Map.of()).build();

McpServerFeatures.SyncToolSpecification specification = McpServerFeatures.SyncToolSpecification.builder()
.tool(tool)
Expand All @@ -62,7 +61,7 @@ void builderShouldThrowExceptionWhenToolIsNull() {

@Test
void builderShouldThrowExceptionWhenCallToolIsNull() {
Tool tool = Tool.builder().name("test-tool").description("A test tool").inputSchema(EMPTY_JSON_SCHEMA).build();
Tool tool = Tool.builder().name("test-tool").description("A test tool").inputSchema(Map.of()).build();

assertThatThrownBy(() -> McpServerFeatures.SyncToolSpecification.builder().tool(tool).build())
.isInstanceOf(IllegalArgumentException.class)
Expand All @@ -71,7 +70,7 @@ void builderShouldThrowExceptionWhenCallToolIsNull() {

@Test
void builderShouldAllowMethodChaining() {
Tool tool = Tool.builder().name("test-tool").description("A test tool").inputSchema(EMPTY_JSON_SCHEMA).build();
Tool tool = Tool.builder().name("test-tool").description("A test tool").inputSchema(Map.of()).build();
McpServerFeatures.SyncToolSpecification.Builder builder = McpServerFeatures.SyncToolSpecification.builder();

// Then - verify method chaining returns the same builder instance
Expand All @@ -83,11 +82,7 @@ void builderShouldAllowMethodChaining() {

@Test
void builtSpecificationShouldExecuteCallToolCorrectly() {
Tool tool = Tool.builder()
.name("calculator")
.description("Simple calculator")
.inputSchema(EMPTY_JSON_SCHEMA)
.build();
Tool tool = Tool.builder().name("calculator").description("Simple calculator").inputSchema(Map.of()).build();
String expectedResult = "42";

McpServerFeatures.SyncToolSpecification specification = McpServerFeatures.SyncToolSpecification.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,4 @@ public final class ToolsUtils {
private ToolsUtils() {
}

public static final McpSchema.JsonSchema EMPTY_JSON_SCHEMA = new McpSchema.JsonSchema("object",
Collections.emptyMap(), null, null, null, null);

}
Loading