feat(ui): support prefersBorder option for MCP Apps (#6465)

This commit is contained in:
Andrew Harvard
2026-01-13 12:17:10 -05:00
committed by GitHub
parent b913ad1628
commit 1a2bc4807a
@@ -32,6 +32,12 @@ interface McpAppRendererProps {
append?: (text: string) => void;
}
interface ResourceData {
html: string | null;
csp: CspMetadata | null;
prefersBorder: boolean;
}
export default function McpAppRenderer({
resourceUri,
extensionName,
@@ -42,8 +48,11 @@ export default function McpAppRenderer({
toolCancelled,
append,
}: McpAppRendererProps) {
const [resourceHtml, setResourceHtml] = useState<string | null>(null);
const [resourceCsp, setResourceCsp] = useState<CspMetadata | null>(null);
const [resource, setResource] = useState<ResourceData>({
html: null,
csp: null,
prefersBorder: true,
});
const [error, setError] = useState<string | null>(null);
const [iframeHeight, setIframeHeight] = useState(DEFAULT_IFRAME_HEIGHT);
@@ -60,11 +69,15 @@ export default function McpAppRenderer({
if (response.data) {
const content = response.data;
const meta = content._meta as
| { ui?: { csp?: CspMetadata; prefersBorder?: boolean } }
| undefined;
setResourceHtml(content.text);
const meta = content._meta as { ui?: { csp?: CspMetadata } } | undefined;
setResourceCsp(meta?.ui?.csp || null);
setResource({
html: content.text,
csp: meta?.ui?.csp || null,
prefersBorder: meta?.ui?.prefersBorder ?? true,
});
}
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load resource');
@@ -161,8 +174,8 @@ export default function McpAppRenderer({
}, []);
const { iframeRef, proxyUrl } = useSandboxBridge({
resourceHtml: resourceHtml || '',
resourceCsp,
resourceHtml: resource.html || '',
resourceCsp: resource.csp,
resourceUri,
toolInput,
toolInputPartial,
@@ -174,25 +187,20 @@ export default function McpAppRenderer({
if (error) {
return (
<div className="mt-3 p-4 border border-red-500 rounded-lg bg-red-50 dark:bg-red-900/20">
<div className="p-4 border border-red-500 rounded-lg bg-red-50 dark:bg-red-900/20">
<div className="text-red-700 dark:text-red-300">Failed to load MCP app: {error}</div>
</div>
);
}
if (!resourceHtml) {
return (
<div className="mt-3 p-4 border border-borderSubtle rounded-lg bg-bgApp">
<div className="flex items-center justify-center" style={{ minHeight: '200px' }}>
Loading MCP app...
</div>
</div>
);
}
return (
<div className={cn('mt-3 bg-bgApp', 'border border-borderSubtle rounded-lg overflow-hidden')}>
{proxyUrl ? (
<div
className={cn(
'bg-bgApp overflow-hidden',
resource.prefersBorder ? 'border border-borderSubtle rounded-lg' : 'my-6'
)}
>
{resource.html && proxyUrl ? (
<iframe
ref={iframeRef}
src={proxyUrl}
@@ -205,16 +213,8 @@ export default function McpAppRenderer({
sandbox="allow-scripts allow-same-origin"
/>
) : (
<div
style={{
width: '100%',
minHeight: '200px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
Loading...
<div className="flex items-center justify-center p-4" style={{ minHeight: '200px' }}>
Loading MCP app...
</div>
)}
</div>