|
26 | 26 | use Mcp\Capability\Registry\ReferenceHandlerInterface; |
27 | 27 | use Mcp\Capability\RegistryInterface; |
28 | 28 | use Mcp\Exception\InvalidArgumentException; |
| 29 | +use Mcp\Exception\LogicException; |
29 | 30 | use Mcp\JsonRpc\MessageFactory; |
30 | 31 | use Mcp\Schema\Annotations; |
31 | 32 | use Mcp\Schema\Enum\ProtocolVersion; |
@@ -240,22 +241,18 @@ public function setCapabilities(ServerCapabilities $serverCapabilities): self |
240 | 241 | * Enable one or more MCP protocol extensions, announced to clients under |
241 | 242 | * `capabilities.extensions` during the initialize handshake. |
242 | 243 | * |
243 | | - * Pass either fully qualified class names (instantiated with no arguments) or |
244 | | - * pre-built instances. |
245 | | - * |
246 | | - * @param class-string<ServerExtensionInterface>|ServerExtensionInterface ...$extensions |
| 244 | + * @throws LogicException if the same extension is enabled more than once |
247 | 245 | */ |
248 | | - public function enableExtension(string|ServerExtensionInterface ...$extensions): self |
| 246 | + public function enableExtension(ServerExtensionInterface ...$extensions): self |
249 | 247 | { |
250 | 248 | foreach ($extensions as $extension) { |
251 | | - if (\is_string($extension)) { |
252 | | - if (!is_subclass_of($extension, ServerExtensionInterface::class)) { |
253 | | - throw new InvalidArgumentException(\sprintf('Extension class "%s" must implement "%s".', $extension, ServerExtensionInterface::class)); |
254 | | - } |
255 | | - $extension = new $extension(); |
| 249 | + $id = $extension->getId(); |
| 250 | + |
| 251 | + if (isset($this->extensions[$id])) { |
| 252 | + throw new LogicException(\sprintf('Extension "%s" is already enabled.', $id)); |
256 | 253 | } |
257 | 254 |
|
258 | | - $this->extensions[$extension->getId()] = $extension->getCapabilities(); |
| 255 | + $this->extensions[$id] = $extension->getCapabilities(); |
259 | 256 | } |
260 | 257 |
|
261 | 258 | return $this; |
@@ -621,6 +618,12 @@ public function build(): Server |
621 | 618 | extensions: [] !== $this->extensions ? $this->extensions : null, |
622 | 619 | ); |
623 | 620 |
|
| 621 | + // Extensions enabled via enableExtension() are folded into caller-supplied |
| 622 | + // capabilities too, so setCapabilities() does not silently drop them. |
| 623 | + if (null !== $this->serverCapabilities && [] !== $this->extensions) { |
| 624 | + $capabilities = $capabilities->withExtensions($this->extensions); |
| 625 | + } |
| 626 | + |
624 | 627 | $serverInfo = $this->serverInfo ?? new Implementation(); |
625 | 628 | $configuration = new Configuration($serverInfo, $capabilities, $this->paginationLimit, $this->instructions, $this->protocolVersion); |
626 | 629 | $referenceHandler = $this->referenceHandler ?? new ReferenceHandler($container); |
|
0 commit comments