Address open PHPStan issues from baseline (#92)

This commit is contained in:
Christopher Hertel 2025-10-07 23:16:47 +02:00 • committed by GitHub
commit d06b57d285
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 79 additions and 120 deletions

View file

@ -12,92 +12,15 @@ parameters:
count: 2 count: 2
path: examples/http-discovery-userprofile/McpElements.php path: examples/http-discovery-userprofile/McpElements.php
-
message: '#^PHPDoc tag @return with type array is incompatible with native type object\.$#'
identifier: return.phpDocType
count: 1
path: src/Schema/Result/EmptyResult.php
- -
message: '#^Method Mcp\\Schema\\Result\\ReadResourceResult\:\:jsonSerialize\(\) should return array\{contents\: array\<Mcp\\Schema\\Content\\BlobResourceContents\|Mcp\\Schema\\Content\\TextResourceContents\>\} but returns array\{contents\: array\<Mcp\\Schema\\Content\\ResourceContents\>\}\.$#' message: '#^Method Mcp\\Schema\\Result\\ReadResourceResult\:\:jsonSerialize\(\) should return array\{contents\: array\<Mcp\\Schema\\Content\\BlobResourceContents\|Mcp\\Schema\\Content\\TextResourceContents\>\} but returns array\{contents\: array\<Mcp\\Schema\\Content\\ResourceContents\>\}\.$#'
identifier: return.type identifier: return.type
count: 1 count: 1
path: src/Schema/Result/ReadResourceResult.php path: src/Schema/Result/ReadResourceResult.php
-
message: '#^Method Mcp\\Server\\Builder\:\:addPrompt\(\) has parameter \$handler with no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php
-
message: '#^Method Mcp\\Server\\Builder\:\:addResource\(\) has parameter \$handler with no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php
-
message: '#^Method Mcp\\Server\\Builder\:\:addResourceTemplate\(\) has parameter \$handler with no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php
-
message: '#^Method Mcp\\Server\\Builder\:\:addTool\(\) has parameter \$handler with no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php
-
message: '#^Method Mcp\\Server\\Builder\:\:addTool\(\) has parameter \$inputSchema with no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php
-
message: '#^Method Mcp\\Server\\Builder\:\:getCompletionProviders\(\) return type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php
-
message: '#^Method Mcp\\Server\\Builder\:\:setDiscovery\(\) has parameter \$excludeDirs with no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php
-
message: '#^Method Mcp\\Server\\Builder\:\:setDiscovery\(\) has parameter \$scanDirs with no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php
- -
message: '#^Property Mcp\\Server\\Builder\:\:\$instructions is never read, only written\.$#' message: '#^Property Mcp\\Server\\Builder\:\:\$instructions is never read, only written\.$#'
identifier: property.onlyWritten identifier: property.onlyWritten
count: 1 count: 1
path: src/Server/Builder.php path: src/Server/Builder.php
-
message: '#^Property Mcp\\Server\\Builder\:\:\$prompts type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php
-
message: '#^Property Mcp\\Server\\Builder\:\:\$resourceTemplates type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php
-
message: '#^Property Mcp\\Server\\Builder\:\:\$resources type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php
-
message: '#^Property Mcp\\Server\\Builder\:\:\$tools type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Server/Builder.php

View file

@ -32,9 +32,6 @@ class EmptyResult implements ResultInterface
return new self(); return new self();
} }
/**
* @return array{}
*/
public function jsonSerialize(): object public function jsonSerialize(): object
{ {
return new \stdClass(); return new \stdClass();

View file

@ -14,6 +14,7 @@ namespace Mcp\Server;
use Mcp\Capability\Attribute\CompletionProvider; use Mcp\Capability\Attribute\CompletionProvider;
use Mcp\Capability\Completion\EnumCompletionProvider; use Mcp\Capability\Completion\EnumCompletionProvider;
use Mcp\Capability\Completion\ListCompletionProvider; use Mcp\Capability\Completion\ListCompletionProvider;
use Mcp\Capability\Completion\ProviderInterface;
use Mcp\Capability\Discovery\CachedDiscoverer; use Mcp\Capability\Discovery\CachedDiscoverer;
use Mcp\Capability\Discovery\Discoverer; use Mcp\Capability\Discovery\Discoverer;
use Mcp\Capability\Discovery\DocBlockParser; use Mcp\Capability\Discovery\DocBlockParser;
@ -23,6 +24,7 @@ use Mcp\Capability\Prompt\PromptGetter;
use Mcp\Capability\Prompt\PromptGetterInterface; use Mcp\Capability\Prompt\PromptGetterInterface;
use Mcp\Capability\Registry; use Mcp\Capability\Registry;
use Mcp\Capability\Registry\Container; use Mcp\Capability\Registry\Container;
use Mcp\Capability\Registry\ElementReference;
use Mcp\Capability\Registry\ReferenceHandler; use Mcp\Capability\Registry\ReferenceHandler;
use Mcp\Capability\Resource\ResourceReader; use Mcp\Capability\Resource\ResourceReader;
use Mcp\Capability\Resource\ResourceReaderInterface; use Mcp\Capability\Resource\ResourceReaderInterface;
@ -50,6 +52,8 @@ use Psr\Log\NullLogger;
use Psr\SimpleCache\CacheInterface; use Psr\SimpleCache\CacheInterface;
/** /**
* @phpstan-import-type Handler from ElementReference
*
* @author Kyrian Obikwelu <koshnawaza@gmail.com> * @author Kyrian Obikwelu <koshnawaza@gmail.com>
*/ */
final class Builder final class Builder
@ -80,40 +84,48 @@ final class Builder
private ?string $instructions = null; private ?string $instructions = null;
/** @var array< /**
* array{handler: array|string|\Closure, * @var array{
* name: string|null, * handler: Handler,
* description: string|null, * name: ?string,
* annotations: ToolAnnotations|null} * description: ?string,
* > */ * annotations: ?ToolAnnotations,
* }[]
*/
private array $tools = []; private array $tools = [];
/** @var array< /**
* array{handler: array|string|\Closure, * @var array{
* handler: Handler,
* uri: string, * uri: string,
* name: string|null, * name: ?string,
* description: string|null, * description: ?string,
* mimeType: string|null, * mimeType: ?string,
* size: int|null, * size: int|null,
* annotations: Annotations|null} * annotations: ?Annotations,
* > */ * }[]
*/
private array $resources = []; private array $resources = [];
/** @var array< /**
* array{handler: array|string|\Closure, * @var array{
* handler: Handler,
* uriTemplate: string, * uriTemplate: string,
* name: string|null, * name: ?string,
* description: string|null, * description: ?string,
* mimeType: string|null, * mimeType: ?string,
* annotations: Annotations|null} * annotations: ?Annotations,
* > */ * }[]
*/
private array $resourceTemplates = []; private array $resourceTemplates = [];
/** @var array< /**
* array{handler: array|string|\Closure, * @var array{
* name: string|null, * handler: Handler,
* description: string|null} * name: ?string,
* > */ * description: ?string,
* }[]
*/
private array $prompts = []; private array $prompts = [];
private ?string $discoveryBasePath = null; private ?string $discoveryBasePath = null;
@ -223,6 +235,10 @@ final class Builder
return $this; return $this;
} }
/**
* @param string[] $scanDirs
* @param string[] $excludeDirs
*/
public function setDiscovery( public function setDiscovery(
string $basePath, string $basePath,
array $scanDirs = ['.', 'src'], array $scanDirs = ['.', 'src'],
@ -239,6 +255,9 @@ final class Builder
/** /**
* Manually registers a tool handler. * Manually registers a tool handler.
*
* @param Handler $handler
* @param array<string, mixed>|null $inputSchema
*/ */
public function addTool( public function addTool(
callable|array|string $handler, callable|array|string $handler,
@ -254,9 +273,11 @@ final class Builder
/** /**
* Manually registers a resource handler. * Manually registers a resource handler.
*
* @param Handler $handler
*/ */
public function addResource( public function addResource(
callable|array|string $handler, \Closure|array|string $handler,
string $uri, string $uri,
?string $name = null, ?string $name = null,
?string $description = null, ?string $description = null,
@ -271,9 +292,11 @@ final class Builder
/** /**
* Manually registers a resource template handler. * Manually registers a resource template handler.
*
* @param Handler $handler
*/ */
public function addResourceTemplate( public function addResourceTemplate(
callable|array|string $handler, \Closure|array|string $handler,
string $uriTemplate, string $uriTemplate,
?string $name = null, ?string $name = null,
?string $description = null, ?string $description = null,
@ -294,8 +317,10 @@ final class Builder
/** /**
* Manually registers a prompt handler. * Manually registers a prompt handler.
*
* @param Handler $handler
*/ */
public function addPrompt(callable|array|string $handler, ?string $name = null, ?string $description = null): self public function addPrompt(\Closure|array|string $handler, ?string $name = null, ?string $description = null): self
{ {
$this->prompts[] = compact('handler', 'name', 'description'); $this->prompts[] = compact('handler', 'name', 'description');
@ -387,9 +412,7 @@ final class Builder
$tool = new Tool($name, $inputSchema, $description, $data['annotations']); $tool = new Tool($name, $inputSchema, $description, $data['annotations']);
$registry->registerTool($tool, $data['handler'], true); $registry->registerTool($tool, $data['handler'], true);
$handlerDesc = $data['handler'] instanceof \Closure ? 'Closure' : (\is_array( $handlerDesc = $this->getHandlerDescription($data['handler']);
$data['handler'],
) ? implode('::', $data['handler']) : $data['handler']);
$logger->debug("Registered manual tool {$name} from handler {$handlerDesc}"); $logger->debug("Registered manual tool {$name} from handler {$handlerDesc}");
} catch (\Throwable $e) { } catch (\Throwable $e) {
$logger->error( $logger->error(
@ -425,9 +448,7 @@ final class Builder
$resource = new Resource($uri, $name, $description, $mimeType, $annotations, $size); $resource = new Resource($uri, $name, $description, $mimeType, $annotations, $size);
$registry->registerResource($resource, $data['handler'], true); $registry->registerResource($resource, $data['handler'], true);
$handlerDesc = $data['handler'] instanceof \Closure ? 'Closure' : (\is_array( $handlerDesc = $this->getHandlerDescription($data['handler']);
$data['handler'],
) ? implode('::', $data['handler']) : $data['handler']);
$logger->debug("Registered manual resource {$name} from handler {$handlerDesc}"); $logger->debug("Registered manual resource {$name} from handler {$handlerDesc}");
} catch (\Throwable $e) { } catch (\Throwable $e) {
$logger->error( $logger->error(
@ -463,9 +484,7 @@ final class Builder
$completionProviders = $this->getCompletionProviders($reflection); $completionProviders = $this->getCompletionProviders($reflection);
$registry->registerResourceTemplate($template, $data['handler'], $completionProviders, true); $registry->registerResourceTemplate($template, $data['handler'], $completionProviders, true);
$handlerDesc = $data['handler'] instanceof \Closure ? 'Closure' : (\is_array( $handlerDesc = $this->getHandlerDescription($data['handler']);
$data['handler'],
) ? implode('::', $data['handler']) : $data['handler']);
$logger->debug("Registered manual template {$name} from handler {$handlerDesc}"); $logger->debug("Registered manual template {$name} from handler {$handlerDesc}");
} catch (\Throwable $e) { } catch (\Throwable $e) {
$logger->error( $logger->error(
@ -517,9 +536,7 @@ final class Builder
$completionProviders = $this->getCompletionProviders($reflection); $completionProviders = $this->getCompletionProviders($reflection);
$registry->registerPrompt($prompt, $data['handler'], $completionProviders, true); $registry->registerPrompt($prompt, $data['handler'], $completionProviders, true);
$handlerDesc = $data['handler'] instanceof \Closure ? 'Closure' : (\is_array( $handlerDesc = $this->getHandlerDescription($data['handler']);
$data['handler'],
) ? implode('::', $data['handler']) : $data['handler']);
$logger->debug("Registered manual prompt {$name} from handler {$handlerDesc}"); $logger->debug("Registered manual prompt {$name} from handler {$handlerDesc}");
} catch (\Throwable $e) { } catch (\Throwable $e) {
$logger->error( $logger->error(
@ -533,6 +550,28 @@ final class Builder
$logger->debug('Manual element registration complete.'); $logger->debug('Manual element registration complete.');
} }
/**
* @param Handler $handler
*/
private function getHandlerDescription(\Closure|array|string $handler): string
{
if ($handler instanceof \Closure) {
return 'Closure';
}
if (\is_array($handler)) {
return \sprintf('%s::%s',
\is_object($handler[0]) ? $handler[0]::class : $handler[0],
$handler[1],
);
}
return (string) $handler;
}
/**
* @return array<string, ProviderInterface>
*/
private function getCompletionProviders(\ReflectionMethod|\ReflectionFunction $reflection): array private function getCompletionProviders(\ReflectionMethod|\ReflectionFunction $reflection): array
{ {
$completionProviders = []; $completionProviders = [];