Skip to content

[Client] Add client-side elicitation support#371

Open
wachterjohannes wants to merge 1 commit into
modelcontextprotocol:mainfrom
wachterjohannes:feature/client-elicitation
Open

[Client] Add client-side elicitation support#371
wachterjohannes wants to merge 1 commit into
modelcontextprotocol:mainfrom
wachterjohannes:feature/client-elicitation

Conversation

@wachterjohannes
Copy link
Copy Markdown
Contributor

Summary

The SDK already supports server-initiated elicitation (ClientGateway::elicit()), but the client could not receive elicitation/create requests:

  • there was no client request handler for it, and
  • ElicitRequest was not registered in MessageFactory, so incoming elicitation/create messages failed to parse (InvalidInputMessageException).

This PR closes that gap, mirroring the existing Sampling pattern one-to-one.

Changes

  • MessageFactory — register ElicitRequest::class so elicitation/create parses (the critical fix).
  • ElicitationRequestHandler — handles incoming elicitation/create, wraps a user callback, returns Response<ElicitResult> or an Error.
  • ElicitationCallbackInterface — the __invoke(ElicitRequest): ElicitResult contract users implement.
  • ElicitationException — throw from a callback to forward a specific message to the server; any other throwable returns a generic error (same semantics as SamplingException).
  • Unit tests for the handler + a MessageFactory parse test.
  • Runnable example examples/client/stdio_elicitation.php against the existing elicitation demo server.
  • Docs: docs/client.md Elicitation section + README.md capability entries.
  • ROADMAP.md: tick "Implement full support for elicitations" (now complete end-to-end).

Usage

$client = Client::builder()
    ->setCapabilities(new ClientCapabilities(elicitation: true))
    ->addRequestHandler(new ElicitationRequestHandler($myCallback))
    ->build();

Verification

  • New unit tests pass (handler accept/decline/exception/generic-error paths + elicitation/create parsing).
  • End-to-end: ran examples/client/stdio_elicitation.php against examples/server/elicitation/server.phpbook_restaurant round-trips elicited content into a confirmed booking; confirm_action returns the boolean.
  • php-cs-fixer clean; no new PHPStan errors introduced.

@wachterjohannes wachterjohannes force-pushed the feature/client-elicitation branch 2 times, most recently from 2315af2 to 5d1f416 Compare June 1, 2026 15:25
The SDK could send elicitation/create requests from a server tool via
ClientGateway::elicit(), but the client could not receive them: there was
no request handler, and ElicitRequest was not registered in MessageFactory,
so incoming elicitation/create messages failed to parse.

This adds the client half, mirroring the existing Sampling pattern:

- Register ElicitRequest in MessageFactory so elicitation/create parses.
- ElicitationRequestHandler wraps a user callback and returns an
  ElicitResult (accept/decline/cancel) or an Error.
- ElicitationCallbackInterface defines the callback contract.
- ElicitationException forwards a specific message to the server; any
  other throwable returns a generic error.

Includes unit tests, a runnable client example against the elicitation
demo server, and client docs/README updates.
@wachterjohannes wachterjohannes force-pushed the feature/client-elicitation branch from 5d1f416 to 6f04701 Compare June 1, 2026 15:30
@wachterjohannes wachterjohannes marked this pull request as ready for review June 1, 2026 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant