Originally created by: imshaikot
Part of [#56]. Cursor stays in beta until a real side-panel conversation has been through it (see Not verified).
Cursor CLI has been a side-panel agent since [#25], in beta. Its only recorded turn was "hello from cursor"; it had never made a tool call through Browsentic. To bring it up to Claude Code, I measured it first: six real turns against cursor-agent 2026.09.18-9a7762b. Each ran the runner's own plan through drive.ts, with a stand-in MCP server in place of browsentic mcp. The full results are on [#56].
The first turn found a bug in what has already shipped. A Cursor run has never had the browser tools. Cursor starts an MCP server from a project's .cursor/mcp.json only once that server is approved (cursor-agent mcp list reports not loaded (needs approval)), and nothing approved ours. The model searched, grepped and tried the shell until Cursor stopped it with Agent Looping Detected.
The turns that followed found the rest:
GetMcpTools.~/.cursor/projects/<folder>/agent-tools/<uuid>.txt, and the model gets only the path, which the run cannot read.AGENTS.md its session began with.Cursor runs reach the browser
Plan can now carry prepare: commands of the same CLI, run in the run's folder through spawnCli once its files are written and before the turn. vetPlan allows exactly the set-up commands CONTAINMENT names. For Cursor that is cursor-agent mcp enable browsentic, for a run and never a task. An approval covers the server's exact config, which names the run, so each turn approves its own; it took 0.26–0.35 s. --approve-mcps, which approves every server the user has, stays forbidden.Mcp(plugin-*:*), beside the user's own servers by name. If any server but browsentic answers a call, the run stops with AGENT_UNSAFE.AGENTS.md tells the model to look up the browser tools it needs in one step.keepsFirstPrompt: true, and opens: text, pdf, image; a one-shot read a PNG and a PDF correctly.providerIdentifier, schema lookups are left off the timeline, Cursor's own tools get a toolResult, and usage summed over the turn is no longer reported.Every runner can declare limits: { callMs, resultBytes }, and only Cursor declares any (60,000 ms and 40,000 bytes).
APPROVAL_PENDING and the card stays up. The same call with the same input rejoins the card, with no second row. Any other call, the run ending, or Stop withdraws it, and a late answer does nothing.timeoutMs on runCode, callSiteTool or waitForElement) are cut to what is left of the call.BROWSENTIC_RESULT_BYTES. It refuses a longer result with RESULT_TOO_LARGE instead of cutting it, and says the call itself went through. It also asks page_extractText for groups of a quarter of the limit in characters.On every agent, a call its client abandons withdraws its approval. The MCP server passes the request's cancel signal to the bridge, which sends a new control op { op: 'cancel', id }. The daemon aborts that invoke, and a tool server whose socket closes aborts everything it had in flight. Until now, a late Allow ran the action after the model had moved on. Old daemons ignore the new op.
Three new recordings: fixtures/cursor/2026.09.18-mcp-calls, -resumed and -mcp-timeout.
spawn.test.ts: the set-up step is allowed, and every other step, a task, or another agent is refused; the plugin deny is required.drive.test.ts: the step runs in the folder before the turn, and a failing step stops the turn with what it printed.service.test.ts: parking, rejoining, withdrawing on another call, on Stop and on cancel; no parking without limits; waits cut to fit.server.test.ts: the size guard counts UTF-8 bytes and ignores pictures; reads are narrowed; cancel reaches the bridge.remote-bridge.test.ts and cursor.test.ts: the cancel op, and the new recordings.vitest run passed 2030/2030. yarn check passed both type checks and every coverage floor; the daemon is at 78.0% against a 61% floor.yarn check timeouts. Its coverage run pushed this machine's load average past 80 and timed out 1–6 tests per run, a different set each time (self-update, preferences, socket, index readiness, the profile and follow-up prompt tests in service.test.ts). Every one passed when run alone, and vitest run without coverage was all green.beta from Cursor's catalog entry and the README.limits in one line.🤖 Generated with Claude Code
Ticket changed by: imshaikot