At the MCP Dev Summit, we announced Prefab, a new UI framework for building interactive applications… in Python.
It turns out that composing frontends in Python is blasphemous surprisingly natural.
Here’s a quick example (try it!):
It looks pretty standard, even a little boring, until you look at the code that generated it:
from prefab_ui.components import *from prefab_ui.rx import Rx
name = Rx("name").default("world")
with Card():
with CardContent(): with Column(gap=3): H3(f"Hello, {name}!") Muted("Type below and watch this update in real time.") Input(name="name", placeholder="Your name...")
with CardFooter(): with Row(gap=2): Badge(f"Name: {name}", variant="default") Badge("Prefab", variant="success")You can edit this code and see changes live in the Prefab Playground. Every example in this blog post has a Playground link for you to explore!
As a front-end DSL, Python is both token-efficient and streaming-compatible. Context managers turn out to be a remarkably straightforward way to express a component hierarchy: the indentation is the layout. Rx variables handle the reactive state; that Rx("name") in the code above is a live binding to the input field, which is why the heading updates as you type (even through f-strings).
The possibilities are kind of endless:
See the Python code and edit this example live in the Prefab Playground →
Why Prefab?
MCP Apps are one of the most exciting things happening in MCP right now, letting a server ship a fully interactive UI to its users that renders right inside the conversation. I really wanted to bring this to FastMCP, in part because I think the feature is amazing, and in part because we want to make sure our users aren’t left out.
But what does it actually mean for a Python framework to integrate with a frontend feature? The answer depends on what you’re building. Most people still think of MCP as a way to reach customers, but what we at Prefect overwhelmingly see is companies deploying MCP to replace internal tools, workflows, and dashboards. And for that, Python developers don’t need the full JavaScript ecosystem. They need the right components.
Our north star with Prefab is composition, not construction: compose existing components into powerful interactive applications, rather than constructing a brand new UI from scratch. That turns out to deliver the first truly delightful frontend experience I’ve had in Python.
Prefab ships more than 100 prebuilt components built on shadcn/ui. You compose them into a declarative hierarchy using context managers, and the result serializes to a JSON protocol that gets rendered as a full React application. Python is the authoring layer. The output knows nothing about Python.
Beyond components
Prefab has a full actions system for client-side interactivity with no JavaScript. Components expose hooks like on_click, on_change, and on_success, and you can chain multiple actions together: update state, hit an API, call a tool, show a notification, navigate, all in sequence. Actions are declarative, so they serialize safely alongside the rest of the UI.
See the Python code and edit this example live in the Prefab Playground →
There’s also a full reactive state system. Rx variables are reactive references that you can bind to form inputs and interpolate into component values. They survive f-string transformations, so H3(f"Hello, {name}!") actually updates live as the variable changes. They support formatting pipes like .currency() and .truncate(20), basic math and comparisons, index operations, and ternary conditionals. You can express a lot of client-side logic without writing any JavaScript.
Here’s a slider driving a ring chart, four progress bars, and a text label, all reactively bound through Rx expressions:
See the Python code and edit this example live in the Prefab Playground →
And we have control flow: ForEach for loops, If/Else for conditional rendering, SetInterval for timers and delays. Between the actions, the reactive state, and the control flow, you can build genuinely interactive applications that respond to user input, communicate with backends, and manage complex state, all from a Python declaration.
Here’s conditional rendering driven by toggle switches:
See the Python code and edit this example live in the Prefab Playground →
And a dynamic list with add/remove, powered by ForEach:
See the Python code and edit this example live in the Prefab Playground →
MCP Apps
Prefab was built from the ground up for MCP Apps, and FastMCP has a native integration that supports a wide variety of applications. There are three ways to use it.
Interactive tools
The simplest way to build an interactive application in FastMCP is to return any Prefab component or app from a tool and set app=True. FastMCP will automatically compile, serialize, and render the application when the agent calls that tool.
For example, the following tool takes a fairly traditional pattern of loading rows from a database, and wraps them in an interactive data table component that will be shown directly to the user:
from prefab_ui.components import DataTable
@mcp.tool(app=True)def team_directory(department: str) -> DataTable: employees = db.query(department) return DataTable( data=[ {"name": e.name, "role": e.role, "email": e.email} for e in employees ] )Interactive tools are perfect when you want to present information visually rather than dumping it into the context window. See the FastMCP Apps docs for the full guide.
FastMCP Apps
Returning UIs from tools is extremely convenient, but wiring those UIs up to other tools requires some coordination. FastMCP App is a utility class that makes it easy to turn your MCP server into a full backend for your application. It exposes two entry points: @app.ui() returns the main UI, and @app.tool() defines backend tools that the UI can call directly.
from fastmcp import FastMCP, FastMCPAppmcp = FastMCP()app = FastMCPApp("Contacts")
@app.ui()def show_contacts(): return DataTable(contacts)
@app.tool()def save_contact(name: str, email: str): db.save(name, email)
mcp.add_provider(app)Generative UI
The last way to expose Prefab on your MCP server is as a fully generative endpoint, where your agent writes valid Prefab code and the MCP App renders it live.
Prefab’s JSON serialization was originally intended to be written by LLMs. But we quickly realized that the Python DSL itself was a far better, more compact, and more streamlined agent-friendly authoring format. It also supports streaming naturally, because Python context managers don’t require closing tags the way JSON does.
Best of all: while an LLM needs a skill or instruction manual to learn the available components, it already knows how to write Python. The Prefab DSL is Pythonic enough that LLMs grok it extremely quickly from a few examples.
That means we can expose an endpoint where LLMs write Prefab code, execute it in a sandbox, and render UIs on the fly. Here’s an early video of Claude streaming an example dashboard as an MCP App:
We ship a generative UI provider with a batteries-included implementation that includes not only the generative endpoint, but tools that an agent can use to learn about the full spectrum of Prefab components:
from fastmcp import FastMCPfrom fastmcp.apps.generative_ui import GenerativeUI
mcp = FastMCP()
mcp.add_provider(GenerativeUI())Generative UI doesn’t have to be streaming… but it’s cooler when it is. I’m very interested in what happens when we combine this with custom component libraries, which we’ll be doing in a near-term release.
Theming
Because Prefab is built on shadcn/ui, theming feels native rather than locked into Prefab itself. You can customize colors, typography, and component styles using the same patterns you’d use in any shadcn project.
One of my favorites is the presentation theme, which generates clean single-component slides. A colleague recently used it to give an entire presentation built in Prefab.
See the Python code and edit this example live in the Prefab Playground →
Lightweight and embeddable
Prefab doesn’t require a server. The output is a self-contained application that you can open in a browser, embed in an iframe, or deploy to any static host.
As you’ve obviously noticed, almost every interactive demo in this blog post is a real Prefab application, created by running prefab export on a Python file and embedded as an iframe. The Prefab docs work the same way: every component page shows a live preview alongside the Python code that produced it, the corresponding protocol JSON, and a link to edit it live in the Prefab Playground.
Get started
You can try Prefab right now! It’s really easy to get started. I gave a preview of it at a conference a few weeks ago, and a few people in the audience managed to build their first apps before the talk was over.
- Give us a star on GitHub ⭐
- Read the Documentation
- Try the Prefab Playground
pip install prefab-uiPlease note that Prefab is under active development and evolving quickly.
Happy (generative) engineering!
Subscribe
Comments
Join the conversation by posting on social media.
No comments yet...
🦗🦗🦗