Repository navigation
🤖 feat: MCP Apps views in the Artifacts tab - #5426
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
Security findingsAdvisory findings (4)
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
fcf7b1e to
055c6e5
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fcf7b1e322
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
055c6e5 to
6dfd5cb
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6dfd5cb378
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Here are some automated security review suggestions for this pull request.
Reviewed commit: 6dfd5cb378
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
6dfd5cb to
bd187d5
Compare
|
@codex review |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bd187d596c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
bd187d5 to
5aa9c5e
Compare
|
@codex review |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5aa9c5eb6b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
5aa9c5e to
5573aac
Compare
|
@codex review |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5573aac574
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5573aac574
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Here are some automated security review suggestions for this pull request.
Reviewed commit: 5573aac574
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
5573aac to
1ce21dc
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. 👍 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
a8fa73a to
c451af5
Compare
c451af5 to
2774e9e
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2774e9e0cb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
2774e9e to
4e24434
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4e24434238
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Here are some automated security review suggestions for this pull request.
Reviewed commit: 4e24434238
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
- MCP Apps host backend: advertise the ui extension, fetch `ui://` view resources, keep tool results in a bounded side store - MCP Apps views in the Artifacts tab (App views picker group) with a sandboxed frame, CSP and the host bridge - "Open in Artifacts" on MCP tool calls that carry a view - Storybook play test for an MCP Apps view - Codex review round 1 fixes: the stored result record is the authoritative view binding (getView returns invocation), failure snapshots keep resourceUri, records publish only after the atomic write, view tool calls honor the effective tool allowlist, optional resourceUri with independent visibility, consent shows an argument preview, Reload remounts the view, connections made under the other MCP Apps setting restart when idle, frame navigation guard on McpAppFrame - Codex review round 2 fixes: MCP App views fail closed outside the desktop app (no fetch, frame or host), failed or interrupted app calls record their invocation, oversize display snapshots drop only the app link, the picker stays above listing errors while views are open, the narrow layout opens views only in the dialog, the consent strip shows the full arguments and declines calls over 64 KiB - Codex review round 3 fixes: callMcpAppTool dispatches the view's tools/call at most once when the stable-plugin-epoch postflight re-runs the operation (authorization still runs on every attempt before the first dispatch) --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high` • Cost: `$123.74`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high costs=123.74 -->
…rom its display form (Codex r4 QiQG) Tool cards carry the sanitized display key (whitespace-collapsed, capped at 80 chars), while the result record and the server manager use the raw configured key, so getView refused the binding and Open failed for such servers. The record check now accepts the record's raw key or its display form, and the resource is read from the record's key. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
…x r5 RxWr, cross-layer) MCP App views use their own document preamble (CSP only, no artifact bridge), so the L3 WebRTC removal did not reach them. CSP cannot stop STUN/TURN and Chromium ignores webrtc 'block', so a view could send data out regardless of its granted connectDomains. The view document now starts with a script that deletes every RTC global; frame-src 'none' keeps child frames from handing back a fresh constructor. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
…restart (Codex r6 SJup) Server operations start servers only from request options recorded by a send or prompt discovery. Right after a backend restart there are none, so opening a persisted MCP App view failed with "not connected" until the next send. getView now runs the same startup as prompt discovery first when the workspace has no recorded options. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
… composer (Codex r6 SLg-) ui/message appended up to 32,000 characters to the draft without any confirmation. Padded text could sit below the visible part of the draft and go out with the user's next Send. The view's message now shows in the consent strip in full, and it reaches the composer only after the user clicks Add; a declined message fails the request. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
… r7 UKEM) A newer consent request replaced the shown strip in place, so a view could swap the payload between the user's pointerdown and click and the same Allow/Open/Add button approved the new request. While a strip is shown, newer requests are now declined, and the buttons settle only the request that is displayed (moved down from L9; the confirm arming delay stays in L9). --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
…prompts (Codex r10 WmkN) Since the view is bound to the record's raw server key (Codex r4 QiQG), the Allow and Add prompts rendered that raw key, so a repo-defined key with bidi or control characters could reorder or disguise the question. The prompts now show the card's sanitized display key; tool calls still go to the raw key. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
…n MCP App consent (Codex r11 Xhga, Xjg8) ui/open-link accepted https URLs with credentials, so https://trusted.example@evil.example/ was shown as-is in the only gate before the OS opened evil.example. Such links now fail, and the strip names the parsed host ahead of the full URL. The consent previews (tool arguments, message text, link) also rendered bidi controls live, so a view could make the text it asks the user to approve display reordered; they now show as visible \uXXXX escapes, while the request itself is unchanged. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
4e24434 to
3f026cb
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3f026cb498
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…r#5559) ## Summary HTML and SVG artifacts now render as live previews in browser/server mode (the phone client included), not only in the Electron desktop app. Outside desktop the preview has no host bridge: `window.xum.send`, `setState`, frame annotations and key forwarding do nothing there. MCP App views stay desktop-only.  ## Background coder#5424 and coder#5426 mounted these sandboxed `srcdoc` frames only when the desktop preload bridge existed (`executableFrames.ts`). The reason: CSP does not cover navigation, so a frame can still run `location.href = "https://host/?d=..."` or follow a tapped link. Electron refuses that navigation before the request leaves (`will-frame-navigate`, `src/desktop/subframeNavigation.ts`). A browser has no API that cancels a frame navigation in advance. That rule showed only escaped source on phones, which made the Artifacts tab useless there. ## Implementation - `ArtifactViewer` mounts the HTML/SVG frame in every mode. - `executableFrames.ts` now gates the bridge, not the frame: `canBridgeExecutableFrames()` (desktop only). Outside desktop, `SandboxedArtifactFrame` attaches no `message` listener, and the panel hides the frame Annotate button. - Why no bridge in browser mode: a page the frame navigates to keeps the same `contentWindow`, and its scripts run before the iframe's second `load` event, which is when `frameNavigationGuard.tsx` notices. So the host cannot tell the destination's messages from the artifact's (Codex review finding). - `McpAppFrame` keeps its desktop-only gate (renamed import only), because MCP App views need the bridge. ## Risks Outside Electron, an artifact can send **one** navigation request to any URL with what the page already holds: its content and the saved state baked into the `srcdoc`. This risk was accepted on purpose. The frame still cannot read Xum's DOM, storage, cookies, or API (opaque-origin sandbox, `allow-scripts` only), and with no listener a navigated page cannot drive Xum. Interactive artifacts that rely on `window.xum.send` or `setState` render on phones but their sends and saves are ignored there. ## Validation - New regression test: in browser mode, `send` and `setState` posted from the frame window before any second `load` reach nothing, and no `message` listener is attached. It fails with the gate line removed. - Annotate is offered for a frame in desktop mode and hidden in browser mode (one test covers both). - Storybook at 390 px with no preload bridge: the frame mounts with `sandbox="allow-scripts"` and its script runs ("Host theme: dark" in the screenshot comes from the baked-in initial theme). ## Follow-ups - coder#5560: tell phone users when `window.xum` interactions are unavailable; optional `event.origin` hardening for the OAuth listeners. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high` • Cost: `$2.65`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high costs=2.65 -->
…facts (coder#5710) ## Summary Expanding an MCP Apps tool card now shows the app's view inline, and a **Show input/output** toggle under the view shows the raw arguments and result. The Artifacts tab's **App views** picker now lists every finished app call from the chat, not only views opened with **Open in Artifacts**. A bug bash on these changes found four defects, and this PR fixes them. It also adds the dice-board MCP Apps server, seed and agent-driven e2e suite used to find and verify them. ## Background MCP Apps views (artifacts experiment, coder#5426) opened only in the Artifacts tab. Expanding the card showed JSON, and the picker held only views opened during the session, so after a reload or without a click the picker had no app views. ## Implementation 1. **Inline view** (`GenericToolCall.tsx`, `McpAppFrame.tsx`): a finished call with a `ui://` view renders `McpAppFrame` with a new `inline` variant (no Close header, height from the view's size reports, 720 px cap). The JSON renders below the view, not instead of it, so toggling never reloads the view. Running calls, VS Code and experiment-off rows render as before. 2. **Picker from the transcript** (`mcpAppViewsStore.ts`): `useMcpAppViews` derives views from finished transcript tool parts with `mcpServer.app`, through a cached snapshot that keeps its identity until the set of views changes (no re-render per stream delta). Views opened from cards outside the loaded window are added after them. **Close** returns to the files and keeps transcript views listed. 3. **Review and bug-bash fixes:** - Picker entries of one tool were identical: each now shows the call's arguments and `failed`/`interrupted`. - A failed call hid its error behind the toggle: failed calls open with input/output shown, and the view gets `tool-cancelled` with reason `failed` instead of `interrupted`. - The inline consent strip could sit above the visible chat: it is now `sticky top-0`. `scrollIntoView` does not work here, because the chat pinned to the bottom scrolls back (`useAutoScroll`). - The card's two buttons had no keyboard focus style: both get a focus ring. - Narrow cards show Open in Artifacts as an icon and truncate long names. J/K walk the App views. Repeats of one call are numbered, and model-written argument text shows control characters as escapes. App calls nested in `code_execution` are listed too. 4. **Test harness** (`tests/bugbash`): `startApp.ts --mcp-apps` seeds a dice-board MCP Apps server and a chat with four calls (with result, without stored result, failed, and a tool without a view), because mock AI cannot call MCP tools. `run.ts --config` selects `e2e.mcpapps.config.ts`. `make mcp-apps-e2e` runs `mcpapps/mcp-apps.e2e.ts`: seven tests that drive each flow with `agent.act` and pin the outcome with exact checks. `docs/AGENTS.md` explains how to run and write them. No CI job runs this suite: it makes model calls. ## Validation - Bug bash: 5 charters (inline view, picker state, keyboard, cross-checking, phone) with Opus 5.5 and Sonnet 5.5, 35 findings, triaged against the source. Four were confirmed with failing repro tests and are fixed here. - E2E suite: on the build before the fixes, 3 of 7 passed and the 4 bug tests failed with `ASSERTION_FAILED` on their own checks. On this head, 7 of 7 pass (`make mcp-apps-e2e`). - Unit tests for the inline body, the toggle (the frame stays the same element), the transcript-derived picker, Close, failed calls and the cancel reason. Each new test fails with its fix removed. - Storybook: `App/Chat/Tools/Generic` → `McpAppInline` and `McpAppInlinePhone`. The phone story pins a 358px width and asserts that the header action stays inside the card. Both are excluded from Pixel snapshots (budget). Failed call, expanded: the error shows at once, and the view says `tool cancelled: failed`.  App views in the picker, told apart by arguments and outcome:  The consent prompt stays on screen when the chat is scrolled to the view's buttons (from the e2e run):  Inline view with input/output open (Storybook):  ## Risks Low. Every change is behind the artifacts experiment (off by default) and only affects MCP tools that declare a `ui://` view. The sandbox, CSP and consent rules of the view frame are unchanged. The transcript subscription reads the workspace's existing message list and returns a cached result unless the set of views changes. ## Decisions and follow-ups - **Per-card activation.** A call with an app view expands, and so mounts its view, only on its own card's toggle. The remembered per-tool expansion does not apply to it, so a reload does not start a view for every earlier call. A restored Artifacts selection still reopens its one view after a reload. Consent rules are unchanged. - **Redacted calls get no view.** Their output was excluded on purpose, and a view would show it again from the host-only result record. - **No keybind for Show input/output.** The toggle is a native button in the card's tab order, like the card's other per-call controls. A global shortcut needs a focused-card model, which tool cards do not have. - **Follow-up (unverified):** in one run of the e2e suite with 4 parallel browsers on one server, a view's `tools/call` (Re-roll) never answered. The same click works alone, and 3 other parallel runs passed. The suite now runs serially (`workers: 1`). Whether concurrent clients can stall a view's tool call in `mcpServerManager` is not yet known. ## Pains The default bug-bash seed has no MCP data and mock AI cannot call MCP tools, so the seed writes `chat.jsonl` rows and the host-only result record directly. Tutorial popovers appear late and swallow the first click in automated runs. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high` • Cost: `$20.96`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high costs=20.96 -->
Summary
Implements the host side of MCP Apps (
io.modelcontextprotocol/ui, spec 2026-01-26) so MCP servers can show theirui://views in the Artifacts tab.Implementation
_meta.ui(and the deprecated flat key) is kept; tools not visible to the model are hidden from it.resources/readforui://views: exact MIME type, 2 MB cap. FullCallToolResults for views are kept in a host-only side store (session dir, capped), never sent to the model.srcdocframe (desktop-host model; SECURITY AUDIT comment explains why no proxy frame). CSP starts from the spec default and only grants declared https domains that are also on the CDN allowlist with the setting on.mcpAppHost.ts): initialize, tool input/result, size changes, logging,tools/call(same server, app-visible tools, consent strip for model-visible tools),ui/open-link(https, confirm),ui/message(into the composer, never auto-sent); everything else-32601.Validation
Router/CSP/visibility/validation unit tests and a Storybook play test with a fake view (handshake, tool result, consent). Dogfooded against a local stdio MCP server fixture with a real model turn.
Stack: part 5 of 9 of the Artifacts stack (each PR shows only its own layer). Everything is behind the Artifacts experiment (Settings → Experiments, off by default). The user-facing page lands in part 9 (
docs/workspaces/artifacts.mdx).Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high• Cost:$98.34