Skip to content

Commit 4cf59a8

Browse files
committed
Add support for icons on explicit builder registration and attributes
1 parent 5804ba9 commit 4cf59a8

File tree

6 files changed

+90
-34
lines changed

6 files changed

+90
-34
lines changed

src/Capability/Attribute/McpPrompt.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Mcp\Capability\Attribute;
1313

14+
use Mcp\Schema\Icon;
15+
1416
/**
1517
* Marks a PHP method as an MCP Prompt generator.
1618
* The method should return the prompt messages, potentially using arguments for templating.
@@ -23,11 +25,13 @@ final class McpPrompt
2325
/**
2426
* @param ?string $name overrides the prompt name (defaults to method name)
2527
* @param ?string $description Optional description of the prompt. Defaults to method DocBlock summary.
28+
* @param ?Icon[] $icons Optional list of icon URLs representing the prompt
2629
* @param ?array<string, mixed> $meta Optional metadata
2730
*/
2831
public function __construct(
2932
public ?string $name = null,
3033
public ?string $description = null,
34+
public ?array $icons = null,
3135
public ?array $meta = null,
3236
) {
3337
}

src/Capability/Attribute/McpResource.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Mcp\Capability\Attribute;
1313

1414
use Mcp\Schema\Annotations;
15+
use Mcp\Schema\Icon;
1516

