Skip to content

Commit 7cd281d

Browse files
authored
Rework registry to combine provider and registry interface, move capabilities out and enable Registry injection in Builder (#150)
1 parent 7a58ab3 commit 7cd281d

22 files changed

+567
-736
lines changed

src/Capability/Registry.php

Lines changed: 66 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313

1414
use Mcp\Capability\Discovery\DiscoveryState;
1515
use Mcp\Capability\Registry\PromptReference;
16-
use Mcp\Capability\Registry\ReferenceProviderInterface;
17-
use Mcp\Capability\Registry\ReferenceRegistryInterface;
1816
use Mcp\Capability\Registry\ResourceReference;
1917
use Mcp\Capability\Registry\ResourceTemplateReference;
2018
use Mcp\Capability\Registry\ToolReference;
@@ -31,21 +29,17 @@
3129
use Mcp\Schema\Prompt;
3230
use Mcp\Schema\Resource;
3331
use Mcp\Schema\ResourceTemplate;
34-
use Mcp\Schema\ServerCapabilities;
3532
use Mcp\Schema\Tool;
3633
use Psr\EventDispatcher\EventDispatcherInterface;
3734
use Psr\Log\LoggerInterface;
3835
use Psr\Log\NullLogger;
3936

4037
/**
4138
* Registry implementation that manages MCP element registration and access.
42-
* Implements both ReferenceProvider (for access) and ReferenceRegistry (for registration)
43-
* following the Interface Segregation Principle.
4439
*
4540
* @author Kyrian Obikwelu <koshnawaza@gmail.com>
46-
* @author Pavel Buchnev <butschster@gmail.com>
4741
*/
48-
final class Registry implements ReferenceProviderInterface, ReferenceRegistryInterface
42+
final class Registry implements RegistryInterface
4943
{
5044
/**
5145
* @var array<string, ToolReference>
@@ -67,34 +61,13 @@ final class Registry implements ReferenceProviderInterface, ReferenceRegistryInt
6761
*/
6862
private array $resourceTemplates = [];
6963

70-
private ServerCapabilities $serverCapabilities;
71-
7264
public function __construct(
7365
private readonly ?EventDispatcherInterface $eventDispatcher = null,
7466
private readonly LoggerInterface $logger = new NullLogger(),
7567
private readonly NameValidator $nameValidator = new NameValidator(),
7668
) {
7769
}
7870

79-
public function getCapabilities(): ServerCapabilities
80-
{
81-
if (!$this->hasElements()) {
82-
$this->logger->info('No capabilities registered on server.');
83-
}
84-
85-
return $this->serverCapabilities ?? new ServerCapabilities(
86-
tools: [] !== $this->tools,
87-
toolsListChanged: $this->eventDispatcher instanceof EventDispatcherInterface,
88-
resources: [] !== $this->resources || [] !== $this->resourceTemplates,
89-
resourcesSubscribe: false,
90-
resourcesListChanged: $this->eventDispatcher instanceof EventDispatcherInterface,
91-
prompts: [] !== $this->prompts,
92-
promptsListChanged: $this->eventDispatcher instanceof EventDispatcherInterface,
93-
logging: false,
94-
completions: true,
95-
);
96-
}
97-
9871
public function registerTool(Tool $tool, callable|array|string $handler, bool $isManual = false): void
9972
{
10073
$toolName = $tool->name;
@@ -220,41 +193,9 @@ public function clear(): void
220193
}
221194
}
222195

223-
public function getTool(string $name): ToolReference
224-
{
225-
return $this->tools[$name] ?? throw new ToolNotFoundException($name);
226-
}
227-
228-
public function getResource(
229-
string $uri,
230-
bool $includeTemplates = true,
231-
): ResourceReference|ResourceTemplateReference {
232-
$registration = $this->resources[$uri] ?? null;
233-
if ($registration) {
234-
return $registration;
235-
}
236-
237-
if ($includeTemplates) {
238-
foreach ($this->resourceTemplates as $template) {
239-
if ($template->matches($uri)) {
240-
return $template;
241-
}
242-
}
243-
}
244-
245-
$this->logger->debug('No resource matched URI.', ['uri' => $uri]);
246-
247-
throw new ResourceNotFoundException($uri);
248-
}
249-
250-
public function getResourceTemplate(string $uriTemplate): ResourceTemplateReference
196+
public function hasTools(): bool
251197
{
252-
return $this->resourceTemplates[$uriTemplate] ?? throw new ResourceNotFoundException($uriTemplate);
253-
}
254-
255-
public function getPrompt(string $name): PromptReference
256-
{
257-
return $this->prompts[$name] ?? throw new PromptNotFoundException($name);
198+
return [] !== $this->tools;
258199
}
259200

260201
public function getTools(?int $limit = null, ?string $cursor = null): Page
@@ -279,6 +220,16 @@ public function getTools(?int $limit = null, ?string $cursor = null): Page
279220
return new Page($paginatedTools, $nextCursor);
280221
}
281222

