Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/mcp-elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ class Calculator
- **`name`** (optional): Tool identifier. Defaults to method name if not provided.
- **`description`** (optional): Tool description. Defaults to docblock summary if not provided, otherwise uses method name.
- **`annotations`** (optional): `ToolAnnotations` object for additional metadata.
- **`icons`** (optional): Array of `Icon` objects for visual representation.
- **`meta`** (optional): Arbitrary key-value pairs for custom metadata.

**Priority for name/description**: Attribute parameters → DocBlock content → Method name

Expand Down Expand Up @@ -217,6 +219,9 @@ class ConfigProvider
- **`description`** (optional): Resource description. Defaults to docblock summary if not provided.
- **`mimeType`** (optional): MIME type of the resource content.
- **`size`** (optional): Size in bytes if known.
- **`annotations`** (optional): Additional metadata.
- **`icons`** (optional): Array of `Icon` objects for visual representation.
- **`meta`** (optional): Arbitrary key-value pairs for custom metadata.

**Standard Protocol URI Schemes**: `https://` (web resources), `file://` (filesystem), `git://` (version control).
**Custom schemes**: `config://`, `data://`, `db://`, `api://` or any RFC 3986 compliant scheme.
Expand Down Expand Up @@ -399,6 +404,8 @@ class PromptGenerator

- **`name`** (optional): Prompt identifier. Defaults to method name if not provided.
- **`description`** (optional): Prompt description. Defaults to docblock summary if not provided.
- **`icons`** (optional): Array of `Icon` objects for visual representation.
- **`meta`** (optional): Arbitrary key-value pairs for custom metadata.

### Prompt Return Values

Expand Down
51 changes: 50 additions & 1 deletion docs/server-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,25 @@ final `Server` instance ready for use.
Set the server's identity with name, version, and optional description:

```php
use Mcp\Schema\Icon;
use Mcp\Server;

$server = Server::builder()
->setServerInfo('Calculator Server', '1.2.0', 'Advanced mathematical calculations');
->setServerInfo(
name: 'Calculator Server',
version: '1.2.0',
description: 'Advanced mathematical calculations',
icons: [new Icon('https://example.com/icon.png', 'image/png', ['64x64'])],
websiteUrl: 'https://example.com'
');
```

**Parameters:**
- `$name` (string): The server name
- `$version` (string): Version string (semantic versioning recommended)
- `$description` (string|null): Optional description
- `$icons` (Icon[]|null): Optional array of server icons
- `$websiteUrl` (string|null): Optional server website URL

### Pagination Limit

Expand Down Expand Up @@ -263,6 +274,16 @@ $server = Server::builder()
);
```

#### Parameters

- `handler` (callable|string): The tool handler
- `name` (string|null): Optional tool name
- `description` (string|null): Optional tool description
- `annotations` (ToolAnnotations|null): Optional annotations for the tool
- `inputSchema` (array|null): Optional input schema for the tool
- `icons` (Icon[]|null): Optional array of icons for the tool
- `meta` (array|null): Optional metadata for the tool

### Manual Resource Registration

Register static resources:
Expand All @@ -278,6 +299,18 @@ $server = Server::builder()
);
```

#### Parameters

- `handler` (callable|string): The resource handler
- `uri` (string): The resource URI
- `name` (string|null): Optional resource name
- `description` (string|null): Optional resource description
- `mimeType` (string|null): Optional MIME type of the resource
- `size` (int|null): Optional size of the resource in bytes
- `annotations` (Annotations|null): Optional annotations for the resource
- `icons` (Icon[]|null): Optional array of icons for the resource
- `meta` (array|null): Optional metadata for the resource

### Manual Resource Template Registration

Register dynamic resources with URI templates:
Expand All @@ -293,6 +326,15 @@ $server = Server::builder()
);
```

#### Parameters

- `handler` (callable|string): The resource template handler
- `uriTemplate` (string): The resource URI template
- `name` (string|null): Optional resource template name
- `description` (string|null): Optional resource template description
- `mimeType` (string|null): Optional MIME type of the resource
- `annotations` (Annotations|null): Optional annotations for the resource template

### Manual Prompt Registration

Register prompt generators:
Expand All @@ -306,6 +348,13 @@ $server = Server::builder()
);
```

#### Parameters

- `handler` (callable|string): The prompt handler
- `name` (string|null): Optional prompt name
- `description` (string|null): Optional prompt description
- `icons` (Icon[]|null): Optional array of icons for the prompt

**Note:** `name` and `description` are optional for all manual registrations. If not provided, they will be derived from
the handler's method name and docblock.

