> ## 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 Apps registerAppTool - Register UI Tools

> Register MCP tools that render interactive HTML UIs. Configure tool visibility, input schemas, structured content, and UI metadata with registerAppTool.

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

```ts theme={null}
import { registerAppTool } from '@modelcontextprotocol/ext-apps/server';
```

## Overview

`registerAppTool` is a convenience wrapper around the MCP SDK's [`server.registerTool()`](/mcp-apps/mcp/tools) that normalizes [UI metadata](/mcp-apps/introduction#how-are-tools-linked-to-uis) for compatibility across hosts. Use it instead of `registerTool` when your tool should render a View or when it needs MCP App visibility metadata.

## Signature

```ts theme={null}
function registerAppTool(
  server: McpServer,
  name: string,
  config: McpUiAppToolConfig,
  cb: ToolCallback
): RegisteredTool;
```

## Parameters

<ResponseField name="server" type="McpServer" required>
  The MCP server instance.
</ResponseField>

<ResponseField name="name" type="string" required>
  Tool name/identifier.
</ResponseField>

<ResponseField name="config" type="McpUiAppToolConfig" required>
  Tool configuration. Extends the standard MCP `ToolConfig` with a required `_meta` field containing UI metadata.

  <ResponseField name="title" type="string">
    Human-readable tool title.
  </ResponseField>

  <ResponseField name="description" type="string">
    Tool description for the model.
  </ResponseField>

  <ResponseField name="inputSchema" type="ZodRawShape | AnySchema">
    Zod schema or JSON Schema for tool arguments.
  </ResponseField>

  <ResponseField name="outputSchema" type="ZodRawShape | AnySchema">
    Zod schema or JSON Schema for tool output.
  </ResponseField>

  <ResponseField name="annotations" type="ToolAnnotations">
    Standard MCP tool annotations, such as `readOnlyHint`, `destructiveHint`, `idempotentHint`,
    and `openWorldHint`. See [Tool Annotations](/mcp-apps/server/tool-annotations).
  </ResponseField>

  <ResponseField name="_meta" type="object" required>
    UI metadata linking this tool to a resource, controlling tool visibility, or both. See [\_meta Reference](#_meta-reference) below for full details.

    <ResponseField name="ui" type="McpUiToolMeta" required>
      <ResponseField name="resourceUri" type="string">
        URI of the UI resource to display (e.g., `"ui://weather/view.html"`). Required for tools that render a View. Must match a URI registered via [`registerAppResource`](/mcp-apps/server/register-app-resource).
      </ResponseField>

      <ResponseField name="visibility" type="McpUiToolVisibility[]">
        Who can access this tool. Default: `["model", "app"]`. See [visibility](#visibility) below.
      </ResponseField>
    </ResponseField>
  </ResponseField>
</ResponseField>

<ResponseField name="cb" type="ToolCallback" required>
  Tool handler function. Receives parsed arguments and returns a `CallToolResult`.
</ResponseField>

## Usage

### Basic tool with UI

```ts theme={null}
import { registerAppTool } from '@modelcontextprotocol/ext-apps/server';
import { z } from 'zod';

registerAppTool(
  server,
  'get-weather',
  {
    title: 'Get Weather',
    description: 'Get current weather for a location',
    inputSchema: { location: z.string() },
    _meta: {
      ui: { resourceUri: 'ui://weather/view.html' },
    },
  },
  async (args) => {
    const weather = await fetchWeather(args.location);
    return {
      content: [{ type: 'text', text: JSON.stringify(weather) }],
      structuredContent: weather,
    };
  }
);
```

### Read-only tool annotations

Add `annotations` when a UI tool is read-only, destructive, idempotent, or calls external systems. Hosts can use these hints for review UI and tool-calling behavior.

```ts theme={null}
registerAppTool(
  server,
  'search-orders',
  {
    title: 'Search Orders',
    description: 'Search orders and display the results.',
    inputSchema: { query: z.string() },
    annotations: {
      readOnlyHint: true,
      openWorldHint: false,
    },
    _meta: {
      ui: { resourceUri: 'ui://orders/view.html' },
    },
  },
  handler
);
```

### App-only tool (hidden from model)

Set `visibility: ["app"]` for tools that should only be callable from the View, such as polling, pagination, or UI-driven server interactions. Omit `resourceUri` when the helper does not render a new View:

```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 tool

Set `visibility: ["model"]` for tools that the model can call but the View cannot:

```ts theme={null}
registerAppTool(
  server,
  'show-cart',
  {
    description: "Display the user's shopping cart",
    _meta: {
      ui: {
        resourceUri: 'ui://shop/cart.html',
        visibility: ['model'],
      },
    },
  },
  async () => {
    const cart = await getCart();
    return { content: [{ type: 'text', text: JSON.stringify(cart) }] };
  }
);
```

## `_meta` Reference

See **[Tool `_meta`](/mcp-apps/server/tool-meta)** for the complete reference on `resourceUri`, `visibility`, host behavior rules, and metadata normalization.

See **[Tool Annotations](/mcp-apps/server/tool-annotations)** for when to set `readOnlyHint`, `destructiveHint`, `idempotentHint`, and `openWorldHint`.

See **[Tool and Resource Contract](/mcp-apps/server/tool-resource-contract)** for how tool metadata, resource metadata, `content`, and `structuredContent` fit together.

<Tip>
  In the [sunpeak framework](/quickstart), tools are defined as auto-discovered files. See the [Tool
  File Reference](/app-framework/tools/tool-file).
</Tip>
