{
  "markdown": "# open-mcp-apps\n\n[![CI](https://github.com/2nd1st/open-mcp-apps/actions/workflows/ci.yml/badge.svg)](https://github.com/2nd1st/open-mcp-apps/actions/workflows/ci.yml)\n[![npm](https://img.shields.io/npm/v/%402nd1st%2Fopen-mcp-apps?logo=npm&label=npm)](https://www.npmjs.com/package/@2nd1st/open-mcp-apps)\n[![license](https://img.shields.io/npm/l/%402nd1st%2Fopen-mcp-apps)](LICENSE)\n[![node](https://img.shields.io/node/v/%402nd1st%2Fopen-mcp-apps)](package.json)\n[![MCP Registry](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fregistry.modelcontextprotocol.io%2Fv0%2Fservers%3Fsearch%3Dopen-mcp-apps%26version%3Dlatest&query=%24.servers%5B0%5D.server.version&label=MCP%20Registry&color=blue&prefix=v)](https://registry.modelcontextprotocol.io/v0/servers?search=open-mcp-apps&version=latest)\n\n**English** | [简体中文](i18n/README.zh-CN.md)\n\n> Give your AI a persistent, reusable UI. It builds the app once — you keep it forever.\n\n**open-mcp-apps** is an open engine built on [MCP Apps](https://modelcontextprotocol.io/extensions/apps/overview)\n(`ui://`, `io.modelcontextprotocol/ui`) — an extension to the core Model Context Protocol\nspecification, and [the first official one](https://blog.modelcontextprotocol.io/posts/2026-01-26-mcp-apps/),\nlive since 26 January 2026. It gives any MCP-Apps-capable host (Claude Desktop, claude.ai, Codex,\nChatGPT, …) three things the extension itself doesn't provide:\n\n1. **An app registry the AI can write to.** Ask for a UI that doesn't exist — the AI reads\n   the authoring guide, writes a single-file HTML app against a tiny `window.oma` API,\n   and saves it. From that moment you can open it by name, in this chat and every future one.\n2. **Persistent, versioned data — separate from the UI.** Apps bind to generic\n   *collections* of items backed by SQLite plus an append-only `change_event` ledger. Every\n   mutation is an idempotent domain command (`command_id`) with optimistic concurrency\n   (`expected_version`). The AI and the human edit the same store — the widget is just a view.\n3. **A shell runtime so AI-written apps actually work.** Serving `ui://`, the engine wraps\n   the app with the official MCP App bridge, host theming (Claude's design tokens,\n   light/dark), and the `window.oma` data API. What you write is a view; the protocol,\n   persistence, idempotency and theming are the engine's problem.\n\n**Which of those hosts *this* engine reaches.** It runs on your machine and binds `127.0.0.1`, so it\nserves the hosts on that same machine: Claude Desktop, Claude Code, Codex, plus its own browser\nviewer. A browser host cannot reach a loopback server on your laptop, so **claude.ai and ChatGPT web\nneed a remote deployment** — today that means the hosted [openmcp.app](https://openmcp.app), which\nruns this same engine for you. Running that remote shape *yourself* is on the roadmap and not done.\n\n| | |\n|---|---|\n| **Version** | 0.7.0 ([`CHANGELOG.md`](CHANGELOG.md)) |\n| **License** | MIT, whole repository ([`LICENSE`](LICENSE) · [`LICENSING.md`](LICENSING.md)) |\n| **npm** | `@2nd1st/open-mcp-apps` — **scoped**; the unscoped name is an unrelated package |\n| **Command** | `npx -y @2nd1st/open-mcp-apps` — the line your host's MCP config runs; a stdio server, not something to run by hand (typed into a terminal it just waits, and says so) |\n| **Requires** | Node 22 or newer. `git` too, on the installer path |\n| **Surface** | 33 tools · a built-in App Store · 3 system apps seeded |\n| **Platforms** | macOS · Windows · Linux |\n| **Hosts** | Claude Desktop · Claude Code · Codex · ChatGPT web — see [Host support](#host-support) |\n| **Hosted** | [openmcp.app](https://openmcp.app) — the remote shape, and the way to reach browser hosts (claude.ai, ChatGPT) |\n\n## Install\n\nopen-mcp-apps runs as a local MCP server. First get it **connected** to your host (below); then\n**onboarding happens inside the host, separately** — that's where the AI builds your first app.\n\n### From npm — nothing to clone\n\nIf you are comfortable editing your host's config file, point it at the published package and\nlet `npx` fetch the engine. This path needs only Node 22 — no `git`, and no checkout for you to\nkeep updated. Paste this into your host's MCP server config:\n\n```json\n{\n  \"mcpServers\": {\n    \"open-mcp-apps\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@2nd1st/open-mcp-apps\"]\n    }\n  }\n}\n```\n\nTwo things the installer below does that this path does not: it registers the server into every\nhost it finds, and it pre-seeds the built-in system apps (settings, dashboard, App Store) into\nyour store — so on the `npx` path your registry starts empty and your AI installs what it needs\nfrom the App Store on demand, which is fully available either way. Your data lives in the same\nfixed per-user store, so you can move between an `npx` server and a cloned one without migrating\nanything.\n\n> **A note on npm:** this project publishes under the **scoped** name\n> [`@2nd1st/open-mcp-apps`](https://www.npmjs.com/package/@2nd1st/open-mcp-apps). The *unscoped*\n> `open-mcp-apps` on the registry is **not this project** — that name is held by an unrelated\n> package. Check for the `@2nd1st/` prefix; the scope is the only thing telling the two apart.\n\n### With the installer — one command\n\nInstalling needs a shell, so the chat apps (Claude Desktop, Codex) can't install themselves — use\none of these instead:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/2nd1st/open-mcp-apps/main/install.sh | sh\n```\n\nIt opens a short picker to choose which hosts to register into — **Claude Desktop, Claude Code,\nCodex** — plus your permission preference. Skip it with `-s -- --yes`, or target one host with\n`-s -- --host codex`.\n\n**Where it puts the clone**, before you pipe anything into a shell: `~/open-mcp-apps`. Set `OMA_DIR`\nto put it somewhere else — `curl -fsSL <url> | OMA_DIR=~/src/oma sh`. Re-running the one-liner\nupdates that same clone in place instead of making a second one. Your apps and data are *not* in it\n(they live in the per-user store under [Configuration](#configuration)), so the folder is safe to\nmove or delete — and `node uninstall.mjs` does not delete it for you.\n\n**With a coding agent** (Claude Code, Codex CLI — they have a shell), paste:\n\n> Read https://raw.githubusercontent.com/2nd1st/open-mcp-apps/main/install.md and follow it.\n\nEither way, `install.mjs` registers the server into each host you pick, idempotently — it never\nclobbers your other servers, pins a stable `node` launcher (native SQLite ABI), reports what\nchanged, and cleans up a pre-rename entry if one lingers. Your data lives in a **fixed per-user\nstore** (not inside the clone), so every host shares the same apps and data.\n\n### From a clone — for development\n\n```bash\ngit clone https://github.com/2nd1st/open-mcp-apps && cd open-mcp-apps\nnpm install\nnode install.mjs        # same picker as the one-liner above\n```\n\nTo wire a clone into a host by hand instead, point it at the checkout — this is the shape\n`install.mjs` writes:\n\n```json\n{\n  \"mcpServers\": {\n    \"open-mcp-apps\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/open-mcp-apps/src/server.mjs\"]\n    }\n  }\n}\n```\n\n### Hosted\n\n[openmcp.app](https://openmcp.app) runs the engine for you. The engine in this repository binds\n`127.0.0.1` by design, so a self-hosted remote deployment is not a supported shape yet — see\n[Status and roadmap](#status-and-roadmap).\n\n### Uninstall\n\n`node uninstall.mjs` unregisters the server from every host it finds — but **keeps your data**:\nthe shared store stays put, so re-installing later restores every app and all data. It also leaves\nthe installer's clone (`~/open-mcp-apps`, or wherever `OMA_DIR` pointed) on disk — nothing here ever\ndeletes that folder, so remove it yourself when you want the checkout gone.\n\n```bash\nnode uninstall.mjs           # unregister from all detected hosts — keeps your data\nnode uninstall.mjs --purge   # also delete the shared store (apps + data), irreversible\nnode uninstall.mjs --check   # read-only: show what's registered and what would change\n```\n\n## Requirements\n\n- **Node 22 or newer**, on macOS, Windows or Linux.\n- **`git`** — only on the installer path. The `npx` path above needs neither `git` nor a checkout.\n  The installer checks for both and stops with a message rather than half-installing if either is\n  missing.\n- **A host that renders `ui://`** if you want widgets *in the conversation*. Terminal hosts (Claude\n  Code in a terminal, codex CLI) drive the same data by design and put the UI on a browser screen\n  beside the terminal instead — one that can follow along, showing whatever the AI just opened. The\n  per-host detail is in [Host support](#host-support).\n- **After installing or updating, fully quit and reopen the host** (Cmd-Q, not just closing the\n  window) — it keeps its old server process on the old data until fully quit.\n\n## Configuration\n\nEvery setting is an environment variable, set in the `env` block of your host's MCP server entry:\n\n```json\n{\n  \"mcpServers\": {\n    \"open-mcp-apps\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@2nd1st/open-mcp-apps\"],\n      \"env\": {\n        \"OMA_VIEWER\": \"1\",\n        \"PORT\": \"8787\",\n        \"OMA_DYNAMIC_TOOLS\": \"0\"\n      }\n    }\n  }\n}\n```\n\n| Variable | Default | What it does |\n|---|---|---|\n| `OMA_VIEWER` | `1` | The browser viewer on loopback. `0` doesn't start it at all. |\n| `PORT` | `8787` | Where the viewer listens. |\n| `OMA_DYNAMIC_TOOLS` | `0` | `1` also publishes one `open_<name>` tool per saved app. Off by default because it costs prompt cache — and one approval prompt per app. |\n| `OMA_DB` | per-user store | Path to the SQLite store. Set it to isolate a store. |\n\n**Where your data lives.** The whole store is one SQLite file, `open-mcp-apps.db`, in\n`~/Library/Application Support/open-mcp-apps/` (macOS), `%APPDATA%\\open-mcp-apps\\` (Windows), or\n`$XDG_DATA_HOME` else `~/.local/share/open-mcp-apps/` (Linux). It is outside any clone, which is\nwhy every host shares the same apps and data.\n\n**First-run permissions.** The first few tool calls each show an approval dialog — pick\n**\"Always allow\"**. The tool set is small and stable on purpose: read-only tools generally\nskip approval, and the single `open_app` tool covers opening *every* app (including ones the AI\ncreates later) behind that one grant, so nothing new asks again — on every host the installer\nregisters, with no exceptions any more. From 2026-07-28 to 2026-08-16 there were two: **Claude\nDesktop and Claude Code** were registered with `OMA_DYNAMIC_TOOLS=1`, which routed around a\nchat-surface bridge regression by giving every app its own `open_<name>` tool, at one approval\nprompt per app. Re-measured on Desktop 1.30096.5, that symptom is gone, so the installer no longer\nsets the flag for anybody — [`KNOWN-ISSUES.md`](KNOWN-ISSUES.md) carries both readings.\n**If you installed during that window, your entry still has the flag:** `node install.mjs --check`\nreports it as `stale`, and re-running the installer removes that one key while leaving every other\nenv value you have set exactly where it is.\nYou can also batch approvals in **Settings → Connectors → open-mcp-apps → Tool permissions**.\n\n## Usage\n\n**Start in your host.** Restart it after installing. New here? The engine ships one MCP prompt,\n`get_started`. A host that surfaces prompts lists it as **Get started with open-mcp-apps**; hosts\nthat render prompts as slash commands spell it `/mcp__open-mcp-apps__get_started`. Picking it hands\nthe AI the whole opening move. Not every host surfaces prompts — where yours doesn't, nothing is\nlost, because the prompt is just a sentence you can say yourself: **\"I just installed open-mcp-apps\n— show me how to use it with a couple of examples, and suggest a few apps that fit how I work.\"**\nEither way it looks at what you already have and what the App Store already offers, asks you a\ncouple of questions, and sets up a first app tailored to you. This step is separate from install and lives in the host. Or just ask directly:\n\n- *\"make me a board for what I'm juggling right now\"* → the AI writes it, seeds it, and opens it (persistent)\n- *\"make me a habit tracker\"* → watch it read the guide, write the app, save it, open it\n- close the app, reopen, ask again → everything is still there\n\n### The loop\n\n```\n\"make me a kanban\"\n      │\n      ▼\nlist_apps ── exists? ──► open_app {app: \"kanban\"}     (reuse, instant)\n      │ no\n      ▼\nget_app_guide ──► AI writes HTML ──► save_app\n      │\n      ▼\nopen_app {app: \"kanban\"}  →  rendered inline, themed, persistent — reusable in every future chat\n```\n\nApps accumulate. Each one is single-purpose and independent — a board, a tracker, a\nsplitter — minted for the task in front of you and kept for the next time you need it.\n\n### What it looks like\n\nApps render inline, in the chat you were already having. Ask for one and the AI writes it:\n\n![Codex — asking for a reading tracker; the AI writes it and it renders inline, already holding the three books](.github/screenshots/host-codex.webp)\n\nCome back in another chat — or another host — and it's still there, with your data in it:\n\n![Claude — a new chat opens the same reading list, now eight books long](.github/screenshots/host-claude.webp)\n\nThe built-in App Store — rebuilt in 0.5.0 as a real storefront — ships 22 ready-made apps, with\nworking previews and one-click install:\n\n![The App Store — live previews of ready-made apps](.github/screenshots/app-store.webp)\n\n| | |\n|---|---|\n| ![Companion — an AI character with shared memory](.github/screenshots/companion.webp) | ![Family Week — dinners, chores rotation, shopping and weekend plans](.github/screenshots/family-week.webp) |\n| ![Study Cards — spaced repetition with review heatmap and deck shelf](.github/screenshots/study-cards.webp) | ![Knowledge Cards — a visual library of saved answers](.github/screenshots/knowledge-cards.webp) |\n\nEvery app above is a single HTML file bound to plain data collections — written with the same\n`window.oma` API and authoring guide your AI will use for the apps it builds you.\n\nMultiple widgets in one conversation work fine (habit-streaks + meal-planner side by side).\n\n### The browser viewer, and the port it binds\n\nEvery install runs a small local web server on **<http://127.0.0.1:8787>**. It is how you *see*\nyour apps outside a chat window — one page per app, the same data your AI is reading — and in a\nterminal host it is the only way to see them at all, so the AI hands you the link when it builds\nor opens something.\n\nIt starts on its own; `OMA_VIEWER` and `PORT` above change that. If the port is already taken by\nanother open-mcp-apps process, that one is already serving the same data and this one just shares\nits address; if it is taken by something else, you get no viewer and no links rather than a link\ninto a stranger's server.\n\n**There is no password on it, and that is deliberate.** The listener is hard-wired to `127.0.0.1`,\nso there is no setting that makes it answer from another machine. Any program on your computer that\ncould reach the port can already open the SQLite file directly — a password would be a lock beside\nan open wall. The one way this reaches the internet is a tunnel you start yourself, which is its own\ndeliberate decision; **while a tunnel is up, treat its URL as a secret**, because it is currently the\nonly thing standing between the internet and your data.\n\n## Host support\n\nLive-tested 2026-07-22; ChatGPT web row updated 2026-07-28. **Both readings predate 0.5.0** — the\nlargest change so far, and later than either date. Apart from the cells that carry their own\n2026-08-16 date, nothing in this table has been re-tested on 0.5.0 or newer; a date says when that\nrow was true, not that it was checked again since.\n\n| Host | Renders widgets | Human clicks widget | AI operates data | Same store |\n|---|---|---|---|---|\n| **Claude Desktop** (local stdio) | ✅ — re-checked 2026-08-16 on 1.30096.5: the universal `open_app` renders in chat without the `OMA_DYNAMIC_TOOLS` workaround that shipped for 1.24012.9 (see KNOWN-ISSUES) | ✅ full loop incl. `sendMessage` reply | ✅ | ✅ |\n| **Browser viewer** (`/view/<name>`) | ✅ | ✅ (no chat attached — `sendMessage` degrades to a notice) | via CLI AI | ✅ |\n| **Codex desktop** (ChatGPT app, `enable_mcp_apps` flag) — tested against a **local** engine; remote not established | ✅ experimental | ◐ updates/toggles from widget clicks work; adds were blocked host-side. The umbrella request [openai/codex#28912](https://github.com/openai/codex/issues/28912) (an `enhancement`: \"make MCP apps work end-to-end in the Codex GUI\") closed as completed on 2026-08-05 — but [#30092](https://github.com/openai/codex/issues/30092), the `bug` matching this exact failure and reproduced there by a third party, was still open on 2026-08-16. Not re-tested here either way, so the cell stays ◐. See KNOWN-ISSUES | ✅ | ✅ |\n| **Claude Code** — in a terminal (`claude mcp`) | — in the chat, by design (text fallback) — but see **[a screen beside the terminal](#a-screen-beside-the-terminal)** | — in the chat | ✅ | ✅ |\n| **Claude Code** — the Code surface inside the Claude app | ✅ live-tested 2026-08-16: an app opened with the universal `open_app` renders inline, the same shape the chat surface gives | not measured on this surface | ✅ | ✅ |\n| **codex CLI / IDE** | — in the chat, by design (text fallback) — but see **[a screen beside the terminal](#a-screen-beside-the-terminal)** | — in the chat | ✅ | ✅ |\n| **ChatGPT web** (Work mode) | ✅ live-tested 2026-07-28 (remote HTTPS) — renders at full height, no clamping; a widget loses its data after a page refresh (mitigation shipped, awaiting live re-test here — see KNOWN-ISSUES) | ✅ a widget button added a row and it stuck | ✅ | ✅ |\n\nEverything rides the MCP Apps bridge, so host fixes upstream (e.g. #28912) benefit this\nproject with zero changes.\n\n**On Claude Code specifically:** it is one product with two surfaces, and only one of them can\ndraw — which is why it takes two rows. In a terminal there is no inline widget surface at all: that\nis architecture rather than a gap, and it is exactly what [a screen beside the\nterminal](#a-screen-beside-the-terminal) is for. The Code surface inside the Claude app has a UI and\nrenders inline; the 2026-08-16 reading there came through the universal `open_app`.\n\n**On Codex specifically:** plugins are registered on the web side, so a locally-installed engine\nis reached as an **MCP server**, not as a plugin — which is the right path for a self-hosted\ninstall anyway. Widget rendering in the ChatGPT desktop app also appears to depend on how you are\nsigned in (we have seen it work under an account sign-in; not yet established under an API key).\n\n### A screen beside the terminal\n\nThose two `—` cells say the **chat** shows text. They do not say there is no UI. Since 0.5.1 the\nengine remembers which app was opened last and pushes that pointer to the viewer on the `/events`\nframe, and an app can place a region — `oma.embed(\"@live\", {into})` — that mounts whatever the AI\nopened last and swaps itself when the AI opens another. The App Store ships one: install **`live`**,\nopen `http://127.0.0.1:8787/view/live` in a window you then leave alone, and the terminal keeps the\nconversation while that screen shows the app. The AI opens or writes from the CLI, the screen\nfollows, and you can click, edit and type into it there. Headless CLI use is what it was built for.\n\n**The cheapest form of \"that screen\" is a browser pane in the same tiled workspace** — one column\nover from the agent, in the window you are already working in. Same machine, no tunnel, no second\ndevice; most modern terminal setups can put a browser next to a shell, and that is all this needs.\nA second monitor is the same idea with more desk, and a screen on another device is the same idea\nagain with the caveat below.\n\nThe costs are real and worth stating plainly. There is still **no widget in the transcript**.\n`sendMessage` degrades to a notice on a standalone page, exactly as in the **Browser viewer** row —\nclicks change data, they do not talk back to the chat. The viewer has to be running (`OMA_VIEWER`,\non by default) with a browser pointed at it; this is not zero-config. And the listener is bound to\n`127.0.0.1`, so \"a spare tablet on the wall\" means *this machine's* screen unless you put up the\ntunnel described above and accept what that section says about it. Inside a chat host the same\nregion deliberately draws a placeholder instead of following anything.\n\n*Described from the code as built, not measured on a host — the live-test dates above cover the\ntable, not this section.*\n\n## Writing an app yourself\n\nThe AI is the usual author, but it isn't the only one — its context window shouldn't be the ceiling\non what an app can be. Build one in your own editor, with your own bundler, and install it:\n\n```bash\nnode install-app.mjs ./my-app.html              # yours, full trust — same as an AI-authored app\nnode install-app.mjs ./my-app.html --sandboxed  # untrusted: runs behind the runner, no capabilities\nnode install-app.mjs --list                     # what's installed, and under whose provenance\n\n# a build pipeline's output: a readable template + its bundle, plus the declaration as its own file\nnode install-app.mjs ./ui.html --name my-app --manifest ./manifest.json \\\n  --asset ./dist/app.js --asset ./dist/app.css --update\n```\n\nTwo shapes are accepted. **One self-contained HTML document** — no size cap (keep it lean: data\nlives in the collection, source is read in windows) — the engine injects the kit CSS, the host's\ndesign tokens and `window.oma`. Or **a template plus a bundle**: the HTML is a readable mount\npoint that references its own build output (`<script type=\"module\" src=\"oma-asset:app.js\">`,\n`<link rel=\"stylesheet\" href=\"oma-asset:app.css\">`), `--asset` pushes those files into the app's\nfile plane, and the engine inlines them the moment the document leaves the store — a widget's CSP\nallows no external subresource, and a host iframe could not reach this machine anyway.\n\nThe trade: the AI can no longer iterate on it — your files are the source of truth, you rebuild\nand re-install. It can still read a single-document app's source; for a template + bundle app it\nreads the template and the bundle stays yours (`edit_app` and the AI's `save_app` refuse with\n`built_outside`; re-running the command above is the edit). Either way the app shares your data\nlike any other. Provenance is not overwritable in either direction, so an app installed\n`--sandboxed` stays sandboxed until you delete it. What a widget may connect to is the app's own\ndeclaration (`manifest.csp`, relayed to the host per the MCP Apps spec — nothing by default), and\nan app's *functions* run engine-side and may `fetch` — see RUNTIME.md §5.1 and §6.1, and\nthe two type files for what an app sees — `@2nd1st/open-mcp-apps/types/window-oma` (the\n`window.oma` API) and `@2nd1st/open-mcp-apps/types/oma-function` (the `args`/`api` a function body\ngets) — both resolve through the package `exports`.\n\n**[`RUNTIME.md`](RUNTIME.md) is the contract** — the `window.oma` API in both modes, what a\nsandboxed app can still do, and the traps that only bite authors who aren't the AI. It carries a\nversion (`oma.contract`) and `test/runtime-contract.mjs` pins it to the two runtimes' real\nsurfaces, so it can't drift from them silently.\n\n## Security model\n\nTrust is tiered by where an app came from. Locally-authored and system apps run in\n**direct mode**. The engine also ships a **runner** — a sandboxed `srcdoc` iframe with a\nCSP-first document and a minimal read-scoped bridge — as the mandatory execution mode for any\napp that isn't locally trusted, plus reserved `security:*` / `policy:*` config keys that\ngeneric data writes can't touch and an out-of-band privileged writer.\n\n**Honest status:** everything in the OSS version — your apps, AI-built apps, and the built-in\nApp Store apps (all first-party) — runs locally in direct mode with full trust; there is nothing\nthird-party to sandbox yet. The runner is *built and tested but dormant*: it is the ready seam\nfor shared/published apps later, where review + sandboxing arrive together. See\n[`SECURITY.md`](SECURITY.md) for the full threat model and trust tiers.\n\n## Design positions (why it's built this way)\n\n- **UI and data persist separately, both versioned.** Apps are views; collections are\n  truth; the ledger is history. Swap either without losing the other.\n- **The AI talks domain commands, never SQL, never raw state.** That's what makes human+AI\n  concurrent editing safe (idempotency + optimistic concurrency at the command layer).\n- **Extension-first.** Everything rides the MCP Apps bridge — no host-private APIs.\n  One codebase should serve every host that renders `ui://`.\n- **Single-purpose, not composite.** Each app owns one scenario and its own collection; the\n  engine mints a new one rather than cramming features into an old one. System apps (settings,\n  dashboard) are the deliberate exception — engine-owned, privileged, allowed to see across\n  collections.\n\n## Troubleshooting\n\n| Symptom | What it is |\n|---|---|\n| Updated, but the host still shows the old behaviour | The host keeps its old server process on the old data until **fully quit** (Cmd-Q, not just closing the window). |\n| Approval dialogs came back after a Claude Desktop auto-update | A Desktop auto-update occasionally resets these decisions (upstream [#56954](https://github.com/anthropics/claude-code/issues/56954), closed 2026-06-23 as *not planned*) — no fix is coming from that issue, so just re-allow. |\n| One approval prompt per app | `OMA_DYNAMIC_TOOLS=1` is in your host entry — either you put it there, or you installed between 2026-07-28 and 2026-08-16, when the installer set it for Claude Desktop and Claude Code as a workaround. `node install.mjs --check` calls such an entry `stale`; re-running the installer removes that one key and keeps the rest of your env. See [Configuration](#configuration). |\n| No viewer link, or the viewer is somebody else's | The port is taken by a non-open-mcp-apps process. Set `PORT` to something free. |\n| A widget loses its data after a page refresh (ChatGPT web) | Known, mitigation shipped, live re-test pending — [`KNOWN-ISSUES.md`](KNOWN-ISSUES.md). |\n| Widget clicks can update but not add (Codex desktop) | Blocked host-side. The umbrella request [openai/codex#28912](https://github.com/openai/codex/issues/28912) closed as completed on 2026-08-05, but that one is an `enhancement`, not this defect: the matching `bug`, [#30092](https://github.com/openai/codex/issues/30092), was still open on 2026-08-16. Update Codex and try, but expect it to still bite. |\n| You want to start completely clean | Fully quit your host(s), delete `open-mcp-apps.db` (plus its `-wal`/`-shm` siblings) from the store directory under [Configuration](#configuration). All apps and data gone, irreversibly, while staying installed. |\n| `pnpm install` exits 1 with `ERR_PNPM_IGNORED_BUILDS` | pnpm 11 refuses third-party build scripts until you decide about them, and calls that an error. Nothing here needs building — `better-sqlite3` loads a prebuilt binary it ships, and esbuild's binary comes from its platform package — so the tree it leaves behind is complete and working. Answer `pnpm approve-builds` however you like, or use npm. We do not declare those scripts as allowed, because that would make pnpm compile `better-sqlite3` on machines with no toolchain (a container, most CI) and fail there for nothing. |\n\n## Development\n\n| | |\n|---|---|\n| `src/server.mjs` | stdio MCP server; single `open_app` path (per-app `open_<name>` tools off unless `OMA_DYNAMIC_TOOLS=1`) |\n| `src/http.mjs` | `/mcp` (stateless Streamable HTTP) + `/view/<name>` browser viewer, bound to `127.0.0.1` |\n| `src/store.mjs` | SQLite: items + app registry + `change_event` ledger (idempotent, OCC) |\n| `src/shell-runtime.js` | browser runtime injected into every app (`window.oma`) |\n| `src/shell.mjs` | wraps stored HTML with runtime + design-token fallbacks at serve time |\n| `src/guide.mjs` | the authoring contract the AI reads before generating an app |\n| `install-app.mjs` | install an app you wrote yourself, from a file — the one door into the registry that doesn't go through the AI |\n| `components/` | 3 system apps installed on seed (settings, dashboard, app-store) + 22 App Store apps — not auto-installed; browse the app-store app for live previews with sample data and one-click install |\n\n```bash\nnpm test                     # every suite below, plus the static invariants and budget checks\nnode test/server-smoke.mjs   # 453 assertions over real stdio — incl. runtime app creation\nnode test/http-smoke.mjs     #  81 assertions over the HTTP transport (incl. SSE /events, viewer)\nnode test/provenance.mjs     #  39 assertions that an app's author — its trust tier — is not overwritable\nnode test/seed-smoke.mjs     #  22 assertions on the seed / design-kit pipeline\nnode test/files-smoke.mjs    #  41 assertions on the per-app file store (chunked uploads, GC races)\n```\n\nContributions need nothing signed — MIT in, MIT out ([`CONTRIBUTING.md`](CONTRIBUTING.md)).\n\n## Status and roadmap\n\nEarly v0 — proven end-to-end on Claude Desktop; cross-vendor render + shared store proven\non Codex desktop and the browser viewer.\n\n**What 0.5.0 changed** (breaking, and the largest change so far —\n[`CHANGELOG.md`](CHANGELOG.md) has the full account):\n\n- **An app's declaration is a first-class object.** `save_app` takes `ui` and `manifest` as two\n  slots instead of a manifest block buried in the document, and every revision snapshots both, so\n  restoring brings back the pair.\n- **An app can expose a function** — a data→data closure the AI calls with `call_function`, run by\n  the engine against that app's own collections. The seat is opt-in at `createEngine` and absent by\n  default, so a hosted deployment cannot inherit it.\n- **Deleting a row is confirmed by the engine**, inside the store transaction every path passes\n  through. App authors no longer write confirmation UI; the apps that carried their own\n  arm-then-delete had it removed.\n- **`promote_app`** turns a one-off `visual` into a kept app in one atomic step, and **`edit_app`\n  takes a hash-checked `{offset, length}` range**, so a model that has read a window can edit it\n  without sending an anchor back up.\n- **Settings and the App Store were rebuilt** — rail navigation, in-place detail pages, and the\n  storefront pictured above.\n- Underneath: **SDK v1 → v2**, `2026-07-28` in the supported protocol versions, and a tool surface\n  audited down to **33 tools**. Renamed and removed tools mean hosts will ask you to approve the\n  tools once more after upgrading.\n\nWhere it stands:\n\n- [x] engine: registry + shell + generic data commands + ledger\n- [x] system apps installed (settings, dashboard, app-store); 22 App Store apps with live previews, one-click install\n- [x] AI app creation loop (guide → save → open)\n- [x] in-context onboarding (ask how to use it → the AI reads your history/memory and builds a tailored starter set)\n- [x] security foundation: trust tiers + sandboxed runner + reserved config keys\n- [x] multi-host discovery installer (Claude Desktop · Claude Code · Codex) + shared per-user store\n- [x] `npx` one-command install (`@2nd1st/open-mcp-apps` on npm)\n- [ ] **self-hosted** remote (Streamable HTTP) as a *supported* shape → claude.ai / ChatGPT / mobile\n      off an engine *you* run — the transport exists (`src/http.mjs`) and has been live-tested over\n      HTTPS; what's missing is the hosted story, since the engine binds `127.0.0.1` by design.\n      Those browser hosts already work against the hosted [openmcp.app](https://openmcp.app); this\n      box is about doing it yourself\n- [ ] one-click install with no shell\n- [ ] app export/import → sharing → community App Store (review + runner sandbox activate here)\n\n## License\n\n**MIT**, for the whole repository — the engine and the apps in\n[`components/`](components/) alike ([`LICENSE`](LICENSE) ·\n[`LICENSING.md`](LICENSING.md)). Use it, fork it, modify it, embed it, run a\nmodified version as a hosted service; keep the copyright notice with substantial\nportions you redistribute. That is the whole obligation. Up to v0.5.2 the engine\nwas AGPL-3.0-only under a directory split — see [`LICENSING.md`](LICENSING.md)\nfor what changed and why.\n\nThe names **open-mcp-apps**, **openmcp.app**, **SecondFirst**, and **2nd1st**,\nand their logos, are **not** granted by the license — see\n[`TRADEMARKS.md`](TRADEMARKS.md). Fork the code freely; give your fork its own name.\n\nCopyright © 2026 2nd1st.\n\n© 2026 [2nd1st](https://github.com/2nd1st)\n",
  "bytes": 32672,
  "sha": "f9f879ba1791014cbd414d73953d09ad16b5568daa3cee8cd745dbfeead15f8f",
  "repo_slug": "2nd1st/open-mcp-apps",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_2nd1st_open_mcp_apps_5fa3a401/readme"
}