ACP: built-in web search tool cannot be pre-approved via any config (always prompts, even under approvalMode: unrestricted)

Summary:
When cursor-agent runs in ACP mode (cursor-agent acp), the built-in web search tool (toolCall.kind: "search") unconditionally issues a session/request_permission for every call. No configuration — allowlist token, approvalMode, or otherwise — auto-approves it. Every other tool type has an approval path; web search has none.

Environment:

  • cursor-agent version 2026.07.09-a3815c0
  • macOS (Darwin), running cursor-agent acp as a JSON-RPC ACP server over stdio
  • ACP session mode agent, model grok-4.5

Repro:

  1. Drive cursor-agent acp with the minimal ACP client below: initializesession/newsession/prompt with a prompt that forces a web search (e.g. “Search the web for the latest Node.js LTS version. Use your web search tool.”).
  2. Observe the client receives session/request_permission with toolCall.kind: "search".
  3. Attempt to pre-authorize via ~/.cursor/cli-config.json / project .cursor/cli.json. Tried allow tokens: Web(search), WebSearch(*), Search(*), Search(), Web(*), WebFetch(*).
  4. Also set approvalMode: "unrestricted".

Captured IDs (live run):

sessionId:                  630bcd3f-271f-4fca-9517-a510bc9809ba
session/request_permission: jsonrpc id=0
toolCall.toolCallId:        web_search_0
toolCall.kind:              search
toolCall.title:             "Web search: latest Node.js LTS version 2026"

Expected: Some config should let the web search tool run without a per-call prompt (as Shell(...) allowlist entries and unrestricted do for shell commands).

Actual: Web search prompts in every case. Notably, under approvalMode: unrestricted, a non-allowlisted shell command (date) runs with no prompt — proving unrestricted is in effect — yet the web search request (id: 0, toolCallId: web_search_0) still fires. The documented permission tool types (Shell, Read, Write, WebFetch(domain), Mcp) include no web-search token, and WebFetch(domain) governs URL fetching, not the search tool.

Impact: Headless/ACP integrations (custom clients, IDE integrations) cannot run web-search-using agents unattended — every search blocks on a manual approval with no way to allowlist it.

Suggested fix: Add a web-search permission token (e.g. Search(*) / WebSearch) honored in ACP, and/or have approvalMode: unrestricted cover the search tool like it covers shell/read/write.


Attachment — minimal ACP repro client (acp-repro.mjs)

Run with node acp-repro.mjs <cwd> "<prompt>". It auto-approves any permission request (so the run completes) and logs the sessionId + every session/request_permission with its ids.

import { spawn } from "node:child_process";

const cwd = process.argv[2] ?? process.cwd();
const text = process.argv[3] ?? "Search the web for the latest Node.js LTS version. Use your web search tool.";

const child = spawn("cursor-agent", ["acp"], { cwd, stdio: ["pipe", "pipe", "pipe"] });
let buf = "";
let id = 0;
const pending = new Map();

const send = (method, params) => {
  const msg = { jsonrpc: "2.0", id: ++id, method, params };
  child.stdin.write(JSON.stringify(msg) + "\n");
  return new Promise((r) => pending.set(msg.id, r));
};
const respond = (rid, result) =>
  child.stdin.write(JSON.stringify({ jsonrpc: "2.0", id: rid, result }) + "\n");

child.stdout.on("data", (d) => {
  buf += d.toString();
  let i;
  while ((i = buf.indexOf("\n")) >= 0) {
    const line = buf.slice(0, i);
    buf = buf.slice(i + 1);
    if (!line.trim()) continue;
    let m;
    try { m = JSON.parse(line); } catch { continue; }
    if (m.method === "session/request_permission") {
      const tc = m.params.toolCall ?? {};
      console.log(
        `PERMISSION_REQUEST jsonrpc.id=${m.id} toolCallId=${tc.toolCallId} ` +
        `kind=${tc.kind} title=${JSON.stringify(tc.title)}`,
      );
      // auto-approve so the turn completes
      respond(m.id, { outcome: { outcome: "selected", optionId: m.params.options?.[0]?.optionId } });
    } else if (m.id && pending.has(m.id)) {
      pending.get(m.id)(m);
      pending.delete(m.id);
    }
  }
});
child.stderr.on("data", (d) => process.stderr.write("[stderr] " + d));

await send("initialize", {
  protocolVersion: 1,
  clientCapabilities: { fs: { readTextFile: true, writeTextFile: true } },
});
const sess = await send("session/new", { cwd, mcpServers: [] });
console.log(
  `sessionId=${sess.result.sessionId} currentMode=${sess.result.modes?.currentModeId} ` +
  `model=${sess.result.models?.currentModelId}`,
);
await send("session/prompt", { sessionId: sess.result.sessionId, prompt: [{ type: "text", text }] });
child.kill();
process.exit(0);

Hi there!

We detected that this may be a bug report, so we’ve moved your post to the Bug Reports category.

To help us investigate and fix this faster, could you edit your original post to include the details from the template below?

Bug Report Template - Click to expand

Where does the bug appear (feature/product)?

  • Editor, Tab & Chat (autocomplete, Composer, in-editor agent)
  • Terminal & commands
  • Models, pricing & API keys (availability, Auto/Max, BYOK/Bedrock)
  • MCP & tools
  • Cloud Agents & Automations (cursor.com/agents, scheduled/event)
  • BugBot & Code Review
  • Cursor CLI
  • Cursor Mobile
  • Remote (SSH / Dev Containers / WSL)
  • Account, billing & login
  • Something else…

Describe the Bug
A clear and concise description of what the bug is.


Steps to Reproduce
How can you reproduce this bug? We have a much better chance at fixing issues if we can reproduce them!


Expected Behavior
What is meant to happen here that isn’t working correctly?


Screenshots / Screen Recordings
If applicable, attach images or videos (.jpg, .png, .gif, .mp4, .mov)


Operating System

  • Windows 10/11
  • MacOS
  • Linux

Version Information

  • For Cursor IDE: Menu → About Cursor → Copy
  • For Cursor CLI: Run agent about in your terminal
IDE:
Version: 2.xx.x
VSCode Version: 1.105.1
Commit: ......

CLI:
CLI Version 2026.01.17-d239e66

For AI issues: which model did you use?
Model name (e.g., Sonnet 4, Tab…)


For AI issues: add Request ID with privacy disabled
Request ID: f9a7046a-279b-47e5-ab48-6e8dc12daba1
For Background Agent issues, also post the ID: bc-…


Additional Information
Add any other context about the problem here.


Does this stop you from using Cursor?

  • Yes - Cursor is unusable
  • Sometimes - I can sometimes use Cursor
  • No - Cursor works, but with this issue

The more details you provide, the easier it is for us to reproduce and fix the issue. Thanks!