223+
public function getTool(string $name): ToolReference
224+
{
225+
return $this->tools[$name] ?? throw new ToolNotFoundException($name);
226+
}
227+
228+
public function hasResources(): bool
229+
{
230+
return [] !== $this->resources;
231+
}
232+
282233
public function getResources(?int $limit = null, ?string $cursor = null): Page
283234
{
284235
$resources = [];
@@ -301,26 +252,31 @@ public function getResources(?int $limit = null, ?string $cursor = null): Page
301252
return new Page($paginatedResources, $nextCursor);
302253
}
303254

304-
public function getPrompts(?int $limit = null, ?string $cursor = null): Page
305-
{
306-
$prompts = [];
307-
foreach ($this->prompts as $promptReference) {
308-
$prompts[$promptReference->prompt->name] = $promptReference->prompt;
255+
public function getResource(
256+
string $uri,
257+
bool $includeTemplates = true,
258+
): ResourceReference|ResourceTemplateReference {
259+
$registration = $this->resources[$uri] ?? null;
260+
if ($registration) {
261+
return $registration;
309262
}
310263

311-
if (null === $limit) {
312-
return new Page($prompts, null);
264+
if ($includeTemplates) {
265+
foreach ($this->resourceTemplates as $template) {
266+
if ($template->matches($uri)) {
267+
return $template;
268+
}
269+
}
313270
}
314271

315-
$paginatedPrompts = $this->paginateResults($prompts, $limit, $cursor);
272+
$this->logger->debug('No resource matched URI.', ['uri' => $uri]);
316273

317-
$nextCursor = $this->calculateNextCursor(
318-
\count($prompts),
319-
$cursor,
320-
$limit
321-
);
274+
throw new ResourceNotFoundException($uri);
275+
}
322276

323-
return new Page($paginatedPrompts, $nextCursor);
277+
public function hasResourceTemplates(): bool
278+
{
279+
return [] !== $this->resourceTemplates;
324280
}
325281

326282
public function getResourceTemplates(?int $limit = null, ?string $cursor = null): Page
@@ -345,12 +301,41 @@ public function getResourceTemplates(?int $limit = null, ?string $cursor = null)
345301
return new Page($paginatedTemplates, $nextCursor);
346302
}
347303

348-
public function hasElements(): bool
304+
public function getResourceTemplate(string $uriTemplate): ResourceTemplateReference
349305
{
350-
return !empty($this->tools)
351-
|| !empty($this->resources)
352-
|| !empty($this->prompts)
353-
|| !empty($this->resourceTemplates);
306+
return $this->resourceTemplates[$uriTemplate] ?? throw new ResourceNotFoundException($uriTemplate);
307+
}
308+
309+
public function hasPrompts(): bool
310+
{
311+
return [] !== $this->prompts;
312+
}
313+
314+
public function getPrompts(?int $limit = null, ?string $cursor = null): Page
315+
{
316+
$prompts = [];
317+
foreach ($this->prompts as $promptReference) {
318+
$prompts[$promptReference->prompt->name] = $promptReference->prompt;
319+
}
320+
321+
if (null === $limit) {
322+
return new Page($prompts, null);
323+
}
324+
325+
$paginatedPrompts = $this->paginateResults($prompts, $limit, $cursor);
326+
327+
$nextCursor = $this->calculateNextCursor(
328+
\count($prompts),
329+
$cursor,
330+
$limit
331+
);
332+
333+
return new Page($paginatedPrompts, $nextCursor);
334+
}
335+
336+
public function getPrompt(string $name): PromptReference
337+
{
338+
return $this->prompts[$name] ?? throw new PromptNotFoundException($name);
354339
}
355340

356341
/**
@@ -464,9 +449,4 @@ private function paginateResults(array $items, int $limit, ?string $cursor = nul
464449

465450
return array_values(\array_slice($items, $offset, $limit));
466451
}
467-
468-
public function setServerCapabilities(ServerCapabilities $serverCapabilities): void
469-
{
470-
$this->serverCapabilities = $serverCapabilities;
471-
}
472452
}

src/Capability/Registry/Loader/ArrayLoader.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
use Mcp\Capability\Discovery\HandlerResolver;
2020
use Mcp\Capability\Discovery\SchemaGenerator;
2121
use Mcp\Capability\Registry\ElementReference;
22-
use Mcp\Capability\Registry\ReferenceRegistryInterface;
22+
use Mcp\Capability\RegistryInterface;
2323
use Mcp\Exception\ConfigurationException;
2424
use Mcp\Schema\Annotations;
2525
use Mcp\Schema\Icon;
@@ -86,7 +86,7 @@ public function __construct(
8686
) {
8787
}
8888

89-
public function load(ReferenceRegistryInterface $registry): void
89+
public function load(RegistryInterface $registry): void
9090
{
9191
$docBlockParser = new DocBlockParser(logger: $this->logger);
9292
$schemaGenerator = new SchemaGenerator($docBlockParser);

src/Capability/Registry/Loader/DiscoveryLoader.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
use Mcp\Capability\Discovery\CachedDiscoverer;
1515
use Mcp\Capability\Discovery\Discoverer;
16-
use Mcp\Capability\Registry\ReferenceRegistryInterface;
16+
use Mcp\Capability\RegistryInterface;
1717
use Psr\Log\LoggerInterface;
1818
use Psr\SimpleCache\CacheInterface;
1919

@@ -35,7 +35,7 @@ public function __construct(
3535
) {
3636
}
3737

38-
public function load(ReferenceRegistryInterface $registry): void
38+
public function load(RegistryInterface $registry): void
3939
{
4040
// This now encapsulates the discovery process
4141
$discoverer = new Discoverer($this->logger);

src/Capability/Registry/Loader/LoaderInterface.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111

1212
namespace Mcp\Capability\Registry\Loader;
1313

14-
use Mcp\Capability\Registry\ReferenceRegistryInterface;
14+
use Mcp\Capability\RegistryInterface;
1515

1616
/**
1717
* @author Antoine Bluchet <soyuka@gmail.com>
1818
*/
1919
interface LoaderInterface
2020
{
21-
public function load(ReferenceRegistryInterface $registry): void;
21+
public function load(RegistryInterface $registry): void;
2222
}

src/Capability/Registry/ReferenceHandlerInterface.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
namespace Mcp\Capability\Registry;
1313

14+
use Mcp\Exception\InvalidArgumentException;
15+
use Mcp\Exception\RegistryException;
16+
1417
/**
1518
* Interface for handling execution of MCP elements.
1619
* Allows custom implementations of element execution logic.
@@ -27,8 +30,8 @@ interface ReferenceHandlerInterface
2730
*
2831
* @return mixed the result of the element execution
2932
*
30-
* @throws \Mcp\Exception\InvalidArgumentException if the handler is invalid
31-
* @throws \Mcp\Exception\RegistryException if execution fails
33+
* @throws InvalidArgumentException if the handler is invalid
34+
* @throws RegistryException if execution fails
3235
*/
3336
public function handle(ElementReference $reference, array $arguments): mixed;
3437
}

src/Capability/Registry/ReferenceProviderInterface.php

Lines changed: 0 additions & 79 deletions
This file was deleted.

0 commit comments

Comments
 (0)