Permissions.json does not appear to control the effective allowlist

The permissions.json documentation states that Cursor reads permission configuration from:

~/.cursor/permissions.json
<workspace>/.cursor/permissions.json

For mcpAllowlist, the documented behavior is that file-defined entries replace the in-app allowlist, make the Settings list read-only, hide Add to allowlist, merge user- and repository-level entries, and are re-read automatically.

We cannot reproduce this behavior.

We tested permissions.json at both user and repository level. In both cases, the configured mcpAllowlist appears to be ignored:

  • Entries are not reflected in Cursor Settings.

  • MCP/Browser approval behavior does not change.

  • Existing entries created through Always allow remain active.

  • The approval dialog can still offer Add to allowlist.

  • The read-only Settings list does not appear to match either permissions.json.

There is also a persistence issue: after deleting permissions.json, the MCP allowlist in Settings remains read-only. Previously persisted entries therefore cannot be removed through the UI.

Browser Protection interaction

With Browser Protection enabled, Browser tool calls initially require approval as expected.

However, selecting Always allow / Add to allowlist permanently allows that tool, and subsequent calls can run without approval.

Because those entries can currently become impossible to remove, it is unclear what the intended precedence is between:

  • Browser Protection

  • mcpAllowlist

  • permissions.json

  • local IDE permission state

In particular: is an MCP allowlist entry intentionally supposed to bypass Browser Protection, or should Browser Protection remain the higher-level approval gate?

Desired configuration

We want a small, explicit allowlist:

  • defined terminal commands and MCP/Browser tools may run automatically;

  • everything else requires approval;

  • the policy is managed declaratively through permissions.json, ideally also at repository level.

This would make the policy reviewable, version-controlled, reproducible across developers, and independent of local Always allow state.

At the moment, we cannot determine how to configure this reliably.

There is no team-admin MCP, Browser, Auto-run, or permission policy configured that should override the local configuration. We are on a Teams plan.

Could someone clarify the currently supported way to achieve:

Allow a defined set of terminal commands and Browser/MCP tools automatically, require approval for everything else, and manage that policy through permissions.json?

It would also be helpful to know whether the current behavior is expected and we missed something, a regression, or whether the documentation no longer reflects the desktop IDE implementation.

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!

Hey @Philipp_Nolte,

  1. Put terminalAllowlist and mcpAllowlist in ~/.cursor/permissions.json only (user-level). Repo-level allowlists in <workspace>/.cursor/permissions.json aren’t applied yet - same gap as this thread.
  2. Set Run Mode to Allowlist (or Allowlist with Sandbox).
  3. Use exact server:tool entries, or whole-part wildcards like server:* / *:tool / *:*. Avoid partial globs such as server:list_*.
  4. After creating, editing, or deleting the file, fully quit Cursor and reopen. That also clears a stuck read-only Settings state after a delete.

A couple of related notes:

  • Make sure Settings shows the allowlist as coming from permissions.json (not admin-controlled), and that MCP server names match the exact keys in mcp.json.
  • Once a Browser tool is on the allowlist, it can run without another approval even with Browser Protection on. Leave Browser tools off the list if you still want those prompts.

Format reference: permissions.json. We’ve let the team know about the docs vs desktop gaps here, and I’ll post when there’s an update.

If user-level still does nothing after a full quit, reply with your Cursor version from About Cursor.

Thanks @mohitjain,
I was able to narrow this down further.

I tested the user-level ~/.cursor/permissions.json again after a full Cmd+Q / restart.

With an explicitly empty allowlist:

{
  "mcpAllowlist": []
}

the file does not appear to take ownership of the effective MCP allowlist. Instead, Cursor falls back to the previously persisted IDE allowlist, including old entries that I had added earlier via Always allow in the approval UI.

However, as soon as the allowlist contains at least one entry, for example:

{
  "mcpAllowlist": [
    "dummy:nothing"
  ]
}

the file-based configuration is applied as expected.

So the behavior I can reproduce is:

  • non-empty mcpAllowlistpermissions.json is applied
  • empty mcpAllowlist: [] → Cursor falls back to the existing IDE/persisted allowlist
  • the fallback includes stale entries previously added through Always allow

That explains why my earlier test looked like permissions.json was being ignored entirely.

Is this empty-array fallback intended behavior?

And separately, is there a supported way to inspect the persisted IDE allowlist that Cursor falls back to? I suspect those old Always allow entries are stored in local state, possibly in state.vscdb.

If that is the case, could you point me to the relevant key/entry so I can inspect which stale MCP allowlist entries are currently persisted? I’d only use this for diagnostics, not as a configuration mechanism.

I have been having issues with agents running unauthorized scripts (arbitrary python execution for example), despite my settings not granting this ability.

As an attempt to remedy this, I have created this file:


$ cat $HOME/.cursor/permissions.json
{
  "terminalAllowlist": []
}

I hope this will fix the problem of agents invoking arbitrary cli commands. My intention is to review any commands the agent wants to run.

Is there an eta on workspace level being applied?