fix(cursor): honor download_path on MCP resource reads

`ReadMcpResourceExecArgs.download_path` means "write the resource to
this workspace-relative path and return no model content". The handler
I added forwarded only server and uri, so a download reported success
while creating no file and leaving `ReadMcpResourceSuccess.download_path`
unset - the model was pointed at a path that did not exist.

The path now reaches the handler, the bridge writes the bytes (decoding
a base64 blob, or the joined text) under the session cwd, and the
answer carries the path with the content oneof deliberately unset: a
host that also has the payload on hand must not have it forwarded, or
the download mode puts it right back in context.

(cherry picked from commit f0a6784533201f412529fb0ae5a6542531012197)
This commit is contained in:
Diogo Soares Rodrigues
2026-07-27 13:50:31 -03:00
committed by can1357
parent 6d42f6e52e
commit 01be80b9ea
7 changed files with 135 additions and 17 deletions
@@ -695,6 +695,41 @@ describe("CursorExecHandlers mounted tool bridge", () => {
expect(await handlers.readMcpResource({ server: "files", uri: "files://missing" })).toBeNull();
});
it("writes a download to the workspace path and returns no content", async () => {
// The frame's `download_path` means "put it on disk, don't hand me the
// bytes". Reporting success without creating the file leaves the model
// pointing at nothing.
const workspace = await fs.mkdtemp(path.join(os.tmpdir(), "cursor-mcp-download-"));
try {
const handlers = new CursorExecHandlers({
cwd: workspace,
tools: new Map(),
mcpResources: {
serverNames: () => ["files"],
getServerResources: () => undefined,
readServerResource: async (_name, uri) => ({
contents: [{ uri, mimeType: "image/png", blob: Buffer.from("PNG-BYTES").toString("base64") }],
}),
},
});
const read = await handlers.readMcpResource({
server: "files",
uri: "files://logo",
downloadPath: "assets/logo.png",
});
expect(read?.downloadPath).toBe("assets/logo.png");
// No content: that is the whole point of the download mode.
expect(read?.text).toBeUndefined();
expect(read?.blob).toBeUndefined();
// The file is really there, decoded from base64, under the workspace.
expect(await Bun.file(path.join(workspace, "assets/logo.png")).text()).toBe("PNG-BYTES");
} finally {
await removeWithRetries(workspace);
}
});
it("answers nothing when the session has no MCP manager", async () => {
// A host without MCP must still answer truthfully rather than throwing:
// an empty catalog and `not_found` are the honest responses.