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

# MCP App Tool _meta — Visibility & Resource Linking

> Complete reference for MCP App tool _meta.ui fields: resourceUri for linking tools to HTML Views, and visibility for controlling access by model vs app.

<Badge color="green">MCP Apps SDK</Badge>

## Overview

MCP App tools use `_meta.ui` to link a tool to an HTML View, control who can access it, or both. This metadata is set in the tool config passed to [`registerAppTool`](/docs/mcp-apps/server/register-app-tool).

```ts theme={null}
registerAppTool(
  server,
  'get-weather',
  {
    description: 'Get current weather for a location',
    _meta: {
      ui: {
        resourceUri: 'ui://weather/view.html',
        visibility: ['model', 'app'],
      },
    },
  },
  handler
);
```

## Fields

### `_meta.ui.resourceUri`

<ResponseField name="resourceUri" type="string">
  URI of the HTML resource to render when this tool is called. Uses the `ui://` protocol. Required
  for tools that should launch or preload a View. Optional for app-only helper tools that do not
  render their own View.
</ResponseField>

```ts theme={null}
_meta: {
  ui: {
    resourceUri: 'ui://weather/view.html',
  }
}
```

For UI-launching tools, this must match a URI registered via [`registerAppResource`](/docs/mcp-apps/server/register-app-resource). When the host invokes the tool, it calls [`resources/read`](/docs/mcp-apps/mcp/resources#reading-resourcesread) with this URI to fetch the HTML content, then renders it in a sandboxed iframe.

### `_meta.ui.visibility`

<ResponseField name="visibility" type="McpUiToolVisibility[]" default="[&#x22;model&#x22;, &#x22;app&#x22;]">
  Who can discover and call this tool. An array containing `"model"`, `"app"`, or both.
</ResponseField>

| Value     | Meaning                                                                                                                                    |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `"model"` | Tool is included in the agent's tool list and callable by the LLM                                                                          |
| `"app"`   | Tool is callable by the View (your UI) via [`app.callServerTool()`](/docs/mcp-apps/app/requests/call-server-tool) on the same server connection |

**Default:** `["model", "app"]` — both model and app can access.

## Visibility Examples

### Model + App (default)

Both the LLM and the View can call this tool. This is the default when `visibility` is omitted.

```ts theme={null}
registerAppTool(
  server,
  'show-cart',
  {
    description: "Display the user's shopping cart",
    _meta: {
      ui: { resourceUri: 'ui://shop/cart.html' },
    },
  },
  handler
);
```

### App-only (hidden from model)

The View can call this tool, but it's hidden from the agent's tool list. Use this for UI-driven server interactions, such as polling, pagination, form submissions, or any action the user triggers directly in the View.

If the tool only returns data to an already-rendered View, omit `resourceUri`. Add `resourceUri` only when the helper should also be associated with a specific UI resource.

```ts theme={null}
registerAppTool(
  server,
  'update-quantity',
  {
    description: 'Update item quantity in cart',
    inputSchema: { itemId: z.string(), quantity: z.number() },
    _meta: {
      ui: {
        visibility: ['app'],
      },
    },
  },
  async ({ itemId, quantity }) => {
    const cart = await updateCartItem(itemId, quantity);
    return {
      content: [{ type: 'text', text: JSON.stringify(cart) }],
      structuredContent: cart,
    };
  }
);
```

### Model-only

The model can call this tool, but the View cannot. Use this when the tool should only be triggered by the LLM in conversation, never by the UI directly.

```ts theme={null}
registerAppTool(
  server,
  'show-cart',
  {
    description: "Display the user's shopping cart",
    _meta: {
      ui: {
        resourceUri: 'ui://shop/cart.html',
        visibility: ['model'],
      },
    },
  },
  handler
);
```

## Host Behavior

Hosts enforce visibility rules:

* The host **MUST NOT** include tools with `visibility: ["app"]` in the agent's tool list.
* The host **MUST** reject [`tools/call`](/docs/mcp-apps/mcp/tools#invocation-toolscall) requests from Views for tools that don't include `"app"` in visibility.
* Cross-server tool calls are always blocked for app-only tools. A View can only call app-visible tools on its **own** MCP server.

## Metadata Normalization

[`registerAppTool`](/docs/mcp-apps/server/register-app-tool) automatically normalizes between the current format (`_meta.ui.resourceUri`) and the deprecated flat key (`_meta["ui/resourceUri"]`) for backward compatibility with older hosts. You don't need to set both.

## TypeScript Types

```ts theme={null}
import type { McpUiToolMeta, McpUiToolVisibility } from '@modelcontextprotocol/ext-apps';

type McpUiToolVisibility = 'model' | 'app';

interface McpUiToolMeta {
  resourceUri?: string;
  visibility?: McpUiToolVisibility[];
}
```

<Tip>
  The [sunpeak framework](/docs/quickstart) provides [`useAppTools`](/docs/app-framework/hooks/use-app-tools)
  for calling app-visible tools from React components, and the [Tool File
  Reference](/docs/app-framework/tools/tool-file) for defining tool metadata.
</Tip>

For a complete field-by-field checklist across tools, resources, resource metadata, and tool results, see the [Tool and Resource Contract](/docs/mcp-apps/server/tool-resource-contract).
