voygent-mcp-app-demo
Click on "Install 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., "@voygent-mcp-app-demobuild me a pizza"
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.
voygent-mcp-app-demo
A worked, runnable example of building interactive in-chat UI with MCP Apps, plus a field guide to the gotchas you only learn by shipping one.
MCP Apps (the io.modelcontextprotocol/ui extension, SEP-1865) lets an MCP server hand the host a sandboxed HTML widget instead of a wall of text. The model calls one tool and the user gets a real interface: option pickers, live totals, buttons that talk back to the model. This repo is a minimal working example of that pattern, distilled from a production app (Voygent's Folio Board, a whole-trip interactive board running in claude.ai today).

The example app is a Pizza Builder: pick size, crust, and toppings; watch the price update live; hit Place order and it hands the choice back to the model. The domain is intentionally simple so the MCP Apps mechanics stay in focus. Every pattern here maps directly to what the Folio Board uses for a 10-day trip.
What you'll learn
This repo demonstrates, in ~350 lines of commented source, every capability that makes an MCP App feel native:
Capability | How | Where |
Render an interactive widget from a tool call |
| |
Keep the model's context tiny | launcher returns a | |
Let the user pick options without spending tokens |
| |
Hand a result back to the model |
| |
Show external images |
| |
Download a file |
| |
Go fullscreen |
| |
Match the host's theme/fonts |
| |
See what the host actually granted you |
|
Also included: 10 gotchas covering URI caching, the silent updateModelContext, the red caution banner, the session-locked tool catalog, and more.
Related MCP server: MCPizza
Quickstart
git clone https://github.com/iamneilroberts/voygent-mcp-app-demo
cd voygent-mcp-app-demo
npm install
npm run buildSee the widget immediately, no host required. The build produces a single self-contained dist/builder.html that falls back to mock data when opened directly:
# macOS
open dist/builder.html
# Linux
xdg-open dist/builder.htmlRun it as a real MCP server:
npm start # Streamable HTTP at http://localhost:3001/mcp
npm run start:stdio # stdio, for Claude Desktop / MCP InspectorConnect it to a host:
Claude Desktop: add to your MCP config:
{ "mcpServers": { "pizza": { "command": "node", "args": ["/abs/path/to/voygent-mcp-app-demo/dist/index.js", "--stdio"] } } }Then ask Claude: "build me a pizza" → the board renders inline.
MCP Inspector:
npx @modelcontextprotocol/inspector node dist/index.js --stdio.
Architecture in one diagram
┌─────────┐ tool call ┌──────────┐ postMessage ┌──────────────┐
│ Model │ ───────────▶ │ Host │ ◀────JSON-RPC──▶│ Widget │
│ (Claude)│ ◀─result/UI─ │(claude.ai│ (the bridge) │ (iframe, │
└─────────┘ │ /Desktop)│ │ sandboxed) │
└────┬─────┘ └──────┬───────┘
│ proxies app.callServerTool()│
▼ ▼
┌─────────────────────────────────────┐
│ Your MCP server (src/server.ts) │
│ build_pizza · pizza_state · pizza_pick │
└─────────────────────────────────────┘The model launches the board once. After that the widget talks to your server directly through the host (app.callServerTool), so picking toppings costs zero model tokens. The widget hands control back to the model only when the user is done. Full walkthrough: docs/01.
Repo layout
src/
server.ts the MCP server: 1 launcher tool + 2 app-only tools + 1 UI resource
data.ts the toy domain (menu, orders, pricing)
index.ts transport wiring (Streamable HTTP + stdio)
widget/
widget.ts the App: render, pick, place-order, download, fullscreen, theme
widget.html the shell (CSS + JS get inlined here at build time)
styles.css
esbuild.mjs bundles the widget into one self-contained HTML the server serves
docs/ 01–08: the deep dives
CASE-STUDY.md Voygent's Folio Board: the production app this was distilled from
media/ screenshotsThe deep dives
Architecture & lifecycle: the handshake, the bridge, the two-part registration.
Declaring UI resources:
ui://, the MIME type,_meta.ui.resourceUri, tool visibility.The host API: every
app.*method, and the capabilities-vs-context distinction.CSP & imagery: why your image is blocked and how to declare the domains you need.
Two-way comms:
updateModelContextvssendMessage, the caution banner, no progress tokens.The token economy: the ref-and-fetch pattern that kept a 9k-token payload out of the model's context (~98.5% smaller).
Probing host capabilities: how to find out what a host actually grants, with real Claude Desktop results.
Gotchas: 10 things to know before shipping.
Status of the findings
The capability claims in docs/07 come from running a probe app inside a live host. Claude Desktop (Claude/1.569.0, 2026-06-13) is empirically confirmed. Some claude.ai web cells are marked pending where we hadn't yet captured them in-host. They are labeled as pending, not guessed. Hosts evolve; re-probe before you rely on a specific cell.
Credits
Built by Neil Roberts, distilled from Voygent's Folio Board. MCP Apps spec: modelcontextprotocol/ext-apps. MIT licensed.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/iamneilroberts/voygent-mcp-app-demo'
If you have feedback or need assistance with the MCP directory API, please join our Discord server