`experimental_MCPAppRenderer`

experimental_MCPAppRenderer

`experimental_MCPAppRenderer` 는 실험적이며 향후 릴리스에서 변경될 수 있어요.

experimental_MCPAppRenderer 는 AI SDK tool UI 파트에 대해 MCP App을 렌더링해요. tool 파트에서 MCP App 메타데이터를 감지하고, 앱 리소스를 로드하고, sandbox 프록시 iframe에서 앱을 렌더링하며, iframe과 호스트 애플리케이션 사이에 MCP Apps JSON-RPC 메시지를 브리징해요.

MCP App 메타데이터가 없는 tool 파트의 경우 컴포넌트는 fallback 을 렌더링해요.

출처: 문서

본문

Import

<Snippet text={import { experimental_MCPAppRenderer as MCPAppRenderer } from "@ai-sdk/react"} prompt={false} />

예제 (Example)

'use client';

import {
  experimental_MCPAppRenderer as MCPAppRenderer,
  type MCPAppBridgeHandlers,
  type MCPAppMetadata,
  type MCPAppResource,
  type MCPAppSandboxConfig,
} from '@ai-sdk/react';
import { isToolUIPart } from 'ai';

const sandbox = {
  url: '/mcp-app-sandbox',
  className: 'h-80 w-full rounded-lg border',
  style: { border: 0 },
} satisfies MCPAppSandboxConfig;

async function loadResource(app: MCPAppMetadata): Promise<MCPAppResource> {
  const response = await fetch('/api/mcp-app-host/read-resource', {
    method: 'POST',
    body: JSON.stringify({ uri: app.resourceUri }),
  });

  if (!response.ok) {
    throw new Error('Failed to load MCP App resource');
  }

  return response.json();
}

const handlers: MCPAppBridgeHandlers = {
  callTool: params =>
    fetch('/api/mcp-app-host/call-tool', {
      method: 'POST',
      body: JSON.stringify(params),
    }).then(response => response.json()),
  openLink: ({ url }) => {
    window.open(url, '_blank', 'noopener,noreferrer');
    return {};
  },
};

export function MessagePart({ part }: { part: unknown }) {
  if (!isToolUIPart(part)) {
    return null;
  }

  return (
    <MCPAppRenderer
      part={part}
      loadResource={loadResource}
      handlers={handlers}
      sandbox={sandbox}
      fallback={null}
    />
  );
}

Props

<PropertiesTable content={[ { name: 'part', type: 'ToolUIPart | DynamicToolUIPart', description: 'The AI SDK tool UI part. The renderer looks for MCP App metadata in part.toolMetadata.mcp.app.', }, { name: 'sandbox', type: 'MCPAppSandboxConfig', description: 'Configuration for the outer sandbox proxy iframe used to host the app.', }, { name: 'resource', type: 'MCPAppResource', isOptional: true, description: 'A preloaded MCP App resource. Provide either resource or loadResource.', }, { name: 'loadResource', type: '(app: MCPAppMetadata) => Promise', isOptional: true, description: 'Loads the MCP App resource for the app metadata found on the tool part.', }, { name: 'handlers', type: 'MCPAppBridgeHandlers', isOptional: true, description: 'Callbacks used to handle iframe requests such as tools/call, resources/read, ui/open-link, and display mode changes.', }, { name: 'hostInfo', type: '{ name: string; version: string }', isOptional: true, description: 'Host identity returned to the app during the ui/initialize handshake.', }, { name: 'hostContext', type: 'MCPAppHostContext', isOptional: true, description: 'Host context sent to the app, such as theme, display mode, and available display modes.', }, { name: 'fallback', type: 'ReactNode', isOptional: true, description: 'Rendered while the resource is loading, when loading fails, or when the tool part is not an MCP App.', }, ]} />

Sandbox 구성 (Sandbox Config)

<PropertiesTable content={[ { name: 'url', type: 'string | URL', description: 'The URL of the sandbox proxy iframe. The proxy receives app HTML from the host and creates the inner app iframe.', }, { name: 'title', type: 'string', isOptional: true, description: 'Accessible iframe title.', }, { name: 'className', type: 'string', isOptional: true, description: 'Class name applied to the outer iframe.', }, { name: 'style', type: 'CSSProperties', isOptional: true, description: 'Inline styles applied to the outer iframe.', }, { name: 'targetOrigin', type: 'string', isOptional: true, description: 'Target origin used for postMessage. Defaults to *; set this to your sandbox origin in production.', }, { name: 'outerSandbox', type: 'string', isOptional: true, description: 'Sandbox attribute for the outer proxy iframe. Defaults to allow-scripts allow-same-origin allow-forms.', }, { name: 'innerSandbox', type: 'string', isOptional: true, description: 'Sandbox attribute sent to the proxy for the inner app iframe. Defaults to allow-scripts allow-forms.', }, ]} />

브리지 핸들러 (Bridge Handlers)

experimental_MCPAppRenderer 는 이 핸들러를 사용해 iframe 요청에 응답해요. 프로덕션에서 서버 기반 핸들러는 MCP 서버를 호출하기 전에 인가와 MCP Apps tool 가시성을 검증해야 해요.

<PropertiesTable content={[ { name: 'allowedTools', type: 'string[]', isOptional: true, description: 'Optional client-side allowlist checked before forwarding tools/call requests.', }, { name: 'callTool', type: '(params: MCPAppToolCallParams) => Promise | unknown', isOptional: true, description: 'Handles app-initiated tools/call requests.', }, { name: 'readResource', type: '(params: { uri: string }) => Promise | unknown', isOptional: true, description: 'Handles app-initiated resources/read requests.', }, { name: 'listResources', type: '(params?: unknown) => Promise | unknown', isOptional: true, description: 'Handles app-initiated resources/list requests.', }, { name: 'openLink', type: '(params: { url: string }) => Promise | unknown', isOptional: true, description: 'Handles app-initiated ui/open-link requests.', }, { name: 'sendMessage', type: '(params: unknown) => Promise | unknown', isOptional: true, description: 'Handles app-initiated ui/message requests.', }, { name: 'updateModelContext', type: '(params: unknown) => Promise | unknown', isOptional: true, description: 'Handles app-initiated ui/update-model-context requests.', }, { name: 'requestDisplayMode', type: "(params: { mode: 'inline' | 'fullscreen' | 'pip' }) => Promise<{ mode: MCPAppDisplayMode }> | { mode: MCPAppDisplayMode }", isOptional: true, description: 'Handles app-initiated ui/request-display-mode requests.', }, { name: 'onSizeChange', type: '(params: { width?: number; height?: number }) => void', isOptional: true, description: 'Called when the app sends a size change notification.', }, { name: 'onInitialized', type: '() => void', isOptional: true, description: 'Called after the app sends ui/notifications/initialized.', }, { name: 'onRequestTeardown', type: '(params: unknown) => void', isOptional: true, description: 'Called when the app requests teardown.', }, { name: 'onLog', type: '(params: unknown) => void', isOptional: true, description: 'Called when the app sends a log notification.', }, { name: 'onError', type: '(error: Error) => void', isOptional: true, description: 'Called when a supported iframe request fails while being handled.', }, ]} />

함께 보기 (See Also)

<ExampleLinks examples={[ { title: 'MCP Apps guide', link: '/docs/ai-sdk-core/mcp-apps', }, { title: 'MCP Apps helpers', link: '/docs/reference/ai-sdk-core/mcp-apps', }, ]} />

더 알아보기 (Learn more)

전체 사이트맵