From 7f205d27aec4c7e8addf38f20abdfba78fdef973 Mon Sep 17 00:00:00 2001 From: Kyrian Obikwelu Date: Mon, 30 Jun 2025 22:56:36 +0100 Subject: [PATCH 1/2] feat: use callable instead of Closure|array|string for handler type --- src/Elements/RegisteredElement.php | 13 ++++++++++--- src/Elements/RegisteredPrompt.php | 4 ++-- src/Elements/RegisteredResource.php | 4 ++-- src/Elements/RegisteredResourceTemplate.php | 4 ++-- src/Elements/RegisteredTool.php | 4 ++-- src/Registry.php | 8 ++++---- src/ServerBuilder.php | 8 ++++---- tests/Unit/Attributes/CompletionProviderTest.php | 14 ++++---------- tests/Unit/Elements/RegisteredPromptTest.php | 3 ++- 9 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/Elements/RegisteredElement.php b/src/Elements/RegisteredElement.php index 918e3a7..3740514 100644 --- a/src/Elements/RegisteredElement.php +++ b/src/Elements/RegisteredElement.php @@ -18,10 +18,17 @@ class RegisteredElement implements JsonSerializable { + /** @var callable|array|string */ + public readonly mixed $handler; + public readonly bool $isManual; + public function __construct( - public readonly \Closure|array|string $handler, - public readonly bool $isManual = false, - ) {} + callable|array|string $handler, + bool $isManual = false, + ) { + $this->handler = $handler; + $this->isManual = $isManual; + } public function handle(ContainerInterface $container, array $arguments): mixed { diff --git a/src/Elements/RegisteredPrompt.php b/src/Elements/RegisteredPrompt.php index b37ad1e..3ebcc0d 100644 --- a/src/Elements/RegisteredPrompt.php +++ b/src/Elements/RegisteredPrompt.php @@ -24,14 +24,14 @@ class RegisteredPrompt extends RegisteredElement { public function __construct( public readonly Prompt $schema, - \Closure|array|string $handler, + callable|array|string $handler, bool $isManual = false, public readonly array $completionProviders = [] ) { parent::__construct($handler, $isManual); } - public static function make(Prompt $schema, \Closure|array|string $handler, bool $isManual = false, array $completionProviders = []): self + public static function make(Prompt $schema, callable|array|string $handler, bool $isManual = false, array $completionProviders = []): self { return new self($schema, $handler, $isManual, $completionProviders); } diff --git a/src/Elements/RegisteredResource.php b/src/Elements/RegisteredResource.php index d139774..489aa24 100644 --- a/src/Elements/RegisteredResource.php +++ b/src/Elements/RegisteredResource.php @@ -16,13 +16,13 @@ class RegisteredResource extends RegisteredElement { public function __construct( public readonly Resource $schema, - \Closure|array|string $handler, + callable|array|string $handler, bool $isManual = false, ) { parent::__construct($handler, $isManual); } - public static function make(Resource $schema, \Closure|array|string $handler, bool $isManual = false): self + public static function make(Resource $schema, callable|array|string $handler, bool $isManual = false): self { return new self($schema, $handler, $isManual); } diff --git a/src/Elements/RegisteredResourceTemplate.php b/src/Elements/RegisteredResourceTemplate.php index e88c9ab..dc3e6a7 100644 --- a/src/Elements/RegisteredResourceTemplate.php +++ b/src/Elements/RegisteredResourceTemplate.php @@ -22,7 +22,7 @@ class RegisteredResourceTemplate extends RegisteredElement public function __construct( public readonly ResourceTemplate $schema, - \Closure|array|string $handler, + callable|array|string $handler, bool $isManual = false, public readonly array $completionProviders = [] ) { @@ -31,7 +31,7 @@ public function __construct( $this->compileTemplate(); } - public static function make(ResourceTemplate $schema, \Closure|array|string $handler, bool $isManual = false, array $completionProviders = []): self + public static function make(ResourceTemplate $schema, callable|array|string $handler, bool $isManual = false, array $completionProviders = []): self { return new self($schema, $handler, $isManual, $completionProviders); } diff --git a/src/Elements/RegisteredTool.php b/src/Elements/RegisteredTool.php index 2592662..9e35a0e 100644 --- a/src/Elements/RegisteredTool.php +++ b/src/Elements/RegisteredTool.php @@ -14,13 +14,13 @@ class RegisteredTool extends RegisteredElement { public function __construct( public readonly Tool $schema, - \Closure|array|string $handler, + callable|array|string $handler, bool $isManual = false, ) { parent::__construct($handler, $isManual); } - public static function make(Tool $schema, \Closure|array|string $handler, bool $isManual = false): self + public static function make(Tool $schema, callable|array|string $handler, bool $isManual = false): self { return new self($schema, $handler, $isManual); } diff --git a/src/Registry.php b/src/Registry.php index 689a0a9..07125ce 100644 --- a/src/Registry.php +++ b/src/Registry.php @@ -181,7 +181,7 @@ public function load(): void } } - public function registerTool(Tool $tool, \Closure|array|string $handler, bool $isManual = false): void + public function registerTool(Tool $tool, callable|array|string $handler, bool $isManual = false): void { $toolName = $tool->name; $existing = $this->tools[$toolName] ?? null; @@ -197,7 +197,7 @@ public function registerTool(Tool $tool, \Closure|array|string $handler, bool $i $this->checkAndEmitChange('tools', $this->tools); } - public function registerResource(Resource $resource, \Closure|array|string $handler, bool $isManual = false): void + public function registerResource(Resource $resource, callable|array|string $handler, bool $isManual = false): void { $uri = $resource->uri; $existing = $this->resources[$uri] ?? null; @@ -215,7 +215,7 @@ public function registerResource(Resource $resource, \Closure|array|string $hand public function registerResourceTemplate( ResourceTemplate $template, - \Closure|array|string $handler, + callable|array|string $handler, array $completionProviders = [], bool $isManual = false, ): void { @@ -235,7 +235,7 @@ public function registerResourceTemplate( public function registerPrompt( Prompt $prompt, - \Closure|array|string $handler, + callable|array|string $handler, array $completionProviders = [], bool $isManual = false, ): void { diff --git a/src/ServerBuilder.php b/src/ServerBuilder.php index 59127ce..dacfda3 100644 --- a/src/ServerBuilder.php +++ b/src/ServerBuilder.php @@ -215,7 +215,7 @@ public function withLoop(LoopInterface $loop): self /** * Manually registers a tool handler. */ - public function withTool(\Closure|array|string $handler, ?string $name = null, ?string $description = null, ?ToolAnnotations $annotations = null, ?array $inputSchema = null): self + public function withTool(callable|array|string $handler, ?string $name = null, ?string $description = null, ?ToolAnnotations $annotations = null, ?array $inputSchema = null): self { $this->manualTools[] = compact('handler', 'name', 'description', 'annotations', 'inputSchema'); @@ -225,7 +225,7 @@ public function withTool(\Closure|array|string $handler, ?string $name = null, ? /** * Manually registers a resource handler. */ - public function withResource(\Closure|array|string $handler, string $uri, ?string $name = null, ?string $description = null, ?string $mimeType = null, ?int $size = null, ?Annotations $annotations = null): self + public function withResource(callable|array|string $handler, string $uri, ?string $name = null, ?string $description = null, ?string $mimeType = null, ?int $size = null, ?Annotations $annotations = null): self { $this->manualResources[] = compact('handler', 'uri', 'name', 'description', 'mimeType', 'size', 'annotations'); @@ -235,7 +235,7 @@ public function withResource(\Closure|array|string $handler, string $uri, ?strin /** * Manually registers a resource template handler. */ - public function withResourceTemplate(\Closure|array|string $handler, string $uriTemplate, ?string $name = null, ?string $description = null, ?string $mimeType = null, ?Annotations $annotations = null): self + public function withResourceTemplate(callable|array|string $handler, string $uriTemplate, ?string $name = null, ?string $description = null, ?string $mimeType = null, ?Annotations $annotations = null): self { $this->manualResourceTemplates[] = compact('handler', 'uriTemplate', 'name', 'description', 'mimeType', 'annotations'); @@ -245,7 +245,7 @@ public function withResourceTemplate(\Closure|array|string $handler, string $uri /** * Manually registers a prompt handler. */ - public function withPrompt(\Closure|array|string $handler, ?string $name = null, ?string $description = null): self + public function withPrompt(callable|array|string $handler, ?string $name = null, ?string $description = null): self { $this->manualPrompts[] = compact('handler', 'name', 'description'); diff --git a/tests/Unit/Attributes/CompletionProviderTest.php b/tests/Unit/Attributes/CompletionProviderTest.php index cbe1c8a..ba5288d 100644 --- a/tests/Unit/Attributes/CompletionProviderTest.php +++ b/tests/Unit/Attributes/CompletionProviderTest.php @@ -8,13 +8,7 @@ use PhpMcp\Server\Tests\Fixtures\General\CompletionProviderFixture; use PhpMcp\Server\Defaults\ListCompletionProvider; use PhpMcp\Server\Defaults\EnumCompletionProvider; - -enum TestEnum: string -{ - case DRAFT = 'draft'; - case PUBLISHED = 'published'; - case ARCHIVED = 'archived'; -} +use PhpMcp\Server\Tests\Fixtures\Enums\StatusEnum; it('can be constructed with provider class', function () { $attribute = new CompletionProvider(provider: CompletionProviderFixture::class); @@ -43,11 +37,11 @@ enum TestEnum: string }); it('can be constructed with enum class', function () { - $attribute = new CompletionProvider(enum: TestEnum::class); + $attribute = new CompletionProvider(enum: StatusEnum::class); expect($attribute->provider)->toBeNull(); expect($attribute->values)->toBeNull(); - expect($attribute->enum)->toBe(TestEnum::class); + expect($attribute->enum)->toBe(StatusEnum::class); }); it('throws exception when no parameters provided', function () { @@ -65,6 +59,6 @@ enum TestEnum: string new CompletionProvider( provider: CompletionProviderFixture::class, values: ['test'], - enum: TestEnum::class + enum: StatusEnum::class ); })->throws(\InvalidArgumentException::class, 'Only one of provider, values, or enum can be set'); diff --git a/tests/Unit/Elements/RegisteredPromptTest.php b/tests/Unit/Elements/RegisteredPromptTest.php index ff59a71..e3ff637 100644 --- a/tests/Unit/Elements/RegisteredPromptTest.php +++ b/tests/Unit/Elements/RegisteredPromptTest.php @@ -12,6 +12,7 @@ use PhpMcp\Schema\Content\ImageContent; use PhpMcp\Schema\Content\AudioContent; use PhpMcp\Schema\Content\EmbeddedResource; +use PhpMcp\Server\Tests\Fixtures\Enums\StatusEnum; use PhpMcp\Server\Tests\Fixtures\General\PromptHandlerFixture; use PhpMcp\Server\Tests\Fixtures\General\CompletionProviderFixture; use PhpMcp\Server\Tests\Unit\Attributes\TestEnum; @@ -261,7 +262,7 @@ [PromptArgument::make('priority')] ); - $enumProvider = new \PhpMcp\Server\Defaults\EnumCompletionProvider(TestEnum::class); + $enumProvider = new \PhpMcp\Server\Defaults\EnumCompletionProvider(StatusEnum::class); $providers = ['priority' => $enumProvider]; $original = RegisteredPrompt::make( From 7ede46303ef330a25ac9a56399895aad850937a7 Mon Sep 17 00:00:00 2001 From: Kyrian Obikwelu Date: Mon, 30 Jun 2025 23:08:12 +0100 Subject: [PATCH 2/2] fix(tests): wrong enum used in DispatcherTest --- tests/Unit/DispatcherTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/DispatcherTest.php b/tests/Unit/DispatcherTest.php index a6c83ea..79e7b15 100644 --- a/tests/Unit/DispatcherTest.php +++ b/tests/Unit/DispatcherTest.php @@ -52,8 +52,8 @@ use PhpMcp\Schema\Request\ListResourceTemplatesRequest; use PhpMcp\Schema\ResourceReference; use PhpMcp\Server\Protocol; +use PhpMcp\Server\Tests\Fixtures\Enums\StatusEnum; use React\EventLoop\Loop; -use PhpMcp\Server\Tests\Unit\Attributes\TestEnum; const DISPATCHER_SESSION_ID = 'dispatcher-session-xyz'; const DISPATCHER_PAGINATION_LIMIT = 3; @@ -528,7 +528,7 @@ $currentValue = 'a'; $expectedCompletions = ['archived']; - $enumProvider = new \PhpMcp\Server\Defaults\EnumCompletionProvider(TestEnum::class); + $enumProvider = new \PhpMcp\Server\Defaults\EnumCompletionProvider(StatusEnum::class); $promptSchema = PromptSchema::make($promptName, '', [PromptArgument::make($argName)]); $registeredPrompt = new RegisteredPrompt(