Skip to main content
import { registerAppResource, RESOURCE_MIME_TYPE } from "sunpeak/mcp";

Overview

registerAppResource is a convenience wrapper around the MCP SDK’s server.registerResource() that defaults the MIME type to RESOURCE_MIME_TYPE ("text/html;profile=mcp-app"). Use it to register the HTML resources that your tools reference via _meta.ui.resourceUri.

Signature

function registerAppResource(
  server: McpServer,
  name: string,
  uri: string,
  config: McpUiAppResourceConfig,
  readCallback: McpUiReadResourceCallback,
): RegisteredResource

Parameters

server
McpServer
required
The MCP server instance.
name
string
required
Human-readable resource name.
uri
string
required
Resource URI. Should match the _meta.ui.resourceUri in your tool config.
config
McpUiAppResourceConfig
required
Resource configuration extending MCP SDK’s ResourceMetadata.
description
string
Human-readable resource description.
mimeType
string
MIME type. Defaults to RESOURCE_MIME_TYPE if omitted.
_meta
object
Optional UI metadata for the resource listing (static default for hosts to review at connection time).
readCallback
McpUiReadResourceCallback
required
Callback that returns the resource contents. The contents[] items can include _meta.ui for per-read security configuration.

Usage

Basic resource

registerAppResource(
  server,
  "Weather View",
  "ui://weather/view.html",
  {
    description: "Interactive weather display",
  },
  async () => ({
    contents: [
      {
        uri: "ui://weather/view.html",
        mimeType: RESOURCE_MIME_TYPE,
        text: await fs.readFile("dist/view.html", "utf-8"),
      },
    ],
  }),
);

With CSP configuration

Declare network domains your View needs in _meta.ui.csp on the contents[] items:
registerAppResource(
  server,
  "Music Player",
  "ui://music/player.html",
  {},
  async () => ({
    contents: [
      {
        uri: "ui://music/player.html",
        mimeType: RESOURCE_MIME_TYPE,
        text: musicPlayerHtml,
        _meta: {
          ui: {
            csp: {
              connectDomains: ["https://api.example.com"],
              resourceDomains: ["https://cdn.example.com"],
            },
          },
        },
      },
    ],
  }),
);

With permissions

Request browser capabilities like camera, microphone, geolocation, or clipboard access:
_meta: {
  ui: {
    permissions: {
      microphone: {},
      clipboardWrite: {},
    },
  },
}

With stable origin (domain)

Use _meta.ui.domain to give your View a stable origin for CORS allowlists:
_meta: {
  ui: {
    csp: { connectDomains: ["https://api.example.com"] },
    domain: APP_DOMAIN,  // e.g., "{hash}.claudemcpcontent.com"
  },
}
The domain format is host-specific. Check each host’s documentation for the expected format.

CSP Reference

CSP is set in the contents[] items returned by the read callback, not in the registerAppResource config.
FieldCSP DirectivePurpose
connectDomainsconnect-srcfetch/XHR/WebSocket origins
resourceDomainsimg-src, script-src, style-src, font-src, media-srcStatic resource origins
frameDomainsframe-srcNested iframe origins
baseUriDomainsbase-uriAllowed base URIs

Permissions Reference

FieldPermission PolicyPurpose
cameracameraCamera access
microphonemicrophoneMicrophone access
geolocationgeolocationLocation access
clipboardWriteclipboard-writeClipboard write access

Other Resource Options

prefersBorder
boolean
Visual boundary preference. true requests a visible border and background from the host; false requests none. Omit to let the host decide.

Constants

ConstantValueDescription
RESOURCE_MIME_TYPE"text/html;profile=mcp-app"MIME type for MCP App UI resources
RESOURCE_URI_META_KEY"ui/resourceUri"Deprecated metadata key for tool-resource linkage