The Interaction Loop
The core mental model is a cycle between your server and the host’s renderer:- A tool returns a component tree (as a
Componentor wrapped inAppResult) - The renderer displays it in the host application
- The user interacts — clicks a button, fills an input, moves a slider
- That interaction triggers an action: either an instant client-side state change, or a server round-trip via
ToolCall - The server tool returns a new view, and the renderer updates the display
Getting Started
Mark a tool withui=True to enable UI rendering. This tells FastMCP to register the built-in renderer resource that the host needs to display your components.
The simplest pattern returns a component directly from the tool:
AppResult instead:
ToolCall action calls the search tool again with the current input value. The tool returns a new view with the results, and the renderer replaces the display.
State
Every named form control automatically syncs its value to client-side state. When a user types inInput(name="city"), the key city is updated on every keystroke. No explicit wiring needed.
You can reference state values in actions and component props using {{ key }} interpolation:
For state that does not come from a form control, use AppResult(state={...}) to seed initial values, and SetState or ToggleState to mutate them from interactions.
Actions
Actions define what happens when a user interacts with a component. There are two categories. Client actions execute instantly with no server round-trip:| Action | Purpose |
|---|---|
SetState | Set a state variable to a value |
ToggleState | Flip a boolean state variable |
ShowToast | Display a toast notification |
OpenLink | Open a URL in the host’s browser |
| Action | Purpose |
|---|---|
ToolCall | Call a server tool and update the view with the result |
SendMessage | Send a message to the chat as if the user typed it |
UpdateContext | Silently update structured data the model can see |
Components
FastMCP includes 30+ components spanning layout, form controls, data display, and feedback. Layout containers use Python context managers for nesting: See the component reference pages in the sidebar for the full catalog, and the Playground to try components interactively.The ui=True Flag
Adding ui=True to @mcp.tool() does two things:
- Registers a built-in renderer resource on the server, which the host reads to get the JavaScript needed to display your components
- Marks the tool’s output as renderable, so the host knows to pass it to the renderer instead of displaying raw text
ui=True can return either a Component instance directly (for simple displays) or an AppResult (when you need state management or a text fallback for non-UI hosts).