Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ All notable changes to `mcp/sdk` will be documented in this file.
* Fix an `int` parameter receiving a wrong value: a number beyond the integer range wrapped around, also past the schema's `minimum` or `maximum`, a numeric string beyond it became `PHP_INT_MAX` or `PHP_INT_MIN`, and `"--5"` became `0`. They are refused now.
* Fix a nullable parameter with a default (e.g. `?string $category = 'books'`) receiving the default when the client sends `null`.
* Fix DocBlock types producing wrong schemas, so valid arguments were rejected with `-32602`: PHPStan/Psalm pseudo-types and literal types (`non-empty-string`, `positive-int`, `'asc'|'desc'`, `array<array-key, T>`) get the JSON Schema type of their base type, nullable and union keys of an array shape (`array{nickname: string|null}`) and union elements of a generic (`array<string|null>`) get their own types instead of `object`, and a `null` inside them, or in a class name, no longer makes the parameter nullable.
* [BC Break] Generate `{"type": "array"}` for an `iterable` parameter, as for `array` and `iterable<T>`, instead of `{"type": "object"}`, which refused a JSON array with `-32602` although the handler accepts one. A JSON object is refused instead, as for `array`.
* Fix tool name validation to follow the spec (1 to 128 characters of `A-Z`, `a-z`, `0-9`, `_`, `-` and `.`): names of 65 to 128 characters no longer log a warning, names with a `/` or a trailing newline do.
* Fix `content`, `messages` and `contents` being sent as a JSON object when the handler returned a non-list array, e.g. from `array_filter()`, and named keys in nested mixed arrays overwriting each other.
* Fix a scalar `structuredContent` on `2026-07-28` going out as raw text in `content`: `'sunny'` is sent as the JSON `"sunny"`, as SEP-2106 requires.
Expand Down
2 changes: 1 addition & 1 deletion src/Server/Capability/Discovery/SchemaGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ private function mapPhpTypeToJsonSchemaType(string $phpTypeString): array
'int', 'integer' => ['integer'],
'float', 'double', 'number' => ['number'],
'bool', 'boolean' => ['boolean'],
'array' => ['array'],
'array', 'iterable' => ['array'],
'object', 'stdclass' => ['object'],
'null' => ['null'],
'resource', 'callable' => ['object'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public function typeHintsOnly(string $name, int $age, bool $active, array $tags,
{
}

public function iterableParameters(iterable $items, ?iterable $optional = null): void
{
}

/**
* DocBlock types only - no PHP type hints, no Schema attributes.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ public function testInfersBasicTypesFromPhpTypeHints(): void
$this->assertEqualsCanonicalizing(['name', 'age', 'active', 'tags'], $schema['required']);
}

public function testRepresentsIterableParametersAsArrays(): void
{
$schema = $this->schemaGenerator->generate(new \ReflectionMethod(SchemaGeneratorFixture::class, 'iterableParameters'));
$this->assertEquals(['type' => 'array', 'items' => new \stdClass()], $schema['properties']['items']);
$this->assertEquals(['type' => ['array', 'null'], 'default' => null, 'items' => new \stdClass()], $schema['properties']['optional']);
$this->assertSame([], (new SchemaValidator())->validateAgainstJsonSchema(['items' => [1, 2]], $schema));
}

public function testInfersTypesAndDescriptionsFromDocBlockTags(): void
{
$method = new \ReflectionMethod(SchemaGeneratorFixture::class, 'docBlockOnly');
Expand Down
Loading