From aaa9597b3f25bc2d6e17af4de76f9cca53515939 Mon Sep 17 00:00:00 2001 From: Eduard Lupacescu Date: Fri, 24 Oct 2025 14:20:48 +0300 Subject: [PATCH] fix: wrapper json schema object --- src/MCP/Concerns/WrapperToolHelpers.php | 32 ++++++++++++----------- tests/MCP/WrapperToolsIntegrationTest.php | 14 ++++++---- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/MCP/Concerns/WrapperToolHelpers.php b/src/MCP/Concerns/WrapperToolHelpers.php index 6df33088..57de4f6d 100644 --- a/src/MCP/Concerns/WrapperToolHelpers.php +++ b/src/MCP/Concerns/WrapperToolHelpers.php @@ -2,32 +2,34 @@ namespace Binaryk\LaravelRestify\MCP\Concerns; +use Illuminate\JsonSchema\JsonSchemaTypeFactory; + trait WrapperToolHelpers { /** * Format operation schema for display. + * + * Wraps the schema properties in an ObjectType before serialization to properly + * handle required fields and other attributes according to JSON Schema spec. + * This matches how Laravel MCP's Tool::toArray() works. */ protected function formatSchemaForDisplay(array $schema): array { - $formatted = []; - - foreach ($schema as $key => $value) { - if (is_object($value) && method_exists($value, 'toArray')) { - $formatted[$key] = $value->toArray(); - } else { - $formatted[$key] = $value; - } - } + $schemaFactory = new JsonSchemaTypeFactory; + $objectType = $schemaFactory->object($schema); - return $formatted; + return $objectType->toArray(); } /** * Generate examples from operation schema. + * + * After wrapping in ObjectType, the schema has a 'properties' key containing all fields. */ protected function generateExamplesFromSchema(array $schema, string $operationType): array { $examples = []; + $properties = $schema['properties'] ?? []; switch ($operationType) { case 'index': @@ -39,7 +41,7 @@ protected function generateExamplesFromSchema(array $schema, string $operationTy ], ]; - if (isset($schema['search'])) { + if (isset($properties['search'])) { $examples[] = [ 'description' => 'Search with pagination', 'parameters' => [ @@ -50,7 +52,7 @@ protected function generateExamplesFromSchema(array $schema, string $operationTy ]; } - if (isset($schema['include'])) { + if (isset($properties['include'])) { $examples[] = [ 'description' => 'With relationships', 'parameters' => [ @@ -70,7 +72,7 @@ protected function generateExamplesFromSchema(array $schema, string $operationTy ], ]; - if (isset($schema['include'])) { + if (isset($properties['include'])) { $examples[] = [ 'description' => 'Show with relationships', 'parameters' => [ @@ -83,7 +85,7 @@ protected function generateExamplesFromSchema(array $schema, string $operationTy case 'store': $exampleParams = []; - foreach ($schema as $key => $field) { + foreach ($properties as $key => $field) { if ($key === 'include') { continue; } @@ -101,7 +103,7 @@ protected function generateExamplesFromSchema(array $schema, string $operationTy case 'update': $exampleParams = ['id' => '1']; - foreach ($schema as $key => $field) { + foreach ($properties as $key => $field) { if (in_array($key, ['id', 'include'])) { continue; } diff --git a/tests/MCP/WrapperToolsIntegrationTest.php b/tests/MCP/WrapperToolsIntegrationTest.php index 3dd42f47..cd048af1 100644 --- a/tests/MCP/WrapperToolsIntegrationTest.php +++ b/tests/MCP/WrapperToolsIntegrationTest.php @@ -441,11 +441,14 @@ public function mcpAllowsIndex(): bool $this->assertArrayHasKey('examples', $resultContent); // Assert schema contains expected fields + // Schema is now wrapped in ObjectType following JSON Schema spec $schema = $resultContent['schema']; - $this->assertArrayHasKey('page', $schema); - $this->assertArrayHasKey('perPage', $schema); - $this->assertArrayHasKey('search', $schema); - $this->assertArrayHasKey('include', $schema); + $this->assertEquals('object', $schema['type']); + $this->assertArrayHasKey('properties', $schema); + $this->assertArrayHasKey('page', $schema['properties']); + $this->assertArrayHasKey('perPage', $schema['properties']); + $this->assertArrayHasKey('search', $schema['properties']); + $this->assertArrayHasKey('include', $schema['properties']); // Assert examples are provided $this->assertNotEmpty($resultContent['examples']); @@ -729,7 +732,8 @@ public function mcpAllowsStore(): bool $detailsResult = json_decode($detailsResponse->json()['result']['content'][0]['text'], true); $this->assertArrayHasKey('schema', $detailsResult); - $this->assertArrayHasKey('title', $detailsResult['schema']); + // Schema is now wrapped in ObjectType, so check for properties + $this->assertArrayHasKey('properties', $detailsResult['schema']); // Step 4: Execute the store operation $executePayload = [