feat: enhance sandbox capability negotiation (#158)

* feat: enhance sandbox capability negotiation

* Update specification/draft/apps.mdx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* add all csp and permissions to host capabilities + update SEP

* feat: add clipboard-write permission support

Adds clipboardWrite to McpUiResourcePermissions for clipboard access.
Maps to Permission Policy 'clipboard-write' feature.

* rm files added by mistake

* refactor: change McpUiResourcePermissions properties to empty objects

* chore: remove scratch files and redundant cross-env dependency

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Olivier Chafik <ochafik@anthropic.com>
This commit is contained in:
Ido Salomon 2026-01-12 17:10:27 +02:00 • committed by GitHub
commit 9acc52cb96
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -66,6 +66,24 @@ const PROXY_READY_NOTIFICATION: McpUiSandboxProxyReadyNotification["method"] =
// Security: CSP is enforced via HTTP headers on sandbox.html (set by serve.ts
// based on ?csp= query param). This is tamper-proof unlike meta tags.
// Build iframe allow attribute from permissions
function buildAllowAttribute(permissions?: {
camera?: boolean;
microphone?: boolean;
geolocation?: boolean;
clipboardWrite?: boolean;
}): string {
if (!permissions) return "";
const allowList: string[] = [];
if (permissions.camera) allowList.push("camera");
if (permissions.microphone) allowList.push("microphone");
if (permissions.geolocation) allowList.push("geolocation");
if (permissions.clipboardWrite) allowList.push("clipboard-write");
return allowList.join("; ");
}
window.addEventListener("message", async (event) => {
if (event.source === window.parent) {
// Validate that messages from parent come from the expected host origin.
@ -81,10 +99,16 @@ window.addEventListener("message", async (event) => {
}
if (event.data && event.data.method === RESOURCE_READY_NOTIFICATION) {
const { html, sandbox } = event.data.params;
const { html, sandbox, permissions } = event.data.params;
if (typeof sandbox === "string") {
inner.setAttribute("sandbox", sandbox);
}
// Set Permission Policy allow attribute if permissions are requested
const allowAttribute = buildAllowAttribute(permissions);
if (allowAttribute) {
console.log("[Sandbox] Setting allow attribute:", allowAttribute);
inner.setAttribute("allow", allowAttribute);
}
if (typeof html === "string") {
// Use document.write instead of srcdoc for WebGL compatibility.
// srcdoc creates an opaque origin which prevents WebGL canvas updates