aeat.entrypoints.mcp._elicitation module

Elicitation-backed CONFIRM enforcement and its capability-degradation matrix.

ADR R6 makes the CONFIRM tier real: a confirm-tier tool call pauses and asks the HUMAN through MCP elicitation (accept / decline / cancel) before it runs. Client support for elicitation is negotiated, not assumed, so the decision of HOW to enforce a tier is a matrix over (policy, handoff-ness, client capability):

  • BLOCK refuses outright, always — the permanent live-write rail.

  • CONFIRM with elicitation support elicits a yes/no from the user.

  • CONFIRM without elicitation degrades by CONSEQUENCE: a filing-handoff verb (an export, a record marker — the irreversible boundary) REFUSES by default with an instructive message, while a non-handoff destructive verb proceeds under the client’s own destructiveHint-driven confirmation UI, which every surveyed client renders for annotated tools.

  • AUTO_APPROVE runs without asking.

The elicitation request itself is deliberately minimal and never carries sensitive data (a hard MCP-spec constraint): the message names the command and its consequence; the requested schema is one boolean field.

Like the sibling _hitl module this is SDK-independent pure logic; _server owns reading the negotiated client capabilities and performing the actual elicit round-trip.

class ConfirmRoute(*values)[source]

Bases: StrEnum

How one tool call’s confirmation tier is enforced for this client.

AUTO

Auto-approved; run without asking.

ELICIT

Ask the user through an elicitation round-trip before running.

CLIENT_HINT

Proceed; the client’s destructiveHint confirmation UI carries the ask.

REFUSE_NO_CHANNEL

Refuse a handoff-tier verb that has no elicitation channel to a human.

REFUSE_BLOCKED

Refuse the call under the permanent live-write block.

class ConfirmDecision(*values)[source]

Bases: StrEnum

The outcome of an elicitation round-trip for a confirm-tier call.

PROCEED
REFUSED_DECLINED
REFUSED_CANCELLED
REFUSED_NOT_CONFIRMED

Accepted the form but answered no — treated exactly like a decline.

class ConfirmationRequest(**data)[source]

Bases: BaseModel

The elicitation payload for one confirm-tier call.

message names the command and its consequence in plain language; requested_schema is the spec-restricted flat object with one boolean field. No argument values, figures, or taxpayer data ride in either — the MCP spec forbids eliciting sensitive information, and a confirmation needs none.

Parameters:
message: str
requested_schema: dict[str, object]
resolve_confirm_route(*, policy, command_key, client_supports_elicitation)[source]

The degradation matrix: how this call’s tier is enforced for this client.

Return type:

ConfirmRoute

Returns:

A ConfirmRoute.

Parameters:
confirmation_request(*, command_key)[source]

Build the elicitation request for one confirm-tier command.

The message and field description are rendered by the client TO THE HUMAN taxpayer, so both are localized through tr() (the configured output language), unlike the model-facing refusal/advisory strings in this layer, which the model re-narrates in the user’s language itself.

Return type:

ConfirmationRequest

Returns:

A ConfirmationRequest.

Parameters:

command_key (str)

decision_from_elicitation(*, action, content)[source]

Map an elicitation result onto the confirm decision.

Fail-closed on every path that is not an explicit accepted yes: a decline, a cancel, a malformed accept, and an accepted confirm: false all refuse.

Return type:

ConfirmDecision

Returns:

A ConfirmDecision.

Parameters:
refusal_message(route, *, command_key)[source]

The instructive refusal text for the two refusing routes (client-relayed, localized).

Return type:

str

Parameters: