From workshop-skills
Add Generative UI to a FastMCP server — let the LLM author Prefab UIs at runtime instead of pre-building tools. ONLY use this skill when the user explicitly asks about "generative UI", "genui", `GenerativeUI`, `generate_prefab_ui`, `search_prefab_components`, or "let the LLM build the UI". Do NOT use this when the user just wants more dashboards, forms, or charts — that's the `prefab` skill (Stage 2). This is Stage 3 of the workshop and assumes the `prefab` skill's setup is already done.
How this skill is triggered — by the user, by Claude, or both
Slash command
/workshop-skills:genuiThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Workshop Stage 3. Stage 1 = scaffold, Stage 2 = hard-coded Prefab apps, **Stage 3 = let the LLM author UIs from data**.
Workshop Stage 3. Stage 1 = scaffold, Stage 2 = hard-coded Prefab apps, Stage 3 = let the LLM author UIs from data.
Skip this skill unless the user explicitly asks about Generative UI / GenerativeUI / streaming model-authored Prefab. For pre-built dashboards/forms, use the prefab skill instead.
fastmcp.apps.generative.GenerativeUI is a single provider that registers two MCP tools:
generate_prefab_ui(code, data=...) — model writes Prefab Python; runs in browser-side Pyodide for streaming preview, then validated server-side (Deno + Pyodide).search_prefab_components(query, detail=False) — model discovers what Prefab components exist before writing code.The provider also adds a ui://prefab/generative.html resource (the streaming renderer) and configures CSP automatically.
from fastmcp import FastMCP
from fastmcp.apps.generative import GenerativeUI
mcp = FastMCP("My Server", providers=[GenerativeUI()])
# or, on an existing server:
# mcp.add_provider(GenerativeUI())
Coexists fine with @mcp.tool(app=True) display tools and FastMCPApp providers — just append to the providers list.
GenerativeUI is useless if the model can't get raw data. Pre-built Prefab tools that return only ToolResult(structured_content=view, ...) give the model rendered UI, not queryable rows. Add at least one plain @mcp.tool that returns structured data (list of dicts) the model can pass into generate_prefab_ui's data= parameter.
@mcp.tool
def query_transactions(month: str | None = None, category: str | None = None) -> list[dict]:
"""Return transactions as raw rows the model can analyze or feed to generate_prefab_ui."""
rows = data.TRANSACTIONS
if month:
rows = [t for t in rows if t.date.startswith(month)]
if category:
rows = [t for t in rows if t.category == category]
return [{"date": t.date, "merchant": t.merchant, "amount": t.amount, ...} for t in rows]
If you skip this step the user will see Claude say "I'd be making up numbers — none of your tools return queryable data". Real failure mode from this workshop's first attempt.
fastmcp[apps] already installed (Stage 2 added this).brew install denoAfter restart + reconnect, the model decides on its own to call search_prefab_components and generate_prefab_ui when a request doesn't match a pre-built tool. Useful test prompts:
ImportError if the model tries.css_class, data_key, x_axis) inside the sandbox. That's fine — ty doesn't see sandboxed code. The host server code still uses camelCase per the prefab skill.When teaching or demoing, present the three stages in order:
| Stage | What you build | Skill |
|---|---|---|
| 1 | scaffold a FastMCP server (uv/just/ruff/ty/pydantic-settings, stdio + HTTP) | scaffolding-python-repo |
| 2 | hard-code 2–3 Prefab apps over a fake dataset (display + form) | prefab |
| 3 | bolt on GenerativeUI + a query_* data tool, install Deno | genui (this one) |
Don't jump to Stage 3 first — the contrast with hard-coded apps is the point. People appreciate generative UI more after they've felt the friction of pre-building every chart they might want.
GenerativeUI only matters in a host that actually renders Prefab — that means Claude Desktop (or fastmcp dev apps for local preview). If the user hasn't registered the server yet, prompt: "To try GenUI in Claude Desktop, the server needs an entry in claude_desktop_config.json — want me to add it?" and follow connecting-to-claude-desktop. After the entry exists, a full Cmd-Q + relaunch is still required for newly-added tools to appear.
npx claudepluginhub vibber-ai/workshop-skills --plugin workshop-skillsCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.