1617
/**
1718
* Marks a PHP class as representing or handling a specific MCP Resource instance.
@@ -29,6 +30,7 @@ final class McpResource
2930
* @param ?string $mimeType the MIME type, if known and constant for this resource
3031
* @param ?int $size the size in bytes, if known and constant
3132
* @param Annotations|null $annotations optional annotations describing the resource
33+
* @param ?Icon[] $icons Optional list of icon URLs representing the prompt
3234
* @param ?array<string, mixed> $meta Optional metadata
3335
*/
3436
public function __construct(
@@ -38,6 +40,7 @@ public function __construct(
3840
public ?string $mimeType = null,
3941
public ?int $size = null,
4042
public ?Annotations $annotations = null,
43+
public ?array $icons = null,
4144
public ?array $meta = null,
4245
) {
4346
}

src/Capability/Attribute/McpTool.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Mcp\Capability\Attribute;
1313

14+
use Mcp\Schema\Icon;
1415
use Mcp\Schema\ToolAnnotations;
1516

1617
/**
@@ -23,12 +24,14 @@ class McpTool
2324
* @param string|null $name The name of the tool (defaults to the method name)
2425
* @param string|null $description The description of the tool (defaults to the DocBlock/inferred)
2526
* @param ToolAnnotations|null $annotations Optional annotations describing tool behavior
27+
* @param ?Icon[] $icons Optional list of icon URLs representing the prompt
2628
* @param ?array<string, mixed> $meta Optional metadata
2729
*/
2830
public function __construct(
2931
public ?string $name = null,
3032
public ?string $description = null,
3133
public ?ToolAnnotations $annotations = null,
34+
public ?array $icons = null,
3235
public ?array $meta = null,
3336
) {
3437
}

src/Capability/Discovery/Discoverer.php

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,14 @@ private function processMethod(\ReflectionMethod $method, array &$discoveredCoun
222222
$name = $instance->name ?? ('__invoke' === $methodName ? $classShortName : $methodName);
223223
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
224224
$inputSchema = $this->schemaGenerator->generate($method);
225-
$meta = $instance->meta ?? null;
226-
$tool = new Tool($name, $inputSchema, $description, $instance->annotations, $meta);
225+
$tool = new Tool(
226+
$name,
227+
$inputSchema,
228+
$description,
229+
$instance->annotations,
230+
$instance->icons,
231+
$instance->meta,
232+
);
227233
$tools[$name] = new ToolReference($tool, [$className, $methodName], false);
228234
++$discoveredCount['tools'];
229235
break;
@@ -232,11 +238,16 @@ private function processMethod(\ReflectionMethod $method, array &$discoveredCoun
232238
$docBlock = $this->docBlockParser->parseDocBlock($method->getDocComment() ?? null);
233239
$name = $instance->name ?? ('__invoke' === $methodName ? $classShortName : $methodName);
234240
$description = $instance->description ?? $this->docBlockParser->getSummary($docBlock) ?? null;
235-
$mimeType = $instance->mimeType;
236-
$size = $instance->size;
237-
$annotations = $instance->annotations;
238-
$meta = $instance->meta;
239-
$resource = new Resource($instance->uri, $name, $description, $mimeType, $annotations, $size, $meta);
241+
$resource = new Resource(
242+
$instance->uri,
243+
$name,
244+
$description,
245+
$instance->mimeType,
246+
$instance->annotations,
247+
$instance->size,
248+
$instance->icons,
249+
$instance->meta,
250+
);
240251
$resources[$instance->uri] = new ResourceReference($resource, [$className, $methodName], false);
241252

242253
++$discoveredCount['resources'];
@@ -256,8 +267,7 @@ private function processMethod(\ReflectionMethod $method, array &$discoveredCoun
256267
$paramTag = $paramTags['$'.$param->getName()] ?? null;
257268
$arguments[] = new PromptArgument($param->getName(), $paramTag ? trim((string) $paramTag->getDescription()) : null, !$param->isOptional() && !$param->isDefaultValueAvailable());
258269
}
259-
$meta = $instance->meta ?? null;
260-
$prompt = new Prompt($name, $description, $arguments, $meta);
270+
$prompt = new Prompt($name, $description, $arguments, $instance->icons, $instance->meta);
261271
$completionProviders = $this->getCompletionProviders($method);
262272
$prompts[$name] = new PromptReference($prompt, [$className, $methodName], false, $completionProviders);
263273
++$discoveredCount['prompts'];

src/Capability/Registry/Loader/ArrayLoader.php

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Mcp\Capability\Registry\ReferenceRegistryInterface;
2323
use Mcp\Exception\ConfigurationException;
2424
use Mcp\Schema\Annotations;
25+
use Mcp\Schema\Icon;
2526
use Mcp\Schema\Prompt;
2627
use Mcp\Schema\PromptArgument;
2728
use Mcp\Schema\Resource;
@@ -45,6 +46,7 @@ final class ArrayLoader implements LoaderInterface
4546
* name: ?string,
4647
* description: ?string,
4748
* annotations: ?ToolAnnotations,
49+
* icons: ?Icon[],
4850
* meta: ?array<string, mixed>
4951
* }[] $tools
5052
* @param array{
@@ -55,6 +57,7 @@ final class ArrayLoader implements LoaderInterface
5557
* mimeType: ?string,
5658
* size: int|null,
5759
* annotations: ?Annotations,
60+
* icons: ?Icon[],
5861
* meta: ?array<string, mixed>
5962
* }[] $resources
6063
* @param array{
@@ -70,14 +73,15 @@ final class ArrayLoader implements LoaderInterface
7073
* handler: Handler,
7174
* name: ?string,
7275
* description: ?string,
76+
* icons: ?Icon[],
7377
* meta: ?array<string, mixed>
7478
* }[] $prompts
7579
*/
7680
public function __construct(
77-
private array $tools = [],
78-
private array $resources = [],
79-
private array $resourceTemplates = [],
80-
private array $prompts = [],
81+
private readonly array $tools = [],
82+
private readonly array $resources = [],
83+
private readonly array $resourceTemplates = [],
84+
private readonly array $prompts = [],
8185
private LoggerInterface $logger = new NullLogger(),
8286
) {
8387
}
@@ -106,7 +110,7 @@ public function load(ReferenceRegistryInterface $registry): void
106110

107111
$inputSchema = $data['inputSchema'] ?? $schemaGenerator->generate($reflection);
108112

109-
$tool = new Tool($name, $inputSchema, $description, $data['annotations'], $data['meta'] ?? null);
113+
$tool = new Tool($name, $inputSchema, $description, $data['annotations'], $data['icons'], $data['meta'] ?? null);
110114
$registry->registerTool($tool, $data['handler'], true);
111115

112116
$handlerDesc = $this->getHandlerDescription($data['handler']);
@@ -137,13 +141,16 @@ public function load(ReferenceRegistryInterface $registry): void
137141
$description = $data['description'] ?? $docBlockParser->getSummary($docBlock) ?? null;
138142
}
139143

140-
$uri = $data['uri'];
141-
$mimeType = $data['mimeType'];
142-
$size = $data['size'];
143-
$annotations = $data['annotations'];
144-
$meta = $data['meta'];
145-
146-
$resource = new Resource($uri, $name, $description, $mimeType, $annotations, $size, $meta);
144+
$resource = new Resource(
145+
$data['uri'],
146+
$name,
147+
$description,
148+
$data['mimeType'],
149+
$data['annotations'],
150+
$data['size'],
151+
$data['icons'],
152+
$data['meta'],
153+
);
147154
$registry->registerResource($resource, $data['handler'], true);
148155

149156
$handlerDesc = $this->getHandlerDescription($data['handler']);
@@ -174,12 +181,14 @@ public function load(ReferenceRegistryInterface $registry): void
174181
$description = $data['description'] ?? $docBlockParser->getSummary($docBlock) ?? null;
175182
}
176183

