Roll out meta properties in attributes and more schema classes (#129)
This commit is contained in:
parent
09596c0382
commit
d3a07912b0
8 changed files with 178 additions and 88 deletions
|
|
@ -21,12 +21,14 @@ namespace Mcp\Capability\Attribute;
|
|||
final class McpPrompt
|
||||
{
|
||||
/**
|
||||
* @param ?string $name overrides the prompt name (defaults to method name)
|
||||
* @param ?string $description Optional description of the prompt. Defaults to method DocBlock summary.
|
||||
* @param ?string $name overrides the prompt name (defaults to method name)
|
||||
* @param ?string $description Optional description of the prompt. Defaults to method DocBlock summary.
|
||||
* @param ?array<string, mixed> $meta Optional metadata
|
||||
*/
|
||||
public function __construct(
|
||||
public ?string $name = null,
|
||||
public ?string $description = null,
|
||||
public ?array $meta = null,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,13 @@ use Mcp\Schema\Annotations;
|
|||
final class McpResource
|
||||
{
|
||||
/**
|
||||
* @param string $uri The specific URI identifying this resource instance. Must be unique within the server.
|
||||
* @param ?string $name A human-readable name for this resource. If null, a default might be generated from the method name.
|
||||
* @param ?string $description An optional description of the resource. Defaults to class DocBlock summary.
|
||||
* @param ?string $mimeType the MIME type, if known and constant for this resource
|
||||
* @param ?int $size the size in bytes, if known and constant
|
||||
* @param Annotations|null $annotations optional annotations describing the resource
|
||||
* @param string $uri The specific URI identifying this resource instance. Must be unique within the server.
|
||||
* @param ?string $name A human-readable name for this resource. If null, a default might be generated from the method name.
|
||||
* @param ?string $description An optional description of the resource. Defaults to class DocBlock summary.
|
||||
* @param ?string $mimeType the MIME type, if known and constant for this resource
|
||||
* @param ?int $size the size in bytes, if known and constant
|
||||
* @param Annotations|null $annotations optional annotations describing the resource
|
||||
* @param ?array<string, mixed> $meta Optional metadata
|
||||
*/
|
||||
public function __construct(
|
||||
public string $uri,
|
||||
|
|
@ -37,6 +38,7 @@ final class McpResource
|
|||
public ?string $mimeType = null,
|
||||
public ?int $size = null,
|
||||
public ?Annotations $annotations = null,
|
||||
public ?array $meta = null,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,11 +23,12 @@ use Mcp\Schema\Annotations;
|
|||
final class McpResourceTemplate
|
||||
{
|
||||
/**
|
||||
* @param string $uriTemplate the URI template string (RFC 6570)
|
||||
* @param ?string $name A human-readable name for the template type. If null, a default might be generated from the method name.
|
||||
* @param ?string $description Optional description. Defaults to class DocBlock summary.
|
||||
* @param ?string $mimeType optional default MIME type for matching resources
|
||||
* @param ?Annotations $annotations optional annotations describing the resource template
|
||||
* @param string $uriTemplate the URI template string (RFC 6570)
|
||||
* @param ?string $name A human-readable name for the template type. If null, a default might be generated from the method name.
|
||||
* @param ?string $description Optional description. Defaults to class DocBlock summary.
|
||||
* @param ?string $mimeType optional default MIME type for matching resources
|
||||
* @param ?Annotations $annotations optional annotations describing the resource template
|
||||
* @param ?array<string, mixed> $meta Optional metadata
|
||||
*/
|
||||
public function __construct(
|
||||
public string $uriTemplate,
|
||||
|
|
@ -35,6 +36,7 @@ final class McpResourceTemplate
|
|||
public ?string $description = null,
|
||||
public ?string $mimeType = null,
|
||||
public ?Annotations $annotations = null,
|
||||
public ?array $meta = null,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,14 +20,16 @@ use Mcp\Schema\ToolAnnotations;
|
|||
class McpTool
|
||||
{
|
||||
/**
|
||||
* @param string|null $name The name of the tool (defaults to the method name)
|
||||
* @param string|null $description The description of the tool (defaults to the DocBlock/inferred)
|
||||
* @param ToolAnnotations|null $annotations Optional annotations describing tool behavior
|
||||
* @param string|null $name The name of the tool (defaults to the method name)
|
||||
* @param string|null $description The description of the tool (defaults to the DocBlock/inferred)
|
||||
* @param ToolAnnotations|null $annotations Optional annotations describing tool behavior
|
||||
* @param ?array<string, mixed> $meta Optional metadata
|
||||
*/
|
||||
public function __construct(
|
||||
public ?string $name = null,
|
||||
public ?string $description = null,
|
||||
public ?ToolAnnotations $annotations = null,
|
||||
public ?array $meta = null,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,7 +222,8 @@ class Discoverer
|
|||
$name = $instance->name ?? ('__invoke' === $methodName ? $classShortName : $methodName);
|
||||
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
|
||||
$inputSchema = $this->schemaGenerator->generate($method);
|
||||
$tool = new Tool($name, $inputSchema, $description, $instance->annotations);
|
||||
$meta = $instance->meta ?? null;
|
||||
$tool = new Tool($name, $inputSchema, $description, $instance->annotations, $meta);
|
||||
$tools[$name] = new ToolReference($tool, [$className, $methodName], false);
|
||||
++$discoveredCount['tools'];
|
||||
break;
|
||||
|
|
@ -234,8 +235,10 @@ class Discoverer
|
|||
$mimeType = $instance->mimeType;
|
||||
$size = $instance->size;
|
||||
$annotations = $instance->annotations;
|
||||
$resource = new Resource($instance->uri, $name, $description, $mimeType, $annotations, $size);
|
||||
$meta = $instance->meta;
|
||||
$resource = new Resource($instance->uri, $name, $description, $mimeType, $annotations, $size, $meta);
|
||||
$resources[$instance->uri] = new ResourceReference($resource, [$className, $methodName], false);
|
||||
|
||||
++$discoveredCount['resources'];
|
||||
break;
|
||||
|
||||
|
|
@ -253,7 +256,8 @@ class Discoverer
|
|||
$paramTag = $paramTags['$'.$param->getName()] ?? null;
|
||||
$arguments[] = new PromptArgument($param->getName(), $paramTag ? trim((string) $paramTag->getDescription()) : null, !$param->isOptional() && !$param->isDefaultValueAvailable());
|
||||
}
|
||||
$prompt = new Prompt($name, $description, $arguments);
|
||||
$meta = $instance->meta ?? null;
|
||||
$prompt = new Prompt($name, $description, $arguments, $meta);
|
||||
$completionProviders = $this->getCompletionProviders($method);
|
||||
$prompts[$name] = new PromptReference($prompt, [$className, $methodName], false, $completionProviders);
|
||||
++$discoveredCount['prompts'];
|
||||
|
|
@ -265,7 +269,8 @@ class Discoverer
|
|||
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
|
||||
$mimeType = $instance->mimeType;
|
||||
$annotations = $instance->annotations;
|
||||
$resourceTemplate = new ResourceTemplate($instance->uriTemplate, $name, $description, $mimeType, $annotations);
|
||||
$meta = $instance->meta ?? null;
|
||||
$resourceTemplate = new ResourceTemplate($instance->uriTemplate, $name, $description, $mimeType, $annotations, $meta);
|
||||
$completionProviders = $this->getCompletionProviders($method);
|
||||
$resourceTemplates[$instance->uriTemplate] = new ResourceTemplateReference($resourceTemplate, [$className, $methodName], false, $completionProviders);
|
||||
++$discoveredCount['resourceTemplates'];
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ final class ArrayLoader implements LoaderInterface
|
|||
* name: ?string,
|
||||
* description: ?string,
|
||||
* annotations: ?ToolAnnotations,
|
||||
* meta: ?array<string, mixed>
|
||||
* }[] $tools
|
||||
* @param array{
|
||||
* handler: Handler,
|
||||
|
|
@ -54,6 +55,7 @@ final class ArrayLoader implements LoaderInterface
|
|||
* mimeType: ?string,
|
||||
* size: int|null,
|
||||
* annotations: ?Annotations,
|
||||
* meta: ?array<string, mixed>
|
||||
* }[] $resources
|
||||
* @param array{
|
||||
* handler: Handler,
|
||||
|
|
@ -62,11 +64,13 @@ final class ArrayLoader implements LoaderInterface
|
|||
* description: ?string,
|
||||
* mimeType: ?string,
|
||||
* annotations: ?Annotations,
|
||||
* meta: ?array<string, mixed>
|
||||
* }[] $resourceTemplates
|
||||
* @param array{
|
||||
* handler: Handler,
|
||||
* name: ?string,
|
||||
* description: ?string,
|
||||
* meta: ?array<string, mixed>
|
||||
* }[] $prompts
|
||||
*/
|
||||
public function __construct(
|
||||
|
|
@ -102,7 +106,7 @@ final class ArrayLoader implements LoaderInterface
|
|||
|
||||
$inputSchema = $data['inputSchema'] ?? $schemaGenerator->generate($reflection);
|
||||
|
||||
$tool = new Tool($name, $inputSchema, $description, $data['annotations']);
|
||||
$tool = new Tool($name, $inputSchema, $description, $data['annotations'], $data['meta'] ?? null);
|
||||
$registry->registerTool($tool, $data['handler'], true);
|
||||
|
||||
$handlerDesc = $this->getHandlerDescription($data['handler']);
|
||||
|
|
@ -137,8 +141,9 @@ final class ArrayLoader implements LoaderInterface
|
|||
$mimeType = $data['mimeType'];
|
||||
$size = $data['size'];
|
||||
$annotations = $data['annotations'];
|
||||
$meta = $data['meta'];
|
||||
|
||||
$resource = new Resource($uri, $name, $description, $mimeType, $annotations, $size);
|
||||
$resource = new Resource($uri, $name, $description, $mimeType, $annotations, $size, $meta);
|
||||
$registry->registerResource($resource, $data['handler'], true);
|
||||
|
||||
$handlerDesc = $this->getHandlerDescription($data['handler']);
|
||||
|
|
@ -172,8 +177,9 @@ final class ArrayLoader implements LoaderInterface
|
|||
$uriTemplate = $data['uriTemplate'];
|
||||
$mimeType = $data['mimeType'];
|
||||
$annotations = $data['annotations'];
|
||||
$meta = $data['meta'];
|
||||
|
||||
$template = new ResourceTemplate($uriTemplate, $name, $description, $mimeType, $annotations);
|
||||
$template = new ResourceTemplate($uriTemplate, $name, $description, $mimeType, $annotations, $meta);
|
||||
$completionProviders = $this->getCompletionProviders($reflection);
|
||||
$registry->registerResourceTemplate($template, $data['handler'], $completionProviders, true);
|
||||
|
||||
|
|
@ -224,8 +230,8 @@ final class ArrayLoader implements LoaderInterface
|
|||
!$param->isOptional() && !$param->isDefaultValueAvailable(),
|
||||
);
|
||||
}
|
||||
|
||||
$prompt = new Prompt($name, $description, $arguments);
|
||||
$meta = $data['meta'];
|
||||
$prompt = new Prompt($name, $description, $arguments, $meta);
|
||||
$completionProviders = $this->getCompletionProviders($reflection);
|
||||
$registry->registerPrompt($prompt, $data['handler'], $completionProviders, true);
|
||||
|
||||
|
|
|
|||
|
|
@ -68,9 +68,11 @@ class ResourceReference extends ElementReference
|
|||
return [$readResult->resource];
|
||||
}
|
||||
|
||||
$meta = $this->schema->meta;
|
||||
|
||||
if (\is_array($readResult)) {
|
||||
if (empty($readResult)) {
|
||||
return [new TextResourceContents($uri, 'application/json', '[]')];
|
||||
return [new TextResourceContents($uri, 'application/json', '[]', $meta)];
|
||||
}
|
||||
|
||||
$allAreResourceContents = true;
|
||||
|
|
@ -118,14 +120,15 @@ class ResourceReference extends ElementReference
|
|||
if (\is_string($readResult)) {
|
||||
$mimeType = $mimeType ?? $this->guessMimeTypeFromString($readResult);
|
||||
|
||||
return [new TextResourceContents($uri, $mimeType, $readResult)];
|
||||
return [new TextResourceContents($uri, $mimeType, $readResult, $meta)];
|
||||
}
|
||||
|
||||
if (\is_resource($readResult) && 'stream' === get_resource_type($readResult)) {
|
||||
$result = BlobResourceContents::fromStream(
|
||||
$uri,
|
||||
$readResult,
|
||||
$mimeType ?? 'application/octet-stream'
|
||||
$mimeType ?? 'application/octet-stream',
|
||||
$meta
|
||||
);
|
||||
|
||||
@fclose($readResult);
|
||||
|
|
@ -136,21 +139,21 @@ class ResourceReference extends ElementReference
|
|||
if (\is_array($readResult) && isset($readResult['blob']) && \is_string($readResult['blob'])) {
|
||||
$mimeType = $readResult['mimeType'] ?? $mimeType ?? 'application/octet-stream';
|
||||
|
||||
return [new BlobResourceContents($uri, $mimeType, $readResult['blob'])];
|
||||
return [new BlobResourceContents($uri, $mimeType, $readResult['blob'], $meta)];
|
||||
}
|
||||
|
||||
if (\is_array($readResult) && isset($readResult['text']) && \is_string($readResult['text'])) {
|
||||
$mimeType = $readResult['mimeType'] ?? $mimeType ?? 'text/plain';
|
||||
|
||||
return [new TextResourceContents($uri, $mimeType, $readResult['text'])];
|
||||
return [new TextResourceContents($uri, $mimeType, $readResult['text'], $meta)];
|
||||
}
|
||||
|
||||
if ($readResult instanceof \SplFileInfo && $readResult->isFile() && $readResult->isReadable()) {
|
||||
if ($mimeType && str_contains(strtolower($mimeType), 'text')) {
|
||||
return [new TextResourceContents($uri, $mimeType, file_get_contents($readResult->getPathname()))];
|
||||
return [new TextResourceContents($uri, $mimeType, file_get_contents($readResult->getPathname()), $meta)];
|
||||
}
|
||||
|
||||
return [BlobResourceContents::fromSplFileInfo($uri, $readResult, $mimeType)];
|
||||
return [BlobResourceContents::fromSplFileInfo($uri, $readResult, $mimeType, $meta)];
|
||||
}
|
||||
|
||||
if (\is_array($readResult)) {
|
||||
|
|
@ -159,7 +162,7 @@ class ResourceReference extends ElementReference
|
|||
try {
|
||||
$jsonString = json_encode($readResult, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT);
|
||||
|
||||
return [new TextResourceContents($uri, $mimeType, $jsonString)];
|
||||
return [new TextResourceContents($uri, $mimeType, $jsonString, $meta)];
|
||||
} catch (\JsonException $e) {
|
||||
throw new RuntimeException(\sprintf('Failed to encode array as JSON for URI "%s": %s', $uri, $e->getMessage()));
|
||||
}
|
||||
|
|
@ -169,7 +172,7 @@ class ResourceReference extends ElementReference
|
|||
$jsonString = json_encode($readResult, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT);
|
||||
$mimeType = $mimeType ?? 'application/json';
|
||||
|
||||
return [new TextResourceContents($uri, $mimeType, $jsonString)];
|
||||
return [new TextResourceContents($uri, $mimeType, $jsonString, $meta)];
|
||||
} catch (\JsonException $e) {
|
||||
throw new RuntimeException(\sprintf('Failed to encode array as JSON for URI "%s": %s', $uri, $e->getMessage()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,9 +101,11 @@ class ResourceTemplateReference extends ElementReference
|
|||
return [$readResult->resource];
|
||||
}
|
||||
|
||||
$meta = $this->resourceTemplate->meta;
|
||||
|
||||
if (\is_array($readResult)) {
|
||||
if (empty($readResult)) {
|
||||
return [new TextResourceContents($uri, 'application/json', '[]')];
|
||||
return [new TextResourceContents($uri, 'application/json', '[]', $meta)];
|
||||
}
|
||||
|
||||
$allAreResourceContents = true;
|
||||
|
|
@ -151,14 +153,15 @@ class ResourceTemplateReference extends ElementReference
|
|||
if (\is_string($readResult)) {
|
||||
$mimeType = $mimeType ?? $this->guessMimeTypeFromString($readResult);
|
||||
|
||||
return [new TextResourceContents($uri, $mimeType, $readResult)];
|
||||
return [new TextResourceContents($uri, $mimeType, $readResult, $meta)];
|
||||
}
|
||||
|
||||
if (\is_resource($readResult) && 'stream' === get_resource_type($readResult)) {
|
||||
$result = BlobResourceContents::fromStream(
|
||||
$uri,
|
||||
$readResult,
|
||||
$mimeType ?? 'application/octet-stream'
|
||||
$mimeType ?? 'application/octet-stream',
|
||||
$meta
|
||||
);
|
||||
|
||||
@fclose($readResult);
|
||||
|
|
@ -169,21 +172,21 @@ class ResourceTemplateReference extends ElementReference
|
|||
if (\is_array($readResult) && isset($readResult['blob']) && \is_string($readResult['blob'])) {
|
||||
$mimeType = $readResult['mimeType'] ?? $mimeType ?? 'application/octet-stream';
|
||||
|
||||
return [new BlobResourceContents($uri, $mimeType, $readResult['blob'])];
|
||||
return [new BlobResourceContents($uri, $mimeType, $readResult['blob'], $meta)];
|
||||
}
|
||||
|
||||
if (\is_array($readResult) && isset($readResult['text']) && \is_string($readResult['text'])) {
|
||||
$mimeType = $readResult['mimeType'] ?? $mimeType ?? 'text/plain';
|
||||
|
||||
return [new TextResourceContents($uri, $mimeType, $readResult['text'])];
|
||||
return [new TextResourceContents($uri, $mimeType, $readResult['text'], $meta)];
|
||||
}
|
||||
|
||||
if ($readResult instanceof \SplFileInfo && $readResult->isFile() && $readResult->isReadable()) {
|
||||
if ($mimeType && str_contains(strtolower($mimeType), 'text')) {
|
||||
return [new TextResourceContents($uri, $mimeType, file_get_contents($readResult->getPathname()))];
|
||||
return [new TextResourceContents($uri, $mimeType, file_get_contents($readResult->getPathname()), $meta)];
|
||||
}
|
||||
|
||||
return [BlobResourceContents::fromSplFileInfo($uri, $readResult, $mimeType)];
|
||||
return [BlobResourceContents::fromSplFileInfo($uri, $readResult, $mimeType, $meta)];
|
||||
}
|
||||
|
||||
if (\is_array($readResult)) {
|
||||
|
|
@ -192,7 +195,7 @@ class ResourceTemplateReference extends ElementReference
|
|||
try {
|
||||
$jsonString = json_encode($readResult, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT);
|
||||
|
||||
return [new TextResourceContents($uri, $mimeType, $jsonString)];
|
||||
return [new TextResourceContents($uri, $mimeType, $jsonString, $meta)];
|
||||
} catch (\JsonException $e) {
|
||||
throw new RuntimeException("Failed to encode array as JSON for URI '{$uri}': {$e->getMessage()}");
|
||||
}
|
||||
|
|
@ -202,7 +205,7 @@ class ResourceTemplateReference extends ElementReference
|
|||
$jsonString = json_encode($readResult, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT);
|
||||
$mimeType = $mimeType ?? 'application/json';
|
||||
|
||||
return [new TextResourceContents($uri, $mimeType, $jsonString)];
|
||||
return [new TextResourceContents($uri, $mimeType, $jsonString, $meta)];
|
||||
} catch (\JsonException $e) {
|
||||
throw new RuntimeException("Failed to encode array as JSON for URI '{$uri}': {$e->getMessage()}");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue