feat: enforce MCP request ID validation requirements
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
parent
53f7b77edf
commit
1e93776354
3 changed files with 111 additions and 0 deletions
|
|
@ -236,6 +236,17 @@ public final class McpSchema {
|
||||||
@JsonProperty("method") String method,
|
@JsonProperty("method") String method,
|
||||||
@JsonProperty("id") Object id,
|
@JsonProperty("id") Object id,
|
||||||
@JsonProperty("params") Object params) implements JSONRPCMessage { // @formatter:on
|
@JsonProperty("params") Object params) implements JSONRPCMessage { // @formatter:on
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor that validates MCP-specific ID requirements. Unlike base JSON-RPC,
|
||||||
|
* MCP requires that: (1) Requests MUST include a string or integer ID; (2) The ID
|
||||||
|
* MUST NOT be null
|
||||||
|
*/
|
||||||
|
public JSONRPCRequest {
|
||||||
|
Assert.notNull(id, "MCP requests MUST include an ID - null IDs are not allowed");
|
||||||
|
Assert.isTrue(id instanceof String || id instanceof Integer || id instanceof Long,
|
||||||
|
"MCP requests MUST have an ID that is either a string or integer");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -76,4 +76,17 @@ public final class Assert {
|
||||||
return (str != null && !str.isBlank());
|
return (str != null && !str.isBlank());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert a boolean expression, throwing an {@code IllegalArgumentException} if the
|
||||||
|
* expression evaluates to {@code false}.
|
||||||
|
* @param expression a boolean expression
|
||||||
|
* @param message the exception message to use if the assertion fails
|
||||||
|
* @throws IllegalArgumentException if {@code expression} is {@code false}
|
||||||
|
*/
|
||||||
|
public static void isTrue(boolean expression, String message) {
|
||||||
|
if (!expression) {
|
||||||
|
throw new IllegalArgumentException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024-2024 the original author or authors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.modelcontextprotocol.spec;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for MCP-specific validation of JSONRPCRequest ID requirements.
|
||||||
|
*
|
||||||
|
* @author Christian Tzolov
|
||||||
|
*/
|
||||||
|
public class JSONRPCRequestMcpValidationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidStringId() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
var request = new McpSchema.JSONRPCRequest("2.0", "test/method", "string-id", null);
|
||||||
|
assertEquals("string-id", request.id());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidIntegerId() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
var request = new McpSchema.JSONRPCRequest("2.0", "test/method", 123, null);
|
||||||
|
assertEquals(123, request.id());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidLongId() {
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
var request = new McpSchema.JSONRPCRequest("2.0", "test/method", 123L, null);
|
||||||
|
assertEquals(123L, request.id());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNullIdThrowsException() {
|
||||||
|
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
new McpSchema.JSONRPCRequest("2.0", "test/method", null, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue(exception.getMessage().contains("MCP requests MUST include an ID"));
|
||||||
|
assertTrue(exception.getMessage().contains("null IDs are not allowed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoubleIdTypeThrowsException() {
|
||||||
|
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
new McpSchema.JSONRPCRequest("2.0", "test/method", 123.45, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue(exception.getMessage().contains("MCP requests MUST have an ID that is either a string or integer"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBooleanIdThrowsException() {
|
||||||
|
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
new McpSchema.JSONRPCRequest("2.0", "test/method", true, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue(exception.getMessage().contains("MCP requests MUST have an ID that is either a string or integer"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArrayIdThrowsException() {
|
||||||
|
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
new McpSchema.JSONRPCRequest("2.0", "test/method", new String[] { "array" }, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue(exception.getMessage().contains("MCP requests MUST have an ID that is either a string or integer"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testObjectIdThrowsException() {
|
||||||
|
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
new McpSchema.JSONRPCRequest("2.0", "test/method", new Object(), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
assertTrue(exception.getMessage().contains("MCP requests MUST have an ID that is either a string or integer"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue