MCP Apps Architecture
This guide explains how MCPJam Inspector implements MCP Apps (SEP-1865) to render custom UI widgets for MCP tool results. MCP Apps use JSON-RPC 2.0 over postMessage with a double-iframe sandbox architecture for security isolation.MCPJam Inspector also supports OpenAI Apps SDK and
MCP-UI for custom UI rendering.
MCP Apps takes priority when a tool has
ui/resourceUri metadata.Overview
MCP Apps enables MCP servers to provide rich, interactive widgets for tool results. The implementation uses a secure double-iframe architecture where the outer iframe (sandbox proxy) isolates the inner iframe (guest UI) from the host page.Key features
- Double-iframe sandbox: Security isolation via sandbox proxy at different origin
- JSON-RPC 2.0 protocol: Standardized communication over postMessage
- Tool and resource access: Widgets can call MCP tools and read resources
- Theme synchronization: Automatic light/dark mode updates
- Display modes: Inline, Picture-in-Picture, and fullscreen support
Detection priority
When rendering tool results, the Inspector checks for UI metadata in this order:- MCP Apps:
ui/resourceUriin tool metadata - OpenAI Apps SDK:
openai/outputTemplatein tool metadata - MCP-UI: Inline
ui://resource in tool result
Architecture overview
Double-iframe sandbox
The double-iframe architecture provides security isolation:- Host page: MCPJam Inspector React application
- Sandbox proxy: Outer iframe at
/api/mcp/sandbox-proxywith minimal permissions - Guest UI: Inner iframe with widget HTML loaded via
srcdoc
Message flow
SandboxedIframe component
Located inclient/src/components/ui/sandboxed-iframe.tsx:
Widget data flow
1. Tool execution and detection
When a tool is executed, the system checks for MCP Apps support:2. Widget data storage
Before rendering, widget data is stored server-side:3. HTML fetching and injection
The server fetches HTML from the MCP resource and injects the client script:window.mcpApp API
The injected script provides the MCP Apps API to widget code:Events
Widgets can listen for these events:mcp:tool-input- Tool input receivedmcp:tool-result- Tool result receivedmcp:context-change- Host context changed (theme, etc.)mcp:tool-cancelled- Tool was cancelledmcp:teardown- Widget is about to be torn down
JSON-RPC 2.0 protocol
All communication uses JSON-RPC 2.0 format:Requests (with response expected)
Notifications (no response)
Supported methods
| Method | Direction | Description |
|---|---|---|
ui/initialize | Widget → Host | Initialize widget, get host context |
tools/call | Widget → Host | Call an MCP tool |
resources/read | Widget → Host | Read an MCP resource |
ui/open-link | Widget → Host | Open external URL |
ui/message | Widget → Host | Send message to chat |
ui/size-change | Widget → Host | Notify of size change |
ui/notifications/initialized | Widget → Host | Widget finished initializing |
ui/notifications/tool-input | Host → Widget | Send tool input |
ui/notifications/tool-result | Host → Widget | Send tool result |
ui/host-context-change | Host → Widget | Theme or context changed |
Server routes
POST /api/mcp/apps/widget/store
Stores widget data for later retrieval by the iframe.GET /api/mcp/apps/widget-content/:toolId
Fetches widget HTML from MCP resource and injects the client script.GET /api/mcp/sandbox-proxy
Serves the sandbox proxy HTML that creates the double-iframe architecture.Security considerations
Content Security Policy
The sandbox proxy uses a permissive CSP to allow widget content:Iframe sandbox attributes
Security trade-offs
- Double-iframe provides origin isolation
allow-same-originrequired for localStorage access- Widgets should be treated as semi-trusted code
- CSP headers restrict network access
Related files
client/src/components/chat-v2/mcp-apps-renderer.tsx- Main renderer componentclient/src/components/ui/sandboxed-iframe.tsx- Reusable double-iframe componentclient/src/lib/mcp-apps-utils.ts- Detection utilitiesserver/routes/mcp/apps.ts- Widget storage and servingserver/routes/mcp/sandbox-proxy.html- Sandbox proxy HTMLserver/routes/mcp/index.ts- Route mounting
Comparison with OpenAI Apps SDK
| Feature | MCP Apps (SEP-1865) | OpenAI Apps SDK |
|---|---|---|
| Protocol | JSON-RPC 2.0 | Custom postMessage |
| Sandbox | Double-iframe | Single iframe |
| API | window.mcpApp | window.openai |
| Metadata | ui/resourceUri | openai/outputTemplate |
| State persistence | Not supported | localStorage |
| Modal support | Not supported | Supported |
Contributing
When contributing to MCP Apps support:- Test with real MCP servers that implement SEP-1865
- Verify double-iframe security isolation
- Check JSON-RPC message format compliance
- Update this documentation for architecture changes

