{"record":{"id":"06ee53ea0fbd0332","repo":"different-ai/openwork","slug":"unsupported-resource-permissions","errorCode":"unsupported_resource_permissions","errorMessage":"This OpenWork host slice does not grant device permissions or dedicated sandbox origins.","messagePattern":"This OpenWork host slice does not grant device permissions or dedicated sandbox origins\\.","errorType":"error_code","errorClass":"McpAppHostError","httpStatus":null,"severity":"error","filePath":"apps/server/src/mcp-app-host.ts","lineNumber":129,"sourceCode":"function domainList(value: unknown): string[] {\n  if (!Array.isArray(value) || value.length > 16) {\n    if (value === undefined) return [];\n    throw new McpAppHostError(\"invalid_resource_csp\", \"MCP App CSP domain lists must contain at most 16 origins.\");\n  }\n  const domains = value.map(safeDomain);\n  if (domains.some((domain) => domain === null)) {\n    throw new McpAppHostError(\"invalid_resource_csp\", \"MCP App CSP domains must be HTTPS origins (or loopback HTTP origins).\");\n  }\n  return Array.from(new Set(domains as string[]));\n}\n\nfunction resourcePresentationMeta(value: unknown): { csp: McpAppCsp; prefersBorder: boolean } {\n  const meta = isRecord(value) ? value : {};\n  const ui = isRecord(meta.ui) ? meta.ui : {};\n  const csp = isRecord(ui.csp) ? ui.csp : {};\n  const permissions = isRecord(ui.permissions) ? ui.permissions : {};\n  if (Object.keys(permissions).length > 0 || ui.domain !== undefined) {\n    throw new McpAppHostError(\n      \"unsupported_resource_permissions\",\n      \"This OpenWork host slice does not grant device permissions or dedicated sandbox origins.\",\n    );\n  }\n  return {\n    csp: {\n      connectDomains: domainList(csp.connectDomains),\n      resourceDomains: domainList(csp.resourceDomains),\n      frameDomains: domainList(csp.frameDomains),\n      baseUriDomains: domainList(csp.baseUriDomains),\n    },\n    prefersBorder: ui.prefersBorder !== false,\n  };\n}\n\nfunction remoteUrl(config: Record<string, unknown>): URL | null {\n  if (config.enabled === false || typeof config.url !== \"string\") return null;\n  try {","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/server/src/mcp-app-host.ts#L111-L147","documentation":"resourcePresentationMeta reads ui.permissions and ui.domain from an MCP App resource's _meta. This OpenWork host slice intentionally does not implement device-permission grants or dedicated sandbox origins, so if an app requests either, the host throws unsupported_resource_permissions instead of silently ignoring the request.","triggerScenarios":"Connecting to an MCP App whose tool _meta sets ui.permissions (any keys, e.g. camera/microphone/geolocation grants) or ui.domain (requesting a dedicated sandbox origin).","commonSituations":"App built for hosts that support permissions/dedicated origins (e.g. full MCP App hosts) being loaded in OpenWork; server template left the permissions block in; author requesting camera/mic for a widget.","solutions":["Remove ui.permissions and ui.domain from the app's _meta so it runs in the shared host sandbox.","Redesign the app to not require device permissions; do privileged work in the MCP server instead of the UI.","Use a different MCP host that supports permissions if device access is essential.","Ask the OpenWork maintainers about permission support before relying on it."],"exampleFix":"// before\n'\"ui\": { \"permissions\": { \"camera\": {} }, \"domain\": \"app.example.com\" }'\n// after\n'\"ui\": {}'","handlingStrategy":"validation","validationCode":"const ui = (tool?._meta as any)?.ui ?? {}\nconst requested = Object.keys(ui.permissions ?? {}).length > 0 || ui.domain !== undefined\nif (requested) throw new Error('app requests permissions/dedicated origin — unsupported on this host')","typeGuard":"function isHostCompatibleUi(ui: unknown): ui is { csp?: unknown } {\n  const u = ui as { permissions?: Record<string, unknown>; domain?: unknown } | undefined\n  return !!u && Object.keys(u.permissions ?? {}).length === 0 && u.domain === undefined\n}","tryCatchPattern":"try {\n  const presentation = host.presentation(resource)\n} catch (e) {\n  if (e instanceof McpAppHostError && e.code === 'unsupported_resource_permissions') {\n    hideApp(resource.name); notify('app requires permissions this host does not grant')\n  } else throw e\n}","preventionTips":["Do not set ui.permissions or ui.domain in tool _meta unless targeting a supporting host","Perform privileged operations in the MCP server, not the app UI","Audit app templates for leftover permissions blocks","Feature-detect host capability docs before shipping permission-requiring apps"],"tags":["mcp","mcp-apps","permissions","unsupported-feature"],"backgroundTag":"unsupported-mcp-app-capability","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}