Auto-approve MCP tools in Claude Code permissions: the mcp__ syntax and its wildcard limits
Put mcp__server or mcp__server__tool in permissions.allow to stop the prompts, why an allow wildcard needs an mcp__<server>__ prefix, and why parenthesised mcp__ rules are skipped.
Contents
Add an MCP server and Claude Code asks for approval every time one of its tools runs. Stopping for a read-only lookup on every call gets old fast.
In short: put mcp__<server> in permissions.allow to auto-approve every tool from that server, or mcp__<server>__<tool> for one tool. The catch is that an allow wildcard requires a literal mcp__<server>__ prefix — a pattern like mcp__* is skipped entirely.
For registering the servers themselves, see Adding MCP servers to Claude Code.
KEY POINT
What you will learn
- The three rule shapes: whole server, wildcard, single tool
- Why allow wildcards need an anchor, and how deny and ask differ
- That
mcp__rules with parentheses are silently skipped from settings files
The three rule shapes
The docs put it this way: MCP rules use the server name as configured in Claude Code, optionally followed by the name of a tool from that server.
| Rule | What it matches |
|---|---|
mcp__puppeteer | Any tool provided by the puppeteer server |
mcp__puppeteer__* | The same set, written as a wildcard |
mcp__puppeteer__puppeteer_navigate | Only the puppeteer_navigate tool from that server |
In settings.json:
{
"permissions": {
"allow": [
"mcp__puppeteer",
"mcp__github__get_issue",
"mcp__github__list_pull_requests"
]
}
}
The server name is whatever you passed to claude mcp add, or the key in .mcp.json. The separator is two underscores, both between mcp and the server and between the server and the tool.
用語解説
Server name: the name you chose in claude mcp add <name> .... Rename the server and every rule for it changes too, so when a team shares .claude/settings.json, agree on the names in .mcp.json first.
Allow wildcards need an anchor
This is the part that catches people. The docs state that allow rules accept tool-name globs only after a literal mcp__<server>__ prefix, and that the server segment must be glob-free so the rule names a specific server you configured.
| Pattern | Result in allow |
|---|---|
mcp__puppeteer__* | Works. Matches every tool from puppeteer |
mcp__github__get_* | Works. Matches that server's get_ tools |
mcp__* | Skipped with a warning; auto-approves nothing |
* / B* | Skipped, same as above |
So there is no way to say "allow all MCP tools" in one allow rule. List each server.
{
"permissions": {
"allow": [
"mcp__puppeteer__*",
"mcp__github__get_*",
"mcp__linear__*"
]
}
}
Deny and ask follow different rules
Deny and ask rules do accept globs in the tool-name position. The pattern must match the full tool name: "*" matches every tool, and "mcp__*" matches every MCP tool across all servers.
{
"permissions": {
"deny": [
"mcp__*"
]
}
}
Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change it. A broad deny wins over a narrower allow, and an allow rule can't carve an exception out of a deny.
| Goal | Where and what |
|---|---|
| Allow a server's tools wholesale | allow: mcp__<server> |
| Block one dangerous tool | deny: mcp__<server>__<tool> |
| Block all MCP tools | deny: mcp__* |
| Prompt every time | ask: any of the same patterns |
A deny rule that names a bare tool removes the tool from Claude's context, so Claude never sees it. A scoped rule leaves the tool available and blocks matching calls when Claude attempts them.
One thing to watch: a deny or ask rule whose tool name matches no known tool normally produces a startup warning to catch typos, but tool names containing _ or * are exempt from that check. Every mcp__ name qualifies, so a misspelled server name fails silently.
Where rules live, and what gets ignored
Write rules in settings.json and inspect them with /permissions. The dialog lists every rule and the settings.json file it came from. You can open it while Claude is working: adding or removing a rule applies from Claude's next tool call in the same turn (v2.1.234 or later). For the files and their precedence, see Configuring permissions in Claude Code's settings.json, and for driving the dialog, The /permissions command.
mcp__ rules with parentheses are skipped
The Bash(npm run build) style of narrowing by argument does not work for MCP tools. When Claude Code loads a settings file, it skips any mcp__ rule that has parentheses. Skipped rules are listed in the invalid-settings dialog when an interactive session starts, and in claude doctor output. To match a parameter on an MCP tool, pass a deny rule with --disallowedTools instead.
There is a second case where an allow rule has no effect. If your organization has set a claude.ai connector tool to ask and that setting reaches your session, allow rules for that tool don't apply: Claude Code prompts on every call, even in auto and bypassPermissions modes. In dontAsk mode, which never prompts, it denies the call instead. Tools from connectors Claude Code fetches itself appear as mcp__claude_ai_<server>__<tool>.
Summary
allowtakesmcp__<server>for a whole server andmcp__<server>__<tool>for one tool- An allow wildcard only works after
mcp__<server>__;mcp__*and*are skipped with a warning - Deny and ask accept full tool-name globs, so
deny: ["mcp__*"]blocks every MCP tool - Evaluation is deny → ask → allow, first match wins, regardless of specificity
- Parenthesised
mcp__rules are skipped from settings files; use--disallowedToolsto match a parameter
FAQ
- How do I allow every tool from one MCP server?
- Put "mcp__<server>" in permissions.allow in settings.json. "mcp__<server>__*" means the same thing. The server name is the name you registered with Claude Code.
- Why does "mcp__*" in allow do nothing?
- Allow rules accept a tool-name wildcard only after a literal mcp__<server>__ prefix. An unanchored pattern such as "mcp__*" is skipped with a warning and auto-approves nothing.
- Can I write mcp__github__create_issue(title:*)?
- No. When Claude Code loads a settings file it skips any mcp__ rule that has parentheses. To match a parameter on an MCP tool, pass a deny rule with --disallowedTools.
- How do I deny all MCP tools?
- Put "mcp__*" in permissions.deny. Deny and ask rules do accept a glob in the tool-name position, so that pattern works there.
Primary sources
This article was drafted by AI from official documentation and reviewed by the site operator before publishing. Found a mistake? Let us know via the contact page.