future: migrate widget to @modelcontextprotocol/ext-apps SDK #69

Closed
opened 2026-05-23 20:55:30 +00:00 by coilysiren · 1 comment
Owner

Originally filed by @coilysiren on 2026-04-29T09:35:37Z - https://github.com/coilysiren/repo-recall/issues/35

🤖 Filed by Claude Code on Kai's behalf.

Goal

(Future) Migrate the hand-rolled MCP App widget JS to the official @modelcontextprotocol/ext-apps SDK. Adopt React/preact for component-driven widgets, free spec updates, and a tested App class lifecycle.

Why this is "future" not "now"

The current hand-rolled approach (vanilla JS + postMessage) is intentional and working:

  • Single-language repo (no npm / node / Vite in CI or the brew install path).
  • ~80 lines of JS gets you the same five-handler lifecycle the SDK provides.
  • The MCP Apps protocol is small enough that hand-rolling is auditable.
  • Matches the pattern in eco-mcp-app/src/eco_mcp_app/templates/eco.html.

The SDK becomes the better choice when:

  • Multiple interactive widgets (this repo has one today).
  • Component-driven rendering is wanted (React, preact, lit).
  • Server-rendered HTMX hydration like eco-mcp-app's /preview HTTP path.
  • You'd already be shipping a JS toolchain for some other reason.

Trade-offs to revisit at decision time

Hand-rolled (now) SDK (future)
~80 lines of vanilla JS 130 KB bundled SDK per widget
No npm / node / Vite npm + node + Vite + ext-apps + (maybe React)
Track MCP Apps spec updates manually Free spec updates as protocol evolves
Single-file include_str! into Rust binary Multi-file build, output committed or built in CI
Brew formula stays simple Brew formula needs to know about widget bundling
Dev loop: edit .html, rebuild Rust Dev loop: npm run build && cargo build

When to actually migrate

Trigger on any of:

  1. The widget surface grows past 2 widgets.
  2. The dashboard wants component-driven UX (paginated tables, filters, modal) that's painful in vanilla DOM methods.
  3. The MCP Apps spec ships a backwards-incompatible change that's expensive to mirror by hand.
  4. We want React-style useApp / useHostStyles ergonomics.
  5. A different consumer of the same widget code (e.g. a separate web preview) ships and needs the same render path.

Until then, hand-rolled wins.

Cross-references

  • Sibling tracker in eco-mcp-app:
  • The functional parity work (handshake, size-changed, MIME) is tracked separately in this repo's #33. That work is short-term and SHOULD ship in the hand-rolled flow first, BEFORE any SDK migration. Don't confuse "fix the broken handshake" (urgent) with "graduate to the SDK" (this issue, deferred).

🤖 Filed by Claude Code on Kai's behalf.

_Originally filed by @coilysiren on 2026-04-29T09:35:37Z - [https://github.com/coilysiren/repo-recall/issues/35](https://github.com/coilysiren/repo-recall/issues/35)_ > 🤖 Filed by Claude Code on Kai's behalf. ## Goal (Future) Migrate the hand-rolled MCP App widget JS to the official [`@modelcontextprotocol/ext-apps`](https://github.com/modelcontextprotocol/ext-apps) SDK. Adopt React/preact for component-driven widgets, free spec updates, and a tested `App` class lifecycle. ## Why this is "future" not "now" The current hand-rolled approach (vanilla JS + postMessage) is intentional and working: - Single-language repo (no npm / node / Vite in CI or the brew install path). - ~80 lines of JS gets you the same five-handler lifecycle the SDK provides. - The MCP Apps protocol is small enough that hand-rolling is auditable. - Matches the pattern in [`eco-mcp-app/src/eco_mcp_app/templates/eco.html`](https://github.com/coilysiren/eco-mcp-app/blob/main/src/eco_mcp_app/templates/eco.html). The SDK becomes the better choice when: - Multiple interactive widgets (this repo has one today). - Component-driven rendering is wanted (React, preact, lit). - Server-rendered HTMX hydration like eco-mcp-app's `/preview` HTTP path. - You'd already be shipping a JS toolchain for some other reason. ## Trade-offs to revisit at decision time | Hand-rolled (now) | SDK (future) | |---|---| | ~80 lines of vanilla JS | 130 KB bundled SDK per widget | | No npm / node / Vite | npm + node + Vite + ext-apps + (maybe React) | | Track MCP Apps spec updates manually | Free spec updates as protocol evolves | | Single-file `include_str!` into Rust binary | Multi-file build, output committed or built in CI | | Brew formula stays simple | Brew formula needs to know about widget bundling | | Dev loop: edit `.html`, rebuild Rust | Dev loop: `npm run build && cargo build` | ## When to actually migrate Trigger on any of: 1. The widget surface grows past 2 widgets. 2. The dashboard wants component-driven UX (paginated tables, filters, modal) that's painful in vanilla DOM methods. 3. The MCP Apps spec ships a backwards-incompatible change that's expensive to mirror by hand. 4. We want React-style `useApp` / `useHostStyles` ergonomics. 5. A different consumer of the same widget code (e.g. a separate web preview) ships and needs the same render path. Until then, hand-rolled wins. ## Cross-references - Sibling tracker in eco-mcp-app: <link to be filled in once filed> - The functional parity work (handshake, size-changed, MIME) is tracked separately in this repo's `#33`. That work is short-term and SHOULD ship in the hand-rolled flow first, BEFORE any SDK migration. Don't confuse "fix the broken handshake" (urgent) with "graduate to the SDK" (this issue, deferred). > 🤖 Filed by Claude Code on Kai's behalf.
Author
Owner

Iceboxed in the 2026-05-29 backlog burn-down: Self-labeled future SDK migration, no current dependency. Reopen anytime if it becomes real.

Iceboxed in the 2026-05-29 backlog burn-down: Self-labeled future SDK migration, no current dependency. Reopen anytime if it becomes real.
coilysiren 2026-05-30 05:43:53 +00:00
  • closed this issue
  • added the
    P4
    label
Commenting is not possible because the repository is archived.
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/repo-recall#69
No description provided.