Expand Down
7 changes: 6 additions & 1 deletion examples/discovery-calculator/McpElements.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Mcp\Capability\Attribute\McpResource;
use Mcp\Capability\Attribute\McpTool;
use Mcp\Exception\ToolCallException;
use Mcp\Schema\Icon;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;

Expand Down Expand Up @@ -47,7 +48,10 @@ public function __construct(
*
* @return float the result of the calculation
*/
#[McpTool(name: 'calculate')]
#[McpTool(
name: 'calculate',
icons: [new Icon('https://www.svgrepo.com/show/530644/calculator.svg', 'image/svg+xml', ['any'])],
)]
public function calculate(float $a, float $b, string $operation): float
{
$this->logger->info(\sprintf('Calculating: %f %s %f', $a, $operation, $b));
Expand Down Expand Up @@ -92,6 +96,7 @@ public function calculate(float $a, float $b, string $operation): float
name: 'calculator_config',
description: 'Current settings for the calculator tool (precision, allow_negative).',
mimeType: 'application/json',
icons: [new Icon('https://www.svgrepo.com/show/529867/settings.svg', 'image/svg+xml', ['any'])],
)]
public function getConfiguration(): array
{
Expand Down
4 changes: 4 additions & 0 deletions src/Capability/Attribute/McpPrompt.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Mcp\Capability\Attribute;

use Mcp\Schema\Icon;

/**
* Marks a PHP method as an MCP Prompt generator.
* The method should return the prompt messages, potentially using arguments for templating.
Expand All @@ -23,11 +25,13 @@ 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 ?Icon[] $icons Optional list of icon URLs representing the prompt
* @param ?array<string, mixed> $meta Optional metadata
*/
public function __construct(
public ?string $name = null,
public ?string $description = null,
public ?array $icons = null,
public ?array $meta = null,
) {
}
Expand Down
3 changes: 3 additions & 0 deletions src/Capability/Attribute/McpResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Mcp\Capability\Attribute;

use Mcp\Schema\Annotations;
use Mcp\Schema\Icon;

/**
* Marks a PHP class as representing or handling a specific MCP Resource instance.
Expand All @@ -29,6 +30,7 @@ final class McpResource
* @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 ?Icon[] $icons Optional list of icon URLs representing the resource
* @param ?array<string, mixed> $meta Optional metadata
*/
public function __construct(
Expand All @@ -38,6 +40,7 @@ public function __construct(
public ?string $mimeType = null,
public ?int $size = null,
public ?Annotations $annotations = null,
public ?array $icons = null,
public ?array $meta = null,
) {
}
Expand Down
3 changes: 3 additions & 0 deletions src/Capability/Attribute/McpTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Mcp\Capability\Attribute;

use Mcp\Schema\Icon;
use Mcp\Schema\ToolAnnotations;

/**
Expand All @@ -23,12 +24,14 @@ 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 ?Icon[] $icons Optional list of icon URLs representing the tool
* @param ?array<string, mixed> $meta Optional metadata
*/
public function __construct(
public ?string $name = null,
public ?string $description = null,
public ?ToolAnnotations $annotations = null,
public ?array $icons = null,
public ?array $meta = null,
) {
}
Expand Down
28 changes: 19 additions & 9 deletions src/Capability/Discovery/Discoverer.php
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,14 @@ private function processMethod(\ReflectionMethod $method, array &$discoveredCoun
$name = $instance->name ?? ('__invoke' === $methodName ? $classShortName : $methodName);
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
$inputSchema = $this->schemaGenerator->generate($method);
$meta = $instance->meta ?? null;
$tool = new Tool($name, $inputSchema, $description, $instance->annotations, meta: $meta);
$tool = new Tool(
$name,
$inputSchema,
$description,
$instance->annotations,
$instance->icons,
$instance->meta,
);
$tools[$name] = new ToolReference($tool, [$className, $methodName], false);
++$discoveredCount['tools'];
break;
Expand All @@ -232,11 +238,16 @@ private function processMethod(\ReflectionMethod $method, array &$discoveredCoun
$docBlock = $this->docBlockParser->parseDocBlock($method->getDocComment() ?? null);
$name = $instance->name ?? ('__invoke' === $methodName ? $classShortName : $methodName);
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
$mimeType = $instance->mimeType;
$size = $instance->size;
$annotations = $instance->annotations;
$meta = $instance->meta;
$resource = new Resource($instance->uri, $name, $description, $mimeType, $annotations, $size, $meta);
$resource = new Resource(
$instance->uri,
$name,
$description,
$instance->mimeType,
$instance->annotations,
$instance->size,
$instance->icons,
$instance->meta,
);
$resources[$instance->uri] = new ResourceReference($resource, [$className, $methodName], false);

++$discoveredCount['resources'];
Expand All @@ -256,8 +267,7 @@ private function processMethod(\ReflectionMethod $method, array &$discoveredCoun
$paramTag = $paramTags['$'.$param->getName()] ?? null;
$arguments[] = new PromptArgument($param->getName(), $paramTag ? trim((string) $paramTag->getDescription()) : null, !$param->isOptional() && !$param->isDefaultValueAvailable());
}
$meta = $instance->meta ?? null;
$prompt = new Prompt($name, $description, $arguments, $meta);
$prompt = new Prompt($name, $description, $arguments, $instance->icons, $instance->meta);
$completionProviders = $this->getCompletionProviders($method);
$prompts[$name] = new PromptReference($prompt, [$className, $methodName], false, $completionProviders);
++$discoveredCount['prompts'];
Expand Down
47 changes: 27 additions & 20 deletions src/Capability/Registry/Loader/ArrayLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Mcp\Capability\Registry\ReferenceRegistryInterface;
use Mcp\Exception\ConfigurationException;
use Mcp\Schema\Annotations;
use Mcp\Schema\Icon;
use Mcp\Schema\Prompt;
use Mcp\Schema\PromptArgument;
use Mcp\Schema\Resource;
Expand All @@ -45,7 +46,7 @@ final class ArrayLoader implements LoaderInterface
* name: ?string,
* description: ?string,
* annotations: ?ToolAnnotations,
* icons: ?array<int, \Mcp\Schema\Icon>,
* icons: ?Icon[],
* meta: ?array<string, mixed>
* }[] $tools
* @param array{
Expand All @@ -56,6 +57,7 @@ final class ArrayLoader implements LoaderInterface
* mimeType: ?string,
* size: int|null,
* annotations: ?Annotations,
* icons: ?Icon[],
* meta: ?array<string, mixed>
* }[] $resources
* @param array{
Expand All @@ -71,14 +73,15 @@ final class ArrayLoader implements LoaderInterface
* handler: Handler,
* name: ?string,
* description: ?string,
* icons: ?Icon[],
* meta: ?array<string, mixed>
* }[] $prompts
*/
public function __construct(
private array $tools = [],
private array $resources = [],
private array $resourceTemplates = [],
private array $prompts = [],
private readonly array $tools = [],
private readonly array $resources = [],
private readonly array $resourceTemplates = [],
private readonly array $prompts = [],
private LoggerInterface $logger = new NullLogger(),
) {
}
Expand Down Expand Up @@ -145,13 +148,16 @@ public function load(ReferenceRegistryInterface $registry): void
$description = $data['description'] ?? $docBlockParser->getSummary($docBlock) ?? null;
}

$uri = $data['uri'];
$mimeType = $data['mimeType'];
$size = $data['size'];
$annotations = $data['annotations'];
$meta = $data['meta'];

$resource = new Resource($uri, $name, $description, $mimeType, $annotations, $size, $meta);
$resource = new Resource(
$data['uri'],
$name,
$description,
$data['mimeType'],
$data['annotations'],
$data['size'],
$data['icons'],
$data['meta'],
);
$registry->registerResource($resource, $data['handler'], true);

$handlerDesc = $this->getHandlerDescription($data['handler']);
Expand Down Expand Up @@ -182,12 +188,14 @@ public function load(ReferenceRegistryInterface $registry): void
$description = $data['description'] ?? $docBlockParser->getSummary($docBlock) ?? null;
}

$uriTemplate = $data['uriTemplate'];
$mimeType = $data['mimeType'];
$annotations = $data['annotations'];
$meta = $data['meta'];

$template = new ResourceTemplate($uriTemplate, $name, $description, $mimeType, $annotations, $meta);
$template = new ResourceTemplate(
$data['uriTemplate'],
$name,
$description,
$data['mimeType'],
$data['annotations'],
$data['meta'],
);
$completionProviders = $this->getCompletionProviders($reflection);
$registry->registerResourceTemplate($template, $data['handler'], $completionProviders, true);

Expand Down Expand Up @@ -238,8 +246,7 @@ public function load(ReferenceRegistryInterface $registry): void
!$param->isOptional() && !$param->isDefaultValueAvailable(),
);
}
$meta = $data['meta'];
$prompt = new Prompt($name, $description, $arguments, $meta);
$prompt = new Prompt($name, $description, $arguments, $data['icons'], $data['meta']);
$completionProviders = $this->getCompletionProviders($reflection);
$registry->registerPrompt($prompt, $data['handler'], $completionProviders, true);

Expand Down
Loading