microsoft / microsoft/vscode

MCP App webviews duplicate identical multi-MB HTML bundles (35MB in one renderer snapshot)

Open
#327,439 0 comments 0 reactions 1 assignee Claimed by @connor4312 View on GitHub
Dominant language
TypeScript
Stars
193k
Forks
42.4k
PR merge metrics
PR metrics pending

Description

Found while analyzing a renderer heap snapshot from the Agents window (484 MB self-size).

## Summary

**16 `` strings totalling 35.2 MB** were retained via `WebviewElement._content.html`. They are only **two distinct MCP App bundles**, byte-identical, duplicated **11× and 5×** respectively — each ~2.2 MB of HTML with inlined JS.

The snapshot contained **32 live `ChatMcpAppModel` instances**, each with its own `WebviewElement`, plus 33 `ChatToolInvocationWebviewPart`.

## Cause

`ChatMcpAppModel._loadContent()` (`src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatMcpAppModel.ts:216-241`):

```ts
const resourceContent = await this._mcpToolCallUI.loadResource(token);
...
const htmlWithCsp = this._injectPreamble(resourceContent);
...
this._webview.setHtml(htmlWithCsp);
```

Every chat turn that invokes the same MCP app loads the resource again and allocates a **fresh flat copy** of the injected HTML. `WebviewElement._content.html` (`webviewElement.ts:137`) then retains it for the element's lifetime — it's needed by `reload()` / `reinitializeAfterDismount()` — and is never cleared on dispose.

## Suggested fixes

1. **Intern the bundle.** Cache the result of `_injectPreamble` keyed by resource URI + CSP (in `McpToolCallUI` or the resource loader). JS strings are immutable, so all 16 webviews can share one instance: **35 MB → 2.2 MB**, for the cost of a small cache. This is the real fix.
2. **Defensively clear `_content.html` in `WebviewElement.dispose()`.** Cheap, but only helps if some of these 32 models were already disposed. Worth checking either way — 32 simultaneously-live MCP App webviews in one window seems high, and if some are disposed-but-retained there's a second bug here.

## Effort estimate

Easy, and a good return: ~33 MB recovered in this snapshot, and it scales with how heavily MCP Apps get used.

(Written by Copilot)

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.