spring-ai-playground

description: Human-in-the-Loop approval in Spring AI Playground - require explicit approval before a tool runs, set it per tool, and approve or decline calls inside Agentic Chat.

Human-in-the-Loop Approval

Where: set it per tool in Tool Studio → Sandbox & Capabilities → Human-in-the-loop, or per re-exposed tool in the Composed Tools drawer’s HITL column. It then takes effect in Agentic Chat and for any external MCP client.

Human-in-the-loop (HITL) pauses a tool call and waits for you to approve or decline before the tool runs. The risk level warns you how dangerous a tool is; the sandbox limits what it can touch; HITL is the gate that asks “run this exact call?” at the moment it would fire.

It is the final safety layer, on top of the tool sandbox and the MCP risk model. The design and internals are on the Human-in-the-Loop Approval architecture page; this page is the how-to.

flowchart LR
    CALL["Agent decides<br/>to call a tool"]
    GATE{"Tool requires<br/>approval?"}
    ASK["Ask the human<br/>Approve / Decline"]
    RUN["Run the tool"]
    SKIP["Tell the model<br/>it was declined"]
    CALL --> GATE
    GATE -- "no" --> RUN
    GATE -- "yes" --> ASK
    ASK -- "Approve" --> RUN
    ASK -- "Decline / timeout" --> SKIP

The two modes { #modes }

Every tool has an approval mode:

Mode What it does
Required - ask every run The call is gated every time, for both Agentic Chat and external MCP clients.
Disabled - no prompt The tool runs without asking.

The mode defaults to Required above L0 and to Disabled at L0 - the more capable a tool, the more it asks out of the box.

Set approval on a tool you author { #author }

  1. Open Tool Studio and select or create a tool.
  2. Expand Sandbox & Capabilities.
  3. Under Human-in-the-loop, pick Required or Disabled.
  4. (Optional) In Approval prompt (optional), write the question shown at approval time. {toolName} and {args} are substituted at call time - e.g. Run tool '{toolName}' with arguments {args}?
  5. Test & Publish (or Test & Update).

!!! warning “Reducing oversight asks for confirmation” Moving a tool from Required to Disabled opens a Reduce human oversight? confirmation, so you never lower the gate by accident. Disabled lets any client run the tool immediately, with no approval step beyond the sandbox.

Require approval on a re-exposed external tool { #expose }

When you proxy an external tool through the built-in server, each row in the Composed Tools drawer has a HITL toggle:

You can toggle approval per tool, or for all selected tools at once. The same setting is available in YAML via the hitl: true key on a composed tool - see the Configuration reference.

Approve a call in Agentic Chat { #chat }

When the agent calls a gated tool, a dialog appears titled Tool approval required with the tool’s risk-level chip (hover it for the rationale), the rendered prompt, and two buttons:

The dialog escalates with the level, so the ask is proportional to what the tool can do:

Level What you see
L0-L3 Chip + prompt; standard Approve
L4 (High) Warning line (“can modify files, spend money, or change external state”); Approve turns red
L5 (Critical) Critical warning line; Approve is red and stays disabled until you tick “I reviewed the arguments and accept the risk”
![L3 Moderate approval dialog - a yellow L3 - Moderate chip above the prompt, with a plain blue Approve button and no extra warning](/spring-ai-playground/docs/assets/images/chat/hitl-approval-l3.png){ width="360" } ![L4 High approval dialog - an orange L4 - High chip, a High risk warning line, and a red Approve button](/spring-ai-playground/docs/assets/images/chat/hitl-approval-l4.png){ width="360" } ![L5 Critical approval dialog - a red L5 - Critical chip, a red Critical risk warning line, an I reviewed the arguments and accept the risk checkbox, and a red Approve button that is disabled until the checkbox is ticked](/spring-ai-playground/docs/assets/images/chat/hitl-approval-l5.png){ width="360" }

The level shown is the tool’s inherent level (before the HITL -1 display credit) - the dialog itself is the mitigation, so it never discounts the risk it is asking you to accept.

If you don’t answer within two minutes (configurable), or close the dialog, the call is declined automatically - approval fails safe. If the agent requested several gated tools in the same step, they appear together in one dialog with a chip-labeled row per call, so you answer them all at once; ungated calls run without interruption.

Walk through it end to end in Tutorial 11 - Approve a Tool in Chat.

What an external client sees { #external }

For an external MCP client (e.g. Claude Desktop) calling a Required tool on the built-in /mcp server, the built-in server issues an MCP elicitation request - a confirmation card the client renders before the call proceeds. The elicitation message is prefixed with the tool’s risk level (for example [risk L5 Critical]), because the elicitation protocol has no severity field of its own. If the client does not support elicitation, the call is denied (it cannot be approved). The playground’s own MCP Inspector → Elicitation shows elicitation requests the playground receives while acting as an MCP client; external clients render the built-in server’s approval prompt in their own UI.

Good defaults { #defaults }