feat: validate embedded JSON Schema documents against 2020-12 meta-schema (SEP-1613) (#949)
MCP embeds JSON Schema documents in three places — Tool.inputSchema, Tool.outputSchema, and ElicitRequest.requestedSchema — and SEP-1613 mandates that these documents conform to JSON Schema 2020-12 by default. Servers now reject malformed schemas at both build time (McpServer.build()) and runtime (McpAsyncServer/McpStatelessAsyncServer.addTool()), returning an IllegalArgumentException that identifies the offending field and references SEP-1613. Elicitation requests whose requestedSchema violates the meta-schema are rejected before being sent to the client. Schemas that explicitly declare a different dialect via $schema are accepted without meta-schema validation, since 2020-12 is the default, not the only permitted dialect. Refine meta-schema loading and deprecate orphan JsonSchemaValidator Resolves #700 Signed-off-by: Dariusz Jędrzejczyk <2554306+chemicL@users.noreply.github.com>
This commit is contained in:
parent
5d4a1cce42
commit
87e2c7d4de
2 changed files with 903 additions and 35 deletions
|
|
@ -2,22 +2,31 @@
|
|||
|
||||
## Summary
|
||||
|
||||
**Server Tests:** 40/40 passed (100%)
|
||||
**Server Tests (active suite):** 44/44 passed (31 scenarios, 100%)
|
||||
**Server Tests (spec 2025-11-25):** 4/4 passed — SEP-1613 `json-schema-2020-12` scenario ✨
|
||||
**Client Tests:** 3/4 scenarios passed (9/10 checks passed)
|
||||
**Auth Tests:** 14/15 scenarios fully passing (196 passed, 0 failed, 1 warning, 93.3% scenarios, 99.5% checks)
|
||||
|
||||
## Server Test Results
|
||||
|
||||
### Passing (40/40)
|
||||
### Active Suite — Passing (31/31 scenarios, 44/44 checks)
|
||||
|
||||
- **Lifecycle & Utilities (4/4):** initialize, ping, logging-set-level, completion-complete
|
||||
- **Tools (11/11):** All scenarios including progress notifications ✨
|
||||
- **Tools (13/13):** All scenarios including progress notifications, sampling, elicitation ✨
|
||||
- **Elicitation (10/10):** SEP-1034 defaults (5 checks), SEP-1330 enums (5 checks)
|
||||
- **Resources (6/6):** list, read-text, read-binary, templates-read, subscribe, unsubscribe
|
||||
- **Prompts (4/4):** list, simple, with-args, embedded-resource, with-image
|
||||
- **Resources (7/7):** list, read-text, read-binary, templates-read, subscribe, unsubscribe, SEP-2164 resource-not-found
|
||||
- **Prompts (5/5):** list, simple, with-args, embedded-resource, with-image
|
||||
- **SSE Transport (2/2):** Multiple streams
|
||||
- **Security (2/2):** Localhost validation passes, DNS rebinding protection
|
||||
|
||||
### Spec 2025-11-25 Scenarios — Passing (1/1 scenario, 4/4 checks)
|
||||
|
||||
- **JSON Schema 2020-12 (SEP-1613) (4/4):** ✨
|
||||
- `json_schema_2020_12_tool` found
|
||||
- `inputSchema.$schema` field preserved
|
||||
- `inputSchema.$defs` field preserved
|
||||
- `inputSchema.additionalProperties` field preserved
|
||||
|
||||
## Client Test Results
|
||||
|
||||
### Passing (3/4 scenarios, 9/10 checks)
|
||||
|
|
@ -69,7 +78,7 @@ Uses the `client-spring-http-client` module with Spring Security OAuth2 and the
|
|||
|
||||
## Running Tests
|
||||
|
||||
### Server
|
||||
### Server (active suite)
|
||||
```bash
|
||||
# Start server
|
||||
./mvnw compile -pl conformance-tests/server-servlet -am exec:java
|
||||
|
|
@ -78,6 +87,17 @@ Uses the `client-spring-http-client` module with Spring Security OAuth2 and the
|
|||
npx @modelcontextprotocol/conformance server --url http://localhost:8080/mcp --suite active
|
||||
```
|
||||
|
||||
### Server (spec 2025-11-25 scenarios — SEP-1613)
|
||||
```bash
|
||||
# Start server (if not already running)
|
||||
./mvnw compile -pl conformance-tests/server-servlet -am exec:java
|
||||
|
||||
# Run json-schema-2020-12 scenario
|
||||
cd ../conformance && node --import tsx/esm src/index.ts server \
|
||||
--url http://localhost:8080/mcp \
|
||||
--scenario json-schema-2020-12
|
||||
```
|
||||
|
||||
### Client
|
||||
```bash
|
||||
# Build
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import io.modelcontextprotocol.server.McpServer;
|
|||
import io.modelcontextprotocol.server.McpServerFeatures;
|
||||
import io.modelcontextprotocol.server.transport.DefaultServerTransportSecurityValidator;
|
||||
import io.modelcontextprotocol.server.transport.HttpServletStreamableServerTransportProvider;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpSchema.AudioContent;
|
||||
import io.modelcontextprotocol.spec.McpSchema.BlobResourceContents;
|
||||
import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
|
||||
|
|
@ -402,6 +403,29 @@ public class ConformanceServlet {
|
|||
})
|
||||
.build(),
|
||||
|
||||
// json_schema_2020_12_tool - SEP-1613 dialect/keyword preservation
|
||||
McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(Tool
|
||||
.builder("json_schema_2020_12_tool", Map.of("$schema", McpSchema.JSON_SCHEMA_DIALECT_2020_12,
|
||||
"type", "object", "$defs",
|
||||
Map.of("address",
|
||||
Map.of("type", "object", "properties",
|
||||
Map.of("street", Map.of("type", "string"), "city",
|
||||
Map.of("type", "string")))),
|
||||
"properties",
|
||||
Map.of("name", Map.of("type", "string"), "address", Map.of("$ref", "#/$defs/address")),
|
||||
"additionalProperties", false))
|
||||
.description("Tool with JSON Schema 2020-12 features (SEP-1613)")
|
||||
.build())
|
||||
.callHandler((exchange, request) -> {
|
||||
logger.info("Tool 'json_schema_2020_12_tool' called");
|
||||
return CallToolResult.builder()
|
||||
.content(List.of(TextContent.builder("ok").build()))
|
||||
.isError(false)
|
||||
.build();
|
||||
})
|
||||
.build(),
|
||||
|
||||
// test_elicitation_sep1330_enums - Tool with enum schema improvements
|
||||
McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(Tool.builder("test_elicitation_sep1330_enums", EMPTY_JSON_SCHEMA)
|
||||
|
|
|
|||
Loading…
Reference in a new issue