Mcp(...) allowlist entries are written but never matched — every MCP call re-prompts

Where does the bug appear (feature/product)?

Cursor CLI

Describe the Bug

Mcp(…) permission entries are never matched; every MCP call re-prompts

Environment

  • cursor-agent 2026.08.11-e8db854
  • WSL2, Ubuntu 24.04.3 LTS, Linux 6.6.87.2-microsoft-standard-WSL2 x86_64
  • approvalMode: “allowlist”, sandbox.mode: “disabled”, permissions.deny:
  • MCP server “jira” configured in ~/.cursor/mcp.json as type “http”

Summary

Mcp(...) entries in permissions.allow are written by the approval UI but never
consulted when matching a later call. Every MCP tool call prompts for approval on
every invocation, forever. Selecting “AllowList” appends an entry that has no effect,
so the list grows without ever reducing prompts.
Shell(...) entries in the same permissions.allow array match correctly, so this is
specific to MCP token matching, not to config loading or file persistence.

Expected

Per Permissions | Cursor Docs, Mcp(server:tool) allows that
tool and Mcp(server:*) allows all tools from that server. After restart, a call
matching either should run without prompting.

Actual

Entry present in permissions.allow Call made Prompted?
Shell(git) git log -1 --oneline No (correct)
Mcp(jira:*) getTransitionsForJiraIssue Yes
Mcp(jira:getJiraIssue) getJiraIssue Yes
All three entries were present in ~/.cursor/cli-config.json before the process
started, verified by reading the file after startup.

Reproduction

  1. Configure any MCP server in ~/.cursor/mcp.json.
  2. Call one of its tools, select “AllowList” at the prompt. Confirm the entry is
    appended to permissions.allow as Mcp(server:tool).
  3. Fully quit and restart. Confirm the entry is still in the file.
  4. Call the same tool again. It prompts again.
  5. Add Mcp(server:*) manually, restart, call any tool from that server. It prompts.

Deterministic evidence, no UI observation required

An approval rewrites the config file even when the entry already exists, deduping to
byte-identical content. So mtime advances while sha256 does not. Fingerprint the file,
repeat a call whose entry already exists, fingerprint again:
before mtime 1787762001.73649 sha256 154b62b5828476ec size 4100
after mtime 1787762187.64380 sha256 154b62b5828476ec size 4100
Content unchanged, mtime advanced by the call. A matched entry should not produce an
approval write at all.

Ruled out

  • Pattern format. Colon form is per docs; it is also what the UI itself writes.
  • Pattern breadth. An exact-match Mcp(jira:getJiraIssue) entry fails, not just wildcards.
  • Auto-review. Neither ~/.cursor/permissions.json nor a project-level equivalent exists,
    and approvalMode is “allowlist”.
  • Deny precedence. permissions.deny is empty.
  • Config not loading. Shell(...) entries from the same file and array match correctly.
  • Persistence. Entries survive restart; they are present in the file and simply unused.

Impact

MCP servers with large tool surfaces are unusable without prompting on every call. The
Atlassian server here exposes ~30 tools and a single ticket task fans out across several,
so the approval UI cannot be satisfied by repeated use. There is no working configuration
short of Run Everything.

Secondary issue

Agent file-edit tools report success when writing ~/.cursor/cli-config.json, but the
change is silently reverted within seconds. Writing identical content via a shell command
persists. If protected-path enforcement is intended here, the edit should fail loudly
rather than report success and roll back.

The strongest part for triage is the mtime/sha256 fingerprint, since it proves the re-approval without depending on anyone
watching the dialog, and the Shell(git) control rules out config loading in the same breath.

Steps to Reproduce

  1. Configure any MCP server in ~/.cursor/mcp.json.
  2. Call one of its tools, select “AllowList” at the prompt. Confirm the entry is
    appended to permissions.allow as Mcp(server:tool).
  3. Fully quit and restart. Confirm the entry is still in the file.
  4. Call the same tool again. It prompts again.
  5. Add Mcp(server:*) manually, restart, call any tool from that server. It prompts.

Deterministic evidence, no UI observation required

An approval rewrites the config file even when the entry already exists, deduping to
byte-identical content. So mtime advances while sha256 does not. Fingerprint the file,
repeat a call whose entry already exists, fingerprint again:
before mtime 1787762001.73649 sha256 154b62b5828476ec size 4100
after mtime 1787762187.64380 sha256 154b62b5828476ec size 4100
Content unchanged, mtime advanced by the call. A matched entry should not produce an
approval write at all.

Expected Behavior

Expected

Per Permissions | Cursor Docs, Mcp(server:tool) allows that
tool and Mcp(server:*) allows all tools from that server. After restart, a call
matching either should run without prompting.

Operating System

Linux

Version Information

┌──────────────┬────────────────────┐
│ Field │ Value │
├──────────────┼────────────────────┤
│ CLI Version │ 2026.08.11-e8db854 │
├──────────────┼────────────────────┤
│ Model │ Auto Balance │
├──────────────┼────────────────────┤
│ Subscription │ Enterprise │
├──────────────┼────────────────────┤
│ OS │ linux (x64) │
├──────────────┼────────────────────┤
│ Terminal │ windows-terminal │
├──────────────┼────────────────────┤
│ Shell │ bash │
└──────────────┴────────────────────┘

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey @Mike_Hitchcock

When your org has admin-managed MCP settings, MCP approvals come from the team’s MCP configuration rather than the personal permissions.allow in cli-config.json. That’s why your Mcp(...) entries get written but never consulted, while Shell(...) (which stays personal) keeps working.

Reliable fix (admin side): have your Cursor admin give the jira server’s row in Team Settings → MCP Configuration a Name that matches the server name in your mcp.json (jira), with Tools left empty (= all tools). A server can be allowed to run while still prompting on every call if its row isn’t named to match, and naming it is what enables auto-run.

Immediate unblock on your side: set approvalMode to "unrestricted" (a broad grant, so only if that’s acceptable for you).

Two asides: the running CLI writes its in-memory settings back on exit, so edit cli-config.json with the CLI fully closed or your changes get overwritten. And we agree it shouldn’t keep offering an “AllowList” option that can’t take effect here, so we’ve let the team know.

@mohitjain thanks for the very useful information, I appreciate it!