Files in ChatGPT
ChatGPT manages files for you: it stores each one and hands your code a reference to it, never the bytes. References survive across tool calls, so files move through the app in both directions, into a tool and back out.Receive a File
A tool can take a file the user added to the conversation. The model only passes files already there, so the user adds one first, from their device or library; the handler receives a reference and fetches the contents.server.ts
FileRef listed in _meta["openai/fileParams"] (top-level fields only), which tells ChatGPT to route the attachment to it. The host fills download_url, so scan-receipt reads the bytes straight from receipt.download_url.
Return a File
A tool can also hand a file back. The host surfaces it in the conversation, so the user can download it and the model can see it.server.ts
scan-receipt declares summary as a FileRef in its outputSchema and returns it in structuredContent; summarize produces the ref: a file_id and a download_url the host uses to fetch and cache the file.
Steer from the View
The viewcan run the whole exchange itself: pick a file, hand it to a tool, and resolve what comes back, no model in the loop. Here a receipt scanner lets the user pick a receipt and get a summary in return, built up in three steps:Pick a File
upload takes a file from the device and selectFiles opens the user’s library. Both return a FileMetadata, a fileId with no bytes attached, which we hold in state.
views/receipt-scanner.tsx
Hand It to a Tool
scan resolves a fresh download_url for the held file with getDownloadUrl, packs it into a FileRef, and calls scan-receipt with it.
views/receipt-scanner.tsx
Resolve the Returned File
scan-receipt returns its own FileRef on data.structuredContent. Resolve it from summary.file_id when the user asks: a download_url is a temporary cache URL that expires; the file_id is the durable handle. Keep the file_id (in state, or in the model’s context) and regenerate a URL on demand.
views/receipt-scanner.tsx
useFiles is ChatGPT only. It won’t work in other hosts.Files in Claude
Claude has no file store. The one operation is egress: the view hands the host content, and the host writes it to the user’s disk after a confirmation prompt.Download from the View
A view can save a file to the user’s device, whether content it built itself or a file returned by an earlier tool call. The host shows a confirmation, then writes it to disk.views/receipt-summary.tsx
ReceiptSummary builds a CSV from its line items, then hands download a single resource: text carries the content, mimeType types it, and the uri’s last segment sets the suggested filename, here receipt.csv. A resource can instead carry a base64 blob, for bytes the view rendered or a file an earlier tool returned. The call fires from the Export button, not on mount: the host rejects downloads the user didn’t trigger.
Claude doesn’t support
resource_link as a content type.Go Further
Create Views
Craft interactive UIs rendered in conversation
Register Tools
Define what humans and agents can do
UX Design
Account for what makes an MCP App different