|
9 | 9 | import java.util.List; |
10 | 10 | import java.util.Map; |
11 | 11 |
|
| 12 | +import com.fasterxml.jackson.core.type.TypeReference; |
12 | 13 | import com.fasterxml.jackson.databind.ObjectMapper; |
13 | 14 | import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; |
14 | 15 | import io.modelcontextprotocol.spec.McpSchema.TextResourceContents; |
@@ -449,6 +450,106 @@ void testGetPromptResult() throws Exception { |
449 | 450 |
|
450 | 451 | // Tool Tests |
451 | 452 |
|
| 453 | + @Test |
| 454 | + void testJsonSchema() throws Exception { |
| 455 | + String schemaJson = """ |
| 456 | + { |
| 457 | + "type": "object", |
| 458 | + "properties": { |
| 459 | + "name": { |
| 460 | + "type": "string" |
| 461 | + }, |
| 462 | + "address": { |
| 463 | + "$ref": "#/$defs/Address" |
| 464 | + } |
| 465 | + }, |
| 466 | + "required": ["name"], |
| 467 | + "$defs": { |
| 468 | + "Address": { |
| 469 | + "type": "object", |
| 470 | + "properties": { |
| 471 | + "street": {"type": "string"}, |
| 472 | + "city": {"type": "string"} |
| 473 | + }, |
| 474 | + "required": ["street", "city"] |
| 475 | + } |
| 476 | + } |
| 477 | + } |
| 478 | + """; |
| 479 | + |
| 480 | + McpSchema.JsonSchema schema = mapper.readValue(schemaJson, McpSchema.JsonSchema.class); |
| 481 | + |
| 482 | + assertThat(schema.type()).isEqualTo("object"); |
| 483 | + assertThat(schema.properties()).containsKeys("name", "address"); |
| 484 | + assertThat(schema.required()).containsExactly("name"); |
| 485 | + assertThat(schema.defs()).isNotNull(); |
| 486 | + assertThat(schema.defs()).containsKey("Address"); |
| 487 | + |
| 488 | + String value = mapper.writeValueAsString(schema); |
| 489 | + |
| 490 | + // Convert to map for easier assertions |
| 491 | + Map<String, Object> jsonMap = mapper.readValue(value, new TypeReference<HashMap<String, Object>>() { |
| 492 | + }); |
| 493 | + Map<String, Object> defs = (Map<String, Object>) jsonMap.get("$defs"); |
| 494 | + Map<String, Object> address = (Map<String, Object>) defs.get("Address"); |
| 495 | + |
| 496 | + assertThat(address).containsEntry("type", "object"); |
| 497 | + assertThat(((Map<String, Object>) ((Map<String, Object>) address.get("properties")).get("street")).get("type")) |
| 498 | + .isEqualTo("string"); |
| 499 | + assertThat(((Map<String, Object>) ((Map<String, Object>) address.get("properties")).get("city")).get("type")) |
| 500 | + .isEqualTo("string"); |
| 501 | + } |
| 502 | + |
| 503 | + @Test |
| 504 | + void testJsonSchemaWithDefinitions() throws Exception { |
| 505 | + String schemaJson = """ |
| 506 | + { |
| 507 | + "type": "object", |
| 508 | + "properties": { |
| 509 | + "name": { |
| 510 | + "type": "string" |
| 511 | + }, |
| 512 | + "address": { |
| 513 | + "$ref": "#/definitions/Address" |
| 514 | + } |
| 515 | + }, |
| 516 | + "required": ["name"], |
| 517 | + "definitions": { |
| 518 | + "Address": { |
| 519 | + "type": "object", |
| 520 | + "properties": { |
| 521 | + "street": {"type": "string"}, |
| 522 | + "city": {"type": "string"} |
| 523 | + }, |
| 524 | + "required": ["street", "city"] |
| 525 | + } |
| 526 | + } |
| 527 | + } |
| 528 | + """; |
| 529 | + |
| 530 | + McpSchema.JsonSchema schema = mapper.readValue(schemaJson, McpSchema.JsonSchema.class); |
| 531 | + |
| 532 | + assertThat(schema.type()).isEqualTo("object"); |
| 533 | + assertThat(schema.properties()).containsKeys("name", "address"); |
| 534 | + assertThat(schema.required()).containsExactly("name"); |
| 535 | + assertThat(schema.definitions()).isNotNull(); |
| 536 | + assertThat(schema.definitions()).containsKey("Address"); |
| 537 | + |
| 538 | + String value = mapper.writeValueAsString(schema); |
| 539 | + |
| 540 | + // Convert to map for easier assertions |
| 541 | + Map<String, Object> jsonMap = mapper.readValue(value, new TypeReference<HashMap<String, Object>>() { |
| 542 | + }); |
| 543 | + Map<String, Object> definitions = (Map<String, Object>) jsonMap.get("definitions"); |
| 544 | + Map<String, Object> address = (Map<String, Object>) definitions.get("Address"); |
| 545 | + |
| 546 | + assertThat(address).containsEntry("type", "object"); |
| 547 | + assertThat(((Map<String, Object>) ((Map<String, Object>) address.get("properties")).get("street")).get("type")) |
| 548 | + .isEqualTo("string"); |
| 549 | + assertThat(((Map<String, Object>) ((Map<String, Object>) address.get("properties")).get("city")).get("type")) |
| 550 | + .isEqualTo("string"); |
| 551 | + } |
| 552 | + |
452 | 553 | @Test |
453 | 554 | void testTool() throws Exception { |
454 | 555 | String schemaJson = """ |
@@ -477,6 +578,50 @@ void testTool() throws Exception { |
477 | 578 | {"name":"test-tool","description":"A test tool","inputSchema":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"number"}},"required":["name"]}}""")); |
478 | 579 | } |
479 | 580 |
|
| 581 | + @Test |
| 582 | + void testToolWithComplexSchema() throws Exception { |
| 583 | + String complexSchemaJson = """ |
| 584 | + { |
| 585 | + "type": "object", |
| 586 | + "$defs": { |
| 587 | + "Address": { |
| 588 | + "type": "object", |
| 589 | + "properties": { |
| 590 | + "street": {"type": "string"}, |
| 591 | + "city": {"type": "string"} |
| 592 | + }, |
| 593 | + "required": ["street", "city"] |
| 594 | + } |
| 595 | + }, |
| 596 | + "properties": { |
| 597 | + "name": {"type": "string"}, |
| 598 | + "shippingAddress": {"$ref": "#/$defs/Address"} |
| 599 | + }, |
| 600 | + "required": ["name", "shippingAddress"] |
| 601 | + } |
| 602 | + """; |
| 603 | + |
| 604 | + McpSchema.Tool tool = new McpSchema.Tool("addressTool", "Handles addresses", complexSchemaJson); |
| 605 | + |
| 606 | + // Verify the schema was properly parsed and stored with $defs |
| 607 | + assertThat(tool.inputSchema().defs()).isNotNull(); |
| 608 | + assertThat(tool.inputSchema().defs()).containsKey("Address"); |
| 609 | + |
| 610 | + String value = mapper.writeValueAsString(tool); |
| 611 | + |
| 612 | + // Convert to map for easier assertions |
| 613 | + Map<String, Object> jsonMap = mapper.readValue(value, new TypeReference<HashMap<String, Object>>() { |
| 614 | + }); |
| 615 | + Map<String, Object> inputSchema = (Map<String, Object>) jsonMap.get("inputSchema"); |
| 616 | + Map<String, Object> defs = (Map<String, Object>) inputSchema.get("$defs"); |
| 617 | + Map<String, Object> address = (Map<String, Object>) defs.get("Address"); |
| 618 | + Map<String, Object> properties = (Map<String, Object>) inputSchema.get("properties"); |
| 619 | + Map<String, Object> shippingAddress = (Map<String, Object>) properties.get("shippingAddress"); |
| 620 | + |
| 621 | + assertThat(address).containsEntry("type", "object"); |
| 622 | + assertThat(shippingAddress).containsEntry("$ref", "#/$defs/Address"); |
| 623 | + } |
| 624 | + |
480 | 625 | @Test |
481 | 626 | void testCallToolRequest() throws Exception { |
482 | 627 | Map<String, Object> arguments = new HashMap<>(); |
|
0 commit comments