mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-22 05:24:18 +02:00
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Jeremiah Lowin <jlowin@users.noreply.github.com> Co-authored-by: Marvin Context Protocol <41898282+Marvin Context Protocol@users.noreply.github.com> Co-authored-by: voidborne-d <voidborne-d@users.noreply.github.com> Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: d 🔹 <258577966+voidborne-d@users.noreply.github.com> Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Co-authored-by: nightcityblade <nightcityblade@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Bill Easton <strawgate@users.noreply.github.com> Co-authored-by: Sumanshu Nankana <sumanshunankana@gmail.com> Co-authored-by: Eric Robinson <ericrobinson@indeed.com> Co-authored-by: Martim Santos <martimfasantos@gmail.com> Co-authored-by: d 🔹 <liusway405@gmail.com> Co-authored-by: Matthieu B <66959271+mtthidoteu@users.noreply.github.com> Co-authored-by: Sascha Buehrle <47737812+saschabuehrle@users.noreply.github.com> Co-authored-by: Hakancan <142545736+hkc5@users.noreply.github.com> Co-authored-by: nightcityblade <jackchen@haloailabs.com> Co-authored-by: Matt Hallowell <17804673+mhallo@users.noreply.github.com> Co-authored-by: nate nowack <thrast36@gmail.com> Co-authored-by: Bill Easton <williamseaston@gmail.com> Co-authored-by: Marcus Shu <46469249+shulkx@users.noreply.github.com> Co-authored-by: Rushabh Doshi <radoshi@gmail.com> Co-authored-by: AIKAWA Shigechika <shige@aikawa.jp> Co-authored-by: Jeremy Simon <simonjer805@gmail.com> Co-authored-by: Miguel Miranda Dias <7780875+pandego@users.noreply.github.com> Co-authored-by: Anthony James Padavano <padavano.anthony@gmail.com> Co-authored-by: Mostafa Kamal <hiremostafa@gmail.com> Fix auto-close MRE script posting comment without closing (#3386) Fix WorkOS token scope verification bypass 🤖 Generated with Codex (#3407) Fix initialize McpError fallthrough 🤖 Generated with Codex (#3413) Fix transform arg collisions with passthrough params (#3431) Fix get_* returning None when latest version is disabled (#3439) Fix get_* returning None when latest version is disabled (#3421) Fix server lifespan overlap teardown (#3415) Fix $ref output schema object detection regression (#3420) resolved annotations (#3429) Fix async partial callables rejected by iscoroutinefunction (#3438) Fix async partial callables rejected by iscoroutinefunction (#3423) fix: add version to components (#3458) fix: use intent-based flag for OIDC scope patch in load_access_token (#3465) Fixes #3461 fix: normalize Google scope shorthands and surface valid_scopes (#3477) fix: resolve ty 0.0.23 type-checking errors and bump pin (#3481) fix: shield lifespan teardown from cancellation (#3480) fix: forward custom_route endpoints from mounted servers (#3462) fix updates _get_additional_http_routes() to traverse providers, Fixes #3457 fix: remove hardcoded version from CLI help text (#3456) fix: monty 0.0.8 compatibility, drop external_functions from constructor (#3468) fix: task test teardown hanging 5s per test (#3499) Closes #3498 fix: validate workspace path is a directory before cursor install (#3440) Fixes #3426 fix: handle re.error from malformed URI templates in build_regex (#3501) fix: reject empty/OIDC-only required_scopes in AzureProvider (#3503) fix: restrict $ref resolution to local refs only (SSRF/LFI) (#3502) fix warnings and timeouts (#3504) close upgrade check issue when build passes (#3505) Closes #3484 fix: URL-encode path params to prevent SSRF/path traversal (GHSA-vv7q-7jx5-f767) (#3507) fix: prevent path traversal in skill download (#3493) fix: prefer IdP-granted scopes over client-requested scopes in OAuthProxy (#3492) fix: remove unrelated transform and http.py changes from PR scope fix: remove forced follow_redirects from httpx_client_factory calls (#3496) fix: stop passing follow_redirects to httpx_client_factory fix: restore follow_redirects=True for custom httpx client factories Closes #3509 fix: CSRF double-submit cookie check in consent flow (#3519) fix: validate server names in install commands (#3522) fix: use raw strings for regex in pytest.raises match (#3523) fix: reject refresh tokens used as Bearer access tokens (#3524) fix: route ResourcesAsTools/PromptsAsTools through server middleware (#3495) fix: resolve Pyright "Module is not callable" on @tool, @resource, @prompt decorators (#3540) fix: filter warnings by message in KEY_PREFIX test (#3549) fix: suppress output schema for ToolResult subclass annotations (#3548) fix: increase sleep duration in proxy cache tests (#3567) fix: store absolute token expiry to prevent stale expires_in on reload (#3572) fix: preserve tool properties named 'title' during schema compression (#3582) Fix loopback redirect URI port matching per RFC 8252 §7.3 (#3589) Fix app tool routing: visibility check and middleware propagation (#3591) Fix query parameter serialization to respect OpenAPI explode/style settings (#3595) Fix dev apps form: union types, textarea support, JSON parsing (#3597) fix(google): replace deprecated /oauth2/v1/tokeninfo with /oauth2/v3/userinfo (#3603) fix: resolve EntraOBOToken dependency injection through MultiAuth (#3609) fix(docs): correct misleading stateless_http header (#3622) fix: filesystem provider import machinery (#3626) Closes #3625 (issues 2, 3, 6) fix: recover StdioTransport after subprocess exits (#3630) fix(server): preserve mounted tool task metadata (#3632) fix: scope deprecation warning filter to FastMCPDeprecationWarning (#3649) fix imports, add PrefabAppConfig (#3650) fix: resolve CurrentFastMCP/ctx.fastmcp to child server in mounted background tasks (#3651) Fix blocking docs issues: chart imports, Select API, Rx consistency (#3652) closed by default (#3657) Fix prompt caching middleware missing wrap/unwrap round-trip (#3666) fix: serialize object query params per OpenAPI style/explode rules (#3662) Fixes #2857 fix: HTTP request headers not accessible in background task workers (#3631) fix: restore HTTP headers in worker execution path for background tasks (#3681) fix: strip discriminator after dereferencing schemas (#3682) fix: remove stale ty:ignore directives for ty 0.0.26 (#3684) Fix docs gaps in app provider pages (#3690) fix: dev apps log panel UX improvements (#3698) fix dev server empty string args (#3700)
181 lines
7.4 KiB
Text
181 lines
7.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 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.
|
|
</Note>
|
|
|
|
<Warning>
|
|
FastMCP pins a **minimum** version of `prefab-ui` for compatibility but intentionally does **not** pin an upper bound. Prefab is a rapidly evolving library with frequent breaking changes. If you are deploying to production, you **must** pin `prefab-ui` to a specific version in your own dependencies. Without a pin, a fresh deploy could pull a newer Prefab version that changes component APIs, breaking your app.
|
|
</Warning>
|
|
|
|
## 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)**.
|
|
|
|
FastMCP also includes ready-made **[app providers](/apps/providers/approval)** that add common capabilities with a single `add_provider()` call.
|
|
|
|
## Building Apps
|
|
|
|
### 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, or the [provider reference](/apps/providers/generative) for configuration options.
|
|
|
|
### Custom HTML
|
|
|
|
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
|
|
```
|