Interactive UIs Inside AI Chat Windows
MCP Apps Tutorial
Great for fetching data and answering questions.
But what happens when users need to interact with something?
The first official extension to MCP
Servers can now return interactive HTML UIs
that render directly inside the chat window.
Announced January 26, 2026
New URI scheme for UI
_meta.ui.resourceUri
Isolated execution
App ↔ Host ↔ Server
The UI can call server tools directly, bypassing the LLM for fast iteration.
An interactive HTTP client that renders inside the chat.
Ask the agent to test an endpoint, get a full request builder.
mcp-app/ ├── server.ts # MCP server + tools ├── mcp-app.html # HTML entry point ├── src/ │ └── mcp-app.ts # UI logic ├── vite.config.ts # Bundles to single file └── package.json
const resourceUri = "ui://api-explorer/mcp-app.html";
The ui:// scheme tells hosts this is a renderable UI.
registerAppTool(server, "send-request", { title: "Send API Request", description: "Send an HTTP request...", inputSchema: requestInputSchema, _meta: { ui: { resourceUri } }, }, handleRequest);
_meta.ui.resourceUri links the tool to the UI.
registerAppTool(server, "inspect-response", { ... _meta: { ui: { resourceUri, visibility: ["app"] } }, }, handleRequest);
Hidden from LLM. Only the UI can call it.
import { App } from "@modelcontextprotocol/ext-apps"; const app = new App({ name: "API Explorer", version: "1.0.0" }); app.connect();
Two lines to establish the postMessage channel.
app.ontoolresult = (params) => {
const data = JSON.parse(params.content[0].text);
displayResponse(data);
prefillForm(data);
};
Host pushes tool results to your app automatically.
const result = await app.callServerTool({ name: "inspect-response", arguments: { method, url, headers, body }, });
Direct UI → Host → Server → Host → UI. No LLM in the loop.
npm run build # Vite bundles to single HTML npm run serve # Start server on :3001
Test with basic-host or add to Claude as a custom connector.
MCP Apps are ready. Your turn.