Repository navigation
Description
Summary
A Copilot desktop MCP App cannot initialize an embedded Fabric Notebook. The UI resource declares the required origin in _meta.ui.csp.frameDomains, and the native resource bridge returns that metadata correctly. However, a fresh native guest reports an enforced frame-loading CSP violation whose applicable source list is 'none'.
Is there a supported configuration or approval step for enabling declared nested frames, or is this a host compatibility bug?
Related: #4271 reports opaque origins and inherited sandbox restrictions. This report adds an observed CSP denial on macOS.
Environment
- GitHub Copilot desktop: 1.1.33, confirmed using
get_app_info - OS: macOS
- Installed release, not a local source build
- MCP transport: local stdio
- MCP Apps SDK:
@modelcontextprotocol/ext-apps2.0.3 - UI resource MIME type:
text/html;profile=mcp-app - Embedded application: Microsoft Fabric Notebook
Resource declaration
The server supplies this metadata both in resource discovery and on the relevant resources/read contents item:
_meta: {
ui: {
csp: {
frameDomains: [
"https://msit.powerbi.com",
"https://daily.powerbi.com"
]
}
}
}We verified that the Copilot native resource bridge returns the HTML with the expected declared origins, including https://msit.powerbi.com.
Observed errors and diagnostic details
1. Enforced frame-loading denial
A temporary listener registered before creating the nested iframe captured a frame-related SecurityPolicyViolationEvent:
disposition: enforce
blocked origin: https://msit.powerbi.com
applicable frame policy source list: 'none'
The App displayed the following application-generated diagnostic:
Host CSP blocked the Fabric iframe. Required origin: https://msit.powerbi.com.
Enable declared frame domains in the host; Notebook commands are disabled.
This is not a report-only warning. The fresh view did not render the Notebook or receive its expected Fabric-origin message.
Evidence limitation: the probe selected frame-src from originalPolicy, falling back to child-src and then default-src. It retained the source list but not the selected directive name or complete policy string. Therefore we can confirm an enforced frame denial, but cannot identify which directive or host component supplied it.
2. Opaque origin and unavailable storage
The native App also reported:
location.protocol: mcp-app-guest:
self.origin: null
isSecureContext: true
localStorage access: SecurityError
These observations indicate an opaque-origin environment. We did not directly inspect the native ancestor iframe sandbox attributes.
Reproduction flow
- Configure a local stdio MCP server exposing an MCP App resource and an open tool linked through
_meta.ui.resourceUri. - Declare the actual embed origin in
_meta.ui.csp.frameDomains, in discovery andresources/read. - Register a
securitypolicyviolationlistener before constructing the nested iframe. - Open a fresh tool UI in Copilot and load the embedded application from the declared origin.
- Compare the returned resource metadata with the violation's
disposition, blocked origin, and applicable frame-source policy. - Inspect
self.originand whether accessinglocalStoragethrows.
The observed reproduction uses an authenticated Fabric Notebook. Workspace and Notebook identifiers are omitted; a standalone public-domain minimal reproduction has not yet been verified.
Controlled comparisons
The same real Notebook successfully renders in a separate-origin browser AppBridge test host using:
sandbox="allow-scripts allow-same-origin"- Both Chromium and WebKit rendered the Notebook.
- The browser-host test received successful acknowledgements for opening and closing the table of contents.
- Chromium also rendered with non-secure HTTP ancestors, even when
crypto.randomUUIDandcrypto.subtlewere unavailable in the embedded page.
In a separate test, removing only allow-same-origin from the outer App iframe reproduced a missing-handshake symptom without a CSP violation. Chromium logged:
Failed to execute 'postMessage' on 'DOMWindow':
The target origin provided ('https://msit.powerbi.com')
does not match the recipient window's origin ('null').
This demonstrates a separate sandbox-origin compatibility blocker. It does not prove the exact native ancestor attributes or explain every earlier native failure.
Expected behavior and questions
The MCP Apps specification describes allowing nested frames from declared frameDomains, with frame-src 'none' used when no frame domains are provided:
Could maintainers clarify:
- Are declared nested frames supported for local stdio MCP Apps in Copilot desktop?
- Is any user, administrator, or per-server configuration/approval required?
- Could metadata propagation or policy caching explain a fresh guest enforcing a denial despite receiving
frameDomains? - What is the supported approach for embeds requiring real-origin semantics and browser storage, as discussed in MCP App sandbox omits
allow-same-origin, so apps and their embeds run with anullorigin #4271? - Is there documentation for the native guest's actual CSP/sandbox restrictions and a supported macOS inspection workflow?
We want to follow the supported isolation model, not disable CSP or weaken postMessage origin checks.
Privacy and scope
No Copilot binaries or security settings were modified. Temporary probes were removed after testing. No Notebook cells were executed, edited, or saved. Credentials, workspace/Notebook identifiers, authenticated URLs, raw tool payloads, and full logs are omitted. Claude was not freshly probed in this investigation.
Activity
chuwik commentedon Nov 11, 2026
Fixed by github/github-app#25764, released in v1.2.0. In 1.1.33 the app parsed a completed tool call's UI resource twice and lost its declared CSP. A freshly mounted view then fell back to the restrictive default,
frame-src 'none', so declaredframeDomainswere blocked. A regression test withframeDomainsfails at v1.1.33 and passes at v1.2.0. Note that MCP Apps are currently a Dev-ring experiment while they're hardened (github/github-app#26726).bertrandgressier commentedon Nov 12, 2026
@chuwik thanks for noting that MCP Apps are currently a Dev-ring experiment. Two questions, unrelated to the frameDomains bug itself: (1) Is there a target release for MCP Apps in the stable ring? (2) Can a non-staff user opt in to the experiment (or the Dev ring) today? On 1.3.0 the app logs show
mcp_apps_enabled: falseand I can't find the setting. Details in #5705, also related: #1913.