feat(mcp-apps): add Permission Policy support for sandbox iframes (#6947)
This commit is contained in:
@@ -5249,6 +5249,28 @@
|
||||
"never_allow"
|
||||
]
|
||||
},
|
||||
"PermissionsMetadata": {
|
||||
"type": "object",
|
||||
"description": "Sandbox permissions for MCP Apps\nSpecifies which browser capabilities the UI needs access to.\nMaps to the iframe Permission Policy `allow` attribute.",
|
||||
"properties": {
|
||||
"camera": {
|
||||
"type": "boolean",
|
||||
"description": "Request camera access (maps to Permission Policy `camera` feature)"
|
||||
},
|
||||
"clipboardWrite": {
|
||||
"type": "boolean",
|
||||
"description": "Request clipboard write access (maps to Permission Policy `clipboard-write` feature)"
|
||||
},
|
||||
"geolocation": {
|
||||
"type": "boolean",
|
||||
"description": "Request geolocation access (maps to Permission Policy `geolocation` feature)"
|
||||
},
|
||||
"microphone": {
|
||||
"type": "boolean",
|
||||
"description": "Request microphone access (maps to Permission Policy `microphone` feature)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PricingData": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -7021,6 +7043,9 @@
|
||||
"description": "Preferred domain for the app (used for CORS)",
|
||||
"nullable": true
|
||||
},
|
||||
"permissions": {
|
||||
"$ref": "#/components/schemas/PermissionsMetadata"
|
||||
},
|
||||
"prefersBorder": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the app prefers to have a border around it",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -667,6 +667,30 @@ export type ParseRecipeResponse = {
|
||||
*/
|
||||
export type PermissionLevel = 'always_allow' | 'ask_before' | 'never_allow';
|
||||
|
||||
/**
|
||||
* Sandbox permissions for MCP Apps
|
||||
* Specifies which browser capabilities the UI needs access to.
|
||||
* Maps to the iframe Permission Policy `allow` attribute.
|
||||
*/
|
||||
export type PermissionsMetadata = {
|
||||
/**
|
||||
* Request camera access (maps to Permission Policy `camera` feature)
|
||||
*/
|
||||
camera?: boolean;
|
||||
/**
|
||||
* Request clipboard write access (maps to Permission Policy `clipboard-write` feature)
|
||||
*/
|
||||
clipboardWrite?: boolean;
|
||||
/**
|
||||
* Request geolocation access (maps to Permission Policy `geolocation` feature)
|
||||
*/
|
||||
geolocation?: boolean;
|
||||
/**
|
||||
* Request microphone access (maps to Permission Policy `microphone` feature)
|
||||
*/
|
||||
microphone?: boolean;
|
||||
};
|
||||
|
||||
export type PricingData = {
|
||||
context_length?: number | null;
|
||||
currency: string;
|
||||
@@ -1273,6 +1297,7 @@ export type UiMetadata = {
|
||||
* Preferred domain for the app (used for CORS)
|
||||
*/
|
||||
domain?: string | null;
|
||||
permissions?: PermissionsMetadata;
|
||||
/**
|
||||
* Whether the app prefers to have a border around it
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
ToolResult,
|
||||
ToolCancelled,
|
||||
CspMetadata,
|
||||
PermissionsMetadata,
|
||||
McpMethodParams,
|
||||
McpMethodResponse,
|
||||
} from './types';
|
||||
@@ -40,6 +41,7 @@ interface McpAppRendererProps {
|
||||
interface ResourceData {
|
||||
html: string | null;
|
||||
csp: CspMetadata | null;
|
||||
permissions: PermissionsMetadata | null;
|
||||
prefersBorder: boolean;
|
||||
}
|
||||
|
||||
@@ -58,6 +60,7 @@ export default function McpAppRenderer({
|
||||
const [resource, setResource] = useState<ResourceData>({
|
||||
html: cachedHtml || null,
|
||||
csp: null,
|
||||
permissions: null,
|
||||
prefersBorder: true,
|
||||
});
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -82,13 +85,14 @@ export default function McpAppRenderer({
|
||||
if (response.data) {
|
||||
const content = response.data;
|
||||
const meta = content._meta as
|
||||
| { ui?: { csp?: CspMetadata; prefersBorder?: boolean } }
|
||||
| { ui?: { csp?: CspMetadata; permissions?: PermissionsMetadata; prefersBorder?: boolean } }
|
||||
| undefined;
|
||||
|
||||
if (content.text !== cachedHtml) {
|
||||
setResource({
|
||||
html: content.text,
|
||||
csp: meta?.ui?.csp || null,
|
||||
permissions: meta?.ui?.permissions || null,
|
||||
prefersBorder: meta?.ui?.prefersBorder ?? true,
|
||||
});
|
||||
}
|
||||
@@ -241,6 +245,7 @@ export default function McpAppRenderer({
|
||||
const { iframeRef, proxyUrl } = useSandboxBridge({
|
||||
resourceHtml: resource.html || '',
|
||||
resourceCsp: resource.csp,
|
||||
resourcePermissions: resource.permissions,
|
||||
resourceUri,
|
||||
toolInput,
|
||||
toolInputPartial,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type { CspMetadata, CallToolResponse as ToolResult } from '../../api/types.gen';
|
||||
export type { CspMetadata, PermissionsMetadata, CallToolResponse as ToolResult } from '../../api/types.gen';
|
||||
|
||||
export type ContentBlock =
|
||||
| { type: 'text'; text: string }
|
||||
|
||||
@@ -9,6 +9,7 @@ import type {
|
||||
ToolCancelled,
|
||||
HostContext,
|
||||
CspMetadata,
|
||||
PermissionsMetadata,
|
||||
} from './types';
|
||||
import { fetchMcpAppProxyUrl } from './utils';
|
||||
import { useTheme } from '../../contexts/ThemeContext';
|
||||
@@ -18,6 +19,7 @@ import { errorMessage } from '../../utils/conversionUtils';
|
||||
interface SandboxBridgeOptions {
|
||||
resourceHtml: string;
|
||||
resourceCsp: CspMetadata | null;
|
||||
resourcePermissions: PermissionsMetadata | null;
|
||||
resourceUri: string;
|
||||
toolInput?: ToolInput;
|
||||
toolInputPartial?: ToolInputPartial;
|
||||
@@ -40,6 +42,7 @@ export function useSandboxBridge(options: SandboxBridgeOptions): SandboxBridgeRe
|
||||
const {
|
||||
resourceHtml,
|
||||
resourceCsp,
|
||||
resourcePermissions,
|
||||
resourceUri,
|
||||
toolInput,
|
||||
toolInputPartial,
|
||||
@@ -80,7 +83,7 @@ export function useSandboxBridge(options: SandboxBridgeOptions): SandboxBridgeRe
|
||||
sendToSandbox({
|
||||
jsonrpc: '2.0',
|
||||
method: 'ui/notifications/sandbox-resource-ready',
|
||||
params: { html: resourceHtml, csp: resourceCsp },
|
||||
params: { html: resourceHtml, csp: resourceCsp, permissions: resourcePermissions },
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -181,6 +184,7 @@ export function useSandboxBridge(options: SandboxBridgeOptions): SandboxBridgeRe
|
||||
[
|
||||
resourceHtml,
|
||||
resourceCsp,
|
||||
resourcePermissions,
|
||||
resolvedTheme,
|
||||
sendToSandbox,
|
||||
onMcpRequest,
|
||||
|
||||
Reference in New Issue
Block a user