Skip to content

Commit 07b0407

Browse files
nicolas-grekaschr-hertel
authored andcommitted
[Server] Describe tool inputs and outputs with their direction
Input schemas only list the properties a client can send (Direction::Input), and output schemas require the properties that are always present (Direction::Output). A dialect without schema URI makes stripping $schema unnecessary, and definitions keep the plain class name since each schema is a document of its own.
1 parent 1a86ddd commit 07b0407

3 files changed

Lines changed: 14 additions & 6 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ All notable changes to `mcp/sdk` will be documented in this file.
99

1010
* Discovery
1111
* [BC Break] Generate tool input and output schemas with `symfony/json-schema`. Unions are described with `anyOf`, `null` comes last in `type`, `default: null` is no longer emitted, array shapes are closed with `additionalProperties: false`, string-keyed maps get `additionalProperties`, and a class parameter is described by its properties.
12-
* [BC Break] `SchemaGenerator` takes a `Symfony\Component\JsonSchema\SchemaGeneratorInterface`, a `TypeResolverInterface` and a `Configuration` instead of a `DocBlockParser`.
12+
* [BC Break] `SchemaGenerator` takes a `Symfony\Component\JsonSchema\SchemaGeneratorInterface`, a `TypeResolverInterface` and the input and output `Configuration` instead of a `DocBlockParser`.
1313
* [BC Break] Remove `DocBlockParser::getParamTypeString()` and `DocBlockParser::getParamDescription()`.
1414
* Add the `outputSchemaFromReturnType` argument of `SchemaGenerator`, to describe the output of a tool that returns an object by its class.
1515

‎src/Server/Capability/Discovery/SchemaGenerator.php‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
use Mcp\Server\Exception\BadMethodCallException;
1818
use Mcp\Server\Exception\InvalidArgumentException;
1919
use Symfony\Component\JsonSchema\Configuration;
20+
use Symfony\Component\JsonSchema\Dialect;
21+
use Symfony\Component\JsonSchema\Direction;
22+
use Symfony\Component\JsonSchema\NullSyntax;
2023
use Symfony\Component\JsonSchema\Schema as JsonSchema;
2124
use Symfony\Component\JsonSchema\SchemaGenerator as JsonSchemaGenerator;
2225
use Symfony\Component\JsonSchema\SchemaGeneratorInterface as JsonSchemaGeneratorInterface;
@@ -35,11 +38,18 @@ final class SchemaGenerator implements SchemaGeneratorInterface
3538
private readonly JsonSchemaGeneratorInterface $generator;
3639
private readonly TypeResolverInterface $typeResolver;
3740

41+
/**
42+
* Each schema is a document of its own, so definitions are named after their class only.
43+
*
44+
* @param Configuration $configuration The configuration of input schemas
45+
* @param Configuration $outputConfiguration The configuration of output schemas
46+
*/
3847
public function __construct(
3948
?JsonSchemaGeneratorInterface $generator = null,
4049
?TypeResolverInterface $typeResolver = null,
41-
private readonly Configuration $configuration = new Configuration(),
50+
private readonly Configuration $configuration = new Configuration(new Dialect('#/$defs/', NullSyntax::Union), definitionName: '', direction: Direction::Input),
4251
private readonly bool $outputSchemaFromReturnType = false,
52+
private readonly Configuration $outputConfiguration = new Configuration(new Dialect('#/$defs/', NullSyntax::Union), definitionName: '', direction: Direction::Output),
4353
) {
4454
$this->generator = $generator ?? JsonSchemaGenerator::create();
4555
$this->typeResolver = $typeResolver ?? TypeResolver::create();
@@ -72,7 +82,6 @@ public function generate(\Reflector $reflection): array
7282
}
7383

7484
$schema = self::toArray($this->generator->generateForParameters(array_values($parameters), $this->configuration)->flatten());
75-
unset($schema['$schema']);
7685

7786
$methodProperties = $methodSchema['properties'] ?? [];
7887
$methodRequired = $methodSchema['required'] ?? [];
@@ -129,8 +138,7 @@ public function generateOutputSchema(\Reflector $reflection): ?array
129138
return null;
130139
}
131140

132-
$schema = self::toArray($this->generator->generate($type, $this->configuration)->flatten());
133-
unset($schema['$schema']);
141+
$schema = self::toArray($this->generator->generate($type, $this->outputConfiguration)->flatten());
134142

135143
return $schema;
136144
}

‎tests/Unit/Server/Capability/Discovery/SchemaGeneratorTest.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ public function testOutputSchemaFromReturnTypeIsOptIn(): void
790790
$schema = (new SchemaGenerator(outputSchemaFromReturnType: true))->generateOutputSchema($method);
791791
$this->assertNotNull($schema);
792792
$this->assertSame('object', $schema['type']);
793-
$this->assertSame(['email', 'age'], $schema['required']);
793+
$this->assertSame(['email', 'age', 'address', 'tags', 'birthday'], $schema['required']);
794794
}
795795

796796
public function testExplicitOutputSchemaWins(): void

0 commit comments

Comments
 (0)