Skip to content

Commit 73daf65

Browse files
committed
feat: #697 adapted to Map<String, Object> input schema without unmarshalling
1 parent e8bd7e8 commit 73daf65

File tree

4 files changed

+15
-33
lines changed

4 files changed

+15
-33
lines changed

mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ private McpRequestHandler<CallToolResult> toolsCallRequestHandler() {
529529

530530
McpSchema.Tool tool = toolSpecification.get().tool();
531531
CallToolResult validationError = ToolInputValidator.validate(tool, callToolRequest.arguments(),
532-
this.validateToolInputs, this.jsonMapper, this.jsonSchemaValidator);
532+
this.validateToolInputs, this.jsonSchemaValidator);
533533
if (validationError != null) {
534534
return Mono.just(validationError);
535535
}

mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ private McpStatelessRequestHandler<CallToolResult> toolsCallRequestHandler() {
416416

417417
McpSchema.Tool tool = toolSpecification.get().tool();
418418
CallToolResult validationError = ToolInputValidator.validate(tool, callToolRequest.arguments(),
419-
this.validateToolInputs, this.jsonMapper, this.jsonSchemaValidator);
419+
this.validateToolInputs, this.jsonSchemaValidator);
420420
if (validationError != null) {
421421
return Mono.just(validationError);
422422
}

mcp-core/src/main/java/io/modelcontextprotocol/util/ToolInputValidator.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
import java.util.List;
88
import java.util.Map;
99

