microsoft / microsoft/vscode

MCP App webview blank in auxiliary chat window until scroll forces reinitializeAfterDismount; mountTo registers MessagePort handler on main window before DOM node is attached to aux window

Open
#331,140 0 comments 1 reaction 1 assignee Claimed by @roblourens View on GitHub
Dominant language
TypeScript
Stars
193k
Forks
42.4k
PR merge metrics
PR metrics pending

Description

MCP App webviews render correctly in the main chat panel but are completely blank when using "New Chat Window" (workbench.action.newChatWindow). The app's JavaScript never executes. Scrolling the item off-screen and back fixes it (triggers reinitializeAfterDismount()).

Root Cause:
In chatToolInvocationPart.ts, the ChatMcpAppModel is instantiated (which calls mountTo) before the domNode is placed into the auxiliary window's DOM:

```
// chatToolInvocationPart.ts ~line 247
this.mcpAppPart.value = this.instantiationService.createInstance(
ChatMcpAppSubPart, ... // constructor calls mountTo() immediately
);
appDomNode.replaceWith(this.mcpAppPart.value.domNode); // only NOW in aux window DOM
```
Inside ChatMcpAppModel constructor:

```
const targetWindow = dom.getWindow(this._container); // container not yet in aux window DOM → returns main window
this._webview.mountTo(this._container, targetWindow); // registers message handler on WRONG window
```

WebviewElement.mountTo() calls _registerMessageHandler(targetWindow) and sets parentOrigin from targetWindow.origin. Since targetWindow is the main window but the iframe ends up in the auxiliary window, the MessagePort handshake fails silently. The queued _send('content', ...) call never delivers the HTML.

Evidence:

Console in auxiliary window shows only the iframe sandbox warning — zero app log output (JS never executes)
reinitializeAfterDismount() (triggered by scroll off/on) calls getWindow(this.element) when the element IS in the auxiliary window DOM, fixing the window reference
Suggested Fix:
Either:

Defer mountTo() until after the domNode is attached to the target window's DOM (e.g., use queueMicrotask or move mount into a post-attach callback)
Call remount() after appDomNode.replaceWith(...) in the autorun
Pass the correct targetWindow explicitly from the ChatMcpAppSubPart constructor context (which knows the target window from dom.getWindow(this.domNode) after it's been attached by the list renderer)

Repro:

Have an MCP server with an app-enabled tool (uses x-]]mcpApps resource)
Open Chat panel → invoke the tool → renders correctly
Click + dropdown → "New Chat Window" → invoke the same tool → blank area
Scroll the chat up until the result is off-screen, then scroll back down → renders correctly

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.