diff --git a/src/Api/ApiRegistry.php b/src/Api/ApiRegistry.php index e815eb93..806847e3 100644 --- a/src/Api/ApiRegistry.php +++ b/src/Api/ApiRegistry.php @@ -71,13 +71,7 @@ public function getMethodDescriptor(string $method, ?ApiCallContext $context = n return null; } - return new MethodDescriptor( - name: $interface . '.' . $descriptor->name, - description: $descriptor->description, - parameters: $descriptor->parameters, - returnType: $descriptor->returnType, - permissions: $descriptor->permissions, - ); + return $this->prefixDescriptor($interface, $descriptor); } /** @@ -88,13 +82,7 @@ public function listMethods(?ApiCallContext $context = null): array $all = []; foreach ($this->providers as $interface => $provider) { foreach ($provider->listMethods($context) as $descriptor) { - $all[] = new MethodDescriptor( - name: $interface . '.' . $descriptor->name, - description: $descriptor->description, - parameters: $descriptor->parameters, - returnType: $descriptor->returnType, - permissions: $descriptor->permissions, - ); + $all[] = $this->prefixDescriptor($interface, $descriptor); } } @@ -153,6 +141,24 @@ public function getProviderForInterface(string $interface): ApiProvider|MethodIn return $this->providers[$interface] ?? null; } + /** + * Re-wrap a provider-local descriptor with the interface-prefixed name, + * preserving all other metadata (including the JSON schemas needed by + * MCP tool listings). + */ + private function prefixDescriptor(string $interface, MethodDescriptor $descriptor): MethodDescriptor + { + return new MethodDescriptor( + name: $interface . '.' . $descriptor->name, + description: $descriptor->description, + parameters: $descriptor->parameters, + returnType: $descriptor->returnType, + inputSchema: $descriptor->inputSchema, + outputSchema: $descriptor->outputSchema, + permissions: $descriptor->permissions, + ); + } + /** * @return array{string, string}|null */ diff --git a/test/Unit/Api/ApiRegistryTest.php b/test/Unit/Api/ApiRegistryTest.php index c932b097..dc782a4b 100644 --- a/test/Unit/Api/ApiRegistryTest.php +++ b/test/Unit/Api/ApiRegistryTest.php @@ -85,6 +85,42 @@ public function testGetMethodDescriptorPrefixed(): void $this->assertSame('List items', $desc->description); } + public function testDescriptorSchemasPreserved(): void + { + $inputSchema = [ + 'type' => 'object', + 'properties' => [ + 'pagename' => ['type' => 'string', 'description' => 'Page to edit'], + ], + 'required' => ['pagename'], + ]; + $outputSchema = ['type' => 'object']; + $provider = $this->makeProvider( + ['edit' => fn() => null], + ['edit' => new MethodDescriptor( + 'edit', + description: 'Edit a page', + inputSchema: $inputSchema, + outputSchema: $outputSchema, + )], + ); + $registry = new ApiRegistry(); + $registry->registerProvider('wiki', $provider); + + $desc = $registry->getMethodDescriptor('wiki.edit'); + + $this->assertNotNull($desc); + $this->assertSame($inputSchema, $desc->inputSchema); + $this->assertSame($outputSchema, $desc->outputSchema); + + $listed = $registry->listMethods(); + + $this->assertCount(1, $listed); + $this->assertSame('wiki.edit', $listed[0]->name); + $this->assertSame($inputSchema, $listed[0]->inputSchema); + $this->assertSame($outputSchema, $listed[0]->outputSchema); + } + public function testUnknownInterfaceHasMethodReturnsFalse(): void { $registry = new ApiRegistry();