Skip to content

Commit 1a2bc48

Browse files
authored
feat(ui): support prefersBorder option for MCP Apps (#6465)
1 parent b913ad1 commit 1a2bc48

1 file changed

Lines changed: 32 additions & 32 deletions

File tree

ui/desktop/src/components/McpApps/McpAppRenderer.tsx

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ interface McpAppRendererProps {
3232
append?: (text: string) => void;
3333
}
3434

35+
interface ResourceData {
36+
html: string | null;
37+
csp: CspMetadata | null;
38+
prefersBorder: boolean;
39+
}
40+
3541
export default function McpAppRenderer({
3642
resourceUri,
3743
extensionName,
@@ -42,8 +48,11 @@ export default function McpAppRenderer({
4248
toolCancelled,
4349
append,
4450
}: McpAppRendererProps) {
45-
const [resourceHtml, setResourceHtml] = useState<string | null>(null);
46-
const [resourceCsp, setResourceCsp] = useState<CspMetadata | null>(null);
51+
const [resource, setResource] = useState<ResourceData>({
52+
html: null,
53+
csp: null,
54+
prefersBorder: true,
55+
});
4756
const [error, setError] = useState<string | null>(null);
4857
const [iframeHeight, setIframeHeight] = useState(DEFAULT_IFRAME_HEIGHT);
4958

@@ -60,11 +69,15 @@ export default function McpAppRenderer({
6069

6170
if (response.data) {
6271
const content = response.data;
63-
64-
setResourceHtml(content.text);
65-
66-
const meta = content._meta as { ui?: { csp?: CspMetadata } } | undefined;
67-
setResourceCsp(meta?.ui?.csp || null);
72+
const meta = content._meta as
73+
| { ui?: { csp?: CspMetadata; prefersBorder?: boolean } }
74+
| undefined;
75+
76+
setResource({
77+
html: content.text,
78+
csp: meta?.ui?.csp || null,
79+
prefersBorder: meta?.ui?.prefersBorder ?? true,
80+
});
6881
}
6982
} catch (err) {
7083
setError(err instanceof Error ? err.message : 'Failed to load resource');
@@ -161,8 +174,8 @@ export default function McpAppRenderer({
161174
}, []);
162175

163176
const { iframeRef, proxyUrl } = useSandboxBridge({
164-
resourceHtml: resourceHtml || '',
165-
resourceCsp,
177+
resourceHtml: resource.html || '',
178+
resourceCsp: resource.csp,
166179
resourceUri,
167180
toolInput,
168181
toolInputPartial,
@@ -174,25 +187,20 @@ export default function McpAppRenderer({
174187

175188
if (error) {
176189
return (
177-
<div className="mt-3 p-4 border border-red-500 rounded-lg bg-red-50 dark:bg-red-900/20">
190+
<div className="p-4 border border-red-500 rounded-lg bg-red-50 dark:bg-red-900/20">
178191
<div className="text-red-700 dark:text-red-300">Failed to load MCP app: {error}</div>
179192
</div>
180193
);
181194
}
182195

183-
if (!resourceHtml) {
184-
return (
185-
<div className="mt-3 p-4 border border-borderSubtle rounded-lg bg-bgApp">
186-
<div className="flex items-center justify-center" style={{ minHeight: '200px' }}>
187-
Loading MCP app...
188-
</div>
189-
</div>
190-
);
191-
}
192-
193196
return (
194-
<div className={cn('mt-3 bg-bgApp', 'border border-borderSubtle rounded-lg overflow-hidden')}>
195-
{proxyUrl ? (
197+
<div
198+
className={cn(
199+
'bg-bgApp overflow-hidden',
200+
resource.prefersBorder ? 'border border-borderSubtle rounded-lg' : 'my-6'
201+
)}
202+
>
203+
{resource.html && proxyUrl ? (
196204
<iframe
197205
ref={iframeRef}
198206
src={proxyUrl}
@@ -205,16 +213,8 @@ export default function McpAppRenderer({
205213
sandbox="allow-scripts allow-same-origin"
206214
/>
207215
) : (
208-
<div
209-
style={{
210-
width: '100%',
211-
minHeight: '200px',
212-
display: 'flex',
213-
alignItems: 'center',
214-
justifyContent: 'center',
215-
}}
216-
>
217-
Loading...
216+
<div className="flex items-center justify-center p-4" style={{ minHeight: '200px' }}>
217+
Loading MCP app...
218218
</div>
219219
)}
220220
</div>

0 commit comments

Comments
 (0)