Repository navigation
Replies: 1 comment
|
Another case for this proposal: one long-lived app frame that asks repeatedly, not many frames that ask once. What happened. On 29 October, an inline Mobile Dev MCP App (Android emulator screen stream) asked for approval of What the proposal already covers. "Always allow in this thread" for What it does not cover yet: Decline. In Suggested additions:
Tests could cover: approve once, then the app reconnects without a new prompt; decline, then background retries produce no new prompt; a grant for one tool does not apply to other tools or threads. This comment was researched, drafted, and posted by an AI agent (Claude Opus 5.5 via Claude Code in T3 Code) on behalf of the account owner. |
Uh oh!
There was an error while loading. Please reload this page.
Related: #29266 (MCP widget confirmations and permission options), #27067 (inline approvals are hard to spot)
Problem
When several MCP App instances render in one turn, T3 Code asks for approval once per tool call, one modal at a time. With 5 task cards on screen, I have to click Confirm 5 times before the cards finish loading.
What happens today:
readOnlyHint.requestConfirmDialoginMcpAppFrame.tsx.confirmDialog.tskeeps one active dialog and queues the rest in FIFO order.{"task_id": "DEMO-101"}.Why this hurts:
The cost grows with the number of instances: a list of 10 tasks means 10 clicks.
Reproduction (no real data): a fake stdio MCP server called
clickupwith:show_task:readOnlyHint: true,_meta.ui.resourceUri: ui://clickup/task-cardget_task_details:_meta.ui.visibility: ["app"], no annotations. The card calls it on load.Prompt Claude Haiku with "Use show_task for DEMO-101 … DEMO-105, in parallel", then open the thread.
I first ran into this with the real ClickUp MCP App. I haven't confirmed whether its tools leave out
readOnlyHint. Server authors should annotate read-only tools, but even then the host needs to handle many legitimate write calls without a modal for each one.Proposal: one-line inline approval on the app frame
Move MCP App approvals out of the global modal and onto the frame that's asking. This is the same idea as timeline approvals (
TimelinePendingApprovalRow): the request appears where the work is happening, and nothing else gets blocked.I built a working prototype to check that this fits the existing UI:
Each waiting frame gets one line above it:
🛡 Waiting for approval · clickup wants to run get_task_details ⓘ Decline Approve all 4 MoreDetails on demand. Hovering ⓘ shows the full arguments in a popover.
Batch. When several frames wait on the same
server + tool, the first line's primary action becomes Approve all N. "Approve this one" moves to More.Thread-scoped trust. More includes "Always allow in this thread", which is scoped to
<server>.<tool>in that thread only.Doesn't block. You can keep scrolling and typing while frames wait, and each frame resolves on its own.
Stays visible if the card is collapsed. If MCP App cards become collapsible (Allow collapsing or hiding inline MCP app cards while keeping the connector enabled #30907, Per-server "collapse by default" for MCP Apps (Atlassian's Jira cards take over Claude threads) #31591), the approval line stays outside the collapsed area.
Lifecycle. If a frame unmounts, its pending request is declined, the same as when the last dialog host goes away today. Fullscreen isn't allowed while that frame has a pending request.
Paired with an "approvals waiting" banner (addresses #27067)
#27067 points out that inline approval rows are easy to miss once they're off-screen. Inline approval alone would repeat that problem, so the proposal pairs it with a docked banner above the composer:
🛡 5 approvals waiting ShowIt counts all pending approvals in the thread, both provider approvals (
TimelinePendingApprovalRow) and MCP App approvals. That way there is one place to look, whatever kind of request is waiting.Show scrolls to the first waiting row.
It's an ordinary
ComposerBannerStackitem (variant="warning",ShieldIcon, ghostButton size="xs"), the same shape as the model-fallback and fresh-session banners.The banner and the rows complement each other. Each request stays on its row, where its context is, and the banner keeps you from missing it.
Consistency with the existing UI
The bar only combines patterns T3 already uses:
Waiting for approvalintext-warning, then a muted·TimelinePendingApprovalRowMoremenu (side="top" align="end")ComposerPendingApprovalActionswithpresentation="inline"openOnHoverPopoverPopup tooltipStyle side="top"NoticeTextinComposerBannerStackfont-mono text-xs<code>with max height and scrollTimelinePendingApprovalRowlabeltext-xs,flex flex-wrap gap-x-2 gap-y-1, which wraps on narrow widthsComposerBannerStackitems (modelFallbackBannerItem,freshSessionBannerItem)The only intentional difference is "Approve all N" as the primary action when requests are grouped. That's the click reduction this proposal is about.
Security
readOnlyHintstill ask.Mobile
Mobile has the same problem.
McpAppWebView.tsxshows one nativeDialog.alertper call.On Android it's likely worse: a comment there notes that Android dismisses earlier alerts
when a new one opens, and dismissed requests are declined. With 5 cards, the first 4 could
be declined before the user sees them (from reading the code, not yet tested on a device).
The same model should carry over: a one-line approval above the app WebView, plus the
"approvals waiting" banner. I'd ship web/desktop first and follow with mobile in the same
direction, unless you'd rather land both together.
Prototype and open questions
I have a working web prototype: a small approval store, a one-line bar component,
McpAppFrame.tsxswappingrequestConfirmDialogfor the store, and oneComposerBannerStackitem inChatView.tsx. Happy to open a PR if the direction looks right.Open questions:
Reproduction, prototype, and draft prepared with Claude Opus 5.5 via Claude Code inside T3 Code. Real agent turns used Claude Haiku 5.5.
All reactions