diff --git a/examples/integration-server/server.ts b/examples/integration-server/server.ts index a44c007a2..e44689d24 100644 --- a/examples/integration-server/server.ts +++ b/examples/integration-server/server.ts @@ -16,6 +16,7 @@ const DIST_DIR = import.meta.filename.endsWith(".ts") ? path.join(import.meta.dirname, "dist") : import.meta.dirname; const RESOURCE_URI = "ui://get-time/mcp-app.html"; +const SAMPLE_DOWNLOAD_URI = "resource:///sample-report.txt"; /** * Creates a new MCP server instance with tools and resources registered. @@ -70,5 +71,28 @@ export function createServer(): McpServer { }, ); + // Sample downloadable resource — used to demo ResourceLink in ui/download-file + server.resource( + SAMPLE_DOWNLOAD_URI, + SAMPLE_DOWNLOAD_URI, + { + mimeType: "text/plain", + }, + async (): Promise => { + const content = [ + "Integration Test Server — Sample Report", + `Generated: ${new Date().toISOString()}`, + "", + "This file was downloaded via MCP ResourceLink.", + "The host resolved it by calling resources/read on the server.", + ].join("\n"); + return { + contents: [ + { uri: SAMPLE_DOWNLOAD_URI, mimeType: "text/plain", text: content }, + ], + }; + }, + ); + return server; } diff --git a/examples/integration-server/src/mcp-app.tsx b/examples/integration-server/src/mcp-app.tsx index ef280f3a7..7f0b18c27 100644 --- a/examples/integration-server/src/mcp-app.tsx +++ b/examples/integration-server/src/mcp-app.tsx @@ -137,6 +137,45 @@ function GetTimeAppInner({ log.info("Open link request", isError ? "rejected" : "accepted"); }, [app, linkUrl]); + const canDownload = app.getHostCapabilities()?.downloadFile !== undefined; + + const handleDownloadFile = useCallback(async () => { + const sampleContent = JSON.stringify( + { time: serverTime, exported: new Date().toISOString() }, + null, + 2, + ); + log.info("Requesting file download..."); + const { isError } = await app.downloadFile({ + contents: [ + { + type: "resource", + resource: { + uri: "file:///export.json", + mimeType: "application/json", + text: sampleContent, + }, + }, + ], + }); + log.info("Download", isError ? "rejected" : "accepted"); + }, [app, serverTime]); + + const handleDownloadLink = useCallback(async () => { + log.info("Requesting resource link download..."); + const { isError } = await app.downloadFile({ + contents: [ + { + type: "resource_link", + uri: "resource:///sample-report.txt", + name: "sample-report.txt", + mimeType: "text/plain", + }, + ], + }); + log.info("Resource link download", isError ? "rejected" : "accepted"); + }, [app]); + return (
+ + {canDownload && ( +
+

Download file via EmbeddedResource or ResourceLink

+
+ + +
+
+ )}
); } diff --git a/scripts/generate-schemas.ts b/scripts/generate-schemas.ts index 513b2bf07..858ab9145 100644 --- a/scripts/generate-schemas.ts +++ b/scripts/generate-schemas.ts @@ -70,8 +70,10 @@ const JSON_SCHEMA_OUTPUT_FILE = join(GENERATED_DIR, "schema.json"); const EXTERNAL_TYPE_SCHEMAS = [ "ContentBlockSchema", "CallToolResultSchema", + "EmbeddedResourceSchema", "ImplementationSchema", "RequestIdSchema", + "ResourceLinkSchema", "ToolSchema", ]; diff --git a/specification/draft/apps.mdx b/specification/draft/apps.mdx index cb73cabe1..b5fbb6208 100644 --- a/specification/draft/apps.mdx +++ b/specification/draft/apps.mdx @@ -648,6 +648,8 @@ interface HostCapabilities { experimental?: {}; /** Host supports opening external URLs. */ openLinks?: {}; + /** Host supports file downloads via ui/download-file. */ + downloadFile?: {}; /** Host can proxy tool calls to the MCP server. */ serverTools?: { /** Host supports tools/list_changed notifications. */ @@ -1013,6 +1015,75 @@ MCP Apps introduces additional JSON-RPC methods for UI-specific functionality: Host SHOULD open the URL in the user's default browser or a new tab. +`ui/download-file` - Request host to download a file + +```typescript +// Request (EmbeddedResource — inline content) +{ + jsonrpc: "2.0", + id: 1, + method: "ui/download-file", + params: { + contents: [ + { + type: "resource", + resource: { + uri: "file:///export.json", // Used for suggested filename + mimeType: "application/json", + text: "{ ... }" // Text content (or `blob` for base64 binary) + } + } + ] + } +} + +// Request (ResourceLink — host fetches) +{ + jsonrpc: "2.0", + id: 1, + method: "ui/download-file", + params: { + contents: [ + { + type: "resource_link", + uri: "https://api.example.com/reports/q4.pdf", + name: "Q4 Report", + mimeType: "application/pdf" + } + ] + } +} + +// Success Response +{ + jsonrpc: "2.0", + id: 1, + result: {} // Empty result on success +} + +// Error Response (if denied or failed) +{ + jsonrpc: "2.0", + id: 1, + error: { + code: -32000, // Implementation-defined error + message: "Download denied by user" | "Invalid content" | "Policy violation" + } +} +``` + +MCP Apps run in sandboxed iframes where direct file downloads are blocked (`allow-downloads` is not set). `ui/download-file` provides a host-mediated mechanism for apps to offer file exports — useful for visualization tools (SVG/PNG export), document editors, data analysis tools, and any app that produces downloadable artifacts. + +The `contents` array uses standard MCP resource types (`EmbeddedResource` and `ResourceLink`), avoiding custom content formats. For `EmbeddedResource`, content is inline via `text` (UTF-8) or `blob` (base64). For `ResourceLink`, the host can retrieve the content directly from the URI. + +Host behavior: +* Host SHOULD show a confirmation dialog before initiating the download. +* For `EmbeddedResource`, host SHOULD derive the filename from the last segment of `resource.uri`. +* For `EmbeddedResource` with `blob`, host MUST decode the content from base64 before creating the file. +* For `ResourceLink`, host MAY fetch the resource on behalf of the app or open the URI directly. +* Host MAY reject the download based on security policy, file size limits, or user preferences. +* Host SHOULD sanitize filenames to prevent path traversal. + `ui/message` - Send message content to the host's chat interface ```typescript diff --git a/src/app-bridge.ts b/src/app-bridge.ts index 6e1c02172..793782be2 100644 --- a/src/app-bridge.ts +++ b/src/app-bridge.ts @@ -69,6 +69,9 @@ import { McpUiOpenLinkRequest, McpUiOpenLinkRequestSchema, McpUiOpenLinkResult, + McpUiDownloadFileRequest, + McpUiDownloadFileRequestSchema, + McpUiDownloadFileResult, McpUiResourceTeardownRequest, McpUiResourceTeardownResultSchema, McpUiSandboxProxyReadyNotification, @@ -614,6 +617,62 @@ export class AppBridge extends Protocol< ); } + /** + * Register a handler for file download requests from the View. + * + * The View sends `ui/download-file` requests when the user wants to + * download a file. The params contain an array of MCP resource content + * items — either `EmbeddedResource` (inline data) or `ResourceLink` + * (URI the host can fetch). The host should show a confirmation dialog + * and then trigger the download. + * + * @param callback - Handler that receives download params and returns a result + * - `params.contents` - Array of `EmbeddedResource` or `ResourceLink` items + * - `extra` - Request metadata (abort signal, session info) + * - Returns: `Promise` with optional `isError` flag + * + * @example + * ```ts + * bridge.ondownloadfile = async ({ contents }, extra) => { + * for (const item of contents) { + * if (item.type === "resource") { + * // EmbeddedResource — inline content + * const res = item.resource; + * const blob = res.blob + * ? new Blob([Uint8Array.from(atob(res.blob), c => c.charCodeAt(0))], { type: res.mimeType }) + * : new Blob([res.text ?? ""], { type: res.mimeType }); + * const url = URL.createObjectURL(blob); + * const link = document.createElement("a"); + * link.href = url; + * link.download = res.uri.split("/").pop() ?? "download"; + * link.click(); + * URL.revokeObjectURL(url); + * } else if (item.type === "resource_link") { + * // ResourceLink — host fetches or opens directly + * window.open(item.uri, "_blank"); + * } + * } + * return {}; + * }; + * ``` + * + * @see {@link McpUiDownloadFileRequest `McpUiDownloadFileRequest`} for the request type + * @see {@link McpUiDownloadFileResult `McpUiDownloadFileResult`} for the result type + */ + set ondownloadfile( + callback: ( + params: McpUiDownloadFileRequest["params"], + extra: RequestHandlerExtra, + ) => Promise, + ) { + this.setRequestHandler( + McpUiDownloadFileRequestSchema, + async (request, extra) => { + return callback(request.params, extra); + }, + ); + } + /** * Register a handler for display mode change requests from the view. * diff --git a/src/app.ts b/src/app.ts index 16f8da67f..8e133d64c 100644 --- a/src/app.ts +++ b/src/app.ts @@ -33,6 +33,8 @@ import { McpUiMessageResultSchema, McpUiOpenLinkRequest, McpUiOpenLinkResultSchema, + McpUiDownloadFileRequest, + McpUiDownloadFileResultSchema, McpUiResourceTeardownRequest, McpUiResourceTeardownRequestSchema, McpUiResourceTeardownResult, @@ -930,6 +932,83 @@ export class App extends Protocol { /** @deprecated Use {@link openLink `openLink`} instead */ sendOpenLink: App["openLink"] = this.openLink; + /** + * Request the host to download a file. + * + * Since MCP Apps run in sandboxed iframes where direct downloads are blocked, + * this provides a host-mediated mechanism for file exports. The host will + * typically show a confirmation dialog before initiating the download. + * + * Uses standard MCP resource types: `EmbeddedResource` for inline content + * and `ResourceLink` for content the host can fetch directly. + * + * @param params - Resource contents to download + * @param options - Request options (timeout, etc.) + * @returns Result with `isError: true` if the host denied the request (e.g., user cancelled) + * + * @throws {Error} If the request times out or the connection is lost + * + * @example Download a JSON file (embedded text resource) + * ```ts + * const data = JSON.stringify({ items: selectedItems }, null, 2); + * const { isError } = await app.downloadFile({ + * contents: [{ + * type: "resource", + * resource: { + * uri: "file:///export.json", + * mimeType: "application/json", + * text: data, + * }, + * }], + * }); + * if (isError) { + * console.warn("Download denied or cancelled"); + * } + * ``` + * + * @example Download binary content (embedded blob resource) + * ```ts + * const { isError } = await app.downloadFile({ + * contents: [{ + * type: "resource", + * resource: { + * uri: "file:///image.png", + * mimeType: "image/png", + * blob: base64EncodedPng, + * }, + * }], + * }); + * ``` + * + * @example Download via resource link (host fetches) + * ```ts + * const { isError } = await app.downloadFile({ + * contents: [{ + * type: "resource_link", + * uri: "https://api.example.com/reports/q4.pdf", + * name: "Q4 Report", + * mimeType: "application/pdf", + * }], + * }); + * ``` + * + * @see {@link McpUiDownloadFileRequest `McpUiDownloadFileRequest`} for request structure + * @see {@link McpUiDownloadFileResult `McpUiDownloadFileResult`} for result structure + */ + downloadFile( + params: McpUiDownloadFileRequest["params"], + options?: RequestOptions, + ) { + return this.request( + { + method: "ui/download-file", + params, + }, + McpUiDownloadFileResultSchema, + options, + ); + } + /** * Request a change to the display mode. * diff --git a/src/generated/schema.json b/src/generated/schema.json index d9e4b582c..08e229a79 100644 --- a/src/generated/schema.json +++ b/src/generated/schema.json @@ -81,6 +81,215 @@ ], "description": "Display mode for UI presentation." }, + "McpUiDownloadFileRequest": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "method": { + "type": "string", + "const": "ui/download-file" + }, + "params": { + "type": "object", + "properties": { + "contents": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "resource" + }, + "resource": { + "anyOf": [ + { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "_meta": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "text": { + "type": "string" + } + }, + "required": ["uri", "text"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "_meta": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "blob": { + "type": "string" + } + }, + "required": ["uri", "blob"], + "additionalProperties": false + } + ] + }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, + "_meta": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": ["type", "resource"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "title": { + "type": "string" + }, + "icons": { + "type": "array", + "items": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "sizes": { + "type": "array", + "items": { + "type": "string" + } + }, + "theme": { + "type": "string", + "enum": ["light", "dark"] + } + }, + "required": ["src"], + "additionalProperties": false + } + }, + "uri": { + "type": "string" + }, + "description": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, + "_meta": { + "type": "object", + "properties": {}, + "additionalProperties": {} + }, + "type": { + "type": "string", + "const": "resource_link" + } + }, + "required": ["name", "uri", "type"], + "additionalProperties": false + } + ] + }, + "description": "Resource contents to download — embedded (inline data) or linked (host fetches). Uses standard MCP resource types." + } + }, + "required": ["contents"], + "additionalProperties": false + } + }, + "required": ["method", "params"], + "additionalProperties": false + }, + "McpUiDownloadFileResult": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "isError": { + "description": "True if the download failed (e.g., user cancelled or host denied).", + "type": "boolean" + } + }, + "additionalProperties": {} + }, "McpUiHostCapabilities": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", @@ -97,6 +306,12 @@ "properties": {}, "additionalProperties": false }, + "downloadFile": { + "description": "Host supports file downloads via ui/download-file.", + "type": "object", + "properties": {}, + "additionalProperties": false + }, "serverTools": { "description": "Host can proxy tool calls to the MCP server.", "type": "object", @@ -2443,6 +2658,12 @@ "properties": {}, "additionalProperties": false }, + "downloadFile": { + "description": "Host supports file downloads via ui/download-file.", + "type": "object", + "properties": {}, + "additionalProperties": false + }, "serverTools": { "description": "Host can proxy tool calls to the MCP server.", "type": "object", diff --git a/src/generated/schema.test.ts b/src/generated/schema.test.ts index 95ec2f216..47e59788b 100644 --- a/src/generated/schema.test.ts +++ b/src/generated/schema.test.ts @@ -35,6 +35,10 @@ export type McpUiOpenLinkResultSchemaInferredType = z.infer< typeof generated.McpUiOpenLinkResultSchema >; +export type McpUiDownloadFileResultSchemaInferredType = z.infer< + typeof generated.McpUiDownloadFileResultSchema +>; + export type McpUiMessageResultSchemaInferredType = z.infer< typeof generated.McpUiMessageResultSchema >; @@ -123,6 +127,10 @@ export type McpUiClientCapabilitiesSchemaInferredType = z.infer< typeof generated.McpUiClientCapabilitiesSchema >; +export type McpUiDownloadFileRequestSchemaInferredType = z.infer< + typeof generated.McpUiDownloadFileRequestSchema +>; + export type McpUiMessageRequestSchemaInferredType = z.infer< typeof generated.McpUiMessageRequestSchema >; @@ -179,6 +187,12 @@ expectType( expectType( {} as spec.McpUiOpenLinkResult, ); +expectType( + {} as McpUiDownloadFileResultSchemaInferredType, +); +expectType( + {} as spec.McpUiDownloadFileResult, +); expectType({} as McpUiMessageResultSchemaInferredType); expectType({} as spec.McpUiMessageResult); expectType( @@ -287,6 +301,12 @@ expectType( expectType( {} as spec.McpUiClientCapabilities, ); +expectType( + {} as McpUiDownloadFileRequestSchemaInferredType, +); +expectType( + {} as spec.McpUiDownloadFileRequest, +); expectType( {} as McpUiMessageRequestSchemaInferredType, ); diff --git a/src/generated/schema.ts b/src/generated/schema.ts index 9c75c3632..e6ff4ba4c 100644 --- a/src/generated/schema.ts +++ b/src/generated/schema.ts @@ -5,8 +5,10 @@ import { z } from "zod"; import { ContentBlockSchema, CallToolResultSchema, + EmbeddedResourceSchema, ImplementationSchema, RequestIdSchema, + ResourceLinkSchema, ToolSchema, } from "@modelcontextprotocol/sdk/types.js"; @@ -161,6 +163,22 @@ export const McpUiOpenLinkResultSchema = z }) .passthrough(); +/** + * @description Result from a file download request. + * @see {@link McpUiDownloadFileRequest `McpUiDownloadFileRequest`} + */ +export const McpUiDownloadFileResultSchema = z + .object({ + /** @description True if the download failed (e.g., user cancelled or host denied). */ + isError: z + .boolean() + .optional() + .describe( + "True if the download failed (e.g., user cancelled or host denied).", + ), + }) + .passthrough(); + /** * @description Result from sending a message. * @see {@link McpUiMessageRequest `McpUiMessageRequest`} @@ -476,6 +494,11 @@ export const McpUiHostCapabilitiesSchema = z.object({ .object({}) .optional() .describe("Host supports opening external URLs."), + /** @description Host supports file downloads via ui/download-file. */ + downloadFile: z + .object({}) + .optional() + .describe("Host supports file downloads via ui/download-file."), /** @description Host can proxy tool calls to the MCP server. */ serverTools: z .object({ @@ -699,6 +722,28 @@ export const McpUiClientCapabilitiesSchema = z.object({ ), }); +/** + * @description Request to download a file through the host. + * + * Sent from the View to the Host when the app wants to trigger a file download. + * Since MCP Apps run in sandboxed iframes where direct downloads are blocked, + * this provides a host-mediated mechanism for file exports. + * The host SHOULD show a confirmation dialog before initiating the download. + * + * @see {@link app!App.downloadFile `App.downloadFile`} for the method that sends this request + */ +export const McpUiDownloadFileRequestSchema = z.object({ + method: z.literal("ui/download-file"), + params: z.object({ + /** @description Resource contents to download — embedded (inline data) or linked (host fetches). Uses standard MCP resource types. */ + contents: z + .array(z.union([EmbeddedResourceSchema, ResourceLinkSchema])) + .describe( + "Resource contents to download \u2014 embedded (inline data) or linked (host fetches). Uses standard MCP resource types.", + ), + }), +}); + /** * @description Request to send a message to the host's chat interface. * @see {@link app!App.sendMessage `App.sendMessage`} for the method that sends this request diff --git a/src/spec.types.ts b/src/spec.types.ts index 469ca1908..20987d3b9 100644 --- a/src/spec.types.ts +++ b/src/spec.types.ts @@ -13,8 +13,10 @@ import type { CallToolResult, ContentBlock, + EmbeddedResource, Implementation, RequestId, + ResourceLink, Tool, } from "@modelcontextprotocol/sdk/types.js"; @@ -168,6 +170,38 @@ export interface McpUiOpenLinkResult { [key: string]: unknown; } +/** + * @description Request to download a file through the host. + * + * Sent from the View to the Host when the app wants to trigger a file download. + * Since MCP Apps run in sandboxed iframes where direct downloads are blocked, + * this provides a host-mediated mechanism for file exports. + * The host SHOULD show a confirmation dialog before initiating the download. + * + * @see {@link app!App.downloadFile `App.downloadFile`} for the method that sends this request + */ +export interface McpUiDownloadFileRequest { + method: "ui/download-file"; + params: { + /** @description Resource contents to download — embedded (inline data) or linked (host fetches). Uses standard MCP resource types. */ + contents: (EmbeddedResource | ResourceLink)[]; + }; +} + +/** + * @description Result from a file download request. + * @see {@link McpUiDownloadFileRequest `McpUiDownloadFileRequest`} + */ +export interface McpUiDownloadFileResult { + /** @description True if the download failed (e.g., user cancelled or host denied). */ + isError?: boolean; + /** + * Index signature required for MCP SDK `Protocol` class compatibility. + * Note: The generated schema uses passthrough() to allow additional properties. + */ + [key: string]: unknown; +} + /** * @description Request to send a message to the host's chat interface. * @see {@link app!App.sendMessage `App.sendMessage`} for the method that sends this request @@ -450,6 +484,8 @@ export interface McpUiHostCapabilities { experimental?: {}; /** @description Host supports opening external URLs. */ openLinks?: {}; + /** @description Host supports file downloads via ui/download-file. */ + downloadFile?: {}; /** @description Host can proxy tool calls to the MCP server. */ serverTools?: { /** @description Host supports tools/list_changed notifications. */ @@ -746,6 +782,8 @@ export interface McpUiToolMeta { * ``` */ export const OPEN_LINK_METHOD: McpUiOpenLinkRequest["method"] = "ui/open-link"; +export const DOWNLOAD_FILE_METHOD: McpUiDownloadFileRequest["method"] = + "ui/download-file"; export const MESSAGE_METHOD: McpUiMessageRequest["method"] = "ui/message"; export const SANDBOX_PROXY_READY_METHOD: McpUiSandboxProxyReadyNotification["method"] = "ui/notifications/sandbox-proxy-ready"; diff --git a/src/types.ts b/src/types.ts index a4770fdaf..739da6faf 100644 --- a/src/types.ts +++ b/src/types.ts @@ -13,6 +13,7 @@ export { LATEST_PROTOCOL_VERSION, OPEN_LINK_METHOD, + DOWNLOAD_FILE_METHOD, MESSAGE_METHOD, SANDBOX_PROXY_READY_METHOD, SANDBOX_RESOURCE_READY_METHOD, @@ -34,6 +35,8 @@ export { type McpUiHostStyles, type McpUiOpenLinkRequest, type McpUiOpenLinkResult, + type McpUiDownloadFileRequest, + type McpUiDownloadFileResult, type McpUiMessageRequest, type McpUiMessageResult, type McpUiUpdateModelContextRequest, @@ -68,6 +71,7 @@ export { import type { McpUiInitializeRequest, McpUiOpenLinkRequest, + McpUiDownloadFileRequest, McpUiMessageRequest, McpUiUpdateModelContextRequest, McpUiResourceTeardownRequest, @@ -83,6 +87,7 @@ import type { McpUiSandboxProxyReadyNotification, McpUiInitializeResult, McpUiOpenLinkResult, + McpUiDownloadFileResult, McpUiMessageResult, McpUiResourceTeardownResult, McpUiRequestDisplayModeResult, @@ -96,6 +101,8 @@ export { McpUiHostStylesSchema, McpUiOpenLinkRequestSchema, McpUiOpenLinkResultSchema, + McpUiDownloadFileRequestSchema, + McpUiDownloadFileResultSchema, McpUiMessageRequestSchema, McpUiMessageResultSchema, McpUiUpdateModelContextRequestSchema, @@ -159,6 +166,7 @@ import { export type AppRequest = | McpUiInitializeRequest | McpUiOpenLinkRequest + | McpUiDownloadFileRequest | McpUiMessageRequest | McpUiUpdateModelContextRequest | McpUiResourceTeardownRequest @@ -207,6 +215,7 @@ export type AppNotification = export type AppResult = | McpUiInitializeResult | McpUiOpenLinkResult + | McpUiDownloadFileResult | McpUiMessageResult | McpUiResourceTeardownResult | McpUiRequestDisplayModeResult