feat: add ui/download-file method for host-mediated file downloads#475
feat: add ui/download-file method for host-mediated file downloads#475
Conversation
Add a new ui/download-file JSON-RPC request that allows MCP App views to request file downloads through the host. Since MCP Apps run in sandboxed iframes where direct downloads are blocked (allow-downloads not set), this provides a host-mediated mechanism for file exports. Spec changes (draft): - Add ui/download-file request to Requests (View → Host) section - Add downloadFile capability to HostCapabilities - Document host behavior requirements (confirmation dialog, filename sanitization, base64 decoding, size limits) SDK changes: - Add McpUiDownloadFileRequest/Result interfaces to spec.types.ts - Add downloadFile() method to App class - Add ondownloadfile setter to AppBridge class - Add DOWNLOAD_FILE_METHOD constant - Generate Zod schemas Example: - Add download demo to integration-server (exports JSON with server time) - Capability check: only shows download button when host advertises downloadFile capability Based on developer feedback requesting file export capabilities for visualization tools, document editors, and data analysis apps.
|
cc/ @connor4312 @nickcoai for input too :-) |
|
This is kind of neat
|
Replace custom {filename, content, mimeType, encoding} params with
standard MCP resource types: EmbeddedResource for inline content and
ResourceLink for host-resolved references.
New params shape:
params: { contents: (EmbeddedResource | ResourceLink)[] }
This reuses existing MCP primitives instead of inventing new ones,
and enables hosts to show resource 'bubbles' or resolve ResourceLink
URIs via resources/read on the MCP server.
|
thank you @connor4312 |
| * 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. |
There was a problem hiding this comment.
I think this is no longer relevant in the resources world
There was a problem hiding this comment.
Good call — removed the two bullets that were just restating standard EmbeddedResource/ResourceLink behavior. Kept the download-specific ones (confirmation dialog, filename derivation, security policy, path sanitization). Updated in f07bdfb.
Remove bullets that restate standard EmbeddedResource/ResourceLink behavior already defined in the MCP resource spec. Keep download-specific host behavior (confirmation dialog, filename derivation, security policy, path sanitization).
There was a problem hiding this comment.
can you add a test to app-bridge.test.ts that exercices the two ends?
|
|
||
| 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: |
There was a problem hiding this comment.
@antonpk1 should we provide some guidance on payload size? postMessage can be fairly constrained (depending on both browser and device).
* chore: bump ext-apps to 1.1.2 Changes since 1.1.1: - feat: add ui/download-file method for host-mediated file downloads (#475) - pdf-server: robust path validation + folder/file root support (#497) - ci: auto-fix prettier formatting in pre-commit hook and CI (#498) * fix: sync local SDK build into node_modules for examples npm workspaces hoists example dependencies to the root node_modules, but installs the published registry copy of @modelcontextprotocol/ext-apps instead of linking to the local source. This causes type-check failures when examples use features not yet published to npm. Add scripts/link-self.mjs which copies the freshly-built dist/ and package.json into the hoisted node_modules copy after each SDK build, ensuring examples always type-check against the latest local types. See: npm/feedback#774 * Revert "fix: sync local SDK build into node_modules for examples" This reverts commit e3387e8.
What
Add a new
ui/download-fileJSON-RPC request that allows MCP App views to request file downloads through the host.Why
MCP Apps run in sandboxed iframes where direct file downloads are blocked (
allow-downloadsis not set). Based on developer feedback, many apps need file export capabilities — visualization tools (SVG/PNG export), document editors, data analysis tools, and any app producing downloadable artifacts.ui/download-fileprovides a host-mediated mechanism for this, consistent with the existingui/open-linkpattern.Design: MCP Resource Types
Following feedback to reuse existing MCP primitives, the params use standard MCP resource types instead of custom fields:
EmbeddedResource— Inline content viaresource.text(UTF-8) orresource.blob(base64). The host creates a blob and triggers the download directly.ResourceLink— A reference URI the host resolves viaresources/readon the MCP server. This avoids passing large content through postMessage and lets hosts show resource "bubbles" or use native download mechanisms.This approach:
EmbeddedResource,ResourceLink) instead of inventing new content formatsResourceLinkfor cases where the host can fetch directly, avoiding unnecessary data transfer through the iframeChanges
Spec (
specification/draft/apps.mdx)ui/download-filerequest to "Requests (View → Host)" section with examples for bothEmbeddedResourceandResourceLinkdownloadFilecapability toHostCapabilitiesresources/readSDK
spec.types.ts:McpUiDownloadFileRequestuses(EmbeddedResource | ResourceLink)[],McpUiDownloadFileResult,downloadFileinMcpUiHostCapabilities,DOWNLOAD_FILE_METHODconstantapp.ts:App.downloadFile()method with JSDoc examples for embedded text, embedded blob, and resource linkapp-bridge.ts:AppBridge.ondownloadfilesetter with JSDoc example showing both resource typestypes.ts: Re-exports,AppRequest/AppResultunion additionsgenerate-schemas.ts: AddedEmbeddedResourceSchema,ResourceLinkSchemato external type listgenerated/: Auto-generated Zod schemas using SDK schema importsExample
integration-server: Two side-by-side demo buttons:EmbeddedResource(text content)ResourceLink(host resolves viaresources/read)integration-server/server.ts: Registers a sample downloadable resource atresource:///sample-report.txtProtocol
App SDK Usage
Security
ui/open-link)allow-downloadson iframe — download is always host-mediatedResourceLink, host resolves via MCPresources/read(no direct HTTP fetch from iframe)