app=True and return a component tree or a PrefabApp:
ui:// resource, sets the MCP Apps metadata on your tool, and converts PrefabApp returns to structuredContent in the tool result.
How It Works
The flow has three steps:- Tool call — the host calls your tool via MCP
- PrefabApp → structuredContent — FastMCP serializes your return value into the Prefab JSON envelope (
version,view,state,defs) - Renderer — the host loads the Prefab renderer (from
ui://prefab/renderer.html) and passes it the structured content. The renderer builds the UI.
CallTool sends a new tool call through MCP back to your server. The tool returns a fresh PrefabApp, and the renderer updates.
Returning UI
You can return either aPrefabApp or a bare component. Returning a component is a shorthand — FastMCP wraps it in a PrefabApp automatically.
PrefabApp when you need initial state, a page title, or reusable definitions. Return a bare component for simple, stateless views.
Patterns
Calling Back to the Server
CallTool is the MCP equivalent of Fetch. It sends a tool call through MCP and writes the response into client-side state:
browse) defines the layout with a Slot. The second tool (search) returns a component tree that fills that slot. This is the core MCP Apps pattern: the initial tool sets up the shell, and subsequent tool calls swap content in and out.
search doesn’t need app=True — it’s a helper tool called from within the UI, not an entry point that a host would show directly. FastMCP still auto-wires it because its return type is PrefabApp.Dynamic Component Results with Slot
When aCallTool has result_key, the tool’s PrefabApp response is written into that state key. A Slot watching that key renders whatever component tree arrives:
Slot shows its fallback children until a CallTool populates the state key. This is the same pattern as Dynamic Component Routes in the API Server guide — the server decides what to render, not just what data to return.
Error Handling
If a tool raises an exception, the MCP protocol surfaces it as an error. Useon_error to display it:
Communicating with the Host
BeyondCallTool, MCP Apps can interact with the host conversation using SendMessage and UpdateContext.
SendMessage sends a message to the conversation as if the user typed it — useful for quick-action buttons that trigger follow-up questions:
UpdateContext silently updates what the model knows without creating a visible message. The context is attached to the next conversation turn, so the model can reference it without the user needing to re-explain:
UpdateContext depends on host support. The context is delivered to the host, but whether the model sees it depends on the host’s implementation of the MCP Apps ui/update-model-context method.Tool Visibility
By default, all tools registered on your server are visible to the model — including helper tools meant only for UI interactions. When the model can see tools likesearch or delete_item, it may call them directly instead of letting the user interact through the UI.
Use AppConfig(visibility=["app"]) to mark tools as app-only. These tools remain callable via CallTool from the UI, but the host should exclude them when presenting tools to the model:
app=True so the model can invoke it. Helper tools use AppConfig(visibility=["app"]) so they’re accessible to CallTool but won’t appear in the model’s tool list.
Tool visibility is metadata that the host is responsible for enforcing. The server returns all tools from
tools/list regardless of visibility — the host filters based on the visibility field in the tool’s app metadata.API Server vs FastMCP
Both use the same components and state model. The difference is transport:| FastMCP | API Server | |
|---|---|---|
| Transport | MCP protocol | HTTP (fetch) |
| Server action | CallTool | Fetch |
| Host actions | SendMessage, UpdateContext | — |
| Hosting | Inside Claude Desktop, ChatGPT, etc. | Standalone web page |
| Renderer | Provided by the MCP host | Bundled in PrefabApp.html() |
CallTool. If you’re building a web app, use Fetch. SendMessage and UpdateContext are MCP-only — they communicate with the host’s conversation, which doesn’t exist in standalone mode. The component tree and client-side actions are identical either way.
Example App
Theexamples/hitchhikers-guide directory contains a complete working MCP server — a Hitchhiker’s Guide catalog with search, dialog-based entry creation, inline deletion, and error handling. The same directory also contains a FastAPI version of the same app for comparison.