---
schema: rendered-html/v1
title: "Approval - FastMCP"
source_url: https://gofastmcp.com/apps/providers/approval
generated_at: 2026-06-11T19:36:58.323118+00:00
---




[FastMCP home page![light logo](images/gofastmcp__com__apps__providers__approval__wordmark.avif)![dark logo](images/gofastmcp__com__apps__providers__approval__wordmark-white.avif)](gofastmcp__com.md)







Prefab Providers

Approval















  - Prefab Providers

    - [Approval

      NEW](/apps/providers/approval)
    - [Choice

      NEW](gofastmcp__com__apps__providers__choice.md)
    - [File Upload

      NEW](gofastmcp__com__apps__providers__file-upload.md)
    - [Form Input

      NEW](gofastmcp__com__apps__providers__form.md)
  - [Development](gofastmcp__com__apps__development.md)
  - [Examples](gofastmcp__com__apps__examples.md)
  - [Architecture](gofastmcp__com__apps__architecture.md)








- [Configuration](#configuration)
- [How it works](#how-it-works)

Prefab Providers

# Approval


Human-in-the-loop approval gates for agent actions


New in version `3.2.0`
`Approval` adds a human-in-the-loop confirmation step to any server. The LLM presents what it’s about to do, the user approves or rejects via buttons, and the decision flows back into the conversation as a message.

![The Approval provider shown in Goose, with a payment confirmation card and Approve/Cancel buttons](https://mintcdn.com/fastmcp/qxtzRAUiJsjdoWFw/apps/images/app-approval.png?fit=max&auto=format&n=qxtzRAUiJsjdoWFw&q=85&s=a7612b699f039f04ddf85690e46d6695)

from fastmcp.apps.approval import Approval

mcp = FastMCP("My Server")
mcp.add_provider(Approval())

This registers a single tool:

| Tool | Visibility | Purpose |
| --- | --- | --- |
| `request_approval` | Model | Shows an approval card, sends the user’s decision back as a message |

The LLM calls `request_approval` with a summary (and optional details) whenever it’s about to take a significant action. The user sees a card with Approve and Reject buttons. Clicking either sends a message back into the conversation via `SendMessage`, which triggers the LLM’s next turn.
The message looks like it came from the user:

"Deploy v3.2 to production" — I selected: Approve

Approval is an advisory gate, not an enforcement mechanism. The conversation isn’t blocked while the card is open — the user can keep typing, and a determined LLM could proceed without waiting. Think of it as a strong UX signal that encourages confirmation, not a security boundary. For hard enforcement, implement approval logic server-side in your tool implementations.

## [​](#configuration) Configuration

The constructor sets defaults; the LLM can override all of these per-call via tool arguments.

Approval(
    name="Approval",              # App name
    title="Approval Required",    # Card heading
    approve_text="Approve",       # Approve button label
    reject_text="Reject",         # Reject button label
    approve_variant="default",    # "default", "destructive", "success", "info"
    reject_variant="outline",     # same options plus "outline"

The LLM can customize each invocation:

request_approval(
    summary="Delete 47 files from /tmp",
    details="This cannot be undone.",
    title="Destructive Action",
    approve_text="Delete",
    approve_variant="destructive",
    reject_text="Keep files",

## [​](#how-it-works) How it works

When the user clicks a button, two things happen:

1. `SendMessage` pushes the decision into the conversation as a user message
2. `SetState("decided", True)` replaces the buttons with “Response sent.”

The tool description instructs the LLM to stop and wait for the “I selected:” message before proceeding. If approved, it continues. If rejected, it acknowledges and asks how to proceed.

[Custom HTML Apps

Previous](gofastmcp__com__apps__low-level.md)[Choice

Next](gofastmcp__com__apps__providers__choice.md)






