Context
The AppRenderer is the heaviest piece of the Apps tab — it owns the iframe and the AppBridge lifecycle from @modelcontextprotocol/ext-apps. To keep the screen layer "dumb", the wiring layer (Phase 3) constructs the bridge from the active MCP Client and pushes input/result/cancellation through an imperative ref rather than via prop drilling.
See Apps Screen feature spec and storybook component plan entry 2.5b.
Legacy v1 reference: AppRenderer.tsx.
Scope
AppRenderer
- Path:
clients/web/src/components/elements/AppRenderer/ (or groups/ if it ends up composing other parts).
- Props:
sandboxPath: string — URL/path of the sandbox proxy iframe.
tool: Tool — selected app tool (used for resource URI lookup).
bridgeFactory: (iframe: HTMLIFrameElement) => AppBridge — wiring layer constructs the bridge using a real MCP Client.
onError?: (err: Error) => void — error notifications.
- Imperative ref (
AppRendererHandle):
sendToolInput(args: Record<string, unknown>): Promise<void>
sendToolResult(result: CallToolResult): Promise<void>
sendToolCancelled(reason: string): Promise<void>
teardown(): Promise<void>
- Owns the iframe element and
AppBridge handle; no Mantine controls beyond a positioning Box.
- On unmount: invokes
bridge.teardownResource(...) then disconnects the transport.
Stories
- Loading (iframe mounting), Loaded (with mock bridge factory), Error, Maximized.
- Mock the bridge factory in stories so Storybook does not need a real MCP client.
Acceptance criteria
Dependencies
- Blocked by: Apps tab — add @modelcontextprotocol/ext-apps dep and isAppTool helper in core.
- Can run in parallel with:
AppListItem/AppDetailPanel issue.
Branch / Base
Context
The
AppRendereris the heaviest piece of the Apps tab — it owns the iframe and theAppBridgelifecycle from@modelcontextprotocol/ext-apps. To keep the screen layer "dumb", the wiring layer (Phase 3) constructs the bridge from the active MCPClientand pushes input/result/cancellation through an imperative ref rather than via prop drilling.See Apps Screen feature spec and storybook component plan entry 2.5b.
Legacy v1 reference:
AppRenderer.tsx.Scope
AppRendererclients/web/src/components/elements/AppRenderer/(orgroups/if it ends up composing other parts).sandboxPath: string— URL/path of the sandbox proxy iframe.tool: Tool— selected app tool (used for resource URI lookup).bridgeFactory: (iframe: HTMLIFrameElement) => AppBridge— wiring layer constructs the bridge using a real MCPClient.onError?: (err: Error) => void— error notifications.AppRendererHandle):sendToolInput(args: Record<string, unknown>): Promise<void>sendToolResult(result: CallToolResult): Promise<void>sendToolCancelled(reason: string): Promise<void>teardown(): Promise<void>AppBridgehandle; no Mantine controls beyond a positioningBox.bridge.teardownResource(...)then disconnects the transport.Stories
Acceptance criteria
Tool,CallToolResult,Implementation) — no v1.5 wrappers.bridgeFactoryso the renderer is testable in Storybook with mocks.MessagePortlisteners).Dependencies
AppListItem/AppDetailPanelissue.Branch / Base
v2/mainv2