177-
$uriTemplate = $data['uriTemplate'];
178-
$mimeType = $data['mimeType'];
179-
$annotations = $data['annotations'];
180-
$meta = $data['meta'];
181-
182-
$template = new ResourceTemplate($uriTemplate, $name, $description, $mimeType, $annotations, $meta);
184+
$template = new ResourceTemplate(
185+
$data['uriTemplate'],
186+
$name,
187+
$description,
188+
$data['mimeType'],
189+
$data['annotations'],
190+
$data['meta'],
191+
);
183192
$completionProviders = $this->getCompletionProviders($reflection);
184193
$registry->registerResourceTemplate($template, $data['handler'], $completionProviders, true);
185194

@@ -230,8 +239,7 @@ public function load(ReferenceRegistryInterface $registry): void
230239
!$param->isOptional() && !$param->isDefaultValueAvailable(),
231240
);
232241
}
233-
$meta = $data['meta'];
234-
$prompt = new Prompt($name, $description, $arguments, $meta);
242+
$prompt = new Prompt($name, $description, $arguments, $data['icons'], $data['meta']);
235243
$completionProviders = $this->getCompletionProviders($reflection);
236244
$registry->registerPrompt($prompt, $data['handler'], $completionProviders, true);
237245

src/Server/Builder.php

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ final class Builder
8383
* name: ?string,
8484
* description: ?string,
8585
* annotations: ?ToolAnnotations,
86+
* icons: ?Icon[],
8687
* meta: ?array<string, mixed>
8788
* }[]
8889
*/
@@ -97,6 +98,7 @@ final class Builder
9798
* mimeType: ?string,
9899
* size: int|null,
99100
* annotations: ?Annotations,
101+
* icons: ?Icon[],
100102
* meta: ?array<string, mixed>
101103
* }[]
102104
*/
@@ -120,6 +122,7 @@ final class Builder
120122
* handler: Handler,
121123
* name: ?string,
122124
* description: ?string,
125+
* icons: ?Icon[],
123126
* meta: ?array<string, mixed>
124127
* }[]
125128
*/
@@ -315,15 +318,24 @@ public function setProtocolVersion(ProtocolVersion $protocolVersion): self
315318
*
316319
* @param Handler $handler
317320
* @param array<string, mixed>|null $inputSchema
321+
* @param ?Icon[] $icons
318322
*/
319323
public function addTool(
320324
callable|array|string $handler,
321325
?string $name = null,
322326
?string $description = null,
323327
?ToolAnnotations $annotations = null,
324328
?array $inputSchema = null,
329+
?array $icons = null,
325330
): self {
326-
$this->tools[] = compact('handler', 'name', 'description', 'annotations', 'inputSchema');
331+
$this->tools[] = compact(
332+
'handler',
333+
'name',
334+
'description',
335+
'annotations',
336+
'inputSchema',
337+
'icons',
338+
);
327339

328340
return $this;
329341
}
@@ -332,6 +344,7 @@ public function addTool(
332344
* Manually registers a resource handler.
333345
*
334346
* @param Handler $handler
347+
* @param ?Icon[] $icons
335348
*/
336349
public function addResource(
337350
\Closure|array|string $handler,
@@ -341,8 +354,18 @@ public function addResource(
341354
?string $mimeType = null,
342355
?int $size = null,
343356
?Annotations $annotations = null,
357+
?array $icons = null,
344358
): self {
345-
$this->resources[] = compact('handler', 'uri', 'name', 'description', 'mimeType', 'size', 'annotations');
359+
$this->resources[] = compact(
360+
'handler',
361+
'uri',
362+
'name',
363+
'description',
364+
'mimeType',
365+
'size',
366+
'annotations',
367+
'icons',
368+
);
346369

347370
return $this;
348371
}
@@ -376,10 +399,15 @@ public function addResourceTemplate(
376399
* Manually registers a prompt handler.
377400
*
378401
* @param Handler $handler
402+
* @param ?Icon[] $icons
379403
*/
380-
public function addPrompt(\Closure|array|string $handler, ?string $name = null, ?string $description = null): self
381-
{
382-
$this->prompts[] = compact('handler', 'name', 'description');
404+
public function addPrompt(
405+
\Closure|array|string $handler,
406+
?string $name = null,
407+
?string $description = null,
408+
?array $icons = null,
409+
): self {
410+
$this->prompts[] = compact('handler', 'name', 'description', 'icons');
383411

384412
return $this;
385413
}

0 commit comments

Comments
 (0)