[Schema][Server] Harden sampling tools against the spec (#420)

* harden sampling tools against the spec

Report tool-flow violations as -32602 instead of dropping the request,
accept resource_link in tool results, gate tools on sampling.tools, and
reject empty content.

* normalize keyed content arrays to lists

array_filter() and friends preserve keys, and a keyed array serializes as a
JSON object instead of the content-block array the schema requires.
This commit is contained in:
Christopher Hertel 2026-08-15 04:13:53 +02:00 • committed by GitHub
commit 43815e38a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -68,4 +68,47 @@ class ClientCapabilitiesTest extends TestCase
$this->assertTrue($restored->roots);
$this->assertTrue($restored->rootsListChanged);
}
public function testRoundTripPreservesSamplingSubCapabilities(): void
{
$capabilities = new ClientCapabilities(sampling: true, samplingContext: true, samplingTools: true);
$serialized = $capabilities->jsonSerialize();
$this->assertObjectHasProperty('context', $serialized['sampling']);
$this->assertObjectHasProperty('tools', $serialized['sampling']);
$restored = ClientCapabilities::fromArray(json_decode(json_encode($capabilities), true));
$this->assertTrue($restored->sampling);
$this->assertTrue($restored->samplingContext);
$this->assertTrue($restored->samplingTools);
}
public function testPlainSamplingLeavesSubCapabilitiesOff(): void
{
$capabilities = new ClientCapabilities(sampling: true);
$serialized = $capabilities->jsonSerialize();
$this->assertObjectNotHasProperty('context', $serialized['sampling']);
$this->assertObjectNotHasProperty('tools', $serialized['sampling']);
$restored = ClientCapabilities::fromArray(json_decode(json_encode($capabilities), true));
$this->assertTrue($restored->sampling);
$this->assertFalse($restored->samplingContext);
$this->assertFalse($restored->samplingTools);
}
public function testSamplingSubCapabilitiesAreHydratedFromObject(): void
{
$sampling = new \stdClass();
$sampling->context = new \stdClass();
$sampling->tools = new \stdClass();
$capabilities = ClientCapabilities::fromArray(['sampling' => $sampling]);
$this->assertTrue($capabilities->sampling);
$this->assertTrue($capabilities->samplingContext);
$this->assertTrue($capabilities->samplingTools);
}
}