Where does the bug appear (feature/product)?
Cursor CLI
Describe the Bug
When a tool is rejected internally, tool_call_update still sends status: "completed" instead of "failed". Also, session/request_permission is never sent, so the client can’t present a permission dialog at all.
Steps to Reproduce
curl https://cursor.com/install -fsS | bash
npm install @agentclientprotocol/sdk
Run below as node reject-write-permission.mjs:
import * as acp from "@agentclientprotocol/sdk";
import { spawn } from "node:child_process";
import { existsSync, mkdirSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { Readable, Writable } from "node:stream";
const cwd = join(tmpdir(), `repro-${Date.now()}`);
mkdirSync(cwd, { recursive: true });
const testFile = join(cwd, "test.txt");
const child = spawn("cursor-agent", ["acp"], { stdio: ["pipe", "pipe", "inherit"] });
const stream = acp.ndJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout));
const updates = [];
const client = new acp.ClientSideConnection(() => ({
sessionUpdate: async (p) => {
updates.push(p);
if (p.update.sessionUpdate === "tool_call_update") console.log(`tool_call_update: status="${p.update.status}"`);
},
requestPermission: async (p) => {
const reject = p.options.find((o) => o.kind === "reject_once");
console.log(`request_permission: rejecting with "${reject.optionId}"`);
return { outcome: { outcome: "selected", optionId: reject.optionId } };
},
}), stream);
await client.initialize({ protocolVersion: acp.PROTOCOL_VERSION, clientCapabilities: { fs: { readTextFile: true, writeTextFile: false } }, clientInfo: { name: "repro", version: "1.0.0" } });
const { sessionId } = await client.newSession({ cwd, mcpServers: [] });
await client.prompt({ sessionId, prompt: [{ type: "text", text: `Write "should not see this" to ${testFile}` }] });
const hasFailed = updates.some((u) => u.update.sessionUpdate === "tool_call_update" && u.update.status === "failed");
console.log(`\nstatus "failed" found: ${hasFailed ? "YES" : "NO (bug)"}`);
console.log(`File written: ${existsSync(testFile)}`);
child.kill(); process.exit(0);
request_permission never fires. All tool_call_update messages have status: "completed" regardless of outcome. The file isn’t written (the internal rejection works), but the client has no visibility into any of it.
Expected Behavior
request_permission fires, client rejects, tool_call_update has status: "failed".
Operating System
MacOS
Version Information
2026.02.27-e7d2ef6
Additional Information
This breaks any ACP client trying to show a permission dialog or track tool outcomes.
Does this stop you from using Cursor
Sometimes - I can sometimes use Cursor