Repository navigation
feat: add MCP Apps support for rich iframe UIs - #15926
tristan-stahnke-GPS wants to merge 6 commits into
Conversation
7ff0560 to
af15a3d
Compare
ba493e1 to
d4890bc
Compare
025f2cb to
ca77290
Compare
|
Well, it works perfectly. First try. Why hasn't this been merged yet? |
ca77290 to
06aec6c
Compare
Thanks for verifying! It was quite stale with the significant arch changes, just merged with latest dev. @adamdotdevin @thdxr any thoughts on looking at getting this added in? would love to get some in-line review panels that augment the question/answer flows for visualizations etc. |
8a998f2 to
255ee47
Compare
f28734c to
1c42ec7
Compare
|
@tristan-stahnke-GPS appreciate the effort you put in , we need your help to push it o the end, its a long awaited feature, thanks |
Add MCP Apps protocol integration behind OPENCODE_EXPERIMENTAL_MCP_APPS flag, allowing MCP servers to render interactive UIs in sandboxed iframes. - Feature flag, AppMeta schema, tool metadata registry, and resource cache - Visibility filtering (_meta.ui.visibility: ["app"]) hides tools from LLM - structuredContent + resourceUri + server threaded into tool metadata - 3 experimental API routes (apps list, resource fetch, tool-call proxy) - McpAppTool renderer with AppBridge handshake and iframe auto-sizing - Configurable maxHeight (default 640px) via _meta.ui.maxHeight - FetchAppResourceFn wired through DataProvider - SDK regenerated - 15 tests across 3 test files - Demo fixture (server.py, app.html, README.md)
- Remove OPENCODE_EXPERIMENTAL_MCP_APPS flag and guards - Move routes from /experimental/mcp-app to /mcp-app - Create dedicated mcp-app.ts route file - Update all client paths (app, ui, SDK) - Update tests: remove flag manipulation, update paths - Regenerate SDK - Replace removed ToolCall with BasicTool in renderer
- Merge 21 new upstream/dev commits, resolve server.ts conflict
- Mount McpAppRoutes inside mcp.ts as .route('/app') to avoid touching server.ts
- Routes now at /mcp/app, /mcp/app/resource, /mcp/app/tool-call
- Update all client paths and tests accordingly
- Regenerate SDK
1c42ec7 to
482a77e
Compare
|
Can someone please merge this? |
|
Much needed, the right sidebar/custom sidebar tab as the mcp apps surface.. |
|
This branch has been upgraded to V2. We're no longer taking PRs for V1. If you think this is still relevant, please port it over and open it for V2. — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊 |
Add MCP Apps protocol integration, allowing MCP servers to render interactive UIs in sandboxed iframes. No feature flag required — MCP Apps is enabled by default.
_meta.ui.visibility: ["app"]) hides tools from LLMstructuredContent+resourceUri+serverthreaded into tool metadata/mcp-app(apps list, resource fetch, tool-call proxy)__mcp_app__renderer with AppBridge handshake and iframe auto-sizingmaxHeight(default 640px) via_meta.ui.maxHeightFetchAppResourceFnwired throughDataProvider/mcp-approutesserver.py,app.html,README.md)Issue for this PR
Closes #10884
Type of change
What does this PR do?
This adds support for the MCP Apps protocol. MCP servers can declare tools with
_meta.ui.resourceUripointing to aui://resource, and opencode renders the tool result inside a sandboxed iframe with a full AppBridge handshake.How it works end-to-end:
_meta.ui.resourceUrigets registered in atoolMetaRegistry. Tools withvisibility: ["app"]are filtered out of the LLM's tool list (they're only callable by the iframe itself).structuredContent,resourceUri,server, andmaxHeightare threaded into the tool part metadata so the frontend can pick them up.resourceUriin its metadata renders as the__mcp_app__tool instead of the generic tool renderer./mcp-app/resource, renders it in a sandboxed<iframe srcdoc>, and establishes anAppBridgeconnection overPostMessageTransport.oninitialized), the host sendstoolInputandtoolResult(withstructuredContent) to the iframe, which renders the data.onsizechange, capped at a configurablemaxHeight(default 640px, overridable per-tool via_meta.ui.maxHeight).Key implementation details:
AppBridgeandPostMessageTransportare statically imported (not dynamicimport()) to avoid a race condition where the iframe sendsui/initializebefore the host bridge is listening.structuredContentfrom SolidJS reactive state is deep-cloned viaJSON.parse(JSON.stringify())before passing tobridge.sendToolResult(), because SolidJS Proxy objects failpostMessage's structured clone algorithm (DataCloneError).createSignalrather than direct DOM manipulation, so re-renders don't clobber the height set byonsizechange.<div>withoverflow: hiddenconstrains the layout box so the parent container doesn't grow to the iframe's scroll height.Routes (promoted from
/experimental/mcp-appto/mcp-app):GET /mcp-app— list all MCP tools with UI resourcesGET /mcp-app/resource— fetch and cache HTML for aui://URIPOST /mcp-app/tool-call— proxy tool calls from iframe to MCP serverNew/modified files:
packages/opencode/src/server/routes/mcp-app.ts— dedicated route file for MCP App endpointspackages/opencode/src/mcp/index.ts—AppMeta,AppResourceschemas,extractAppMeta(),apps(),appResource(), visibility filteringpackages/opencode/src/session/prompt.ts— threadsstructuredContent+ metadata into tool partspackages/ui/src/components/message-part.tsx—__mcp_app__renderer (~100 lines)packages/ui/src/context/data.tsx—FetchAppResourceFntype + proppackages/app/src/pages/directory-layout.tsx— wiresonFetchAppResourceto/mcp-app/resourcepackages/opencode/test/fixture/mcp-app-demo/(Python MCP server + dashboard HTML app)How did you verify your code works?
extractAppMeta, visibility filtering,toolMetaregistry,apps()list,appResourcefetch/cache,structuredContentpassthrough, route handlers, andmaxHeightextractionbun turbo typecheck)DataCloneErrorin browser console after the structured clone fixChecklist