3.1.0
Prefab UI is a declarative UI framework for Python. You describe what your interface should look like — a chart, a table, a form — and return it from your tool. FastMCP takes care of everything else: registering the renderer, wiring the protocol metadata, and delivering the component tree to the host.
Prefab started as a component library inside FastMCP and grew into a full framework for building interactive applications — with its own state management, reactive expression system, and action model. The Prefab documentation covers all of this in depth. This page focuses on the FastMCP integration: what you return from a tool, and what FastMCP does with it.
with statement, and return it. When the host calls this tool, the user sees an interactive bar chart instead of a JSON blob. The Patterns page has more examples: area charts, data tables, forms, status dashboards, and more.
What You Return
Components
The simplest way to get started. If you’re returning a visual representation of data and don’t need Prefab’s more advanced features like initial state or stylesheets, just return the components directly. FastMCP wraps them in aPrefabApp automatically:
PrefabApp
When you need more control — setting initial state values that components can read and react to, or configuring the rendering engine — return aPrefabApp explicitly:
state dict provides the initial values. Components reference state with {{ expression }} templates. State mutations like ToggleState happen entirely in the browser — no server round-trip. The Prefab state guide covers this in detail.
ToolResult
Every tool result has two audiences: the renderer (which displays the UI) and the LLM (which reads the text content to understand what happened). By default, Prefab Apps send"[Rendered Prefab UI]" as the text content, which tells the LLM almost nothing.
If you want the LLM to understand the result — so it can reference the data in conversation, summarize it, or decide what to do next — wrap your return in a ToolResult with a meaningful content string:
"Total revenue for 2025: $203,000 across 4 quarters" and can reason about it.
Type Inference
If your tool’s return type annotation is a Prefab type —PrefabApp, Component, or their Optional variants — FastMCP detects this and enables app rendering automatically:
@mcp.tool(app=True). Explicit app=True is recommended for clarity, and is required when the return type doesn’t reveal a Prefab type (e.g., -> ToolResult).
How It Works
Behind the scenes, when a tool returns a Prefab component orPrefabApp, FastMCP:
- Registers a shared renderer — a
ui://prefab/renderer.htmlresource containing the JavaScript rendering engine, fetched once by the host and reused across all your Prefab tools. - Wires the tool metadata — so the host knows to load the renderer iframe when displaying the tool result.
- Serializes the component tree — your Python components become
structuredContenton the tool result, which the renderer interprets and displays.
app=True flag (or type inference) is the only thing you need.
Mixing with Custom HTML Apps
Prefab tools and custom HTML tools coexist in the same server. Prefab tools share a single renderer resource; custom tools point to their own. Both use the same MCP Apps protocol:Next Steps
- Patterns — Charts, tables, forms, and other common tool UIs
- Custom HTML Apps — When you need your own HTML, CSS, and JavaScript
- Prefab UI Docs — Components, state, expressions, and actions

