Roll out meta properties in attributes and more schema classes (#129)
This commit is contained in:
parent
09596c0382
commit
d3a07912b0
16 changed files with 178 additions and 88 deletions
|
|
@ -21,12 +21,14 @@ namespace Mcp\Capability\Attribute;
|
||||||
final class McpPrompt
|
final class McpPrompt
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param ?string $name overrides the prompt name (defaults to method name)
|
* @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 $description Optional description of the prompt. Defaults to method DocBlock summary.
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public ?string $name = null,
|
public ?string $name = null,
|
||||||
public ?string $description = null,
|
public ?string $description = null,
|
||||||
|
public ?array $meta = null,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,13 @@ use Mcp\Schema\Annotations;
|
||||||
final class McpResource
|
final class McpResource
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $uri The specific URI identifying this resource instance. Must be unique within the server.
|
* @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 $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 $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 ?string $mimeType the MIME type, if known and constant for this resource
|
||||||
* @param ?int $size the size in bytes, if known and constant
|
* @param ?int $size the size in bytes, if known and constant
|
||||||
* @param Annotations|null $annotations optional annotations describing the resource
|
* @param Annotations|null $annotations optional annotations describing the resource
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string $uri,
|
public string $uri,
|
||||||
|
|
@ -37,6 +38,7 @@ final class McpResource
|
||||||
public ?string $mimeType = null,
|
public ?string $mimeType = null,
|
||||||
public ?int $size = null,
|
public ?int $size = null,
|
||||||
public ?Annotations $annotations = null,
|
public ?Annotations $annotations = null,
|
||||||
|
public ?array $meta = null,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,12 @@ use Mcp\Schema\Annotations;
|
||||||
final class McpResourceTemplate
|
final class McpResourceTemplate
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $uriTemplate the URI template string (RFC 6570)
|
* @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 $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 $description Optional description. Defaults to class DocBlock summary.
|
||||||
* @param ?string $mimeType optional default MIME type for matching resources
|
* @param ?string $mimeType optional default MIME type for matching resources
|
||||||
* @param ?Annotations $annotations optional annotations describing the resource template
|
* @param ?Annotations $annotations optional annotations describing the resource template
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string $uriTemplate,
|
public string $uriTemplate,
|
||||||
|
|
@ -35,6 +36,7 @@ final class McpResourceTemplate
|
||||||
public ?string $description = null,
|
public ?string $description = null,
|
||||||
public ?string $mimeType = null,
|
public ?string $mimeType = null,
|
||||||
public ?Annotations $annotations = null,
|
public ?Annotations $annotations = null,
|
||||||
|
public ?array $meta = null,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,16 @@ use Mcp\Schema\ToolAnnotations;
|
||||||
class McpTool
|
class McpTool
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string|null $name The name of the tool (defaults to the method name)
|
* @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 string|null $description The description of the tool (defaults to the DocBlock/inferred)
|
||||||
* @param ToolAnnotations|null $annotations Optional annotations describing tool behavior
|
* @param ToolAnnotations|null $annotations Optional annotations describing tool behavior
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public ?string $name = null,
|
public ?string $name = null,
|
||||||
public ?string $description = null,
|
public ?string $description = null,
|
||||||
public ?ToolAnnotations $annotations = null,
|
public ?ToolAnnotations $annotations = null,
|
||||||
|
public ?array $meta = null,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,8 @@ class Discoverer
|
||||||
$name = $instance->name ?? ('__invoke' === $methodName ? $classShortName : $methodName);
|
$name = $instance->name ?? ('__invoke' === $methodName ? $classShortName : $methodName);
|
||||||
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
|
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
|
||||||
$inputSchema = $this->schemaGenerator->generate($method);
|
$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);
|
$tools[$name] = new ToolReference($tool, [$className, $methodName], false);
|
||||||
++$discoveredCount['tools'];
|
++$discoveredCount['tools'];
|
||||||
break;
|
break;
|
||||||
|
|
@ -234,8 +235,10 @@ class Discoverer
|
||||||
$mimeType = $instance->mimeType;
|
$mimeType = $instance->mimeType;
|
||||||
$size = $instance->size;
|
$size = $instance->size;
|
||||||
$annotations = $instance->annotations;
|
$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);
|
$resources[$instance->uri] = new ResourceReference($resource, [$className, $methodName], false);
|
||||||
|
|
||||||
++$discoveredCount['resources'];
|
++$discoveredCount['resources'];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -253,7 +256,8 @@ class Discoverer
|
||||||
$paramTag = $paramTags['$'.$param->getName()] ?? null;
|
$paramTag = $paramTags['$'.$param->getName()] ?? null;
|
||||||
$arguments[] = new PromptArgument($param->getName(), $paramTag ? trim((string) $paramTag->getDescription()) : null, !$param->isOptional() && !$param->isDefaultValueAvailable());
|
$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);
|
$completionProviders = $this->getCompletionProviders($method);
|
||||||
$prompts[$name] = new PromptReference($prompt, [$className, $methodName], false, $completionProviders);
|
$prompts[$name] = new PromptReference($prompt, [$className, $methodName], false, $completionProviders);
|
||||||
++$discoveredCount['prompts'];
|
++$discoveredCount['prompts'];
|
||||||
|
|
@ -265,7 +269,8 @@ class Discoverer
|
||||||
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
|
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
|
||||||
$mimeType = $instance->mimeType;
|
$mimeType = $instance->mimeType;
|
||||||
$annotations = $instance->annotations;
|
$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);
|
$completionProviders = $this->getCompletionProviders($method);
|
||||||
$resourceTemplates[$instance->uriTemplate] = new ResourceTemplateReference($resourceTemplate, [$className, $methodName], false, $completionProviders);
|
$resourceTemplates[$instance->uriTemplate] = new ResourceTemplateReference($resourceTemplate, [$className, $methodName], false, $completionProviders);
|
||||||
++$discoveredCount['resourceTemplates'];
|
++$discoveredCount['resourceTemplates'];
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ final class ArrayLoader implements LoaderInterface
|
||||||
* name: ?string,
|
* name: ?string,
|
||||||
* description: ?string,
|
* description: ?string,
|
||||||
* annotations: ?ToolAnnotations,
|
* annotations: ?ToolAnnotations,
|
||||||
|
* meta: ?array<string, mixed>
|
||||||
* }[] $tools
|
* }[] $tools
|
||||||
* @param array{
|
* @param array{
|
||||||
* handler: Handler,
|
* handler: Handler,
|
||||||
|
|
@ -54,6 +55,7 @@ final class ArrayLoader implements LoaderInterface
|
||||||
* mimeType: ?string,
|
* mimeType: ?string,
|
||||||
* size: int|null,
|
* size: int|null,
|
||||||
* annotations: ?Annotations,
|
* annotations: ?Annotations,
|
||||||
|
* meta: ?array<string, mixed>
|
||||||
* }[] $resources
|
* }[] $resources
|
||||||
* @param array{
|
* @param array{
|
||||||
* handler: Handler,
|
* handler: Handler,
|
||||||
|
|
@ -62,11 +64,13 @@ final class ArrayLoader implements LoaderInterface
|
||||||
* description: ?string,
|
* description: ?string,
|
||||||
* mimeType: ?string,
|
* mimeType: ?string,
|
||||||
* annotations: ?Annotations,
|
* annotations: ?Annotations,
|
||||||
|
* meta: ?array<string, mixed>
|
||||||
* }[] $resourceTemplates
|
* }[] $resourceTemplates
|
||||||
* @param array{
|
* @param array{
|
||||||
* handler: Handler,
|
* handler: Handler,
|
||||||
* name: ?string,
|
* name: ?string,
|
||||||
* description: ?string,
|
* description: ?string,
|
||||||
|
* meta: ?array<string, mixed>
|
||||||
* }[] $prompts
|
* }[] $prompts
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
|
@ -102,7 +106,7 @@ final class ArrayLoader implements LoaderInterface
|
||||||
|
|
||||||
$inputSchema = $data['inputSchema'] ?? $schemaGenerator->generate($reflection);
|
$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);
|
$registry->registerTool($tool, $data['handler'], true);
|
||||||
|
|
||||||
$handlerDesc = $this->getHandlerDescription($data['handler']);
|
$handlerDesc = $this->getHandlerDescription($data['handler']);
|
||||||
|
|
@ -137,8 +141,9 @@ final class ArrayLoader implements LoaderInterface
|
||||||
$mimeType = $data['mimeType'];
|
$mimeType = $data['mimeType'];
|
||||||
$size = $data['size'];
|
$size = $data['size'];
|
||||||
$annotations = $data['annotations'];
|
$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);
|
$registry->registerResource($resource, $data['handler'], true);
|
||||||
|
|
||||||
$handlerDesc = $this->getHandlerDescription($data['handler']);
|
$handlerDesc = $this->getHandlerDescription($data['handler']);
|
||||||
|
|
@ -172,8 +177,9 @@ final class ArrayLoader implements LoaderInterface
|
||||||
$uriTemplate = $data['uriTemplate'];
|
$uriTemplate = $data['uriTemplate'];
|
||||||
$mimeType = $data['mimeType'];
|
$mimeType = $data['mimeType'];
|
||||||
$annotations = $data['annotations'];
|
$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);
|
$completionProviders = $this->getCompletionProviders($reflection);
|
||||||
$registry->registerResourceTemplate($template, $data['handler'], $completionProviders, true);
|
$registry->registerResourceTemplate($template, $data['handler'], $completionProviders, true);
|
||||||
|
|
||||||
|
|
@ -224,8 +230,8 @@ final class ArrayLoader implements LoaderInterface
|
||||||
!$param->isOptional() && !$param->isDefaultValueAvailable(),
|
!$param->isOptional() && !$param->isDefaultValueAvailable(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
$meta = $data['meta'];
|
||||||
$prompt = new Prompt($name, $description, $arguments);
|
$prompt = new Prompt($name, $description, $arguments, $meta);
|
||||||
$completionProviders = $this->getCompletionProviders($reflection);
|
$completionProviders = $this->getCompletionProviders($reflection);
|
||||||
$registry->registerPrompt($prompt, $data['handler'], $completionProviders, true);
|
$registry->registerPrompt($prompt, $data['handler'], $completionProviders, true);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,11 @@ class ResourceReference extends ElementReference
|
||||||
return [$readResult->resource];
|
return [$readResult->resource];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$meta = $this->schema->meta;
|
||||||
|
|
||||||
if (\is_array($readResult)) {
|
if (\is_array($readResult)) {
|
||||||
if (empty($readResult)) {
|
if (empty($readResult)) {
|
||||||
return [new TextResourceContents($uri, 'application/json', '[]')];
|
return [new TextResourceContents($uri, 'application/json', '[]', $meta)];
|
||||||
}
|
}
|
||||||
|
|
||||||
$allAreResourceContents = true;
|
$allAreResourceContents = true;
|
||||||
|
|
@ -118,14 +120,15 @@ class ResourceReference extends ElementReference
|
||||||
if (\is_string($readResult)) {
|
if (\is_string($readResult)) {
|
||||||
$mimeType = $mimeType ?? $this->guessMimeTypeFromString($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)) {
|
if (\is_resource($readResult) && 'stream' === get_resource_type($readResult)) {
|
||||||
$result = BlobResourceContents::fromStream(
|
$result = BlobResourceContents::fromStream(
|
||||||
$uri,
|
$uri,
|
||||||
$readResult,
|
$readResult,
|
||||||
$mimeType ?? 'application/octet-stream'
|
$mimeType ?? 'application/octet-stream',
|
||||||
|
$meta
|
||||||
);
|
);
|
||||||
|
|
||||||
@fclose($readResult);
|
@fclose($readResult);
|
||||||
|
|
@ -136,21 +139,21 @@ class ResourceReference extends ElementReference
|
||||||
if (\is_array($readResult) && isset($readResult['blob']) && \is_string($readResult['blob'])) {
|
if (\is_array($readResult) && isset($readResult['blob']) && \is_string($readResult['blob'])) {
|
||||||
$mimeType = $readResult['mimeType'] ?? $mimeType ?? 'application/octet-stream';
|
$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'])) {
|
if (\is_array($readResult) && isset($readResult['text']) && \is_string($readResult['text'])) {
|
||||||
$mimeType = $readResult['mimeType'] ?? $mimeType ?? 'text/plain';
|
$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 ($readResult instanceof \SplFileInfo && $readResult->isFile() && $readResult->isReadable()) {
|
||||||
if ($mimeType && str_contains(strtolower($mimeType), 'text')) {
|
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)) {
|
if (\is_array($readResult)) {
|
||||||
|
|
@ -159,7 +162,7 @@ class ResourceReference extends ElementReference
|
||||||
try {
|
try {
|
||||||
$jsonString = json_encode($readResult, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT);
|
$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) {
|
} catch (\JsonException $e) {
|
||||||
throw new RuntimeException(\sprintf('Failed to encode array as JSON for URI "%s": %s', $uri, $e->getMessage()));
|
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);
|
$jsonString = json_encode($readResult, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT);
|
||||||
$mimeType = $mimeType ?? 'application/json';
|
$mimeType = $mimeType ?? 'application/json';
|
||||||
|
|
||||||
return [new TextResourceContents($uri, $mimeType, $jsonString)];
|
return [new TextResourceContents($uri, $mimeType, $jsonString, $meta)];
|
||||||
} catch (\JsonException $e) {
|
} catch (\JsonException $e) {
|
||||||
throw new RuntimeException(\sprintf('Failed to encode array as JSON for URI "%s": %s', $uri, $e->getMessage()));
|
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];
|
return [$readResult->resource];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$meta = $this->resourceTemplate->meta;
|
||||||
|
|
||||||
if (\is_array($readResult)) {
|
if (\is_array($readResult)) {
|
||||||
if (empty($readResult)) {
|
if (empty($readResult)) {
|
||||||
return [new TextResourceContents($uri, 'application/json', '[]')];
|
return [new TextResourceContents($uri, 'application/json', '[]', $meta)];
|
||||||
}
|
}
|
||||||
|
|
||||||
$allAreResourceContents = true;
|
$allAreResourceContents = true;
|
||||||
|
|
@ -151,14 +153,15 @@ class ResourceTemplateReference extends ElementReference
|
||||||
if (\is_string($readResult)) {
|
if (\is_string($readResult)) {
|
||||||
$mimeType = $mimeType ?? $this->guessMimeTypeFromString($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)) {
|
if (\is_resource($readResult) && 'stream' === get_resource_type($readResult)) {
|
||||||
$result = BlobResourceContents::fromStream(
|
$result = BlobResourceContents::fromStream(
|
||||||
$uri,
|
$uri,
|
||||||
$readResult,
|
$readResult,
|
||||||
$mimeType ?? 'application/octet-stream'
|
$mimeType ?? 'application/octet-stream',
|
||||||
|
$meta
|
||||||
);
|
);
|
||||||
|
|
||||||
@fclose($readResult);
|
@fclose($readResult);
|
||||||
|
|
@ -169,21 +172,21 @@ class ResourceTemplateReference extends ElementReference
|
||||||
if (\is_array($readResult) && isset($readResult['blob']) && \is_string($readResult['blob'])) {
|
if (\is_array($readResult) && isset($readResult['blob']) && \is_string($readResult['blob'])) {
|
||||||
$mimeType = $readResult['mimeType'] ?? $mimeType ?? 'application/octet-stream';
|
$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'])) {
|
if (\is_array($readResult) && isset($readResult['text']) && \is_string($readResult['text'])) {
|
||||||
$mimeType = $readResult['mimeType'] ?? $mimeType ?? 'text/plain';
|
$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 ($readResult instanceof \SplFileInfo && $readResult->isFile() && $readResult->isReadable()) {
|
||||||
if ($mimeType && str_contains(strtolower($mimeType), 'text')) {
|
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)) {
|
if (\is_array($readResult)) {
|
||||||
|
|
@ -192,7 +195,7 @@ class ResourceTemplateReference extends ElementReference
|
||||||
try {
|
try {
|
||||||
$jsonString = json_encode($readResult, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT);
|
$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) {
|
} catch (\JsonException $e) {
|
||||||
throw new RuntimeException("Failed to encode array as JSON for URI '{$uri}': {$e->getMessage()}");
|
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);
|
$jsonString = json_encode($readResult, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT);
|
||||||
$mimeType = $mimeType ?? 'application/json';
|
$mimeType = $mimeType ?? 'application/json';
|
||||||
|
|
||||||
return [new TextResourceContents($uri, $mimeType, $jsonString)];
|
return [new TextResourceContents($uri, $mimeType, $jsonString, $meta)];
|
||||||
} catch (\JsonException $e) {
|
} catch (\JsonException $e) {
|
||||||
throw new RuntimeException("Failed to encode array as JSON for URI '{$uri}': {$e->getMessage()}");
|
throw new RuntimeException("Failed to encode array as JSON for URI '{$uri}': {$e->getMessage()}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ use Mcp\Exception\InvalidArgumentException;
|
||||||
* @phpstan-type BlobResourceContentsData array{
|
* @phpstan-type BlobResourceContentsData array{
|
||||||
* uri: string,
|
* uri: string,
|
||||||
* mimeType?: string|null,
|
* mimeType?: string|null,
|
||||||
* blob: string
|
* blob: string,
|
||||||
|
* _meta?: array<string, mixed>
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
||||||
|
|
@ -27,16 +28,18 @@ use Mcp\Exception\InvalidArgumentException;
|
||||||
class BlobResourceContents extends ResourceContents
|
class BlobResourceContents extends ResourceContents
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $uri the URI of the resource or sub-resource
|
* @param string $uri the URI of the resource or sub-resource
|
||||||
* @param string|null $mimeType the MIME type of the resource or sub-resource
|
* @param string|null $mimeType the MIME type of the resource or sub-resource
|
||||||
* @param string $blob a base64-encoded string representing the binary data of the item
|
* @param string $blob a base64-encoded string representing the binary data of the item
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
string $uri,
|
string $uri,
|
||||||
?string $mimeType,
|
?string $mimeType,
|
||||||
public readonly string $blob,
|
public readonly string $blob,
|
||||||
|
?array $meta = null,
|
||||||
) {
|
) {
|
||||||
parent::__construct($uri, $mimeType);
|
parent::__construct($uri, $mimeType, $meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -51,25 +54,29 @@ class BlobResourceContents extends ResourceContents
|
||||||
throw new InvalidArgumentException('Missing or invalid "blob" for BlobResourceContents.');
|
throw new InvalidArgumentException('Missing or invalid "blob" for BlobResourceContents.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return new self($data['uri'], $data['mimeType'] ?? null, $data['blob']);
|
return new self($data['uri'], $data['mimeType'] ?? null, $data['blob'], $data['_meta'] ?? null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param resource $stream
|
* @param resource $stream
|
||||||
*/
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
public static function fromStream(string $uri, $stream, string $mimeType): self
|
* */
|
||||||
|
public static function fromStream(string $uri, $stream, string $mimeType, ?array $meta = null): self
|
||||||
{
|
{
|
||||||
$blob = stream_get_contents($stream);
|
$blob = stream_get_contents($stream);
|
||||||
|
|
||||||
return new self($uri, $mimeType, base64_encode($blob));
|
return new self($uri, $mimeType, base64_encode($blob), $meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromSplFileInfo(string $uri, \SplFileInfo $file, ?string $explicitMimeType = null): self
|
/**
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
|
* */
|
||||||
|
public static function fromSplFileInfo(string $uri, \SplFileInfo $file, ?string $explicitMimeType = null, ?array $meta = null): self
|
||||||
{
|
{
|
||||||
$mimeType = $explicitMimeType ?? mime_content_type($file->getPathname());
|
$mimeType = $explicitMimeType ?? mime_content_type($file->getPathname());
|
||||||
$blob = file_get_contents($file->getPathname());
|
$blob = file_get_contents($file->getPathname());
|
||||||
|
|
||||||
return new self($uri, $mimeType, base64_encode($blob));
|
return new self($uri, $mimeType, base64_encode($blob), $meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -79,7 +86,7 @@ class BlobResourceContents extends ResourceContents
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'blob' => $this->blob,
|
'blob' => $this->blob,
|
||||||
...$this->jsonSerialize(),
|
...parent::jsonSerialize(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ namespace Mcp\Schema\Content;
|
||||||
*
|
*
|
||||||
* @phpstan-type ResourceContentsData = array{
|
* @phpstan-type ResourceContentsData = array{
|
||||||
* uri: string,
|
* uri: string,
|
||||||
* mimeType?: string|null
|
* mimeType?: string|null,
|
||||||
|
* _meta?: array<string, mixed>
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
||||||
|
|
@ -24,12 +25,14 @@ namespace Mcp\Schema\Content;
|
||||||
abstract class ResourceContents implements \JsonSerializable
|
abstract class ResourceContents implements \JsonSerializable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $uri the URI of the resource or sub-resource
|
* @param string $uri the URI of the resource or sub-resource
|
||||||
* @param string|null $mimeType the MIME type of the resource or sub-resource
|
* @param string|null $mimeType the MIME type of the resource or sub-resource
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public readonly string $uri,
|
public readonly string $uri,
|
||||||
public readonly ?string $mimeType = null,
|
public readonly ?string $mimeType = null,
|
||||||
|
public readonly ?array $meta = null,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,6 +46,10 @@ abstract class ResourceContents implements \JsonSerializable
|
||||||
$data['mimeType'] = $this->mimeType;
|
$data['mimeType'] = $this->mimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null !== $this->meta) {
|
||||||
|
$data['_meta'] = $this->meta;
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ use Mcp\Exception\InvalidArgumentException;
|
||||||
* @phpstan-type TextResourceContentsData array{
|
* @phpstan-type TextResourceContentsData array{
|
||||||
* uri: string,
|
* uri: string,
|
||||||
* mimeType?: string|null,
|
* mimeType?: string|null,
|
||||||
* text: string
|
* text: string,
|
||||||
|
* _meta?: array<string, mixed>
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
||||||
|
|
@ -27,16 +28,18 @@ use Mcp\Exception\InvalidArgumentException;
|
||||||
class TextResourceContents extends ResourceContents
|
class TextResourceContents extends ResourceContents
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $uri the URI of the resource or sub-resource
|
* @param string $uri the URI of the resource or sub-resource
|
||||||
* @param string|null $mimeType the MIME type of the resource or sub-resource
|
* @param string|null $mimeType the MIME type of the resource or sub-resource
|
||||||
* @param string $text The text of the item. This must only be set if the item can actually be represented as text (not binary data).
|
* @param string $text The text of the item. This must only be set if the item can actually be represented as text (not binary data).
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
string $uri,
|
string $uri,
|
||||||
?string $mimeType,
|
?string $mimeType,
|
||||||
public readonly string $text,
|
public readonly string $text,
|
||||||
|
?array $meta = null,
|
||||||
) {
|
) {
|
||||||
parent::__construct($uri, $mimeType);
|
parent::__construct($uri, $mimeType, $meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -51,7 +54,7 @@ class TextResourceContents extends ResourceContents
|
||||||
throw new InvalidArgumentException('Missing or invalid "text" for TextResourceContents.');
|
throw new InvalidArgumentException('Missing or invalid "text" for TextResourceContents.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return new self($data['uri'], $data['mimeType'] ?? null, $data['text']);
|
return new self($data['uri'], $data['mimeType'] ?? null, $data['text'], $data['_meta'] ?? null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ use Mcp\Exception\InvalidArgumentException;
|
||||||
* name: string,
|
* name: string,
|
||||||
* description?: string,
|
* description?: string,
|
||||||
* arguments?: PromptArgumentData[],
|
* arguments?: PromptArgumentData[],
|
||||||
|
* _meta?: array<string, mixed>
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
||||||
|
|
@ -32,11 +33,13 @@ class Prompt implements \JsonSerializable
|
||||||
* @param string $name the name of the prompt or prompt template
|
* @param string $name the name of the prompt or prompt template
|
||||||
* @param string|null $description an optional description of what this prompt provides
|
* @param string|null $description an optional description of what this prompt provides
|
||||||
* @param PromptArgument[]|null $arguments A list of arguments for templating. Null if not a template.
|
* @param PromptArgument[]|null $arguments A list of arguments for templating. Null if not a template.
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public readonly string $name,
|
public readonly string $name,
|
||||||
public readonly ?string $description = null,
|
public readonly ?string $description = null,
|
||||||
public readonly ?array $arguments = null,
|
public readonly ?array $arguments = null,
|
||||||
|
public readonly ?array $meta = null,
|
||||||
) {
|
) {
|
||||||
if (null !== $this->arguments) {
|
if (null !== $this->arguments) {
|
||||||
foreach ($this->arguments as $arg) {
|
foreach ($this->arguments as $arg) {
|
||||||
|
|
@ -60,10 +63,15 @@ class Prompt implements \JsonSerializable
|
||||||
$arguments = array_map(fn (array $argData) => PromptArgument::fromArray($argData), $data['arguments']);
|
$arguments = array_map(fn (array $argData) => PromptArgument::fromArray($argData), $data['arguments']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($data['_meta']) && !\is_array($data['_meta'])) {
|
||||||
|
throw new InvalidArgumentException('Invalid "_meta" in Prompt data.');
|
||||||
|
}
|
||||||
|
|
||||||
return new self(
|
return new self(
|
||||||
name: $data['name'],
|
name: $data['name'],
|
||||||
description: $data['description'] ?? null,
|
description: $data['description'] ?? null,
|
||||||
arguments: $arguments
|
arguments: $arguments,
|
||||||
|
meta: isset($data['_meta']) ? $data['_meta'] : null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,7 +79,8 @@ class Prompt implements \JsonSerializable
|
||||||
* @return array{
|
* @return array{
|
||||||
* name: string,
|
* name: string,
|
||||||
* description?: string,
|
* description?: string,
|
||||||
* arguments?: array<PromptArgument>
|
* arguments?: array<PromptArgument>,
|
||||||
|
* _meta?: array<string, mixed>
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
|
|
@ -83,6 +92,9 @@ class Prompt implements \JsonSerializable
|
||||||
if (null !== $this->arguments) {
|
if (null !== $this->arguments) {
|
||||||
$data['arguments'] = $this->arguments;
|
$data['arguments'] = $this->arguments;
|
||||||
}
|
}
|
||||||
|
if (null !== $this->meta) {
|
||||||
|
$data['_meta'] = $this->meta;
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ use Mcp\Exception\InvalidArgumentException;
|
||||||
* mimeType?: string|null,
|
* mimeType?: string|null,
|
||||||
* annotations?: AnnotationsData|null,
|
* annotations?: AnnotationsData|null,
|
||||||
* size?: int|null,
|
* size?: int|null,
|
||||||
|
* _meta?: array<string, mixed>
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
||||||
|
|
@ -43,14 +44,15 @@ class Resource implements \JsonSerializable
|
||||||
private const URI_PATTERN = '/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^\s]*$/';
|
private const URI_PATTERN = '/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^\s]*$/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $uri the URI of this resource
|
* @param string $uri the URI of this resource
|
||||||
* @param string $name A human-readable name for this resource. This can be used by clients to populate UI elements.
|
* @param string $name A human-readable name for this resource. This can be used by clients to populate UI elements.
|
||||||
* @param string|null $description A description of what this resource represents. This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
|
* @param string|null $description A description of what this resource represents. This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
|
||||||
* @param string|null $mimeType the MIME type of this resource, if known
|
* @param string|null $mimeType the MIME type of this resource, if known
|
||||||
* @param Annotations|null $annotations optional annotations for the client
|
* @param Annotations|null $annotations optional annotations for the client
|
||||||
* @param int|null $size The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.
|
* @param int|null $size The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
*
|
*
|
||||||
* This can be used by Hosts to display file sizes and estimate context window usage.
|
* This can be used by Hosts to display file sizes and estimate context window usage
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public readonly string $uri,
|
public readonly string $uri,
|
||||||
|
|
@ -59,6 +61,7 @@ class Resource implements \JsonSerializable
|
||||||
public readonly ?string $mimeType = null,
|
public readonly ?string $mimeType = null,
|
||||||
public readonly ?Annotations $annotations = null,
|
public readonly ?Annotations $annotations = null,
|
||||||
public readonly ?int $size = null,
|
public readonly ?int $size = null,
|
||||||
|
public readonly ?array $meta = null,
|
||||||
) {
|
) {
|
||||||
if (!preg_match(self::RESOURCE_NAME_PATTERN, $name)) {
|
if (!preg_match(self::RESOURCE_NAME_PATTERN, $name)) {
|
||||||
throw new InvalidArgumentException('Invalid resource name: must contain only alphanumeric characters, underscores, and hyphens.');
|
throw new InvalidArgumentException('Invalid resource name: must contain only alphanumeric characters, underscores, and hyphens.');
|
||||||
|
|
@ -80,13 +83,18 @@ class Resource implements \JsonSerializable
|
||||||
throw new InvalidArgumentException('Invalid or missing "name" in Resource data.');
|
throw new InvalidArgumentException('Invalid or missing "name" in Resource data.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($data['_meta']) && !\is_array($data['_meta'])) {
|
||||||
|
throw new InvalidArgumentException('Invalid "_meta" in Resource data.');
|
||||||
|
}
|
||||||
|
|
||||||
return new self(
|
return new self(
|
||||||
uri: $data['uri'],
|
uri: $data['uri'],
|
||||||
name: $data['name'],
|
name: $data['name'],
|
||||||
description: $data['description'] ?? null,
|
description: $data['description'] ?? null,
|
||||||
mimeType: $data['mimeType'] ?? null,
|
mimeType: $data['mimeType'] ?? null,
|
||||||
annotations: isset($data['annotations']) ? Annotations::fromArray($data['annotations']) : null,
|
annotations: isset($data['annotations']) ? Annotations::fromArray($data['annotations']) : null,
|
||||||
size: isset($data['size']) ? (int) $data['size'] : null
|
size: isset($data['size']) ? (int) $data['size'] : null,
|
||||||
|
meta: isset($data['_meta']) ? $data['_meta'] : null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,6 +106,7 @@ class Resource implements \JsonSerializable
|
||||||
* mimeType?: string,
|
* mimeType?: string,
|
||||||
* annotations?: Annotations,
|
* annotations?: Annotations,
|
||||||
* size?: int,
|
* size?: int,
|
||||||
|
* _meta?: array<string, mixed>
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
|
|
@ -118,6 +127,9 @@ class Resource implements \JsonSerializable
|
||||||
if (null !== $this->size) {
|
if (null !== $this->size) {
|
||||||
$data['size'] = $this->size;
|
$data['size'] = $this->size;
|
||||||
}
|
}
|
||||||
|
if (null !== $this->meta) {
|
||||||
|
$data['_meta'] = $this->meta;
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ use Mcp\Exception\InvalidArgumentException;
|
||||||
* description?: string|null,
|
* description?: string|null,
|
||||||
* mimeType?: string|null,
|
* mimeType?: string|null,
|
||||||
* annotations?: AnnotationsData|null,
|
* annotations?: AnnotationsData|null,
|
||||||
|
* _meta?: array<string, mixed>
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
||||||
|
|
@ -42,11 +43,12 @@ class ResourceTemplate implements \JsonSerializable
|
||||||
private const URI_TEMPLATE_PATTERN = '/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/.*{[^{}]+}.*/';
|
private const URI_TEMPLATE_PATTERN = '/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/.*{[^{}]+}.*/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $uriTemplate a URI template (according to RFC 6570) that can be used to construct resource URIs
|
* @param string $uriTemplate a URI template (according to RFC 6570) that can be used to construct resource URIs
|
||||||
* @param string $name A human-readable name for the type of resource this template refers to. This can be used by clients to populate UI elements.
|
* @param string $name A human-readable name for the type of resource this template refers to. This can be used by clients to populate UI elements.
|
||||||
* @param string|null $description This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
|
* @param string|null $description This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model.
|
||||||
* @param string|null $mimeType The MIME type for all resources that match this template. This should only be included if all resources matching this template have the same type.
|
* @param string|null $mimeType The MIME type for all resources that match this template. This should only be included if all resources matching this template have the same type.
|
||||||
* @param Annotations|null $annotations optional annotations for the client
|
* @param Annotations|null $annotations optional annotations for the client
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public readonly string $uriTemplate,
|
public readonly string $uriTemplate,
|
||||||
|
|
@ -54,6 +56,7 @@ class ResourceTemplate implements \JsonSerializable
|
||||||
public readonly ?string $description = null,
|
public readonly ?string $description = null,
|
||||||
public readonly ?string $mimeType = null,
|
public readonly ?string $mimeType = null,
|
||||||
public readonly ?Annotations $annotations = null,
|
public readonly ?Annotations $annotations = null,
|
||||||
|
public readonly ?array $meta = null,
|
||||||
) {
|
) {
|
||||||
if (!preg_match(self::RESOURCE_NAME_PATTERN, $name)) {
|
if (!preg_match(self::RESOURCE_NAME_PATTERN, $name)) {
|
||||||
throw new InvalidArgumentException('Invalid resource name: must contain only alphanumeric characters, underscores, and hyphens.');
|
throw new InvalidArgumentException('Invalid resource name: must contain only alphanumeric characters, underscores, and hyphens.');
|
||||||
|
|
@ -75,12 +78,17 @@ class ResourceTemplate implements \JsonSerializable
|
||||||
throw new InvalidArgumentException('Invalid or missing "name" in ResourceTemplate data.');
|
throw new InvalidArgumentException('Invalid or missing "name" in ResourceTemplate data.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($data['_meta']) && !\is_array($data['_meta'])) {
|
||||||
|
throw new InvalidArgumentException('Invalid "_meta" in ResourceTemplate data.');
|
||||||
|
}
|
||||||
|
|
||||||
return new self(
|
return new self(
|
||||||
uriTemplate: $data['uriTemplate'],
|
uriTemplate: $data['uriTemplate'],
|
||||||
name: $data['name'],
|
name: $data['name'],
|
||||||
description: $data['description'] ?? null,
|
description: $data['description'] ?? null,
|
||||||
mimeType: $data['mimeType'] ?? null,
|
mimeType: $data['mimeType'] ?? null,
|
||||||
annotations: isset($data['annotations']) ? Annotations::fromArray($data['annotations']) : null
|
annotations: isset($data['annotations']) ? Annotations::fromArray($data['annotations']) : null,
|
||||||
|
meta: isset($data['_meta']) ? $data['_meta'] : null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,6 +99,7 @@ class ResourceTemplate implements \JsonSerializable
|
||||||
* description?: string,
|
* description?: string,
|
||||||
* mimeType?: string,
|
* mimeType?: string,
|
||||||
* annotations?: Annotations,
|
* annotations?: Annotations,
|
||||||
|
* _meta?: array<string, mixed>
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
|
|
@ -108,6 +117,9 @@ class ResourceTemplate implements \JsonSerializable
|
||||||
if (null !== $this->annotations) {
|
if (null !== $this->annotations) {
|
||||||
$data['annotations'] = $this->annotations;
|
$data['annotations'] = $this->annotations;
|
||||||
}
|
}
|
||||||
|
if (null !== $this->meta) {
|
||||||
|
$data['_meta'] = $this->meta;
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ use Mcp\Exception\InvalidArgumentException;
|
||||||
* inputSchema: ToolInputSchema,
|
* inputSchema: ToolInputSchema,
|
||||||
* description?: string|null,
|
* description?: string|null,
|
||||||
* annotations?: ToolAnnotationsData,
|
* annotations?: ToolAnnotationsData,
|
||||||
|
* _meta?: array<string, mixed>
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
|
||||||
|
|
@ -35,18 +36,20 @@ use Mcp\Exception\InvalidArgumentException;
|
||||||
class Tool implements \JsonSerializable
|
class Tool implements \JsonSerializable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $name the name of the tool
|
* @param string $name the name of the tool
|
||||||
* @param string|null $description A human-readable description of the tool.
|
* @param string|null $description A human-readable description of the tool.
|
||||||
* This can be used by clients to improve the LLM's understanding of
|
* This can be used by clients to improve the LLM's understanding of
|
||||||
* available tools. It can be thought of like a "hint" to the model.
|
* available tools. It can be thought of like a "hint" to the model.
|
||||||
* @param ToolInputSchema $inputSchema a JSON Schema object (as a PHP array) defining the expected 'arguments' for the tool
|
* @param ToolInputSchema $inputSchema a JSON Schema object (as a PHP array) defining the expected 'arguments' for the tool
|
||||||
* @param ToolAnnotations|null $annotations optional additional tool information
|
* @param ToolAnnotations|null $annotations optional additional tool information
|
||||||
|
* @param ?array<string, mixed> $meta Optional metadata
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public readonly string $name,
|
public readonly string $name,
|
||||||
public readonly array $inputSchema,
|
public readonly array $inputSchema,
|
||||||
public readonly ?string $description,
|
public readonly ?string $description,
|
||||||
public readonly ?ToolAnnotations $annotations,
|
public readonly ?ToolAnnotations $annotations,
|
||||||
|
public readonly ?array $meta = null,
|
||||||
) {
|
) {
|
||||||
if (!isset($inputSchema['type']) || 'object' !== $inputSchema['type']) {
|
if (!isset($inputSchema['type']) || 'object' !== $inputSchema['type']) {
|
||||||
throw new InvalidArgumentException('Tool inputSchema must be a JSON Schema of type "object".');
|
throw new InvalidArgumentException('Tool inputSchema must be a JSON Schema of type "object".');
|
||||||
|
|
@ -75,7 +78,8 @@ class Tool implements \JsonSerializable
|
||||||
$data['name'],
|
$data['name'],
|
||||||
$data['inputSchema'],
|
$data['inputSchema'],
|
||||||
isset($data['description']) && \is_string($data['description']) ? $data['description'] : null,
|
isset($data['description']) && \is_string($data['description']) ? $data['description'] : null,
|
||||||
isset($data['annotations']) && \is_array($data['annotations']) ? ToolAnnotations::fromArray($data['annotations']) : null
|
isset($data['annotations']) && \is_array($data['annotations']) ? ToolAnnotations::fromArray($data['annotations']) : null,
|
||||||
|
isset($data['_meta']) && \is_array($data['_meta']) ? $data['_meta'] : null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,6 +89,7 @@ class Tool implements \JsonSerializable
|
||||||
* inputSchema: ToolInputSchema,
|
* inputSchema: ToolInputSchema,
|
||||||
* description?: string,
|
* description?: string,
|
||||||
* annotations?: ToolAnnotations,
|
* annotations?: ToolAnnotations,
|
||||||
|
* _meta?: array<string, mixed>
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
|
|
@ -99,6 +104,9 @@ class Tool implements \JsonSerializable
|
||||||
if (null !== $this->annotations) {
|
if (null !== $this->annotations) {
|
||||||
$data['annotations'] = $this->annotations;
|
$data['annotations'] = $this->annotations;
|
||||||
}
|
}
|
||||||
|
if (null !== $this->meta) {
|
||||||
|
$data['_meta'] = $this->meta;
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ final class Builder
|
||||||
* name: ?string,
|
* name: ?string,
|
||||||
* description: ?string,
|
* description: ?string,
|
||||||
* annotations: ?ToolAnnotations,
|
* annotations: ?ToolAnnotations,
|
||||||
|
* meta: ?array<string, mixed>
|
||||||
* }[]
|
* }[]
|
||||||
*/
|
*/
|
||||||
private array $tools = [];
|
private array $tools = [];
|
||||||
|
|
@ -95,6 +96,7 @@ final class Builder
|
||||||
* mimeType: ?string,
|
* mimeType: ?string,
|
||||||
* size: int|null,
|
* size: int|null,
|
||||||
* annotations: ?Annotations,
|
* annotations: ?Annotations,
|
||||||
|
* meta: ?array<string, mixed>
|
||||||
* }[]
|
* }[]
|
||||||
*/
|
*/
|
||||||
private array $resources = [];
|
private array $resources = [];
|
||||||
|
|
@ -107,6 +109,7 @@ final class Builder
|
||||||
* description: ?string,
|
* description: ?string,
|
||||||
* mimeType: ?string,
|
* mimeType: ?string,
|
||||||
* annotations: ?Annotations,
|
* annotations: ?Annotations,
|
||||||
|
* meta: ?array<string, mixed>
|
||||||
* }[]
|
* }[]
|
||||||
*/
|
*/
|
||||||
private array $resourceTemplates = [];
|
private array $resourceTemplates = [];
|
||||||
|
|
@ -116,6 +119,7 @@ final class Builder
|
||||||
* handler: Handler,
|
* handler: Handler,
|
||||||
* name: ?string,
|
* name: ?string,
|
||||||
* description: ?string,
|
* description: ?string,
|
||||||
|
* meta: ?array<string, mixed>
|
||||||
* }[]
|
* }[]
|
||||||
*/
|
*/
|
||||||
private array $prompts = [];
|
private array $prompts = [];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue