import { UIResourceRenderer } from '@mcp-ui/client'; import type { UIResourcePart } from '@dexto/core'; import { AlertTriangle } from 'lucide-react'; interface UIResourceRendererWrapperProps { resource: UIResourcePart; /** Callback when the UI resource triggers an action */ onAction?: (action: { type: string; payload?: unknown }) => void; } /** * Wrapper component that adapts Dexto's UIResourcePart to @mcp-ui/client's UIResourceRenderer. * Renders interactive MCP-UI resources (HTML, external URLs, Remote DOM) in sandboxed iframes. */ export function UIResourceRendererWrapper({ resource, onAction }: UIResourceRendererWrapperProps) { // Map UIResourcePart to the format expected by @mcp-ui/client // MCP SDK uses discriminated unions - either text OR blob, not both // Store metadata in _meta since annotations has a specific schema in MCP SDK const mcpResource = resource.blob ? { type: 'resource' as const, resource: { uri: resource.uri, blob: resource.blob, ...(resource.mimeType ? { mimeType: resource.mimeType } : {}), _meta: { ...(resource.metadata?.title ? { title: resource.metadata.title } : {}), ...(resource.metadata?.preferredSize ? { preferredSize: resource.metadata.preferredSize } : {}), }, }, } : { type: 'resource' as const, resource: { uri: resource.uri, text: resource.content || '', ...(resource.mimeType ? { mimeType: resource.mimeType } : {}), _meta: { ...(resource.metadata?.title ? { title: resource.metadata.title } : {}), ...(resource.metadata?.preferredSize ? { preferredSize: resource.metadata.preferredSize } : {}), }, }, }; // Handle UI actions from the rendered component const handleUIAction = async (result: { type: string; payload?: unknown }) => { if (onAction) { onAction(result); } // Return undefined to acknowledge the action return undefined; }; return (
{resource.metadata?.title && (
{resource.metadata.title}
)}
); } /** * Fallback component shown when UI resource rendering fails or is unsupported. */ export function UIResourceFallback({ resource }: { resource: UIResourcePart }) { return (
Interactive UI Resource {resource.uri} Type: {resource.mimeType} {resource.metadata?.title && ( Title: {resource.metadata.title} )}
); }