[Schema] Serialize a settingless extension as an object (#438)
* [Schema] Serialize a settingless extension as an object
An extension declaring support with no settings was advertised as `[]`, an
empty JSON array, which the wire schema rejects - `extensions` maps an id to
a settings *object*. Both ServerCapabilities and ClientCapabilities now cast
each entry, so it goes out as `{}`.
* Apply suggestion from @chr-hertel
This commit is contained in:
parent
ced762614b
commit
08d332c7ac
3 changed files with 28 additions and 2 deletions
|
|
@ -188,7 +188,10 @@ class ClientCapabilities implements \JsonSerializable
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->extensions) {
|
if ($this->extensions) {
|
||||||
$data['extensions'] = (object) $this->extensions;
|
$data['extensions'] = (object) array_map(
|
||||||
|
static fn (mixed $settings): mixed => \is_array($settings) ? (object) $settings : $settings,
|
||||||
|
$this->extensions,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data ?: new \stdClass();
|
return $data ?: new \stdClass();
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,12 @@ class ServerCapabilities implements \JsonSerializable
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->extensions) {
|
if ($this->extensions) {
|
||||||
$data['extensions'] = (object) $this->extensions;
|
// Each entry is a settings *object*; an extension with no settings
|
||||||
|
// declares `{}`, and an empty PHP array would serialize as `[]`.
|
||||||
|
$data['extensions'] = (object) array_map(
|
||||||
|
static fn (mixed $settings): mixed => \is_array($settings) ? (object) $settings : $settings,
|
||||||
|
$this->extensions,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,24 @@ class CapabilitiesExtensionsTest extends TestCase
|
||||||
$this->assertObjectHasProperty(McpApps::EXTENSION_ID, $json['extensions']);
|
$this->assertObjectHasProperty(McpApps::EXTENSION_ID, $json['extensions']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testServerCapabilitiesSerializeSettinglessExtensionAsObject(): void
|
||||||
|
{
|
||||||
|
$caps = new ServerCapabilities(tools: true, extensions: ['acme/thing' => []]);
|
||||||
|
|
||||||
|
$json = json_encode($caps->jsonSerialize(), \JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
|
$this->assertStringContainsString('"acme/thing":{}', (string) $json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testClientCapabilitiesSerializeSettinglessExtensionAsObject(): void
|
||||||
|
{
|
||||||
|
$caps = new ClientCapabilities(elicitation: true, extensions: ['acme/thing' => []]);
|
||||||
|
|
||||||
|
$json = json_encode($caps->jsonSerialize(), \JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
|
$this->assertStringContainsString('"acme/thing":{}', (string) $json);
|
||||||
|
}
|
||||||
|
|
||||||
public function testServerCapabilitiesJsonSerializeWithoutExtensions(): void
|
public function testServerCapabilitiesJsonSerializeWithoutExtensions(): void
|
||||||
{
|
{
|
||||||
$caps = new ServerCapabilities(tools: true);
|
$caps = new ServerCapabilities(tools: true);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue