From c02eb4d006c3a519178357cb8e2747f4a264b019 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Fri, 30 Jan 2026 11:30:44 -0600 Subject: [PATCH] Improve documentation for CSP and permissions types Add detailed JSDoc comments to `McpUiResourceCsp`, `McpUiResourcePermissions`, and `McpUiResourceMeta` interfaces: - Document CSP directive mappings for `connectDomains`, `resourceDomains`, `frameDomains`, and `baseUriDomains` - Add usage examples showing typical domain patterns - Clarify Permission Policy mappings for `camera`, `microphone`, `geolocation`, and `clipboardWrite` - Explain `domain` field's host-dependent behavior with concrete examples - Document `prefersBorder` semantics including true/false/omitted behavior Co-Authored-By: Claude Opus 4.5 --- src/generated/schema.json | 88 ++++++++++---------- src/generated/schema.ts | 163 ++++++++++++++++++++++++++++++++------ src/spec.types.ts | 124 ++++++++++++++++++++++++++--- 3 files changed, 293 insertions(+), 82 deletions(-) diff --git a/src/generated/schema.json b/src/generated/schema.json index bdbb058e..3a3005a2 100644 --- a/src/generated/schema.json +++ b/src/generated/schema.json @@ -134,25 +134,25 @@ "type": "object", "properties": { "camera": { - "description": "Request camera access (Permission Policy `camera` feature).", + "description": "Request camera access.\n\nMaps to Permission Policy `camera` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "microphone": { - "description": "Request microphone access (Permission Policy `microphone` feature).", + "description": "Request microphone access.\n\nMaps to Permission Policy `microphone` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "geolocation": { - "description": "Request geolocation access (Permission Policy `geolocation` feature).", + "description": "Request geolocation access.\n\nMaps to Permission Policy `geolocation` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "clipboardWrite": { - "description": "Request clipboard write access (Permission Policy `clipboard-write` feature).", + "description": "Request clipboard write access.\n\nMaps to Permission Policy `clipboard-write` feature.", "type": "object", "properties": {}, "additionalProperties": false @@ -165,28 +165,28 @@ "type": "object", "properties": { "connectDomains": { - "description": "Origins for network requests (fetch/XHR/WebSocket).", + "description": "Origins for network requests (fetch/XHR/WebSocket).\n\n- Maps to CSP `connect-src` directive\n- Empty or omitted → no external connections (secure default)", "type": "array", "items": { "type": "string" } }, "resourceDomains": { - "description": "Origins for static resources (scripts, images, styles, fonts).", + "description": "Origins for static resources (images, scripts, stylesheets, fonts, media).\n\n- Maps to CSP `img-src`, `script-src`, `style-src`, `font-src`, `media-src` directives\n- Wildcard subdomains supported: `https://*.example.com`\n- Empty or omitted → no external resources (secure default)", "type": "array", "items": { "type": "string" } }, "frameDomains": { - "description": "Origins for nested iframes (frame-src directive).", + "description": "Origins for nested iframes.\n\n- Maps to CSP `frame-src` directive\n- Empty or omitted → no nested iframes allowed (`frame-src 'none'`)", "type": "array", "items": { "type": "string" } }, "baseUriDomains": { - "description": "Allowed base URIs for the document (base-uri directive).", + "description": "Allowed base URIs for the document.\n\n- Maps to CSP `base-uri` directive\n- Empty or omitted → only same origin allowed (`base-uri 'self'`)", "type": "array", "items": { "type": "string" @@ -2480,25 +2480,25 @@ "type": "object", "properties": { "camera": { - "description": "Request camera access (Permission Policy `camera` feature).", + "description": "Request camera access.\n\nMaps to Permission Policy `camera` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "microphone": { - "description": "Request microphone access (Permission Policy `microphone` feature).", + "description": "Request microphone access.\n\nMaps to Permission Policy `microphone` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "geolocation": { - "description": "Request geolocation access (Permission Policy `geolocation` feature).", + "description": "Request geolocation access.\n\nMaps to Permission Policy `geolocation` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "clipboardWrite": { - "description": "Request clipboard write access (Permission Policy `clipboard-write` feature).", + "description": "Request clipboard write access.\n\nMaps to Permission Policy `clipboard-write` feature.", "type": "object", "properties": {}, "additionalProperties": false @@ -2511,28 +2511,28 @@ "type": "object", "properties": { "connectDomains": { - "description": "Origins for network requests (fetch/XHR/WebSocket).", + "description": "Origins for network requests (fetch/XHR/WebSocket).\n\n- Maps to CSP `connect-src` directive\n- Empty or omitted → no external connections (secure default)", "type": "array", "items": { "type": "string" } }, "resourceDomains": { - "description": "Origins for static resources (scripts, images, styles, fonts).", + "description": "Origins for static resources (images, scripts, stylesheets, fonts, media).\n\n- Maps to CSP `img-src`, `script-src`, `style-src`, `font-src`, `media-src` directives\n- Wildcard subdomains supported: `https://*.example.com`\n- Empty or omitted → no external resources (secure default)", "type": "array", "items": { "type": "string" } }, "frameDomains": { - "description": "Origins for nested iframes (frame-src directive).", + "description": "Origins for nested iframes.\n\n- Maps to CSP `frame-src` directive\n- Empty or omitted → no nested iframes allowed (`frame-src 'none'`)", "type": "array", "items": { "type": "string" } }, "baseUriDomains": { - "description": "Allowed base URIs for the document (base-uri directive).", + "description": "Allowed base URIs for the document.\n\n- Maps to CSP `base-uri` directive\n- Empty or omitted → only same origin allowed (`base-uri 'self'`)", "type": "array", "items": { "type": "string" @@ -3874,28 +3874,28 @@ "type": "object", "properties": { "connectDomains": { - "description": "Origins for network requests (fetch/XHR/WebSocket).", + "description": "Origins for network requests (fetch/XHR/WebSocket).\n\n- Maps to CSP `connect-src` directive\n- Empty or omitted → no external connections (secure default)", "type": "array", "items": { "type": "string" } }, "resourceDomains": { - "description": "Origins for static resources (scripts, images, styles, fonts).", + "description": "Origins for static resources (images, scripts, stylesheets, fonts, media).\n\n- Maps to CSP `img-src`, `script-src`, `style-src`, `font-src`, `media-src` directives\n- Wildcard subdomains supported: `https://*.example.com`\n- Empty or omitted → no external resources (secure default)", "type": "array", "items": { "type": "string" } }, "frameDomains": { - "description": "Origins for nested iframes (frame-src directive).", + "description": "Origins for nested iframes.\n\n- Maps to CSP `frame-src` directive\n- Empty or omitted → no nested iframes allowed (`frame-src 'none'`)", "type": "array", "items": { "type": "string" } }, "baseUriDomains": { - "description": "Allowed base URIs for the document (base-uri directive).", + "description": "Allowed base URIs for the document.\n\n- Maps to CSP `base-uri` directive\n- Empty or omitted → only same origin allowed (`base-uri 'self'`)", "type": "array", "items": { "type": "string" @@ -3909,32 +3909,32 @@ "type": "object", "properties": { "csp": { - "description": "Content Security Policy configuration.", + "description": "Content Security Policy configuration for UI resources.", "type": "object", "properties": { "connectDomains": { - "description": "Origins for network requests (fetch/XHR/WebSocket).", + "description": "Origins for network requests (fetch/XHR/WebSocket).\n\n- Maps to CSP `connect-src` directive\n- Empty or omitted → no external connections (secure default)", "type": "array", "items": { "type": "string" } }, "resourceDomains": { - "description": "Origins for static resources (scripts, images, styles, fonts).", + "description": "Origins for static resources (images, scripts, stylesheets, fonts, media).\n\n- Maps to CSP `img-src`, `script-src`, `style-src`, `font-src`, `media-src` directives\n- Wildcard subdomains supported: `https://*.example.com`\n- Empty or omitted → no external resources (secure default)", "type": "array", "items": { "type": "string" } }, "frameDomains": { - "description": "Origins for nested iframes (frame-src directive).", + "description": "Origins for nested iframes.\n\n- Maps to CSP `frame-src` directive\n- Empty or omitted → no nested iframes allowed (`frame-src 'none'`)", "type": "array", "items": { "type": "string" } }, "baseUriDomains": { - "description": "Allowed base URIs for the document (base-uri directive).", + "description": "Allowed base URIs for the document.\n\n- Maps to CSP `base-uri` directive\n- Empty or omitted → only same origin allowed (`base-uri 'self'`)", "type": "array", "items": { "type": "string" @@ -3944,29 +3944,29 @@ "additionalProperties": false }, "permissions": { - "description": "Sandbox permissions requested by the UI.", + "description": "Sandbox permissions requested by the UI resource.", "type": "object", "properties": { "camera": { - "description": "Request camera access (Permission Policy `camera` feature).", + "description": "Request camera access.\n\nMaps to Permission Policy `camera` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "microphone": { - "description": "Request microphone access (Permission Policy `microphone` feature).", + "description": "Request microphone access.\n\nMaps to Permission Policy `microphone` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "geolocation": { - "description": "Request geolocation access (Permission Policy `geolocation` feature).", + "description": "Request geolocation access.\n\nMaps to Permission Policy `geolocation` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "clipboardWrite": { - "description": "Request clipboard write access (Permission Policy `clipboard-write` feature).", + "description": "Request clipboard write access.\n\nMaps to Permission Policy `clipboard-write` feature.", "type": "object", "properties": {}, "additionalProperties": false @@ -3975,11 +3975,11 @@ "additionalProperties": false }, "domain": { - "description": "Dedicated origin for view sandbox.", + "description": "Dedicated origin for view sandbox.\n\nUseful when views need stable, dedicated origins for OAuth callbacks, CORS policies, or API key allowlists.\n\n**Host-dependent:** The format and validation rules for this field are determined by each host. Servers MUST consult host-specific documentation for the expected domain format. Common patterns include:\n- Hash-based subdomains (e.g., `{hash}.claudemcpcontent.com`)\n- URL-derived subdomains (e.g., `www-example-com.oaiusercontent.com`)\n\nIf omitted, host uses default sandbox origin (typically per-conversation).", "type": "string" }, "prefersBorder": { - "description": "Visual boundary preference - true if UI prefers a visible border.", + "description": "Visual boundary preference - true if view prefers a visible border.\n\nBoolean requesting whether a visible border and background is provided by the host. Specifying an explicit value for this is recommended because hosts' defaults may vary.\n\n- `true`: request visible border + background\n- `false`: request no visible border + background\n- omitted: host decides border", "type": "boolean" } }, @@ -3990,25 +3990,25 @@ "type": "object", "properties": { "camera": { - "description": "Request camera access (Permission Policy `camera` feature).", + "description": "Request camera access.\n\nMaps to Permission Policy `camera` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "microphone": { - "description": "Request microphone access (Permission Policy `microphone` feature).", + "description": "Request microphone access.\n\nMaps to Permission Policy `microphone` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "geolocation": { - "description": "Request geolocation access (Permission Policy `geolocation` feature).", + "description": "Request geolocation access.\n\nMaps to Permission Policy `geolocation` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "clipboardWrite": { - "description": "Request clipboard write access (Permission Policy `clipboard-write` feature).", + "description": "Request clipboard write access.\n\nMaps to Permission Policy `clipboard-write` feature.", "type": "object", "properties": {}, "additionalProperties": false @@ -4082,28 +4082,28 @@ "type": "object", "properties": { "connectDomains": { - "description": "Origins for network requests (fetch/XHR/WebSocket).", + "description": "Origins for network requests (fetch/XHR/WebSocket).\n\n- Maps to CSP `connect-src` directive\n- Empty or omitted → no external connections (secure default)", "type": "array", "items": { "type": "string" } }, "resourceDomains": { - "description": "Origins for static resources (scripts, images, styles, fonts).", + "description": "Origins for static resources (images, scripts, stylesheets, fonts, media).\n\n- Maps to CSP `img-src`, `script-src`, `style-src`, `font-src`, `media-src` directives\n- Wildcard subdomains supported: `https://*.example.com`\n- Empty or omitted → no external resources (secure default)", "type": "array", "items": { "type": "string" } }, "frameDomains": { - "description": "Origins for nested iframes (frame-src directive).", + "description": "Origins for nested iframes.\n\n- Maps to CSP `frame-src` directive\n- Empty or omitted → no nested iframes allowed (`frame-src 'none'`)", "type": "array", "items": { "type": "string" } }, "baseUriDomains": { - "description": "Allowed base URIs for the document (base-uri directive).", + "description": "Allowed base URIs for the document.\n\n- Maps to CSP `base-uri` directive\n- Empty or omitted → only same origin allowed (`base-uri 'self'`)", "type": "array", "items": { "type": "string" @@ -4117,25 +4117,25 @@ "type": "object", "properties": { "camera": { - "description": "Request camera access (Permission Policy `camera` feature).", + "description": "Request camera access.\n\nMaps to Permission Policy `camera` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "microphone": { - "description": "Request microphone access (Permission Policy `microphone` feature).", + "description": "Request microphone access.\n\nMaps to Permission Policy `microphone` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "geolocation": { - "description": "Request geolocation access (Permission Policy `geolocation` feature).", + "description": "Request geolocation access.\n\nMaps to Permission Policy `geolocation` feature.", "type": "object", "properties": {}, "additionalProperties": false }, "clipboardWrite": { - "description": "Request clipboard write access (Permission Policy `clipboard-write` feature).", + "description": "Request clipboard write access.\n\nMaps to Permission Policy `clipboard-write` feature.", "type": "object", "properties": {}, "additionalProperties": false diff --git a/src/generated/schema.ts b/src/generated/schema.ts index 4719ada3..3439e704 100644 --- a/src/generated/schema.ts +++ b/src/generated/schema.ts @@ -187,61 +187,138 @@ export const McpUiSandboxProxyReadyNotificationSchema = z.object({ /** * @description Content Security Policy configuration for UI resources. + * + * Servers declare which external origins their UI needs to access. + * Hosts use this to enforce appropriate CSP headers. + * + * > [!IMPORTANT] + * > MCP App HTML runs in a sandboxed iframe with no same-origin server. + * > **All** origins must be declared—including where your bundled JS/CSS is + * > served from (`localhost` in dev, your CDN in production). */ export const McpUiResourceCspSchema = z.object({ - /** @description Origins for network requests (fetch/XHR/WebSocket). */ + /** + * @description Origins for network requests (fetch/XHR/WebSocket). + * + * - Maps to CSP `connect-src` directive + * - Empty or omitted → no external connections (secure default) + * + * @example + * ```ts + * ["https://api.weather.com", "wss://realtime.service.com"] + * ``` + */ connectDomains: z .array(z.string()) .optional() - .describe("Origins for network requests (fetch/XHR/WebSocket)."), - /** @description Origins for static resources (scripts, images, styles, fonts). */ + .describe( + "Origins for network requests (fetch/XHR/WebSocket).\n\n- Maps to CSP `connect-src` directive\n- Empty or omitted \u2192 no external connections (secure default)", + ), + /** + * @description Origins for static resources (images, scripts, stylesheets, fonts, media). + * + * - Maps to CSP `img-src`, `script-src`, `style-src`, `font-src`, `media-src` directives + * - Wildcard subdomains supported: `https://*.example.com` + * - Empty or omitted → no external resources (secure default) + * + * @example + * ```ts + * ["https://cdn.jsdelivr.net", "https://*.cloudflare.com"] + * ``` + */ resourceDomains: z .array(z.string()) .optional() - .describe("Origins for static resources (scripts, images, styles, fonts)."), - /** @description Origins for nested iframes (frame-src directive). */ + .describe( + "Origins for static resources (images, scripts, stylesheets, fonts, media).\n\n- Maps to CSP `img-src`, `script-src`, `style-src`, `font-src`, `media-src` directives\n- Wildcard subdomains supported: `https://*.example.com`\n- Empty or omitted \u2192 no external resources (secure default)", + ), + /** + * @description Origins for nested iframes. + * + * - Maps to CSP `frame-src` directive + * - Empty or omitted → no nested iframes allowed (`frame-src 'none'`) + * + * @example + * ```ts + * ["https://www.youtube.com", "https://player.vimeo.com"] + * ``` + */ frameDomains: z .array(z.string()) .optional() - .describe("Origins for nested iframes (frame-src directive)."), - /** @description Allowed base URIs for the document (base-uri directive). */ + .describe( + "Origins for nested iframes.\n\n- Maps to CSP `frame-src` directive\n- Empty or omitted \u2192 no nested iframes allowed (`frame-src 'none'`)", + ), + /** + * @description Allowed base URIs for the document. + * + * - Maps to CSP `base-uri` directive + * - Empty or omitted → only same origin allowed (`base-uri 'self'`) + * + * @example + * ```ts + * ["https://cdn.example.com"] + * ``` + */ baseUriDomains: z .array(z.string()) .optional() - .describe("Allowed base URIs for the document (base-uri directive)."), + .describe( + "Allowed base URIs for the document.\n\n- Maps to CSP `base-uri` directive\n- Empty or omitted \u2192 only same origin allowed (`base-uri 'self'`)", + ), }); /** * @description Sandbox permissions requested by the UI resource. + * + * Servers declare which browser capabilities their UI needs. * Hosts MAY honor these by setting appropriate iframe `allow` attributes. * Apps SHOULD NOT assume permissions are granted; use JS feature detection as fallback. */ export const McpUiResourcePermissionsSchema = z.object({ - /** @description Request camera access (Permission Policy `camera` feature). */ + /** + * @description Request camera access. + * + * Maps to Permission Policy `camera` feature. + */ camera: z .object({}) .optional() - .describe("Request camera access (Permission Policy `camera` feature)."), - /** @description Request microphone access (Permission Policy `microphone` feature). */ + .describe( + "Request camera access.\n\nMaps to Permission Policy `camera` feature.", + ), + /** + * @description Request microphone access. + * + * Maps to Permission Policy `microphone` feature. + */ microphone: z .object({}) .optional() .describe( - "Request microphone access (Permission Policy `microphone` feature).", + "Request microphone access.\n\nMaps to Permission Policy `microphone` feature.", ), - /** @description Request geolocation access (Permission Policy `geolocation` feature). */ + /** + * @description Request geolocation access. + * + * Maps to Permission Policy `geolocation` feature. + */ geolocation: z .object({}) .optional() .describe( - "Request geolocation access (Permission Policy `geolocation` feature).", + "Request geolocation access.\n\nMaps to Permission Policy `geolocation` feature.", ), - /** @description Request clipboard write access (Permission Policy `clipboard-write` feature). */ + /** + * @description Request clipboard write access. + * + * Maps to Permission Policy `clipboard-write` feature. + */ clipboardWrite: z .object({}) .optional() .describe( - "Request clipboard write access (Permission Policy `clipboard-write` feature).", + "Request clipboard write access.\n\nMaps to Permission Policy `clipboard-write` feature.", ), }); @@ -490,22 +567,55 @@ export const McpUiInitializedNotificationSchema = z.object({ * @description UI Resource metadata for security and rendering configuration. */ export const McpUiResourceMetaSchema = z.object({ - /** @description Content Security Policy configuration. */ + /** @description Content Security Policy configuration for UI resources. */ csp: McpUiResourceCspSchema.optional().describe( - "Content Security Policy configuration.", + "Content Security Policy configuration for UI resources.", ), - /** @description Sandbox permissions requested by the UI. */ + /** @description Sandbox permissions requested by the UI resource. */ permissions: McpUiResourcePermissionsSchema.optional().describe( - "Sandbox permissions requested by the UI.", + "Sandbox permissions requested by the UI resource.", ), - /** @description Dedicated origin for view sandbox. */ - domain: z.string().optional().describe("Dedicated origin for view sandbox."), - /** @description Visual boundary preference - true if UI prefers a visible border. */ + /** + * @description Dedicated origin for view sandbox. + * + * Useful when views need stable, dedicated origins for OAuth callbacks, CORS policies, or API key allowlists. + * + * **Host-dependent:** The format and validation rules for this field are determined by each host. Servers MUST consult host-specific documentation for the expected domain format. Common patterns include: + * - Hash-based subdomains (e.g., `{hash}.claudemcpcontent.com`) + * - URL-derived subdomains (e.g., `www-example-com.oaiusercontent.com`) + * + * If omitted, host uses default sandbox origin (typically per-conversation). + * + * @example + * ```ts + * "a904794854a047f6.claudemcpcontent.com" + * ``` + * + * @example + * ```ts + * "www-example-com.oaiusercontent.com" + * ``` + */ + domain: z + .string() + .optional() + .describe( + "Dedicated origin for view sandbox.\n\nUseful when views need stable, dedicated origins for OAuth callbacks, CORS policies, or API key allowlists.\n\n**Host-dependent:** The format and validation rules for this field are determined by each host. Servers MUST consult host-specific documentation for the expected domain format. Common patterns include:\n- Hash-based subdomains (e.g., `{hash}.claudemcpcontent.com`)\n- URL-derived subdomains (e.g., `www-example-com.oaiusercontent.com`)\n\nIf omitted, host uses default sandbox origin (typically per-conversation).", + ), + /** + * @description Visual boundary preference - true if view prefers a visible border. + * + * Boolean requesting whether a visible border and background is provided by the host. Specifying an explicit value for this is recommended because hosts' defaults may vary. + * + * - `true`: request visible border + background + * - `false`: request no visible border + background + * - omitted: host decides border + */ prefersBorder: z .boolean() .optional() .describe( - "Visual boundary preference - true if UI prefers a visible border.", + "Visual boundary preference - true if view prefers a visible border.\n\nBoolean requesting whether a visible border and background is provided by the host. Specifying an explicit value for this is recommended because hosts' defaults may vary.\n\n- `true`: request visible border + background\n- `false`: request no visible border + background\n- omitted: host decides border", ), }); @@ -551,7 +661,10 @@ export const McpUiToolMetaSchema = z.object({ * URI of the UI resource to display for this tool, if any. * This is converted to `_meta["ui/resourceUri"]`. * - * @example "ui://weather/view.html" + * @example + * ```ts + * "ui://weather/view.html" + * ``` */ resourceUri: z.string().optional(), /** diff --git a/src/spec.types.ts b/src/spec.types.ts index 7cea3daf..6fc8a1f4 100644 --- a/src/spec.types.ts +++ b/src/spec.types.ts @@ -538,31 +538,98 @@ export interface McpUiInitializedNotification { /** * @description Content Security Policy configuration for UI resources. + * + * Servers declare which external origins their UI needs to access. + * Hosts use this to enforce appropriate CSP headers. + * + * > [!IMPORTANT] + * > MCP App HTML runs in a sandboxed iframe with no same-origin server. + * > **All** origins must be declared—including where your bundled JS/CSS is + * > served from (`localhost` in dev, your CDN in production). */ export interface McpUiResourceCsp { - /** @description Origins for network requests (fetch/XHR/WebSocket). */ + /** + * @description Origins for network requests (fetch/XHR/WebSocket). + * + * - Maps to CSP `connect-src` directive + * - Empty or omitted → no external connections (secure default) + * + * @example + * ```ts + * ["https://api.weather.com", "wss://realtime.service.com"] + * ``` + */ connectDomains?: string[]; - /** @description Origins for static resources (scripts, images, styles, fonts). */ + /** + * @description Origins for static resources (images, scripts, stylesheets, fonts, media). + * + * - Maps to CSP `img-src`, `script-src`, `style-src`, `font-src`, `media-src` directives + * - Wildcard subdomains supported: `https://*.example.com` + * - Empty or omitted → no external resources (secure default) + * + * @example + * ```ts + * ["https://cdn.jsdelivr.net", "https://*.cloudflare.com"] + * ``` + */ resourceDomains?: string[]; - /** @description Origins for nested iframes (frame-src directive). */ + /** + * @description Origins for nested iframes. + * + * - Maps to CSP `frame-src` directive + * - Empty or omitted → no nested iframes allowed (`frame-src 'none'`) + * + * @example + * ```ts + * ["https://www.youtube.com", "https://player.vimeo.com"] + * ``` + */ frameDomains?: string[]; - /** @description Allowed base URIs for the document (base-uri directive). */ + /** + * @description Allowed base URIs for the document. + * + * - Maps to CSP `base-uri` directive + * - Empty or omitted → only same origin allowed (`base-uri 'self'`) + * + * @example + * ```ts + * ["https://cdn.example.com"] + * ``` + */ baseUriDomains?: string[]; } /** * @description Sandbox permissions requested by the UI resource. + * + * Servers declare which browser capabilities their UI needs. * Hosts MAY honor these by setting appropriate iframe `allow` attributes. * Apps SHOULD NOT assume permissions are granted; use JS feature detection as fallback. */ export interface McpUiResourcePermissions { - /** @description Request camera access (Permission Policy `camera` feature). */ + /** + * @description Request camera access. + * + * Maps to Permission Policy `camera` feature. + */ camera?: {}; - /** @description Request microphone access (Permission Policy `microphone` feature). */ + /** + * @description Request microphone access. + * + * Maps to Permission Policy `microphone` feature. + */ microphone?: {}; - /** @description Request geolocation access (Permission Policy `geolocation` feature). */ + /** + * @description Request geolocation access. + * + * Maps to Permission Policy `geolocation` feature. + */ geolocation?: {}; - /** @description Request clipboard write access (Permission Policy `clipboard-write` feature). */ + /** + * @description Request clipboard write access. + * + * Maps to Permission Policy `clipboard-write` feature. + */ clipboardWrite?: {}; } @@ -570,13 +637,41 @@ export interface McpUiResourcePermissions { * @description UI Resource metadata for security and rendering configuration. */ export interface McpUiResourceMeta { - /** @description Content Security Policy configuration. */ + /** @description Content Security Policy configuration for UI resources. */ csp?: McpUiResourceCsp; - /** @description Sandbox permissions requested by the UI. */ + /** @description Sandbox permissions requested by the UI resource. */ permissions?: McpUiResourcePermissions; - /** @description Dedicated origin for view sandbox. */ + /** + * @description Dedicated origin for view sandbox. + * + * Useful when views need stable, dedicated origins for OAuth callbacks, CORS policies, or API key allowlists. + * + * **Host-dependent:** The format and validation rules for this field are determined by each host. Servers MUST consult host-specific documentation for the expected domain format. Common patterns include: + * - Hash-based subdomains (e.g., `{hash}.claudemcpcontent.com`) + * - URL-derived subdomains (e.g., `www-example-com.oaiusercontent.com`) + * + * If omitted, host uses default sandbox origin (typically per-conversation). + * + * @example + * ```ts + * "a904794854a047f6.claudemcpcontent.com" + * ``` + * + * @example + * ```ts + * "www-example-com.oaiusercontent.com" + * ``` + */ domain?: string; - /** @description Visual boundary preference - true if UI prefers a visible border. */ + /** + * @description Visual boundary preference - true if view prefers a visible border. + * + * Boolean requesting whether a visible border and background is provided by the host. Specifying an explicit value for this is recommended because hosts' defaults may vary. + * + * - `true`: request visible border + background + * - `false`: request no visible border + background + * - omitted: host decides border + */ prefersBorder?: boolean; } @@ -621,7 +716,10 @@ export interface McpUiToolMeta { * URI of the UI resource to display for this tool, if any. * This is converted to `_meta["ui/resourceUri"]`. * - * @example "ui://weather/view.html" + * @example + * ```ts + * "ui://weather/view.html" + * ``` */ resourceUri?: string; /**