MCP App Hosts
Reference skill for MCP App host environments and authoring your own host. Each host
(VS Code, AppHub, standalone) has different CSP, sandbox, and capability constraints — this
skill is the source of truth for what works where. It also documents how to build a custom
host (AppHub-style LLM orchestration, or on the GitHub Copilot SDK).
This matrix lists only hosts that have been directly validated firsthand. Treat
every unlisted host as unknown until its lifecycle, CSP, permissions, transport,
accessibility and security behavior are recorded through
hit-process.md.
Quick Capability Matrix
| Capability |
VS Code |
AppHub |
Standalone |
CopilotHub |
eval() / new Function() |
NO |
Yes |
Yes |
Yes |
External <script src> CDN |
NO |
Yes |
Yes |
Yes |
External UI fetch() |
NO |
Yes |
Yes |
Yes |
| External media source |
NO |
Yes |
Yes |
Yes |
| Media autoplay |
NO |
Unvalidated |
Unvalidated |
Unvalidated |
window.open() |
NO |
Yes |
Yes |
Yes |
| Microphone |
NO |
Yes |
Yes |
Yes |
| Camera |
NO |
Yes |
Yes |
Yes |
| Geolocation |
NO |
Yes |
Yes |
Yes |
| Canvas 2D |
Yes |
Yes |
Yes |
Yes |
| WebGL |
Yes |
Yes |
Yes |
Yes |
| Web Workers |
Yes |
Yes |
Yes |
Yes |
| WebSockets |
Yes |
Yes |
Yes |
Yes |
| Nested iframes |
NO |
Yes |
Yes |
Yes |
Sampling (createMessage) |
Yes |
Yes |
Unvalidated |
Yes |
Elicitation (elicitInput) |
Unvalidated |
NO |
Unvalidated |
NO |
The generated Sampling/Elicitation rows are dated host observations for the
legacy server-initiated APIs. In that compatibility profile, reverse requests
require a stateful/bidirectional transport, an advertised client capability, and
possibly host-specific authorization. In VS Code, App-button sampling requires
the exact server entry under chat.mcp.serverSampling with
allowedOutsideChat: true.
For new MCP 2026-07-28 work, use MRTR, subscriptions/listen, explicit
application handles, or a direct model-provider connection as appropriate. See
mcp-app-build/mcp-v2.md and mcp-app-build/sampling.md. Always ship a
Display-Frame fallback where the interactive behavior is optional.
Media in VS Code: media-src 'self' blocks external audio/video URLs and the
sandboxed iframe gets no autoplay / Web Speech grant. The _meta.ui.csp /
sandbox.permissions opt-ins are spec'd but not honored by VS Code today. Proxy media
through the server and return same-origin bytes (data: URL / embedded resource), played on a
user gesture. See vscode.md §7.
VS Code is the most restrictive host in the currently validated set, but a
pass there is not a guarantee for an unknown host. Validate lifecycle,
permissions, accessibility and transport behavior on every declared target.
See hit-process.md for recording evidence.
CopilotHub (GitHub Copilot SDK host) is a permissive custom host — its capability
profile matches AppHub for every row above (full browser, about:srcdoc, popups
allowed), plus a verified server→host sampling bridge (elicitation not implemented).
See host-matrix.json (copilothub) and copilot-sdk-host.md.
Sub-Files
| File |
Purpose |
| host-matrix.json |
Machine-readable capability registry (source of truth) |
| vscode.md |
VS Code Insiders: CSP, sandbox, TLS, OAuth workaround, broken/working patterns |
| apphub.md |
AppHub custom host: architecture, proxy, postMessage protocol |
| standalone.md |
basic-host / standalone browser reference environment |
| copilot-sdk-host.md |
Authoring a host on the GitHub Copilot SDK (createSession): tools: ["*"] requirement, hooks-based tool-call capture |
| host-rendering.md |
Rendering MCP App tiles in a web/React host: iframe sandbox flags, CSP, dual _meta resource-URI shapes, host theming (dark/light), PDF/plugin escapes, the opaque-handle relay fix, and the sampling reverse-channel for interactive tiles |
| hit-process.md |
HIT feedback loop: how to discover, classify, record, propagate |
Usage
When building or auditing an MCP App, check the target host's capabilities:
- Read
host-matrix.json for programmatic checks
- Read the host-specific file for detailed constraints and workarounds
- If you discover something new, follow the HIT process to record it
Authoring a Host
Building your own MCP App host (not just targeting one)? Two reference implementations live here:
- apphub.md — LLM-orchestrated host: your own agent loop, an MCP
Client
proxy to downstream servers, manual postMessage bridge, splash + shared state.
- copilot-sdk-host.md — GitHub Copilot SDK host:
feed servers into
createSession({ mcpServers }), dual-channel architecture, hub-injected
tools, hooks-based tool-call capture, result normalization, and a server→host sampling
bridge. Start here for the tools: ["*"] and tool-capture gotchas.
- host-rendering.md — the web/React rendering side of any host:
turning a tool result into an interactive iframe tile. iframe sandbox flags (interactivity
vs display), per-tile CSP, reading the UI resource URI from both
_meta shapes, theming
tiles + host chrome for dark/light, the always-blocked PDF/plugin case and its escapes, and
the host-side repair for the fragile "relay an opaque handle between two tools" pattern, and
the sampling reverse-channel for tiles that borrow the host model (hint/AI buttons).
A host you author is also a target — once validated, add it to host-matrix.json via the
HIT process so the build/test/audit skills account for it.
The Validated Portable Set
These features work reliably across all validated hosts:
- Canvas 2D / WebGL rendering
- Safe DOM manipulation (
createElement, textContent, classList); sanitize
any intentionally supported HTML
- CSS animations, transitions, custom properties,
var(--host-variables)
postMessage communication (MCP App bridge protocol)
- npm-bundled + vite-plugin-singlefile HTML output
- Server-proxied external data (server.ts fetches, returns via tool result)
app.callServerTool() for UI→server communication
app.updateModelContext() for UI→model communication
If your app stays within this set, it is compatible with the currently validated
hosts under the recorded versions. Unknown hosts still require validation.
1---2name: mcp-app-hosts3description: MCP App host reference AND host-authoring guide. Query host capabilities, check what works where, record discoveries, and build your own host. Use when asking 'does X work in VS Code?', 'which hosts support microphone?', 'why does my app break in VS Code?', 'host compatibility matrix', 'what CSP does VS Code use?', 'record a new host discovery', 'how do I build an MCP App host?', 'author a host on the GitHub Copilot SDK', 'wire MCP servers into createSession', 'implement a sampling bridge in my host'.4---56# MCP App Hosts78Reference skill for MCP App host environments **and authoring your own host**. Each host9(VS Code, AppHub, standalone) has different CSP, sandbox, and capability constraints — this10skill is the source of truth for what works where. It also documents how to **build** a custom11host (AppHub-style LLM orchestration, or on the GitHub Copilot SDK).1213This matrix lists only hosts that have been directly validated firsthand. Treat14every unlisted host as unknown until its lifecycle, CSP, permissions, transport,15accessibility and security behavior are recorded through16[hit-process.md](hit-process.md).1718## Quick Capability Matrix1920<!-- BEGIN GENERATED HOST SUMMARY -->21| Capability | VS Code | AppHub | Standalone | CopilotHub |22|---|---|---|---|---|23| `eval()` / `new Function()` | **NO** | Yes | Yes | Yes |24| External `<script src>` CDN | **NO** | Yes | Yes | Yes |25| External UI `fetch()` | **NO** | Yes | Yes | Yes |26| External media source | **NO** | Yes | Yes | Yes |27| Media autoplay | **NO** | Unvalidated | Unvalidated | Unvalidated |28| `window.open()` | **NO** | Yes | Yes | Yes |29| Microphone | **NO** | Yes | Yes | Yes |30| Camera | **NO** | Yes | Yes | Yes |31| Geolocation | **NO** | Yes | Yes | Yes |32| Canvas 2D | Yes | Yes | Yes | Yes |33| WebGL | Yes | Yes | Yes | Yes |34| Web Workers | Yes | Yes | Yes | Yes |35| WebSockets | Yes | Yes | Yes | Yes |36| Nested iframes | **NO** | Yes | Yes | Yes |37| Sampling (`createMessage`) | Yes | Yes | Unvalidated | Yes |38| Elicitation (`elicitInput`) | Unvalidated | **NO** | Unvalidated | **NO** |39<!-- END GENERATED HOST SUMMARY -->4041The generated Sampling/Elicitation rows are dated host observations for the42legacy server-initiated APIs. In that compatibility profile, reverse requests43require a stateful/bidirectional transport, an advertised client capability, and44possibly host-specific authorization. In VS Code, App-button sampling requires45the exact server entry under `chat.mcp.serverSampling` with46`allowedOutsideChat: true`.4748For new MCP `2026-07-28` work, use MRTR, `subscriptions/listen`, explicit49application handles, or a direct model-provider connection as appropriate. See50`mcp-app-build/mcp-v2.md` and `mcp-app-build/sampling.md`. Always ship a51Display-Frame fallback where the interactive behavior is optional.5253**Media in VS Code**: `media-src 'self'` blocks external audio/video URLs and the54sandboxed iframe gets no `autoplay` / Web Speech grant. The `_meta.ui.csp` /55`sandbox.permissions` opt-ins are spec'd but **not honored** by VS Code today. Proxy media56through the server and return same-origin bytes (`data:` URL / embedded resource), played on a57user gesture. See [vscode.md](vscode.md) §7.5859VS Code is the most restrictive host in the **currently validated set**, but a60pass there is not a guarantee for an unknown host. Validate lifecycle,61permissions, accessibility and transport behavior on every declared target.62See [hit-process.md](hit-process.md) for recording evidence.6364> **CopilotHub** (GitHub Copilot SDK host) is a permissive custom host — its capability65> profile matches **AppHub** for every row above (full browser, `about:srcdoc`, popups66> allowed), **plus** a verified server→host **sampling** bridge (elicitation not implemented).67> See [`host-matrix.json`](host-matrix.json) (`copilothub`) and [copilot-sdk-host.md](copilot-sdk-host.md).6869## Sub-Files7071| File | Purpose |72|---|---|73| [host-matrix.json](host-matrix.json) | Machine-readable capability registry (source of truth) |74| [vscode.md](vscode.md) | VS Code Insiders: CSP, sandbox, TLS, OAuth workaround, broken/working patterns |75| [apphub.md](apphub.md) | AppHub custom host: architecture, proxy, postMessage protocol |76| [standalone.md](standalone.md) | basic-host / standalone browser reference environment |77| [copilot-sdk-host.md](copilot-sdk-host.md) | Authoring a host on the GitHub Copilot SDK (`createSession`): `tools: ["*"]` requirement, hooks-based tool-call capture |78| [host-rendering.md](host-rendering.md) | Rendering MCP App tiles in a web/React host: iframe sandbox flags, CSP, dual `_meta` resource-URI shapes, host theming (dark/light), PDF/plugin escapes, the opaque-handle relay fix, and the sampling reverse-channel for interactive tiles |79| [hit-process.md](hit-process.md) | HIT feedback loop: how to discover, classify, record, propagate |8081## Usage8283When building or auditing an MCP App, check the target host's capabilities:84851. Read `host-matrix.json` for programmatic checks862. Read the host-specific file for detailed constraints and workarounds873. If you discover something new, follow the HIT process to record it8889## Authoring a Host9091Building your own MCP App host (not just targeting one)? Two reference implementations live here:9293- [apphub.md](apphub.md) — **LLM-orchestrated host**: your own agent loop, an MCP `Client`94 proxy to downstream servers, manual postMessage bridge, splash + shared state.95- [copilot-sdk-host.md](copilot-sdk-host.md) — **GitHub Copilot SDK host**:96 feed servers into `createSession({ mcpServers })`, dual-channel architecture, hub-injected97 tools, hooks-based tool-call capture, result normalization, and a **server→host sampling98 bridge**. Start here for the `tools: ["*"]` and tool-capture gotchas.99- [host-rendering.md](host-rendering.md) — **the web/React rendering side** of any host:100 turning a tool result into an interactive iframe tile. iframe sandbox flags (interactivity101 vs display), per-tile CSP, reading the UI resource URI from both `_meta` shapes, theming102 tiles + host chrome for dark/light, the always-blocked PDF/plugin case and its escapes, and103 the host-side repair for the fragile "relay an opaque handle between two tools" pattern, and104 the sampling reverse-channel for tiles that borrow the host model (hint/AI buttons).105106A host you author is also a *target* — once validated, add it to `host-matrix.json` via the107[HIT process](hit-process.md) so the build/test/audit skills account for it.108109## The Validated Portable Set110111These features work reliably across **all** validated hosts:112113- Canvas 2D / WebGL rendering114- Safe DOM manipulation (`createElement`, `textContent`, `classList`); sanitize115 any intentionally supported HTML116- CSS animations, transitions, custom properties, `var(--host-variables)`117- `postMessage` communication (MCP App bridge protocol)118- npm-bundled + vite-plugin-singlefile HTML output119- Server-proxied external data (server.ts fetches, returns via tool result)120- `app.callServerTool()` for UI→server communication121- `app.updateModelContext()` for UI→model communication122123If your app stays within this set, it is compatible with the currently validated124hosts under the recorded versions. Unknown hosts still require validation.