---
title: Apps
sidebarTitle: Overview
description: Give your tools interactive UIs rendered directly in the conversation.
icon: grid-2
tag: NEW
---

import { VersionBadge } from '/snippets/version-badge.mdx'

<VersionBadge version="3.0.0" />

MCP tools normally return text. That works for answers, but not for data the user wants to *explore* — a revenue chart they can hover over, a sortable employee directory, a form that submits structured input. MCP Apps let your tools return interactive UIs rendered right inside the conversation.

<Frame>
  <img src="/apps/images/app-showcase.png" alt="A Prefab app showing forms, charts, metrics, progress bars, data tables, and interactive controls — all built in Python" />
</Frame>

FastMCP builds on the [MCP Apps extension](https://modelcontextprotocol.io/docs/extensions/apps) with [Prefab](https://prefab.prefect.io), a Python component library that compiles to interactive UIs. You write Python; the user sees charts, tables, forms, and dashboards.

<Note>
The examples throughout the Apps docs require the `apps` extra:

```bash
pip install "fastmcp[apps]"
```

This installs [Prefab UI](https://prefab.prefect.io), the component library used to build app UIs. Pin `prefab-ui` to a specific version in production — it's in early development and its API changes frequently.
</Note>

## Prefab Apps

<VersionBadge version="3.1.0" />

The quickest way to give a tool a visual UI. Add `app=True` to any tool and return a Prefab component — when the host calls it, the user sees an interactive UI instead of a JSON blob:

```python
from prefab_ui.app import PrefabApp
from prefab_ui.components import Column, Heading
from prefab_ui.components.charts import BarChart, ChartSeries
from fastmcp import FastMCP

mcp = FastMCP("Dashboard")


@mcp.tool(app=True)
def revenue_chart(year: int) -> PrefabApp:
    """Show annual revenue as an interactive bar chart."""
    data = [
        {"quarter": "Q1", "revenue": 42000},
        {"quarter": "Q2", "revenue": 51000},
        {"quarter": "Q3", "revenue": 47000},
        {"quarter": "Q4", "revenue": 63000},
    ]

    with Column(gap=4, css_class="p-6") as view:
        Heading(f"{year} Revenue")
        BarChart(
            data=data,
            series=[ChartSeries(data_key="revenue", label="Revenue")],
            x_axis="quarter",
        )

    return PrefabApp(view=view)
```

Prefab apps aren't limited to static displays. Prefab's state system and client-side actions (toggles, tabs, conditionals) all work. You can even call other tools from the UI using `CallTool`. There's no hard wall on what a Prefab app can do.

See [Prefab Apps](/apps/prefab) for the full guide.

## FastMCPApp

<VersionBadge version="3.2.0" />

When your app has a lot of server-side interaction — forms that save data, search that queries a database, multi-step workflows — managing the connection between UI and backend tools gets complicated fast. Which tools should the model see vs. only the UI? What happens to tool references when servers are composed under namespaces? How do you keep `CallTool("save_contact")` working when the tool name changes?

`FastMCPApp` is a class that solves these problems. It gives you two decorators that work together:

- **`@app.ui()`** — entry-point tools the model calls to open the app
- **`@app.tool()`** — backend tools the UI calls via `CallTool`

Backend tools get stable identifiers that survive namespacing, visibility is managed automatically (the model sees entry points, the UI sees backends), and `CallTool` accepts tool names that resolve correctly regardless of how servers are composed:

```python
from prefab_ui.actions import SetState, ShowToast
from prefab_ui.actions.mcp import CallTool
from prefab_ui.app import PrefabApp
from prefab_ui.components import (
    Column, Heading, Form, Input, Button, ForEach, Row, Text, Badge, Separator,
)
from prefab_ui.rx import RESULT
from fastmcp import FastMCP, FastMCPApp

app = FastMCPApp("Contacts")


@app.tool()
def save_contact(name: str, email: str) -> list[dict]:
    """Save a contact and return the updated list."""
    db.append({"name": name, "email": email})
    return list(db)


@app.ui()
def contact_manager() -> PrefabApp:
    """Open the contact manager."""
    with Column(gap=6, css_class="p-6") as view:
        Heading("Contacts")
        with ForEach("contacts") as contact:
            with Row(gap=2):
                Text(contact.name)
                Badge(contact.email)
        Separator()
        with Form(
            on_submit=CallTool(
                "save_contact",
                on_success=[
                    SetState("contacts", RESULT),
                    ShowToast("Saved!", variant="success"),
                ],
            )
        ):
            Input(name="name", label="Name", required=True)
            Input(name="email", label="Email", required=True)
            Button("Save")

    return PrefabApp(view=view, state={"contacts": list(db)})


mcp = FastMCP("Server", providers=[app])
```

You *can* build server-interactive UIs without `FastMCPApp` — it's all the same protocol underneath. But once you have multiple tools, composition concerns, or visibility requirements, `FastMCPApp` handles the complexity so you don't have to.

See [FastMCPApp](/apps/interactive-apps) for the full guide.

## Generative UI

<VersionBadge version="3.2.0" />

Instead of pre-building a UI, the LLM can write one from scratch. The `GenerativeUI` provider registers tools that let the model write Prefab Python code, execute it in a sandbox, and render the result — with streaming so the user watches the UI build up in real time.

```python
from fastmcp import FastMCP
from fastmcp.apps.generative import GenerativeUI

mcp = FastMCP("Prefab Studio")
mcp.add_provider(GenerativeUI())
```

See [Generative UI](/apps/generative) for the full guide.

## Which Approach?

Most apps start with **[Prefab Apps](/apps/prefab)** — add `app=True` to a tool and return components. That covers charts, tables, dashboards, and client-side interactivity.

When your UI needs multiple backend tools with managed visibility and composition safety, use **[FastMCPApp](/apps/interactive-apps)**.

When you want the LLM to design the UI at runtime, use **[Generative UI](/apps/generative)**.

When you need your own HTML/JS (maps, 3D, video), use **[Custom HTML](/apps/low-level)**.

## Custom HTML Apps

All the approaches above use [Prefab UI](https://prefab.prefect.io) to build UIs in pure Python. If you need full control — your own HTML, CSS, JavaScript, a specific framework — you can use the [MCP Apps extension directly](/apps/low-level). You write the HTML yourself and communicate with the host via the [`@modelcontextprotocol/ext-apps`](https://github.com/modelcontextprotocol/ext-apps) SDK.

## Previewing Apps Locally

The `fastmcp dev apps` command launches a browser-based preview for your app tools — no MCP host client needed. See [Development](/apps/development).

```bash
fastmcp dev apps server.py
```
