- Prefab
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/apps/demos/contacts.html b/docs/apps/demos/contacts.html
deleted file mode 100644
index 5831d639c..000000000
--- a/docs/apps/demos/contacts.html
+++ /dev/null
@@ -1,172 +0,0 @@
-
-
-
- Prefab
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/apps/demos/dashboard.html b/docs/apps/demos/dashboard.html
deleted file mode 100644
index 21c1c8924..000000000
--- a/docs/apps/demos/dashboard.html
+++ /dev/null
@@ -1,157 +0,0 @@
-
-
-
- Prefab
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/apps/demos/data-table.html b/docs/apps/demos/data-table.html
deleted file mode 100644
index fe84abcd4..000000000
--- a/docs/apps/demos/data-table.html
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
- Prefab
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/apps/demos/hitchhikers.html b/docs/apps/demos/hitchhikers.html
deleted file mode 100644
index 7f26f9796..000000000
--- a/docs/apps/demos/hitchhikers.html
+++ /dev/null
@@ -1,1105 +0,0 @@
-
-
-
- Prefab Showcase
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/apps/demos/pie-chart.html b/docs/apps/demos/pie-chart.html
deleted file mode 100644
index c712eeb33..000000000
--- a/docs/apps/demos/pie-chart.html
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
- Prefab
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/apps/demos/reactive.html b/docs/apps/demos/reactive.html
deleted file mode 100644
index 29f05e2d3..000000000
--- a/docs/apps/demos/reactive.html
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
-
- Prefab
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/apps/demos/team-directory-reactive.html b/docs/apps/demos/team-directory-reactive.html
deleted file mode 100644
index f2ab5bf7e..000000000
--- a/docs/apps/demos/team-directory-reactive.html
+++ /dev/null
@@ -1,237 +0,0 @@
-
-
-
- Prefab
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/apps/demos/team-directory.html b/docs/apps/demos/team-directory.html
deleted file mode 100644
index be577ddde..000000000
--- a/docs/apps/demos/team-directory.html
+++ /dev/null
@@ -1,127 +0,0 @@
-
-
-
- Prefab
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/apps/fastmcp-app.mdx b/docs/apps/fastmcp-app.mdx
index f3463da66..55b3b7ed7 100644
--- a/docs/apps/fastmcp-app.mdx
+++ b/docs/apps/fastmcp-app.mdx
@@ -8,12 +8,13 @@ tag: NEW
import { VersionBadge } from '/snippets/version-badge.mdx'
import PrefabPinWarning from '/snippets/prefab-pin-warning.mdx'
+import { PrefabDemoFrame } from '/snippets/prefab-demo-frame.mdx'
-
+
Search a list, fill out a form, click save, the list updates. That pattern — UI that reads and writes data on the server — needs two things: backend tools that actually do the work, and a way to call them from the UI. `FastMCPApp` handles the wiring.
diff --git a/docs/apps/overview.mdx b/docs/apps/overview.mdx
index ed04580f6..ff9557058 100644
--- a/docs/apps/overview.mdx
+++ b/docs/apps/overview.mdx
@@ -8,6 +8,7 @@ mode: center
import { VersionBadge } from '/snippets/version-badge.mdx'
import PrefabPinWarning from '/snippets/prefab-pin-warning.mdx'
+import { PrefabDemoFrame } from '/snippets/prefab-demo-frame.mdx'
@@ -21,7 +22,7 @@ A FastMCP app is a tool that returns an interactive UI instead of text. When the
maskImage: 'linear-gradient(to bottom, black 75%, transparent)',
WebkitMaskImage: 'linear-gradient(to bottom, black 75%, transparent)',
}}>
-
+
The dashboard above is a [Prefab](https://prefab.prefect.io) showcase — a taste of what you can deliver from a FastMCP tool. Every card, chart, slider, dialog, and carousel is a Python component. Build a composition like this, add `@mcp.tool(app=True)`, and the host renders it inside the conversation.
diff --git a/docs/apps/prefab.mdx b/docs/apps/prefab.mdx
index 1bebc73de..e6ff7070f 100644
--- a/docs/apps/prefab.mdx
+++ b/docs/apps/prefab.mdx
@@ -8,12 +8,13 @@ tag: NEW
import { VersionBadge } from '/snippets/version-badge.mdx'
import PrefabPinWarning from '/snippets/prefab-pin-warning.mdx'
+import { PrefabDemoFrame } from '/snippets/prefab-demo-frame.mdx'
-
+
Believe it or not, that dashboard is a FastMCP tool. The chart has tooltips. The table is sortable. The badges are styled by deal stage. The whole thing is about 40 lines of Python, and the user sees it right inside their conversation instead of a wall of JSON.
@@ -23,7 +24,7 @@ The pattern behind every example on this page is the same: add `app=True` to you
Most tools return data the user wants to explore. A `DataTable` is often the smallest useful upgrade — your data goes from a JSON blob to a searchable, sortable table:
-
+
```python
from prefab_ui.components import DataTable, DataTableColumn
@@ -62,7 +63,7 @@ That's it. Add `app=True`, return a Prefab component instead of raw dicts. FastM
When numbers tell a better story as a visual, swap in a chart. The API is the same: pass your data as a list of dicts, tell the chart which keys to plot.
-
+
```python
@mcp.tool(app=True)
@@ -88,7 +89,7 @@ def quarterly_revenue(year: int) -> BarChart:
Each `ChartSeries` plots a different key from the data. `BarChart`, `LineChart`, `AreaChart`, `PieChart`, `RadarChart`, and `RadialChart` all follow the same pattern. Hover over the bars to see tooltips.
-
+
```python
@mcp.tool(app=True)
@@ -116,7 +117,7 @@ See the [Prefab chart docs](https://prefab.prefect.io/docs/components) for stack
Tables and charts are useful on their own, but the real power comes from composing them. `Column` stacks children vertically, `Row` lays them out side by side, and `with` blocks establish nesting — the indentation is the layout.
-
+
```python expandable
@mcp.tool(app=True)
@@ -184,7 +185,7 @@ Notice how `Badge` components can be placed inside table cells — any Prefab co
Everything above renders once from the data your Python provides. But interactive tools can also respond to user input in real time, without any server round-trips. Prefab's state system lets components read and write client-side values, so the UI updates instantly as the user interacts with it.
-
+
Try switching regions in the dropdown, and toggling the switch on and off.
diff --git a/docs/apps/quickstart.mdx b/docs/apps/quickstart.mdx
index 7b87d1981..2221b9de9 100644
--- a/docs/apps/quickstart.mdx
+++ b/docs/apps/quickstart.mdx
@@ -7,12 +7,13 @@ tag: NEW
---
import { VersionBadge } from '/snippets/version-badge.mdx'
+import { PrefabDemoFrame } from '/snippets/prefab-demo-frame.mdx'
By the end of this page, you'll have a working tool that returns this:
-
+
A pie chart the user can hover, a table they can sort and search — and a single Python tool.
@@ -103,7 +104,7 @@ The UI above renders once from your Python. Prefab apps can also respond to user
Click a row in the demo below to see a detail card appear:
-
+
Add a few imports, give each member a couple more fields, wire up a click handler, and render a detail card when something's selected:
diff --git a/docs/prefab-demo-payloads.js b/docs/prefab-demo-payloads.js
new file mode 100644
index 000000000..885ce713b
--- /dev/null
+++ b/docs/prefab-demo-payloads.js
@@ -0,0 +1 @@
+window.__FASTMCP_PREFAB_DEMOS__ = {"bar-chart":"\n\n\n Prefab\n \n \n \n \n\n\n \n \n\n","contacts":"\n\n\n Prefab\n \n \n \n \n\n\n \n \n\n","dashboard":"\n\n\n Prefab\n \n \n \n \n\n\n \n \n\n","data-table":"\n\n\n Prefab\n \n \n \n \n\n\n \n \n\n","hitchhikers":"\n\n\n Prefab Showcase\n \n \n \n \n\n\n \n \n\n","pie-chart":"\n\n\n Prefab\n \n \n \n \n\n\n \n \n\n","reactive":"\n\n\n Prefab\n \n \n \n \n\n\n \n \n\n","team-directory-reactive":"\n\n\n Prefab\n \n \n \n \n\n\n \n \n\n","team-directory":"\n\n\n Prefab\n \n \n \n \n\n\n \n \n\n"};
diff --git a/docs/snippets/prefab-demo-frame.mdx b/docs/snippets/prefab-demo-frame.mdx
new file mode 100644
index 000000000..c7d639ece
--- /dev/null
+++ b/docs/snippets/prefab-demo-frame.mdx
@@ -0,0 +1,66 @@
+export const PrefabDemoFrame = ({ demo, height, title }) => {
+ const [blobUrl, setBlobUrl] = React.useState(null);
+
+ React.useEffect(() => {
+ let active = true;
+ let objectUrl = null;
+ let payloadsPromise = window.__FASTMCP_PREFAB_DEMOS_PROMISE__;
+
+ if (window.__FASTMCP_PREFAB_DEMOS__) {
+ payloadsPromise = Promise.resolve(window.__FASTMCP_PREFAB_DEMOS__);
+ } else if (!payloadsPromise) {
+ payloadsPromise = new Promise((resolve, reject) => {
+ const script = document.createElement("script");
+ script.src = "/prefab-demo-payloads.js";
+ script.onload = () => resolve(window.__FASTMCP_PREFAB_DEMOS__);
+ script.onerror = reject;
+ document.head.appendChild(script);
+ });
+ window.__FASTMCP_PREFAB_DEMOS_PROMISE__ = payloadsPromise;
+ }
+
+ payloadsPromise
+ .then((payloads) => {
+ const html = payloads[demo];
+ if (!html) {
+ throw new Error(`Unknown Prefab demo: ${demo}`);
+ }
+ objectUrl = URL.createObjectURL(
+ new Blob([html], { type: "text/html" }),
+ );
+ if (active) {
+ setBlobUrl(objectUrl);
+ } else {
+ URL.revokeObjectURL(objectUrl);
+ }
+ });
+
+ return () => {
+ active = false;
+ if (objectUrl) {
+ URL.revokeObjectURL(objectUrl);
+ }
+ };
+ }, [demo]);
+
+ if (!blobUrl) {
+ return ;
+ }
+
+ return (
+
+ );
+};