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("id") Object id,
|
||||
@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());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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