[Schema][Server] Add the extensions framework SEP-2133 defines (#443)

* [Schema][Server] Add the extensions framework SEP-2133 defines

enableExtension() took any string and advertised it, with no way for an
extension to add a method: MessageFactory could not decode one, so nothing
downstream ever saw it.

Identifiers are now checked against the _meta key naming rules through
ExtensionIdentifier - a prefix is mandatory, since an unprefixed name has no
owner, and the modelcontextprotocol/mcp second labels the specification
reserves are recognised. An extension implementing
MethodProvidingExtensionInterface contributes both its message classes and
the handlers serving them.

MessageFactory::make() takes an $additional list of message classes, and
RequestHandlerInterface's result template is covariant so a handler
declaring a concrete result satisfies a collection typed by the interface.

* Fix stale @see reference in MethodProvidingExtensionInterface docblock

* [Schema][Server][Client] Make ExtensionIdentifier a value object

ExtensionInterface::getId() now returns ExtensionIdentifier, which
validates the SEP-2133 naming rules at construction instead of the
callers checking it. getMessages()/getRequestHandlers() move into
ExtensionInterface itself; AbstractExtension gives them empty
defaults for extensions that only announce a capability.
This commit is contained in:
Christopher Hertel 2026-08-18 20:47:27 +02:00 • committed by GitHub
commit 60711951d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -23,6 +23,7 @@ use Mcp\Schema\Elicitation\ElicitationSchema;
use Mcp\Schema\Enum\LoggingLevel;
use Mcp\Schema\Enum\Role;
use Mcp\Schema\Enum\SamplingContext;
use Mcp\Schema\Extension\ExtensionIdentifier;
use Mcp\Schema\JsonRpc\Error;
use Mcp\Schema\JsonRpc\Notification;
use Mcp\Schema\JsonRpc\Request;
@ -359,9 +360,9 @@ class ClientGateway
*
* @return bool True if the client advertised the extension, false otherwise
*/
public function supportsExtension(string $id): bool
public function supportsExtension(ExtensionIdentifier|string $id): bool
{
return $this->hasSubCapability('extensions', $id);
return $this->hasSubCapability('extensions', (string) $id);
}
/**