mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-16 18:49:14 +02:00
* Comprehensive MCP Apps docs, string CallTool resolution, bump prefab-ui >=0.13.0
Rewrites the apps documentation as a learning journey: overview → Prefab apps
→ FastMCPApp → patterns → dev tools → custom HTML. Adds a new FastMCPApp page
covering composable apps with @app.tool()/@app.ui(), CallTool, forms, actions,
and composition. Teaches Rx() and set_initial_state() as the primary state API.
Adds string-based CallTool resolution so CallTool("save_contact") resolves to
the tool's global key, matching callable ref behavior. Requires prefab-ui 0.13.0
which passes strings through the tool resolver.
* Detect ambiguous string CallTool resolution across apps
* Simplify string name registry to plain dict (last-write-wins)
155 lines
6.4 KiB
Text
155 lines
6.4 KiB
Text
---
|
|
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 Apps let tools return interactive UIs — charts, sortable tables, forms, dashboards — rendered in a sandboxed iframe inside the host client's conversation.
|
|
|
|
FastMCP implements the [MCP Apps extension](https://modelcontextprotocol.io/docs/extensions/apps) and gives you two ways to build interactive UIs with [Prefab](https://prefab.prefect.io), depending on how much server-side interaction you need.
|
|
|
|
<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. You return a [Prefab](https://prefab.prefect.io) component or `PrefabApp` from an otherwise standard MCP tool, and when the host calls it, the app is rendered instead of plain text:
|
|
|
|
```python
|
|
from prefab_ui.app import PrefabApp
|
|
from prefab_ui.components import Column, Heading, 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` with string names. 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 global identifiers that survive namespacing, visibility is managed automatically (the model sees entry points, the UI sees backends), and `CallTool` accepts function references instead of string names:
|
|
|
|
```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.
|
|
|
|
## Which Approach?
|
|
|
|
| Scenario | Approach |
|
|
| -------- | -------- |
|
|
| Visual output — charts, tables, status dashboards | [Prefab app](/apps/prefab) — `@mcp.tool(app=True)` |
|
|
| Client-side interactivity — toggles, tabs, conditionals | [Prefab app](/apps/prefab) — state + `Rx()` |
|
|
| Light server interaction — one or two tool calls | [Prefab app](/apps/prefab) — `CallTool("tool_name")` |
|
|
| Heavy server interaction — forms, CRUD, search, multi-step | [FastMCPApp](/apps/interactive-apps) — managed tool binding |
|
|
| Composed servers — apps mounted under namespaces | [FastMCPApp](/apps/interactive-apps) — stable global keys |
|
|
| Custom rendering — maps, 3D, specific JS frameworks | [Custom HTML](/apps/low-level) — raw MCP Apps extension |
|
|
|
|
The boundary isn't sharp. Start with a Prefab app; graduate to `FastMCPApp` when the tool-management complexity justifies it.
|
|
|
|
## Custom HTML Apps
|
|
|
|
Both 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
|
|
```
|