10-
import io.modelcontextprotocol.json.McpJsonMapper;
11-
import io.modelcontextprotocol.json.TypeRef;
1210
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
1311
import io.modelcontextprotocol.spec.McpSchema;
1412
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
@@ -32,21 +30,17 @@ private ToolInputValidator() {
3230
* @param tool the tool definition containing the input schema
3331
* @param arguments the arguments to validate
3432
* @param validateToolInputs whether validation is enabled
35-
* @param jsonMapper the JSON mapper for schema conversion
3633
* @param validator the JSON schema validator (may be null)
3734
* @return CallToolResult with isError=true if validation fails, null if valid or
3835
* validation skipped
3936
*/
4037
public static CallToolResult validate(McpSchema.Tool tool, Map<String, Object> arguments,
41-
boolean validateToolInputs, McpJsonMapper jsonMapper, JsonSchemaValidator validator) {
38+
boolean validateToolInputs, JsonSchemaValidator validator) {
4239
if (!validateToolInputs || tool.inputSchema() == null || validator == null) {
4340
return null;
4441
}
45-
Map<String, Object> inputSchema = jsonMapper.convertValue(tool.inputSchema(),
46-
new TypeRef<Map<String, Object>>() {
47-
});
4842
Map<String, Object> args = arguments != null ? arguments : Map.of();
49-
var validation = validator.validate(inputSchema, args);
43+
var validation = validator.validate(tool.inputSchema(), args);
5044
if (!validation.valid()) {
5145
logger.warn("Tool '{}' input validation failed: {}", tool.name(), validation.errorMessage());
5246
return CallToolResult.builder()

mcp-core/src/test/java/io/modelcontextprotocol/util/ToolInputValidatorTests.java

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,8 @@
77
import java.util.List;
88
import java.util.Map;
99

10-
import io.modelcontextprotocol.json.McpJsonMapper;
11-
import io.modelcontextprotocol.json.TypeRef;
1210
import io.modelcontextprotocol.json.schema.JsonSchemaValidator;
1311
import io.modelcontextprotocol.json.schema.JsonSchemaValidator.ValidationResponse;
14-
import io.modelcontextprotocol.spec.McpSchema;
1512
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
1613
import io.modelcontextprotocol.spec.McpSchema.TextContent;
1714
import io.modelcontextprotocol.spec.McpSchema.Tool;
@@ -26,15 +23,15 @@
2623

2724
/**
2825
* Tests for {@link ToolInputValidator}.
26+
*
27+
* @author Andrei Shakirin
2928
*/
3029
class ToolInputValidatorTests {
3130

32-
private final McpJsonMapper jsonMapper = mock(McpJsonMapper.class);
33-
3431
private final JsonSchemaValidator validator = mock(JsonSchemaValidator.class);
3532

36-
private final McpSchema.JsonSchema inputSchema = new McpSchema.JsonSchema("object",
37-
Map.of("name", Map.of("type", "string")), List.of("name"), null, null, null);
33+
private final Map<String, Object> inputSchema = Map.of("type", "object", "properties",
34+
Map.of("name", Map.of("type", "string")), "required", List.of("name"));
3835

3936
private final Tool toolWithSchema = Tool.builder()
4037
.name("test-tool")
@@ -46,62 +43,53 @@ class ToolInputValidatorTests {
4643

4744
@Test
4845
void validate_whenDisabled_returnsNull() {
49-
CallToolResult result = ToolInputValidator.validate(toolWithSchema, Map.of("name", "test"), false, jsonMapper,
50-
validator);
46+
CallToolResult result = ToolInputValidator.validate(toolWithSchema, Map.of("name", "test"), false, validator);
5147

5248
assertThat(result).isNull();
5349
verify(validator, never()).validate(any(), any());
5450
}
5551

5652
@Test
5753
void validate_whenNoSchema_returnsNull() {
58-
CallToolResult result = ToolInputValidator.validate(toolWithoutSchema, Map.of("name", "test"), true, jsonMapper,
59-
validator);
54+
CallToolResult result = ToolInputValidator.validate(toolWithoutSchema, Map.of("name", "test"), true, validator);
6055

6156
assertThat(result).isNull();
6257
verify(validator, never()).validate(any(), any());
6358
}
6459

6560
@Test
6661
void validate_whenNoValidator_returnsNull() {
67-
CallToolResult result = ToolInputValidator.validate(toolWithSchema, Map.of("name", "test"), true, jsonMapper,
68-
null);
62+
CallToolResult result = ToolInputValidator.validate(toolWithSchema, Map.of("name", "test"), true, null);
6963

7064
assertThat(result).isNull();
7165
}
7266

7367
@Test
74-
@SuppressWarnings("unchecked")
7568
void validate_withValidInput_returnsNull() {
76-
when(jsonMapper.convertValue(any(), any(TypeRef.class))).thenReturn(Map.of("type", "object"));
7769
when(validator.validate(any(), any())).thenReturn(ValidationResponse.asValid(null));
7870

79-
CallToolResult result = ToolInputValidator.validate(toolWithSchema, Map.of("name", "test"), true, jsonMapper,
80-
validator);
71+
CallToolResult result = ToolInputValidator.validate(toolWithSchema, Map.of("name", "test"), true, validator);
8172

8273
assertThat(result).isNull();
8374
}
8475

8576
@Test
86-
@SuppressWarnings("unchecked")
8777
void validate_withInvalidInput_returnsErrorResult() {
88-
when(jsonMapper.convertValue(any(), any(TypeRef.class))).thenReturn(Map.of("type", "object"));
8978
when(validator.validate(any(), any())).thenReturn(ValidationResponse.asInvalid("missing required: 'name'"));
9079

91-
CallToolResult result = ToolInputValidator.validate(toolWithSchema, Map.of(), true, jsonMapper, validator);
80+
CallToolResult result = ToolInputValidator.validate(toolWithSchema, Map.of(), true, validator);
9281

9382
assertThat(result).isNotNull();
9483
assertThat(result.isError()).isTrue();
9584
assertThat(((TextContent) result.content().get(0)).text()).contains("missing required: 'name'");
85+
verify(validator).validate(any(), any());
9686
}
9787

9888
@Test
99-
@SuppressWarnings("unchecked")
10089
void validate_withNullArguments_usesEmptyMap() {
101-
when(jsonMapper.convertValue(any(), any(TypeRef.class))).thenReturn(Map.of("type", "object"));
10290
when(validator.validate(any(), any())).thenReturn(ValidationResponse.asValid(null));
10391

104-
CallToolResult result = ToolInputValidator.validate(toolWithSchema, null, true, jsonMapper, validator);
92+
CallToolResult result = ToolInputValidator.validate(toolWithSchema, null, true, validator);
10593

10694
assertThat(result).isNull();
10795
verify(validator).validate(any(), any());

0 commit comments

Comments
 (0)