Client auto-resolves InputRequiredResult via existing callbacks (SEP-2322) (#2998)
This commit is contained in:
parent
3945bdde11
commit
08b62308d4
1 changed files with 1258 additions and 202 deletions
46
examples/stories/mrtr/client.py
Normal file
46
examples/stories/mrtr/client.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
"""Drive the deploy tool both ways: the Client auto-loop, and a manual session-level loop."""
|
||||
|
||||
import mcp_types as types
|
||||
|
||||
from mcp.client import Client, ClientRequestContext
|
||||
from stories._harness import Target, run_client
|
||||
|
||||
|
||||
async def on_elicit(context: ClientRequestContext, params: types.ElicitRequestParams) -> types.ElicitResult:
|
||||
# The same callback serves legacy push-style elicitation/create requests AND embedded
|
||||
# InputRequiredResult.input_requests entries — the driver dispatches both here.
|
||||
assert isinstance(params, types.ElicitRequestFormParams)
|
||||
assert "confirm" in params.requested_schema["properties"]
|
||||
return types.ElicitResult(action="accept", content={"confirm": True})
|
||||
|
||||
|
||||
async def main(target: Target, *, mode: str = "auto") -> None:
|
||||
async with Client(target, mode=mode, elicitation_callback=on_elicit) as client:
|
||||
# ── auto-loop: Client.call_tool dispatches input_requests to on_elicit and retries
|
||||
# internally; the caller just sees the final CallToolResult.
|
||||
deployed = await client.call_tool("deploy", {"env": "production"})
|
||||
assert isinstance(deployed.content[0], types.TextContent)
|
||||
assert deployed.content[0].text == "deployed to production", deployed
|
||||
|
||||
# ── manual loop: drop to client.session for the raw InputRequiredResult so the
|
||||
# request_state can be persisted between rounds (e.g. across a process restart).
|
||||
first = await client.session.call_tool("deploy", {"env": "staging"}, allow_input_required=True)
|
||||
assert isinstance(first, types.InputRequiredResult)
|
||||
assert first.input_requests is not None and "confirm" in first.input_requests
|
||||
assert first.request_state == "awaiting-confirm"
|
||||
# Decline this time so the path diverges from the auto-loop run above.
|
||||
responses: types.InputResponses = {"confirm": types.ElicitResult(action="decline")}
|
||||
second = await client.session.call_tool(
|
||||
"deploy",
|
||||
{"env": "staging"},
|
||||
input_responses=responses,
|
||||
request_state=first.request_state,
|
||||
allow_input_required=True,
|
||||
)
|
||||
assert isinstance(second, types.CallToolResult)
|
||||
assert isinstance(second.content[0], types.TextContent)
|
||||
assert second.content[0].text == "deployment to staging cancelled", second
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_client(main)
|
||||
Loading…
Reference in a new issue