You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ScriptedAlchemy/cargo-hauler demonstrates that MCP App authors currently rebuild too much framework plumbing inside the browser bundle.
Its src/mcp/hauler/apps/dashboard.tsx manually owns:
JSON-RPC request ids;
window.parent.postMessage(..., '*');
pending request bookkeeping and 15 s timeouts;
tools/call request construction;
result envelope unwrapping (structuredContent nested or direct);
dozens of hand-written unknown interfaces for data already described by the route resultSchema;
runtime shape readers to turn those hand-written interfaces back into typed dashboard models.
The corresponding tool already exports canonical inputSchema / resultSchema. The browser App cannot consume a generated, browser-safe typed client for that contract, so protocol and schema knowledge is duplicated across server and client.
This is exactly the seam #592 intends to remove: Apps should be views over the canonical application graph, not mini MCP clients.
Direction
Generate a browser-safe App client surface from Application IR / route contracts.
The compiler already knows route input/output contracts. Emit browser-safe generated declarations from the same Application IR so importing types does not pull Zod or Node/runtime code into the App bundle.
For a route with resultSchema, client.call(...) should return the inferred structured result type directly or a typed result wrapper with an explicit .structured field. App code should not need to rediscover whether data is under structuredContent.
React integration
A thin optional React layer may provide query/subscription hooks, but the core client should not require React or Effect.
#564 should use this same browser bridge for standalone production hosting. Workbench preview, MCP-host embedded Apps, serve-app, and <plugin> web must not each grow different App client semantics.
Acceptance
Generated browser-safe types expose tool input/output contracts without bundling server route modules or Zod.
An App can call a known tool through a typed framework client without hand-writing JSON-RPC messages.
Structured results are decoded consistently with the MCP projection.
Error, timeout, cancellation, consent, and close/rebind behavior are framework-owned.
Transport validates the expected parent/source/origin semantics rather than requiring app code to use unrestricted postMessage('*') directly.
cargo-hauler can delete its local JSON-RPC client, PendingRequest, manual StructuredContent envelope plumbing, and the protocol-shape interfaces duplicated from its result schemas.
Problem
ScriptedAlchemy/cargo-haulerdemonstrates that MCP App authors currently rebuild too much framework plumbing inside the browser bundle.Its
src/mcp/hauler/apps/dashboard.tsxmanually owns:window.parent.postMessage(..., '*');tools/callrequest construction;structuredContentnested or direct);unknowninterfaces for data already described by the routeresultSchema;The corresponding tool already exports canonical
inputSchema/resultSchema. The browser App cannot consume a generated, browser-safe typed client for that contract, so protocol and schema knowledge is duplicated across server and client.This is exactly the seam #592 intends to remove: Apps should be views over the canonical application graph, not mini MCP clients.
Direction
Generate a browser-safe App client surface from Application IR / route contracts.
Illustrative author experience:
or generated helpers:
Exact API is open. Required properties are not.
Bridge runtime
The framework should own:
ui/*/ tool-call bridge transport;serve-app, and First-classwebsurface (production): ship a browser host for the plugin's MCP Apps inside the artifact, openable from the installed CLI (<plugin> web);/webin dev for parity #564's production browser host.Do not make each App use raw
postMessage('*').Types
The compiler already knows route input/output contracts. Emit browser-safe generated declarations from the same Application IR so importing types does not pull Zod or Node/runtime code into the App bundle.
For a route with
resultSchema,client.call(...)should return the inferred structured result type directly or a typed result wrapper with an explicit.structuredfield. App code should not need to rediscover whether data is understructuredContent.React integration
A thin optional React layer may provide query/subscription hooks, but the core client should not require React or Effect.
Examples:
This should reuse the same underlying client/runtime rather than introduce another transport implementation.
Relationship to #564
#564 should use this same browser bridge for standalone production hosting. Workbench preview, MCP-host embedded Apps,
serve-app, and<plugin> webmust not each grow different App client semantics.Acceptance
postMessage('*')directly.serve-app, host embedding, and First-classwebsurface (production): ship a browser host for the plugin's MCP Apps inside the artifact, openable from the installed CLI (<plugin> web);/webin dev for parity #564's production browser host exercise the same core bridge contract.PendingRequest, manualStructuredContentenvelope plumbing, and the protocol-shape interfaces duplicated from its result schemas.Consumer evidence
ScriptedAlchemy/cargo-hauler/src/mcp/hauler/apps/dashboard.tsxScriptedAlchemy/cargo-hauler/src/mcp/hauler/tools/hauler_status.tsxwebsurface (production): ship a browser host for the plugin's MCP Apps inside the artifact, openable from the installed CLI (<plugin> web);/webin dev for parity #564