|
11 | 11 |
|
12 | 12 | namespace Mcp\Capability; |
13 | 13 |
|
14 | | -use Mcp\Capability\Discovery\DiscoveryState; |
15 | 14 | use Mcp\Capability\Registry\PromptReference; |
16 | 15 | use Mcp\Capability\Registry\ResourceReference; |
17 | 16 | use Mcp\Capability\Registry\ResourceTemplateReference; |
@@ -68,129 +67,120 @@ public function __construct( |
68 | 67 | ) { |
69 | 68 | } |
70 | 69 |
|
71 | | - public function registerTool(Tool $tool, callable|array|string $handler, bool $isManual = false): void |
| 70 | + public function registerTool(Tool $tool, callable|array|string $handler): ToolReference |
72 | 71 | { |
73 | | - $toolName = $tool->name; |
74 | | - $existing = $this->tools[$toolName] ?? null; |
75 | | - |
76 | | - if ($existing && !$isManual && $existing->isManual) { |
77 | | - $this->logger->debug( |
78 | | - \sprintf('Ignoring discovered tool "%s" as it conflicts with a manually registered one.', $toolName), |
79 | | - ); |
80 | | - |
81 | | - return; |
82 | | - } |
83 | | - |
84 | | - if (!$this->nameValidator->isValid($toolName)) { |
| 72 | + if (!$this->nameValidator->isValid($tool->name)) { |
85 | 73 | $this->logger->warning( |
86 | | - \sprintf('Tool name "%s" is invalid. Tool names should only contain letters (a-z, A-Z), numbers, dots, hyphens, underscores, and forward slashes.', $toolName), |
| 74 | + \sprintf('Tool name "%s" is invalid. Tool names should only contain letters (a-z, A-Z), numbers, dots, hyphens, underscores, and forward slashes.', $tool->name), |
87 | 75 | ); |
88 | 76 | } |
89 | 77 |
|
90 | | - $this->tools[$toolName] = new ToolReference($tool, $handler, $isManual); |
| 78 | + $reference = new ToolReference($tool, $handler); |
| 79 | + $this->tools[$tool->name] = $reference; |
91 | 80 |
|
92 | 81 | $this->eventDispatcher?->dispatch(new ToolListChangedEvent()); |
| 82 | + |
| 83 | + return $reference; |
93 | 84 | } |
94 | 85 |
|
95 | | - public function registerResource(Resource $resource, callable|array|string $handler, bool $isManual = false): void |
| 86 | + public function registerResource(Resource $resource, callable|array|string $handler): ResourceReference |
96 | 87 | { |
97 | | - $uri = $resource->uri; |
98 | | - $existing = $this->resources[$uri] ?? null; |
99 | | - |
100 | | - if ($existing && !$isManual && $existing->isManual) { |
101 | | - $this->logger->debug( |
102 | | - \sprintf('Ignoring discovered resource "%s" as it conflicts with a manually registered one.', $uri), |
103 | | - ); |
104 | | - |
105 | | - return; |
106 | | - } |
107 | | - |
108 | | - $this->resources[$uri] = new ResourceReference($resource, $handler, $isManual); |
| 88 | + $reference = new ResourceReference($resource, $handler); |
| 89 | + $this->resources[$resource->uri] = $reference; |
109 | 90 |
|
110 | 91 | $this->eventDispatcher?->dispatch(new ResourceListChangedEvent()); |
| 92 | + |
| 93 | + return $reference; |
111 | 94 | } |
112 | 95 |
|
113 | 96 | public function registerResourceTemplate( |
114 | 97 | ResourceTemplate $template, |
115 | 98 | callable|array|string $handler, |
116 | 99 | array $completionProviders = [], |
117 | | - bool $isManual = false, |
118 | | - ): void { |
119 | | - $uriTemplate = $template->uriTemplate; |
120 | | - $existing = $this->resourceTemplates[$uriTemplate] ?? null; |
121 | | - |
122 | | - if ($existing && !$isManual && $existing->isManual) { |
123 | | - $this->logger->debug( |
124 | | - \sprintf('Ignoring discovered template "%s" as it conflicts with a manually registered one.', $uriTemplate), |
125 | | - ); |
126 | | - |
127 | | - return; |
128 | | - } |
129 | | - |
130 | | - $this->resourceTemplates[$uriTemplate] = new ResourceTemplateReference( |
131 | | - $template, |
132 | | - $handler, |
133 | | - $isManual, |
134 | | - $completionProviders, |
135 | | - ); |
| 100 | + ): ResourceTemplateReference { |
| 101 | + $reference = new ResourceTemplateReference($template, $handler, $completionProviders); |
| 102 | + $this->resourceTemplates[$template->uriTemplate] = $reference; |
136 | 103 |
|
137 | 104 | $this->eventDispatcher?->dispatch(new ResourceTemplateListChangedEvent()); |
| 105 | + |
| 106 | + return $reference; |
138 | 107 | } |
139 | 108 |
|
140 | 109 | public function registerPrompt( |
141 | 110 | Prompt $prompt, |
142 | 111 | callable|array|string $handler, |
143 | 112 | array $completionProviders = [], |
144 | | - bool $isManual = false, |
145 | | - ): void { |
146 | | - $promptName = $prompt->name; |
147 | | - $existing = $this->prompts[$promptName] ?? null; |
148 | | - |
149 | | - if ($existing && !$isManual && $existing->isManual) { |
150 | | - $this->logger->debug( |
151 | | - \sprintf('Ignoring discovered prompt "%s" as it conflicts with a manually registered one.', $promptName), |
152 | | - ); |
| 113 | + ): PromptReference { |
| 114 | + $reference = new PromptReference($prompt, $handler, $completionProviders); |
| 115 | + $this->prompts[$prompt->name] = $reference; |
153 | 116 |
|
| 117 | + $this->eventDispatcher?->dispatch(new PromptListChangedEvent()); |
| 118 | + |
| 119 | + return $reference; |
| 120 | + } |
| 121 | + |
| 122 | + public function unregisterTool(string $name): void |
| 123 | + { |
| 124 | + if (!isset($this->tools[$name])) { |
154 | 125 | return; |
155 | 126 | } |
156 | 127 |
|
157 | | - $this->prompts[$promptName] = new PromptReference($prompt, $handler, $isManual, $completionProviders); |
| 128 | + unset($this->tools[$name]); |
158 | 129 |
|
159 | | - $this->eventDispatcher?->dispatch(new PromptListChangedEvent()); |
| 130 | + $this->eventDispatcher?->dispatch(new ToolListChangedEvent()); |
160 | 131 | } |
161 | 132 |
|
162 | | - public function clear(): void |
| 133 | + public function unregisterResource(string $uri): void |
163 | 134 | { |
164 | | - $clearCount = 0; |
165 | | - |
166 | | - foreach ($this->tools as $name => $tool) { |
167 | | - if (!$tool->isManual) { |
168 | | - unset($this->tools[$name]); |
169 | | - ++$clearCount; |
170 | | - } |
171 | | - } |
172 | | - foreach ($this->resources as $uri => $resource) { |
173 | | - if (!$resource->isManual) { |
174 | | - unset($this->resources[$uri]); |
175 | | - ++$clearCount; |
176 | | - } |
177 | | - } |
178 | | - foreach ($this->prompts as $name => $prompt) { |
179 | | - if (!$prompt->isManual) { |
180 | | - unset($this->prompts[$name]); |
181 | | - ++$clearCount; |
182 | | - } |
| 135 | + if (!isset($this->resources[$uri])) { |
| 136 | + return; |
183 | 137 | } |
184 | | - foreach ($this->resourceTemplates as $uriTemplate => $template) { |
185 | | - if (!$template->isManual) { |
186 | | - unset($this->resourceTemplates[$uriTemplate]); |
187 | | - ++$clearCount; |
188 | | - } |
| 138 | + |
| 139 | + unset($this->resources[$uri]); |
| 140 | + |
| 141 | + $this->eventDispatcher?->dispatch(new ResourceListChangedEvent()); |
| 142 | + } |
| 143 | + |
| 144 | + public function unregisterResourceTemplate(string $uriTemplate): void |
| 145 | + { |
| 146 | + if (!isset($this->resourceTemplates[$uriTemplate])) { |
| 147 | + return; |
189 | 148 | } |
190 | 149 |
|
191 | | - if ($clearCount > 0) { |
192 | | - $this->logger->debug(\sprintf('Removed %d discovered elements from internal registry.', $clearCount)); |
| 150 | + unset($this->resourceTemplates[$uriTemplate]); |
| 151 | + |
| 152 | + $this->eventDispatcher?->dispatch(new ResourceTemplateListChangedEvent()); |
| 153 | + } |
| 154 | + |
| 155 | + public function unregisterPrompt(string $name): void |
| 156 | + { |
| 157 | + if (!isset($this->prompts[$name])) { |
| 158 | + return; |
193 | 159 | } |
| 160 | + |
| 161 | + unset($this->prompts[$name]); |
| 162 | + |
| 163 | + $this->eventDispatcher?->dispatch(new PromptListChangedEvent()); |
| 164 | + } |
| 165 | + |
| 166 | + public function hasTool(string $name): bool |
| 167 | + { |
| 168 | + return isset($this->tools[$name]); |
| 169 | + } |
| 170 | + |
| 171 | + public function hasResource(string $uri): bool |
| 172 | + { |
| 173 | + return isset($this->resources[$uri]); |
| 174 | + } |
| 175 | + |
| 176 | + public function hasResourceTemplate(string $uriTemplate): bool |
| 177 | + { |
| 178 | + return isset($this->resourceTemplates[$uriTemplate]); |
| 179 | + } |
| 180 | + |
| 181 | + public function hasPrompt(string $name): bool |
| 182 | + { |
| 183 | + return isset($this->prompts[$name]); |
194 | 184 | } |
195 | 185 |
|
196 | 186 | public function hasTools(): bool |
@@ -338,59 +328,6 @@ public function getPrompt(string $name): PromptReference |
338 | 328 | return $this->prompts[$name] ?? throw new PromptNotFoundException($name); |
339 | 329 | } |
340 | 330 |
|
341 | | - /** |
342 | | - * Get the current discovery state (only discovered elements, not manual ones). |
343 | | - */ |
344 | | - public function getDiscoveryState(): DiscoveryState |
345 | | - { |
346 | | - return new DiscoveryState( |
347 | | - tools: array_filter($this->tools, static fn ($tool) => !$tool->isManual), |
348 | | - resources: array_filter($this->resources, static fn ($resource) => !$resource->isManual), |
349 | | - prompts: array_filter($this->prompts, static fn ($prompt) => !$prompt->isManual), |
350 | | - resourceTemplates: array_filter($this->resourceTemplates, static fn ($template) => !$template->isManual), |
351 | | - ); |
352 | | - } |
353 | | - |
354 | | - /** |
355 | | - * Set the discovery state, replacing all discovered elements. |
356 | | - * Manual elements are preserved. |
357 | | - */ |
358 | | - public function setDiscoveryState(DiscoveryState $state): void |
359 | | - { |
360 | | - // Clear existing discovered elements |
361 | | - $this->clear(); |
362 | | - |
363 | | - // Import new discovered elements |
364 | | - foreach ($state->getTools() as $name => $tool) { |
365 | | - $this->tools[$name] = $tool; |
366 | | - } |
367 | | - |
368 | | - foreach ($state->getResources() as $uri => $resource) { |
369 | | - $this->resources[$uri] = $resource; |
370 | | - } |
371 | | - |
372 | | - foreach ($state->getPrompts() as $name => $prompt) { |
373 | | - $this->prompts[$name] = $prompt; |
374 | | - } |
375 | | - |
376 | | - foreach ($state->getResourceTemplates() as $uriTemplate => $template) { |
377 | | - $this->resourceTemplates[$uriTemplate] = $template; |
378 | | - } |
379 | | - |
380 | | - // Dispatch events for the imported elements |
381 | | - if ($this->eventDispatcher instanceof EventDispatcherInterface) { |
382 | | - if (!empty($state->getTools())) { |
383 | | - $this->eventDispatcher->dispatch(new ToolListChangedEvent()); |
384 | | - } |
385 | | - if (!empty($state->getResources()) || !empty($state->getResourceTemplates())) { |
386 | | - $this->eventDispatcher->dispatch(new ResourceListChangedEvent()); |
387 | | - } |
388 | | - if (!empty($state->getPrompts())) { |
389 | | - $this->eventDispatcher->dispatch(new PromptListChangedEvent()); |
390 | | - } |
391 | | - } |
392 | | - } |
393 | | - |
394 | 331 | /** |
395 | 332 | * Calculate next cursor for pagination. |
396 | 333 | * |
|
0 commit comments