`app.downloadFile()` returns "Method not found" in ChatGPT host

Summary

The downloadFile method documented in the MCP ext-apps SDK throws MCP error -32601: Method not found when called from a widget running inside ChatGPT.

Expected behavior

app.downloadFile() should trigger a file download for the user, as documented in the ext-apps API reference.

Actual behavior

The call rejects with:

Uncaught (in promise) McpError: MCP error -32601: Method not found

Code

await app.downloadFile({
  contents: [
    {
      type: "resource",
      resource: {
        uri: "file:///file.txt",
        mimeType: "text/plain",
        text: "content here...",
      },
    },
  ],
});

Environment

  • @modelcontextprotocol/ext-apps: ^1.3.1
  • @modelcontextprotocol/sdk: ^1.27.1
  • Host: ChatGPT (web)
  • The same method works on Claude/Anthropic’s host

Notes

The method is defined in the SDK and appears in the API docs, but the ChatGPT host does not
seem to implement it. The ChatGPT-specific window.openai API only exposes uploadFile,
getFileDownloadUrl, selectFiles, and requestClose — there is no equivalent for generating
and downloading a file from the widget.

Is downloadFile planned for ChatGPT, or is there an alternative approach?

Hey, yeah this one’s pretty confusing especially since it works on another platform.

What’s happening:

You’re not doing anything wrong. The gap is on the ChatGPT side. Even though downloadFile exists in the MCP/ext-apps SDK, the ChatGPT host hasn’t implemented that method yet, which is why you’re getting -32601: Method not found. So the SDK and docs are a bit ahead of what ChatGPT currently supports.

Right now, ChatGPT widgets only expose a smaller set of file APIs like:

  • uploadFile
  • getFileDownloadUrl
  • selectFiles
  • requestClose

No direct downloadFile equivalent yet.

What to try instead: Generate your file in the widget.

Use getFileDownloadUrl to create a downloadable link: Trigger a normal browser download (like rendering a link or using window.open)

There’s a doc example here that’s pretty relevant for file flows in ChatGPT widgets. Not ideal, agreed, but a few folks have gotten this pattern working reliably.

We’ll pass this feedback along since this is a legit gap, especially for parity with other hosts. If you end up trying the URL approach and it behaves weirdly (auth, expiry, etc.), share what you’re seeing and we can dig in.

Mark G.