Generative UI MCP Server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Generative UI MCP Servergenerate a Prefab UI showing a deployment progress card"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Generative UI MCP Server
A ready-to-run FastMCP server that lets an MCP-capable LLM generate ephemeral Prefab interfaces at runtime.
It supports:
STDIO (stdin/stdout), for a local MCP client that launches one process per session.
Legacy SSE, for an older network MCP client at
http://HOST:PORT/sse.Streamable HTTP, included as the recommended network alternative at
http://HOST:PORT/mcp.
MCP documentation calls the local transport STDIO, not “stdout.” Requests arrive on stdin and responses leave on stdout. Never print application logs to stdout while using this mode.
What the server provides
FastMCP's GenerativeUI provider registers:
generate_prefab_ui: executes model-authored Prefab Python in a Pyodide sandbox and returns an MCP App.search_prefab_components: searches the installed Prefab component catalog.A
ui://streaming renderer used by an MCP Apps-compatible host.
The LLM runs in the client/host (for example, Phlox), not in this server. The client gathers data and generates the Python supplied to generate_prefab_ui.
Related MCP server: Agent Bridge for Unity
Prerequisites
Python 3.10 or newer.
uvinstalled and onPATH.An MCP Apps-compatible host. A tool-only MCP client can call these tools and inspect results, but it cannot display the interactive iframe UI unless it implements MCP Apps/AppBridge.
Outbound HTTPS from the browser to the Pyodide CDN for the streaming renderer.
Deno for final server-side Pyodide validation. The FastMCP documentation says it can install Deno on first use, but this pinned package combination reports an actionable error when
denois absent. Install it explicitly for deterministic operation.
Versions are deliberately pinned in pyproject.toml and uv.lock:
fastmcp[apps]==4.0.5prefab-ui==0.20.2
Install
cd generative-ui-mcp
uv syncInstall and verify Deno on macOS/Linux:
./scripts/install-deno.sh
export PATH="$HOME/.deno/bin:$PATH"
deno --versionOn Windows, use the official PowerShell installer:
irm https://deno.land/install.ps1 | iexOpen a new shell after installation. Then verify registration and the component catalog:
uv run pytestPreview an app
FastMCP provides a browser MCP Apps development host:
uv run fastmcp dev apps src/generative_ui_mcp/server.py:mcpOpen http://127.0.0.1:8080, select generate_prefab_ui, select edit as JSON and enter the following:
{
"code": "from prefab_ui.app import PrefabApp\nfrom prefab_ui.components import Card, CardContent, Column, Heading, Progress, Text\n\n\nwith PrefabApp() as app:\n with Column(gap=4, css_class=\"p-6\"):\n Heading(\"Build status\")\n with Card():\n with CardContent():\n Text(\"Deployment is 72% complete\")\n Progress(value=72)\n",
"data": {}
}The development command starts an HTTP MCP server on port 8000 and the preview host on port 8080. It is the easiest way to verify UI rendering before connecting Phlox or another real host.
STDIO mode
STDIO is the default and recommended local-process transport. The MCP client launches the server, communicates over stdin/stdout, and terminates it when the session ends.
Run directly
Any of these commands starts the same STDIO server:
uv run generative-ui-mcp-stdiouv run generative-ui-mcp --transport stdiouv run fastmcp run src/generative_ui_mcp/server.py:mcp --transport stdioThe process appears to wait silently. That is expected: it is waiting for framed MCP messages on stdin.
Client configuration
Copy examples/mcp-stdio.json and replace the project path with an absolute path:
{
"mcpServers": {
"generative-ui": {
"transport": "stdio",
"command": "uv",
"args": [
"--directory",
"/opt/generative-ui-mcp",
"run",
"generative-ui-mcp-stdio"
]
}
}
}Some clients omit the explicit transport field and infer STDIO from command and args.
Important logging rule
Do not use print() for diagnostics in STDIO mode because stdout carries the MCP protocol. Use Python logging, which writes to stderr by default:
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
logger.info("This goes to stderr")Legacy SSE mode
SSE is FastMCP's older network transport. It remains useful for clients that explicitly require it, but FastMCP recommends Streamable HTTP for new network deployments.
Start SSE
uv run generative-ui-mcp-sseThe default endpoint is:
http://127.0.0.1:8000/sseConfigure another address through environment variables:
MCP_HOST=0.0.0.0 \
MCP_PORT=9000 \
MCP_SSE_PATH=/sse \
uv run generative-ui-mcp-sseOr use the unified command:
uv run generative-ui-mcp \
--transport sse \
--host 0.0.0.0 \
--port 9000 \
--path /sseThe equivalent FastMCP CLI command is:
uv run fastmcp run src/generative_ui_mcp/server.py:mcp \
--transport sse \
--host 0.0.0.0 \
--port 8000Client configuration
{
"mcpServers": {
"generative-ui": {
"transport": "sse",
"url": "http://127.0.0.1:8000/sse"
}
}
}A programmatic FastMCP client can connect explicitly:
import asyncio
from fastmcp import Client
from fastmcp.client.transports import SSETransport
async def main() -> None:
transport = SSETransport("http://127.0.0.1:8000/sse")
async with Client(transport) as client:
tools = await client.list_tools()
print([tool.name for tool in tools])
asyncio.run(main())The server also exposes the legacy message-posting route used by the SSE transport; clients discover and use it through the SSE connection. Do not configure that route as the server URL.
Reverse proxy
Disable buffering for event streams. An nginx location can use:
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}Use TLS and authentication before exposing the endpoint outside a trusted network.
SSE limitations
It is retained for backward compatibility.
It negotiates the legacy MCP protocol era.
FastMCP SSE does not support the CLI auto-reload mode.
It is less suitable than Streamable HTTP for current bidirectional and sessionless MCP behavior.
Recommended network mode
Although requested examples include legacy SSE, use Streamable HTTP unless the client specifically requires SSE:
uv run generative-ui-mcp \
--transport http \
--host 0.0.0.0 \
--port 8000 \
--path /mcpConnect to:
http://127.0.0.1:8000/mcpThis transport can use SSE inside HTTP responses for streaming, but it is not the legacy two-endpoint SSE transport.
Docker: SSE service
Build and start the included legacy SSE service:
docker compose up --buildConnect to:
http://127.0.0.1:8000/sseThe Compose file intentionally publishes only on loopback. Change the binding only after adding authentication and network controls.
To run the image as Streamable HTTP instead:
docker build -t generative-ui-mcp .
docker run --rm -p 127.0.0.1:8000:8000 \
generative-ui-mcp \
uv run --no-sync generative-ui-mcp \
--transport http --host 0.0.0.0 --port 8000 --path /mcpSTDIO is generally launched directly by the MCP client rather than placed in a long-running container. If required, configure the client to execute docker run -i --rm generative-ui-mcp uv run --no-sync generative-ui-mcp-stdio; the -i flag is mandatory so stdin remains attached.
Phlox configuration
Phlox must first implement generic MCP Apps hosting: preserve UI metadata and structured content, read ui:// resources, render them in a sandboxed iframe, and implement the AppBridge channel. Merely registering this server as an ordinary MCP tool server will expose the tools but will not render the app.
Local Phlox and STDIO
If Phlox supports launching local MCP processes, use the STDIO configuration above. Ensure the Phlox process can execute uv and read this project directory.
Containerized Phlox and SSE
If both services run in the same Compose network, do not use localhost from the Phlox container. Register:
http://generative-ui-mcp:8000/sseFor new Phlox development, prefer a Streamable HTTP sidecar at:
http://generative-ui-mcp:8000/mcpSuggested agent instructions
Add guidance similar to this to the host's agent policy:
Use search_prefab_components and generate_prefab_ui when an interactive
chart, dashboard, table, report, calculator, or form would communicate a
result better than text. Gather and validate the source data first. Pass
large datasets through the data argument instead of embedding them in code.
Use only Python's standard library and Prefab components in generated code.
Do not generate a UI when a concise text response is sufficient.Passing data
generate_prefab_ui accepts code and data. Keys in data become globals in the sandbox, allowing generated code to refer to data without embedding it into source:
{
"code": "from prefab_ui.app import PrefabApp\nfrom prefab_ui.components import DataTable, DataTableColumn\nwith PrefabApp() as app:\n DataTable(rows=records, columns=[DataTableColumn(key='name', header='Name')])",
"data": {
"records": [
{"name": "alpha"},
{"name": "beta"}
]
}
}Do data access and substantial analysis in the host's normal tools first. Generated code is limited to Python's standard library, Prefab, and explicitly passed data; NumPy, pandas, requests, and arbitrary external packages are unavailable in the sandbox.
Security
This server executes model-generated Python, but FastMCP runs that code in Pyodide rather than as normal host Python. Treat the entire feature as untrusted nonetheless:
Keep FastMCP and Prefab exactly pinned and upgrade deliberately.
Restrict who can invoke
generate_prefab_ui.Limit input/result sizes and request rates in the host or reverse proxy.
Do not place secrets in the
dataargument; they become visible to the browser app.Render MCP Apps only in a sandboxed iframe.
Validate every app-originated tool call in the MCP host.
Use TLS and authentication for network transports.
Bind development servers to loopback.
Review browser CSP and permitted CDN access for controlled environments.
Log to stderr in STDIO mode.
This project intentionally does not include authentication because auth design depends on the MCP host and deployment environment. Do not expose the SSE or HTTP listener to an untrusted network as-is.
Troubleshooting
Tools appear but no UI renders
The MCP client is not an MCP Apps-compatible host, or it discarded the tool's UI metadata or structuredContent. Test with fastmcp dev apps first.
First generation is slow or fails
Confirm that deno --version succeeds in the same environment and under the same service account that launches the server. The included container installs Deno explicitly. For offline production environments, preinstall Deno and ensure browser-side Pyodide assets are available under the chosen CSP strategy.
Browser shows a blank app
Check the host's AppBridge messages, iframe sandbox policy, CSP errors, and outbound access to the Pyodide CDN. The FastMCP development host includes an inspector for JSON-RPC and AppBridge traffic.
SSE connects but results never arrive
Disable buffering in the reverse proxy and extend read timeouts. Confirm that the client is explicitly using an SSE transport and the /sse URL, rather than trying to infer Streamable HTTP from the URL.
STDIO client reports malformed JSON
Remove all print() calls and anything else writing to stdout. Send logs to stderr.
ImportError in generated code
Generated code can use the standard library and Prefab, but not arbitrary third-party packages. Perform analysis elsewhere and pass plain JSON-compatible data through data.
Project layout
generative-ui-mcp/
├── src/generative_ui_mcp/
│ ├── __init__.py
│ ├── __main__.py
│ ├── entrypoints.py
│ └── server.py
├── examples/
│ ├── mcp-sse.json
│ └── mcp-stdio.json
├── tests/test_server.py
├── scripts/install-deno.sh
├── Dockerfile
├── docker-compose.yml
├── pyproject.toml
├── uv.lock
└── README.mdUpdate dependencies
Inspect updates explicitly:
uv lock --upgrade-package fastmcp --upgrade-package prefab-ui
uv run pytest
uv run fastmcp dev apps src/generative_ui_mcp/server.py:mcpAfter validating MCP metadata, generated output, iframe rendering, and client compatibility, commit the new exact versions and lockfile together.
Available Tools
2 toolsgenerate_prefab_uiGenerate Prefab UiA
Execute Prefab Python code in a sandbox and render the result.
The code runs in a Pyodide WASM sandbox with full Python support.
Import everything you use. Use the components tool to look up
available components and their import paths.
Always use PrefabApp as the outermost context manager — this enables streaming so the UI renders progressively as code is written:
from prefab_ui.components import Column, Heading, Text, Row, Badge
from prefab_ui.app import PrefabApp
with PrefabApp() as app:
with Column(gap=4):
Heading("Dashboard")
with Row(gap=2):
Text("Revenue: $1.2M")
Badge("On Track", variant="success")For interactive UIs, pass initial state as a dict and use .rx
on stateful components for reactive bindings:
from prefab_ui.components import Column, Slider, Text
from prefab_ui.app import PrefabApp
with PrefabApp(state={"threshold": 50}) as app:
with Column(gap=4):
slider = Slider(value=50, min=0, max=100, name="threshold")
Text(f"Threshold: {slider.rx}%")slider.rx produces {{ threshold }}, a template expression
that resolves against client-side state. Use Rx("key") directly,
or apply pipe filters: Rx("balance").currency() produces
{{ balance | currency }}.
Available pipes: upper, lower, currency, length, json, round(n), default(val), truncate(n).
Charts live in prefab_ui.components.charts:
from prefab_ui.components.charts import BarChart, ChartSeries
BarChart(
data=[{"month": "Jan", "rev": 100}, {"month": "Feb", "rev": 200}],
series=[ChartSeries(data_key="rev", label="Revenue")],
x_axis="month",
)Values passed via data are available as global variables in the
code. Python features like loops, f-strings, and comprehensions all
work.
Layout patterns:
Card sub-components (CardHeader, CardContent, CardFooter) have built-in padding. Don't add extra padding to them. For a simple card without sub-components, use
Card(css_class="p-6").Use
Grid(columns=N, gap=4)for equal-width cards or panels. Grid handles sizing automatically — no flex classes needed. For unequal widths, pass a list:Grid(columns=[2, 1], gap=4)gives a 2:1 ratio.Row is for inline elements (badges, icons + text, buttons). Prefer Grid when children should have equal or proportional widths. Row does not wrap by default.
Column and Row accept
gap(Tailwind scale: 1-12),align(cross-axis), andjustify(main-axis) as native props — prefer these over raw css_class for spacing.Use
css_class="overflow-hidden"on containers if chart or content edges should clip to the container boundary.
Args: code: Python code that builds a Prefab component tree. data: Values injected as variables in the sandbox namespace. sandbox: A Sandbox instance. If not provided, a new one is created on each call.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | ||
| data | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so thoroughly. It discloses Pyodide WASM sandboxing, streaming behavior, reactive state mechanics, data injection as globals, and per-call sandbox creation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured: purpose, code examples, state handling, charts, layout patterns, then args. Each code sample earns its place for a code-generation tool, and the core instruction is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
It covers setup, state, pipes, charts, and layout guidance, which is unusually complete for a two-parameter tool. The lack of an output schema is acceptable since the output is a rendered UI, but the phantom 'sandbox' parameter and lack of explicit error/return behavior keep it from a perfect score.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, and the description compensates by explaining 'code' as building a Prefab component tree and 'data' as injected sandbox variables, reinforced by extensive examples. However, it documents a 'sandbox' argument that does not appear in the input schema, which could mislead an agent into passing an unsupported parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence states a specific action and resource: 'Execute Prefab Python code in a sandbox and render the result.' This clearly distinguishes the tool from the sibling search_prefab_components, which is for lookup rather than execution/rendering.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives concrete conditions: use the components tool for lookups, wrap with PrefabApp for streaming, use .rx for interactive UIs, and choose Grid vs Row based on layout needs. It does not explicitly contrast with sibling search_prefab_components, but the tool's role is evident from context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_prefab_componentsSearch Prefab ComponentsA
Search the Prefab component library.
Use this tool to look up exact argument names, accepted values, and usage examples before writing component code. The skill covers patterns and layout; this tool has the API details.
The query matches component names and descriptions.
Space-separated terms match independently, so
"Card Badge Metric" returns all three.
When a query matches a small number of components, full details
(docstrings, args, examples) are shown automatically. For broad
searches, a compact listing is returned instead. Use detail to
override this behavior.
Args: query: Filter by component name or description. Space-separated terms are OR-matched. detail: Show full docstrings and args. Defaults to automatic (detailed for ≤5 matches, compact otherwise). limit: Max components to return in detail mode (default 8). No limit in compact mode.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max components to return in detail mode (default 8). No limit in compact mode. | |
| query | No | Filter by component name or description. Space-separated terms are OR-matched. | |
| detail | No | Show full docstrings and args. Defaults to automatic (detailed for ≤5 matches, compact otherwise). | |
| components | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full behavioral burden and succeeds. It discloses OR-matching semantics for space-separated terms, automatic detail vs compact mode behavior (≤5 matches threshold), the detail override, and the limit default in detail mode. This is substantial behavioral context beyond just stating 'search.'
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose, then adds usage context, then matching/override behavior, then an Args block. Every sentence earns its place, and the structure makes the nuanced automatic-mode behavior easy to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers query semantics, detail behavior, and limits, and an output schema is present, so return values need no explanation. The only meaningful omission is the 'components' parameter, which is left entirely undocumented. For a mostly simple search tool this is a minor but real gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 75%, so the baseline is 3. The description reinforces the schema's explanations of query, detail, and limit, but adds little semantic value beyond what the schema already provides. The 'components' parameter has no schema description and is never mentioned in the description, leaving a real gap for an agent trying to understand what to pass.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Search the Prefab component library') and clarifies the tool's niche: 'this tool has the API details' while 'the skill covers patterns and layout.' This clearly distinguishes it from the sibling generate_prefab_ui and makes the search intent unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says to use the tool 'before writing component code' to look up argument names, accepted values, and usage examples. It also contrasts the tool with the broader skill. It does not explicitly name generate_prefab_ui as an alternative, but the usage context is clear enough for an agent to route correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.1.0- First observed
generate_prefab_ui - First observed
search_prefab_components
TDQS
Scored across 2 tools
generate_prefab_ui executes and renders UI code, while search_prefab_components is a reference lookup for available components and APIs. There is no overlap between rendering and searching, so an agent cannot confuse their roles.
Both tools follow the same lowercase verb_object pattern with the shared prefab_ prefix: generate_* and search_*. The minor difference between ui and components is not a meaningful inconsistency.
Two tools feels thin, but the server's scope is deliberately narrow: generate/render UI and search the component library. The count is acceptable but leaves little room for additional workflow support.
The tool pairing covers the full intended workflow: discover components with search_prefab_components, then generate and render them with generate_prefab_ui. No essential operation for a generative UI server is missing.
Maintenance
Related MCP Connectors
Your org's AI agents, tasks, runs, search, and brain files as MCP tools and resources.
Use AI models for chat, image, and video generation from Claude Code and other MCP hosts.
Create, browse, remix, collaborate on, and run durable AI workflow nodes from MCP hosts.
Generate game-ready 3D models, textures, and audio from natural language, over MCP.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceUnity Editor MCP SDK that exposes Unity Editor capabilities as MCP tools, enabling AI assistants like Claude Code to drive Unity Editor workflows through prefab inspection, asset manipulation, and preview rendering.MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to control the Unity Editor through MCP, allowing scene building, runtime scripting, visual QA, and more.4Apache 2.0
- FlicenseBqualityDmaintenanceAn MCP server that gives AI assistants tools to generate AccelByte AGS uGUI prefabs in Unity projects, look up AccelByte Unity SDK best practices, search Bytewars C# example components, and configure SDK credentials from a Claude Code or Cursor session.23-
- AlicenseNot gradedqualityBmaintenanceEnables AI coding agents to visually build and run AI generation pipelines on a canvas by adding, wiring, and executing nodes via MCP tools.Apache 2.0