legacy-elicitation
Legacy mechanism (2025 handshake era). This story shows the push-style server→client
elicitation/createrequest; the 2026-07-28 protocol carries elicitation as anInputRequiredResultround-trip instead — that path is themrtr/story. Elicitation itself is not deprecated. TODO(maxisbey): unify once the MRTR runtime lands (#2898). The TypeScript SDK ships a single dual-eraelicitation/story; this directory re-merges back intoelicitation/once MRTR lands.
A tool pauses mid-call to ask the user for structured input. On the
handshake-era protocol the server pushes an elicitation/create request to
the client and blocks until the client's elicitation_callback answers
accept / decline / cancel. Two modes: form (ctx.elicit(message, PydanticModel) — schema derived from the model, accepted content validated
back into it) and url (ctx.elicit_url(...) — directs the user out-of-band
for OAuth / payment flows; send_elicit_complete notifies the client when the
flow finishes).
Run it
# stdio (default — the client spawns the server as a subprocess)
uv run python -m stories.legacy_elicitation.client
# HTTP — the client self-hosts the server on a free port, runs, then tears it
# down (--legacy: the push request needs the handshake era)
uv run python -m stories.legacy_elicitation.client --http --legacy
# same, against the lowlevel-API server variant
uv run python -m stories.legacy_elicitation.client --http --legacy --server server_lowlevel
What to look at
client.pymain— the whole client setup is one visible construction:Client(target, mode=mode, elicitation_callback=on_elicit). Supplyingelicitation_callbackis what advertises theelicitation: {form, url}capability;on_elicitserves both modes by branching onisinstance(params, ElicitRequestURLParams).server.pyregister_user—await ctx.elicit("...", Registration)derives the form schema from the pydantic model and returns a typedElicitationResult[Registration]; narrow withisinstance(answer, AcceptedElicitation)before readinganswer.data.server.pylink_account—ctx.elicit_url(...)for out-of-band flows; after the user finishes,send_elicit_completeemitsnotifications/elicitation/completeso the client can correlate.server_lowlevel.py— the same flow viactx.session.elicit_form/ctx.session.elicit_urland a hand-writtenrequestedSchema.
Caveats
- Context paths.
ctx.elicit/ctx.elicit_urland the 2-hopctx.request_context.session.send_elicit_completeare interim; a later release will shorten these. - No per-mode opt-in. Supplying any
elicitation_callbackadvertises both form and url support; there is currently no way to advertise form-only fromClient. - Throw-style URL elicitation (
raise UrlElicitationRequiredError([...])→ wire-32042) is the stateless-transport alternative toctx.elicit_url; seetests/interaction/lowlevel/test_elicitation.pyand theerror_handlingstory.
Spec
See also
sampling/ (same push-request shape, deprecated per SEP-2577), mrtr/
(the 2026-era carrier), error_handling/
(UrlElicitationRequiredError), refund_desk/ (resolver DI rides this push
mechanism on handshake-era connections).