different-ai/openwork · error · McpAppHostError

unsupported_resource_permissions

unsupported_resource_permissions

Error message

This OpenWork host slice does not grant device permissions or dedicated sandbox origins.

What it means

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.

Source

Thrown at apps/server/src/mcp-app-host.ts:129

function domainList(value: unknown): string[] {
  if (!Array.isArray(value) || value.length > 16) {
    if (value === undefined) return [];
    throw new McpAppHostError("invalid_resource_csp", "MCP App CSP domain lists must contain at most 16 origins.");
  }
  const domains = value.map(safeDomain);
  if (domains.some((domain) => domain === null)) {
    throw new McpAppHostError("invalid_resource_csp", "MCP App CSP domains must be HTTPS origins (or loopback HTTP origins).");
  }
  return Array.from(new Set(domains as string[]));
}

function resourcePresentationMeta(value: unknown): { csp: McpAppCsp; prefersBorder: boolean } {
  const meta = isRecord(value) ? value : {};
  const ui = isRecord(meta.ui) ? meta.ui : {};
  const csp = isRecord(ui.csp) ? ui.csp : {};
  const permissions = isRecord(ui.permissions) ? ui.permissions : {};
  if (Object.keys(permissions).length > 0 || ui.domain !== undefined) {
    throw new McpAppHostError(
      "unsupported_resource_permissions",
      "This OpenWork host slice does not grant device permissions or dedicated sandbox origins.",
    );
  }
  return {
    csp: {
      connectDomains: domainList(csp.connectDomains),
      resourceDomains: domainList(csp.resourceDomains),
      frameDomains: domainList(csp.frameDomains),
      baseUriDomains: domainList(csp.baseUriDomains),
    },
    prefersBorder: ui.prefersBorder !== false,
  };
}

function remoteUrl(config: Record<string, unknown>): URL | null {
  if (config.enabled === false || typeof config.url !== "string") return null;
  try {

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Remove ui.permissions and ui.domain from the app's _meta so it runs in the shared host sandbox.
  2. Redesign the app to not require device permissions; do privileged work in the MCP server instead of the UI.
  3. Use a different MCP host that supports permissions if device access is essential.
  4. Ask the OpenWork maintainers about permission support before relying on it.

Example fix

// before
'"ui": { "permissions": { "camera": {} }, "domain": "app.example.com" }'
// after
'"ui": {}'
Defensive patterns

Strategy: validation

Validate before calling

const ui = (tool?._meta as any)?.ui ?? {}
const requested = Object.keys(ui.permissions ?? {}).length > 0 || ui.domain !== undefined
if (requested) throw new Error('app requests permissions/dedicated origin — unsupported on this host')

Type guard

function isHostCompatibleUi(ui: unknown): ui is { csp?: unknown } {
  const u = ui as { permissions?: Record<string, unknown>; domain?: unknown } | undefined
  return !!u && Object.keys(u.permissions ?? {}).length === 0 && u.domain === undefined
}

Try / catch

try {
  const presentation = host.presentation(resource)
} catch (e) {
  if (e instanceof McpAppHostError && e.code === 'unsupported_resource_permissions') {
    hideApp(resource.name); notify('app requires permissions this host does not grant')
  } else throw e
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/06ee53ea0fbd0332. Report an issue: GitHub.