> ## Documentation Index
> Fetch the complete documentation index at: https://toolgrain.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Permissions and metadata

> Keep widget settings in one object and put each kind of metadata in the right place.

The quickstart's `server/index.ts` has one place to configure the widget:

```ts theme={null}
const widgetUi = {
  prefersBorder: true,
} satisfies AppResourceMeta;
```

Edit that object as the widget needs more capabilities. Import `AppResourceMeta` as a type from `@toolgrain/protocol/apps` for autocomplete and field checking.

## Request a permission

For example, a widget that copies a value to the clipboard can request:

```ts theme={null}
const widgetUi = {
  prefersBorder: true,
  permissions: { clipboardWrite: {} },
} satisfies AppResourceMeta;
```

Use empty objects, such as `{ clipboardWrite: {} }`, rather than booleans. Other permission names are `camera`, `microphone`, and `geolocation`. Request only the permissions your widget uses.

A declaration asks the host for access; the host can deny it. Check the browser API is available and handle permission denial in the widget's interaction handler.

## Allow network requests and external assets

If the React code itself fetches a remote API, add its origin:

```ts theme={null}
const widgetUi = {
  prefersBorder: true,
  permissions: { clipboardWrite: {} },
  csp: {
    connectDomains: ["https://api.example.com"],
    resourceDomains: ["https://images.example.com"],
  },
} satisfies AppResourceMeta;
```

`connectDomains` covers fetch, XHR, and WebSocket connections. `resourceDomains` covers external scripts, styles, fonts, images, and media. Use explicit origins, not paths to individual API methods or images. The host may restrict them further.

The quickstart bundles its JavaScript/CSS into HTML and needs no external origins. Calls made with `useToolCall` travel through the host; add a network origin when your widget makes the network request itself.

## Put settings on the returned HTML

The `widgetUi` object belongs on each resource content item's `_meta.ui`. The quickstart already places it here:

```ts theme={null}
contents: [{
  uri,
  mimeType: APPS_MIME_TYPE,
  text: builtHtml,
  _meta: { ui: widgetUi },
}],
```

Here, `builtHtml` is the string read from your built widget file. Putting permissions/CSP on the tool, or only on the outer resource-read result, does not configure the widget sandbox.

## Resource metadata

| Setting inside `widgetUi` | Use it for |
| - | - |
| `prefersBorder: true` | Request a host-provided border and background |
| `prefersBorder: false` | Request neither; omit the field to let the host choose |
| `permissions` | Request camera, microphone, geolocation, or clipboard-write access |
| `csp.connectDomains` | Origins your widget contacts with fetch/XHR/WebSocket |
| `csp.resourceDomains` | Origins serving external scripts, styles, fonts, images, or media |
| `csp.frameDomains` | Origins for nested iframes |
| `csp.baseUriDomains` | Allowed document base URIs |
| `domain` | A dedicated sandbox origin in the host's required format |

Omitted network/frame origins do not allow arbitrary connections or nested frames. The default base URI is restricted to the sandbox's own origin. A `domain` request does not configure DNS, host allowlists, or OAuth callbacks. Recheck domain/permission behavior for the host you target; the [acceptance record](https://toolgrain.mintlify.site/mcp-apps/compatibility.md) lists what was actually exercised.

## Three kinds of metadata

| Where it goes | What belongs there |
| - | - |
| Tool definition: `_meta.ui` | `resourceUri` and optional `visibility` |
| Returned HTML content: `_meta.ui` | The `widgetUi` permissions, CSP, border, and domain settings above |
| Tool result: `_meta` | Extra application data for the widget, such as chart points or a routing marker |

See [tool linking and visibility](https://toolgrain.mintlify.site/mcp-apps/server.md#tool-linking-and-visibility) for app-only refresh/filter tools.

## Extra widget data

Use `mcpResult()` when the tool also needs result metadata. For example, replace the weather tool's `execute` function and import `mcpResult` from `@toolgrain/mcp`:

```ts theme={null}
execute: ({ city }) => mcpResult({
  content: [{ type: "text", text: `Demo weather for ${city}.` }],
  structuredContent: { city, temperature: city === "London" ? 14 : 29 },
  _meta: { forecast: [24, 26, 29, 27] },
}),
```

React receives the full envelope, including the inferred metadata type:

```tsx theme={null}
const { result } = useToolResult("weather");
const forecast = result?._meta?.forecast;
```

Keep result `_meta` optional in your component: errors or protocol conversion can omit it. Continue returning meaningful content for the assistant. Shared entries can use an application-owned marker such as `_meta.view` for [routing](https://toolgrain.mintlify.site/mcp-apps/shared-entries.md).

## Connection and authorization

The host owns iframe creation, sandboxing, CSP enforcement, and permission grants. Toolgrain's browser connection accepts messages from the embedding parent and validates known wire envelopes. `hostOrigin` can restrict that parent to an exact origin; hosts using opaque sandbox origins may need the default setting.

Permissions, capability claims, and routing metadata do not establish identity or authorize server work. Preserve [endpoint authentication and application authorization](https://toolgrain.mintlify.site/authentication/overview.md) for tool calls and resource reads. Never put bearer credentials or server services in widget HTML. Use `import type` for the tool map and validate application data when your UI requires it.

The [reviewed Apps resource contract](https://github.com/modelcontextprotocol/ext-apps/blob/298e884ec3f02daba085acdb02042d73bd00b355/specification/2026-01-26/apps.mdx#ui-resource-format) defines the wire fields.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.