[Server] Add ClientGateway::supportsSampling() (#418)
Sampling was the one client capability a tool could not check before asking. `supportsRoots()` and `supportsElicitation()` both read the capabilities the client advertised during the handshake; sampling is stored in that same session data but had no accessor, so a tool had to issue the request and catch the refusal.
This commit is contained in:
parent
eb20453f49
commit
c4b163b4c4
3 changed files with 38 additions and 0 deletions
|
|
@ -9,6 +9,7 @@ All notable changes to `mcp/sdk` will be documented in this file.
|
|||
* Prompt generators returning content as typed arrays (`['type' => 'text', ...]` etc.) no longer lose the optional fields: `annotations` on every content type, and `_meta` and an explicit `mimeType` on embedded resource contents, now carry through to the resulting `PromptMessage` instead of being silently dropped. A missing resource `mimeType` still defaults to `text/plain`/`application/octet-stream` as before.
|
||||
* Add `annotations` support to `ImageContent` (constructor, `fromArray()`, `fromFile()`, `fromString()`, `jsonSerialize()`), matching `TextContent` and `AudioContent`.
|
||||
* Add client-side `roots/list` handler (`ListRootsRequestHandler` + `RootsCallbackInterface`) and `Client::sendRootsListChanged()`, plus server-side `ClientGateway::listRoots()` / `supportsRoots()` and `ListRootsResult::fromArray()`.
|
||||
* Add `ClientGateway::supportsSampling()`, so a tool can check the client's advertised capabilities before issuing a `sampling/createMessage` request instead of asking and catching the refusal. Matches the existing `supportsRoots()` and `supportsElicitation()`.
|
||||
* Add `Mcp\Schema\Content\ResourceLink` for the spec's `resource_link` content block (protocol revision 2025-06-18+), letting tool results and prompt messages reference a resource by URI/name without embedding its contents. Accepted anywhere `resource` (`EmbeddedResource`) content is (de)serialized: `CallToolResult::fromArray()`, `PromptMessage::fromArray()`, and `PromptResultFormatter`.
|
||||
* Negotiate the protocol revision during the `initialize` handshake: the server echoes a revision it supports and counter-offers `ProtocolVersion::latestHandshake()` otherwise (`Builder::setProtocolVersion()` pins it to exactly one), and the client fails the handshake on a counter-offer it cannot speak rather than continuing on an unagreed revision. Adds `Client::getProtocolVersion()`, the `2026-07-28` revision, and the era helpers on `ProtocolVersion` — revisions from `2026-07-28` on have no `initialize`, so they are excluded from negotiation and from `ProtocolVersionMiddleware`'s default supported set.
|
||||
|
||||
|
|
|
|||
|
|
@ -250,6 +250,23 @@ class ClientGateway
|
|||
return \array_key_exists('elicitation', $capabilities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the connected client supports sampling.
|
||||
*
|
||||
* Sampling lets a server borrow the client's model during tool execution.
|
||||
* This method checks the client's advertised capabilities to determine if
|
||||
* sampling/createMessage requests are supported.
|
||||
*
|
||||
* @return bool True if the client supports sampling, false otherwise
|
||||
*/
|
||||
public function supportsSampling(): bool
|
||||
{
|
||||
$capabilities = (array) $this->session->get('client_capabilities', []);
|
||||
|
||||
// MCP spec: capability presence indicates support (value is typically {} or [])
|
||||
return \array_key_exists('sampling', $capabilities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request to the client and wait for a response (blocking).
|
||||
*
|
||||
|
|
|
|||
|
|
@ -43,6 +43,26 @@ final class ClientGatewayTest extends TestCase
|
|||
$this->assertFalse($gateway->supportsRoots());
|
||||
}
|
||||
|
||||
public function testSupportsSamplingReturnsTrueWhenAdvertised(): void
|
||||
{
|
||||
$session = $this->createMock(SessionInterface::class);
|
||||
$session->method('get')->with('client_capabilities', [])->willReturn(['sampling' => []]);
|
||||
|
||||
$gateway = new ClientGateway($session);
|
||||
|
||||
$this->assertTrue($gateway->supportsSampling());
|
||||
}
|
||||
|
||||
public function testSupportsSamplingReturnsFalseWhenNotAdvertised(): void
|
||||
{
|
||||
$session = $this->createMock(SessionInterface::class);
|
||||
$session->method('get')->with('client_capabilities', [])->willReturn(['roots' => []]);
|
||||
|
||||
$gateway = new ClientGateway($session);
|
||||
|
||||
$this->assertFalse($gateway->supportsSampling());
|
||||
}
|
||||
|
||||
public function testListRootsReturnsRootsFromClient(): void
|
||||
{
|
||||
$session = $this->createMock(SessionInterface::class);
|
||||
|
|
|
|||
Loading…
Reference in a new issue