mcp-apps-demo-engine
An extensible MCP server and generative UI engine for hosting interactive B2B enterprise workflows with dynamic styling and stateful simulators.
README
Signal Triage — a context-aware MCP App
An MCP Apps (SEP-1865) experiment that grew from plumbing demo into a small demo engine: signals from multiple mock sources land on one interactive triage board, mapped against a customer case (who the signals matter to) and rendered in a brand (what the customer's world looks like). Both the case and the brand are plain markdown files, swappable at runtime.
Quick start — see it in two minutes
Requires Node 20+. No API keys, no accounts.
npm install
npm run build
npm run serve:http # terminal 1 — MCP server on http://localhost:3001/mcp
npm run shim # terminal 2 — minimal host on http://localhost:4180
Open http://localhost:4180/host-shim.html. The shim is a ~100-line reference host: it fetches the UI via resources/read, completes the MCP Apps handshake, and proxies every tool call to the real server — the log under the widget shows each message the app sends. Triage some signals (Keep/Drop/Undo, filter by source), then switch to the Briefing tab and press Draft briefing in chat to watch the v2 hand-back (ui/update-model-context + ui/message) appear in the log.
Triage decisions persist in data/decisions.json (gitignored) — delete it for a fresh board.
What you'll see
v1 — triage. get_signals aggregates all sources and maps each signal to the case's focus areas by keyword (whole-word, plural-tolerant). The board shows focus-area chips with kept/matched counts, source filter tabs, per-row relevance chips ("No direct match" = drop candidate), and Keep/Drop/Undo. Every click travels back as a record_decision tool call (app-only, invisible to the model).
v2 — briefing. The Briefing tab groups kept signals per focus area and flags areas with no kept coverage as gaps. "Draft briefing in chat" pushes the full briefing into model context and sends a short trigger message so the host's assistant drafts the customer-ready briefing. UI-less hosts get the same synthesis from the get_briefing tool.
Both tools keep plain-text fallbacks, so the server stays useful on hosts without MCP Apps support.
The five inputs
| Input | File | Role |
|---|---|---|
| Context | CUSTOMER_CASE.md | An OKF concept document (type: Customer Case); its focus_areas frontmatter (id, title, keywords) is the contract every signal is triaged against. |
| Style | DESIGN.md | A design.md-spec token file. design.ts compiles its frontmatter (colors/typography/rounded) into CSS variables injected into the UI resource at serve time. |
| Data | data/sources/ | Three mock JSON feeds (external news, market intel, internal ops/HR). Mock by design — no API keys. |
| Knowledge | .claude/skills/signal-triage/ | An agent skill whose reference files form an OKF bundle: the case contract, one doc per source, and a triage playbook. |
| Stories | USER_STORIES.md | Stories 1–2 produced v1 (git tag v1); story 3 produced v2 (tag v2). |
Swapping the inputs (no rebuild, no restart)
Both context and style are runtime inputs — the server re-reads CUSTOMER_CASE.md on every tool call, and compiles DESIGN.md into the UI resource every time it's served:
# Switch customer: every signal re-maps to the new focus areas
cp cases/norrsken-freight.md CUSTOMER_CASE.md
# Switch brand: the widget re-renders in the new design tokens
cp designs/nordfrakt.design.md DESIGN.md
Reload the shim (or let the host re-read tool + resource) and the same 14 signals appear re-mapped and re-branded. Ready-made examples live in cases/ and designs/. Unknown or missing design tokens fall back to built-in defaults, and host-provided style variables always win over both.
Where the files come from is the point of the pipeline:
- CUSTOMER_CASE.md is the planned bridge target for the organisational-stress-test project — one
focus_areasentry per stressed area. Contract details: customer case contract. - DESIGN.md is what design-md-generator produces from a live website URL — point it at a customer's site and the demo renders in their brand.
Two verified portability experiments back this up: swapping only the style left every behavior identical, and swapping only the case (Norrsken Freight, a 3PL → Kvist & Söner, an industrial wholesaler) inverted relevance — the warehouse-robotics signal that was noise for Norrsken became Kvist's automation signal, while Norrsken's top talent signal dropped to "No direct match". Relevance is a property of the case, not the signal.
Using it from a real host
For stdio hosts (Claude Desktop / Claude Code style config):
{
"mcpServers": {
"signal-triage": {
"command": "node",
"args": ["/absolute/path/to/dist/main.js", "--stdio"]
}
}
}
For the SDK's reference host: clone ext-apps, cd examples/basic-host, npm install (add tsx, cross-env, @types/cors as dev deps if installing standalone), NODE_ENV=development npm run build, then npx tsx serve.ts and open http://localhost:8080 while this server runs on :3001. No bun required.
npm run dev runs the Vite watcher plus the HTTP server together for iteration (UI changes need a rebuild — the served resource is the compiled dist/mcp-app.html).
Stack
Official SDK + patterns: @modelcontextprotocol/ext-apps, vanilla TS/HTML UI bundled to a single file (Vite + vite-plugin-singlefile), Node + Express for Streamable HTTP, stdio also supported. Frontmatter parsed with yaml.
Versions
v1— user stories 1–2: multi-source board + case relevance.v2— user story 3: briefing view, gaps, hand-back to chat.- after
v2: portability experiments, then runtime ingestion of both swappable inputs.
The pre-build design sketch this repo started from is preserved on the initial-draft branch.
Learnings
The reflective deliverable of the original experiment is LEARNINGS.md — including a v2 addendum on what building "one level up" from the plumbing taught. The original scope-setting PRD is preserved as MCP_App_Learning_PRD.md.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.