diff --git a/CHANGELOG.md b/CHANGELOG.md index 22ad2b37..2b55de28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to `mcp/sdk` will be documented in this file. 0.9.0 ----- +* [BC Break] `SchemaValidator` takes an optional `Opis\JsonSchema\Validator` as its first constructor argument, moving `$logger` to second. Pass `logger:` by name. +* Add `Builder::setSchemaValidator()` to configure the validator used for `tools/call` input, e.g. with a resolver for external `$ref` schemas. * [BC Break] Remove the `providerClass` argument of `#[CompletionProvider]`. Use `provider:`, which takes the same class-string and is now the first positional argument. * Add `HttpTransport::getSessionId()` to read the server-minted `Mcp-Session-Id`: a request-scoped caller can persist it and pass it back through the constructor's `$headers` on a later transport. Always `null` on `2026-07-28`, which removed protocol-level sessions. diff --git a/src/Capability/Discovery/SchemaValidator.php b/src/Capability/Discovery/SchemaValidator.php index 56174bdc..c84a2ffd 100644 --- a/src/Capability/Discovery/SchemaValidator.php +++ b/src/Capability/Discovery/SchemaValidator.php @@ -30,9 +30,8 @@ */ class SchemaValidator { - private ?Validator $jsonSchemaValidator = null; - public function __construct( + private ?Validator $jsonSchemaValidator = null, private LoggerInterface $logger = new NullLogger(), ) { } diff --git a/src/Server/Builder.php b/src/Server/Builder.php index 1a5dd73b..cf9954c4 100644 --- a/src/Server/Builder.php +++ b/src/Server/Builder.php @@ -16,6 +16,7 @@ use Mcp\Capability\Discovery\Discoverer; use Mcp\Capability\Discovery\DiscovererInterface; use Mcp\Capability\Discovery\SchemaGeneratorInterface; +use Mcp\Capability\Discovery\SchemaValidator; use Mcp\Capability\Registry; use Mcp\Capability\Registry\Container; use Mcp\Capability\Registry\ElementReference; @@ -105,6 +106,8 @@ final class Builder private ?SchemaGeneratorInterface $schemaGenerator = null; + private ?SchemaValidator $schemaValidator = null; + private ?ReferenceHandlerInterface $referenceHandler = null; private ?DiscovererInterface $discoverer = null; @@ -582,6 +585,13 @@ public function setSchemaGenerator(SchemaGeneratorInterface $schemaGenerator): s return $this; } + public function setSchemaValidator(SchemaValidator $schemaValidator): self + { + $this->schemaValidator = $schemaValidator; + + return $this; + } + public function setReferenceHandler(ReferenceHandlerInterface $referenceHandler): self { $this->referenceHandler = $referenceHandler; @@ -1084,7 +1094,7 @@ private function resolve(): array $referenceHandler = $this->referenceHandler ?? new ReferenceHandler($container); $requestHandlers = array_merge($this->requestHandlers, [ - new Handler\Request\CallToolHandler($registry, $referenceHandler, $logger), + new Handler\Request\CallToolHandler($registry, $referenceHandler, $logger, $this->schemaValidator), new Handler\Request\CompletionCompleteHandler($registry, $container, $logger), new Handler\Request\GetPromptHandler($registry, $referenceHandler, $logger), new Handler\Request\InitializeHandler($configuration), diff --git a/src/Server/Handler/Request/CallToolHandler.php b/src/Server/Handler/Request/CallToolHandler.php index 72f3c21f..304bb664 100644 --- a/src/Server/Handler/Request/CallToolHandler.php +++ b/src/Server/Handler/Request/CallToolHandler.php @@ -48,7 +48,7 @@ public function __construct( private readonly LoggerInterface $logger = new NullLogger(), ?SchemaValidator $schemaValidator = null, ) { - $this->schemaValidator = $schemaValidator ?? new SchemaValidator($logger); + $this->schemaValidator = $schemaValidator ?? new SchemaValidator(logger: $logger); } public function supports(Request $request): bool diff --git a/tests/Unit/Server/BuilderTest.php b/tests/Unit/Server/BuilderTest.php index 790af5f5..25f1e125 100644 --- a/tests/Unit/Server/BuilderTest.php +++ b/tests/Unit/Server/BuilderTest.php @@ -98,6 +98,23 @@ public function testCustomReferenceHandlerIsUsedForToolCalls(): void $this->assertSame('intercepted', $result); } + #[TestDox('Custom SchemaValidator is used when calling a tool')] + public function testCustomSchemaValidatorIsUsedForToolCalls(): void + { + $schemaValidator = $this->createMock(\Mcp\Capability\Discovery\SchemaValidator::class); + $schemaValidator->expects($this->once()) + ->method('validateAgainstJsonSchema') + ->willReturn([]); + + $server = Server::builder() + ->setServerInfo('test', '1.0.0') + ->setSchemaValidator($schemaValidator) + ->addTool(static fn (): string => 'validated', name: 'test_tool', description: 'A test tool') + ->build(); + + $this->assertSame('validated', $this->callTool($server, 'test_tool')); + } + #[TestDox('A pre-built instance handler with constructor dependencies is registered and invoked on that instance')] public function testPreBuiltInstanceHandlerIsInvokedOnTheGivenInstance(): void {