Control MCP server access for your organization changedmanaged-mcp
Nearest release: v2.1.282, published 7 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Upstream edited this page at 24 Sep 2026 23:46 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 28 Sep 2026 23:37 UTC.
Upstream edited
Recorded here
Lines+81added
Lines−81removed
From line
23
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits20to this page, all time
The whole hunk
from line 23, old and new numbered
/
from line 23
2323
2424Claude Code supports a range of restriction levels. Each pattern uses one or more of the mechanisms covered below: `managed-mcp.json` for deploying a fixed set, the `managedMcpServers` managed setting for providing servers alongside the ones users add, and `allowedMcpServers`/`deniedMcpServers` for filtering what users configure.
2525
26| Pattern | What it does | Configure |
27| :---------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------- |
28| **Disable MCP** | No servers load, apart from [in-process servers the app that started the session registers](#exclusive-control-with-managed-mcp-json) and any you [provide through `managedMcpServers`](#provide-servers-through-managed-settings) | `managed-mcp.json` with an empty server map |
29| **Fixed deployment** | Every user gets the same servers and can't add others | `managed-mcp.json` with the servers you want |
30| **Provided servers** | Every user gets the remote servers you list and keeps their own | `managedMcpServers` in managed settings |
31| **Approved catalog** | Publish a list of approved servers; users add the ones they want, anything else is blocked | `allowedMcpServers` + `allowManagedMcpServersOnly: true` |
32| **Plugin servers only** | Users can't add servers through `~/.claude.json` or `.mcp.json`; plugin servers still load | [`strictPluginOnlyCustomization`](/docs/en/settings-reference#strictpluginonlycustomization) with `mcp` in the list |
33| **Soft allowlist** | Enforce an allowlist that users can broaden in their own settings | `allowedMcpServers` without `allowManagedMcpServersOnly` |
34| **Denylist only** | Block known-bad servers, allow everything else | `deniedMcpServers` |
35| **No restrictions** | Users add anything | Don't deploy any managed MCP configuration |
26| Pattern | What it does | Configure |
27| :- | :- | :- |
28| **Disable MCP** | No servers load, apart from [in-process servers the app that started the session registers](#exclusive-control-with-managed-mcp-json) and any you [provide through `managedMcpServers`](#provide-servers-through-managed-settings) | `managed-mcp.json` with an empty server map |
29| **Fixed deployment** | Every user gets the same servers and can't add others | `managed-mcp.json` with the servers you want |
30| **Provided servers** | Every user gets the remote servers you list and keeps their own | `managedMcpServers` in managed settings |
31| **Approved catalog** | Publish a list of approved servers; users add the ones they want, anything else is blocked | `allowedMcpServers` + `allowManagedMcpServersOnly: true` |
32| **Plugin servers only** | Users can't add servers through `~/.claude.json` or `.mcp.json`; plugin servers still load | [`strictPluginOnlyCustomization`](/docs/en/settings-reference#strictpluginonlycustomization) with `mcp` in the list |
33| **Soft allowlist** | Enforce an allowlist that users can broaden in their own settings | `allowedMcpServers` without `allowManagedMcpServersOnly` |
34| **Denylist only** | Block known-bad servers, allow everything else | `deniedMcpServers` |
35| **No restrictions** | Users add anything | Don't deploy any managed MCP configuration |
3636
3737<Note>
3838 Claude Code doesn't have a built-in MCP server registry that users can browse and install from. For the approved-catalog pattern, share the approved list and its `claude mcp add` commands somewhere your users will find them, such as an internal wiki, or distribute the servers as plugins through a [managed plugin marketplace](/docs/en/plugins/org#restrict-what-users-can-install) so users can browse and install them from `/plugin`.
from line 54
5454
5555Any process that can write to a system path with administrator privileges can deploy the file. Across a fleet, that's usually through device management tooling, such as Jamf or a configuration profile on macOS, Group Policy or Intune on Windows, or your fleet management of choice on Linux. Claude Code looks for the file at one of these paths:
5656
57| Platform | Path |
58| :------------ | :--------------------------------------------------------- |
59| macOS | `/Library/Application Support/ClaudeCode/managed-mcp.json` |
60| Linux and WSL | `/etc/claude-code/managed-mcp.json` |
61| Windows | `C:\Program Files\ClaudeCode\managed-mcp.json` |
57| Platform | Path |
58| :- | :- |
59| macOS | `/Library/Application Support/ClaudeCode/managed-mcp.json` |
60| Linux and WSL | `/etc/claude-code/managed-mcp.json` |
61| Windows | `C:\Program Files\ClaudeCode\managed-mcp.json` |
6262
6363The file uses the same format as a project [`.mcp.json`](/docs/en/mcp#project-scope) file:
6464
from line 255
255255
256256`allowedMcpServers` and `deniedMcpServers` are lists of entries. Each entry is an object with a single key that identifies servers by their URL, their command, or their name:
257257
258| Key | Matches | Use for |
259| :-------------- | :-------------------------------------------------------------------- | :------------------------------------- |
260| `serverUrl` | A remote server URL, exact or with `*` wildcards | HTTP and SSE servers |
261| `serverCommand` | The exact command and arguments that start a stdio server | Stdio servers |
262| `serverName` | The user-assigned label. Exact match only; wildcards are not expanded | Either type, but see the Warning below |
258| Key | Matches | Use for |
259| :- | :- | :- |
260| `serverUrl` | A remote server URL, exact or with `*` wildcards | HTTP and SSE servers |
261| `serverCommand` | The exact command and arguments that start a stdio server | Stdio servers |
262| `serverName` | The user-assigned label. Exact match only; wildcards are not expanded | Either type, but see the Warning below |
263263
264264Leaving `allowedMcpServers` unset is different from setting it to an empty array:
265265
266| Setting | Unset (default) | Empty array `[]` | Populated |
267| :------------------ | :------------------ | :---------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------- |
266| Setting | Unset (default) | Empty array `[]` | Populated |
267| :- | :- | :- | :- |
268268| `allowedMcpServers` | All servers allowed | No servers allowed, apart from [the organization's own](#how-a-server-is-evaluated) | Only matching servers allowed, apart from [the organization's own](#how-a-server-is-evaluated) |
269| `deniedMcpServers` | No servers blocked | No servers blocked | Matching servers blocked |
269| `deniedMcpServers` | No servers blocked | No servers blocked | Matching servers blocked |
270270
271271See [Invalid entries in managed settings](/docs/en/managed-settings#invalid-entries-in-managed-settings) for what happens when an entry fails schema validation.
272272
from line 293
293293
294294 A `managed-mcp.json` server that uses `${VAR}` expansion in its command, arguments, `env`, URL, or headers is still checked, as is every server a user, a plugin, `--mcp-config`, or claude.ai adds.
295295
296| Server type | Allowed when it matches |
297| :------------------- | :--------------------------------------------------------------------------------------------------------------- |
298| Remote (HTTP or SSE) | A `serverUrl` entry. A `serverName` match counts only when the allowlist contains no `serverUrl` entries |
299| Stdio | A `serverCommand` entry. A `serverName` match counts only when the allowlist contains no `serverCommand` entries |
296| Server type | Allowed when it matches |
297| :- | :- |
298| Remote (HTTP or SSE) | A `serverUrl` entry. A `serverName` match counts only when the allowlist contains no `serverUrl` entries |
299| Stdio | A `serverCommand` entry. A `serverName` match counts only when the allowlist contains no `serverCommand` entries |
300300
301301Three matching rules apply inside those checks:
302302
from line 304
304304* **`serverCommand` and `serverUrl` values expand before matching.** Both the policy entry and the server's configured value go through [`${VAR}` and `${VAR:-default}` expansion](/docs/en/mcp#environment-variable-expansion-in-mcp-json), so an entry written as `["${HOME}/bin/server"]` matches a server config that uses either the same reference or the expanded path. On Windows, reference an environment variable that is set there, such as `${USERPROFILE}` instead of `${HOME}`. `serverName` values match literally and never expand. The two sides read different environments; [How policy entries expand](#how-policy-entries-expand) covers which, and how allowlist and denylist entries differ.
305305* **URLs support `*` wildcards** anywhere in the pattern, including the scheme. Hostname matching is case-insensitive and ignores a trailing FQDN dot, so `https://Mcp.Example.com/*` matches `https://mcp.example.com/api`. Paths stay case-sensitive.
306306
307| Pattern | Allows |
308| :-------------------------- | :--------------------------------------------------------------------- |
309| `https://mcp.example.com/*` | All paths on a specific domain |
310| `https://mcp.example.com` | Also all paths on that domain. A pattern with no path matches any path |
311| `https://*.example.com/*` | Any subdomain of `example.com` |
312| `http://localhost:*/*` | Any port on localhost |
313| `*://mcp.example.com/*` | Any scheme to a specific domain |
307| Pattern | Allows |
308| :- | :- |
309| `https://mcp.example.com/*` | All paths on a specific domain |
310| `https://mcp.example.com` | Also all paths on that domain. A pattern with no path matches any path |
311| `https://*.example.com/*` | Any subdomain of `example.com` |
312| `http://localhost:*/*` | Any port on localhost |
313| `*://mcp.example.com/*` | Any scheme to a specific domain |
314314
315315#### How policy entries expand
316316
317317The server's configured value expands from the live process environment, like the rest of `.mcp.json`. A policy entry expands from a pinned environment instead, so a variable set by a project or user settings file can't change what an allowlist entry means. Because a policy entry still depends on the launching shell's value for any variable it references, use literal URLs and commands for entries you rely on for enforcement.
318318
319| Entry list | Expands from | Expansion that would change a URL entry's scheme, host, or path scope |
320| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
321| `allowedMcpServers` | The environment Claude Code started with, plus `env` values from managed settings | Claude Code ignores the entry |
322| `deniedMcpServers` | The same, and a variable with no startup value and no `:-default` fills from settings files outside the repository, such as user or managed settings, which only ever widens what the entry matches | The entry still matches |
319| Entry list | Expands from | Expansion that would change a URL entry's scheme, host, or path scope |
320| - | - | - |
321| `allowedMcpServers` | The environment Claude Code started with, plus `env` values from managed settings | Claude Code ignores the entry |
322| `deniedMcpServers` | The same, and a variable with no startup value and no `:-default` fills from settings files outside the repository, such as user or managed settings, which only ever widens what the entry matches | The entry still matches |
323323
324324Requires Claude Code v2.1.219 or later.
325325
from line 363
363363 }
364364 ```
365365
366 | Server | Result |
367 | :---------------------------------------------------- | :------------------------------------------- |
368 | HTTP server at `https://mcp.example.com/api` | Allowed: matches URL pattern |
369 | HTTP server at `https://api.internal.example.com/mcp` | Allowed: matches wildcard subdomain |
370 | HTTP server at `https://external.example.com/mcp` | Blocked: doesn't match any URL pattern |
371 | Stdio server with any command | Blocked: no name or command entries to match |
366 | Server | Result |
367 | :- | :- |
368 | HTTP server at `https://mcp.example.com/api` | Allowed: matches URL pattern |
369 | HTTP server at `https://api.internal.example.com/mcp` | Allowed: matches wildcard subdomain |
370 | HTTP server at `https://external.example.com/mcp` | Blocked: doesn't match any URL pattern |
371 | Stdio server with any command | Blocked: no name or command entries to match |
372372</Accordion>
373373
374374<Accordion title="Command-only allowlist">
from line 380
380380 }
381381 ```
382382
383 | Server | Result |
384 | :---------------------------------------------------- | :-------------------------------- |
385 | Stdio server with `["npx", "-y", "approved-package"]` | Allowed: matches command |
386 | Stdio server with `["node", "server.js"]` | Blocked: doesn't match command |
387 | HTTP server named `my-api` | Blocked: no name entries to match |
383 | Server | Result |
384 | :- | :- |
385 | Stdio server with `["npx", "-y", "approved-package"]` | Allowed: matches command |
386 | Stdio server with `["node", "server.js"]` | Blocked: doesn't match command |
387 | HTTP server named `my-api` | Blocked: no name entries to match |
388388</Accordion>
389389
390390<Accordion title="Mixed name and command allowlist">
from line 397
397397 }
398398 ```
399399
400 | Server | Result |
401 | :----------------------------------------------------------------------- | :-------------------------------------------------------------------- |
402 | Stdio server named `local-tool` with `["npx", "-y", "approved-package"]` | Allowed: matches command |
403 | Stdio server named `local-tool` with `["node", "server.js"]` | Blocked: command entries exist but doesn't match |
404 | Stdio server named `github` with `["node", "server.js"]` | Blocked: stdio servers must match commands when command entries exist |
405 | HTTP server named `github` | Allowed: matches name |
406 | HTTP server named `other-api` | Blocked: name doesn't match |
400 | Server | Result |
401 | :- | :- |
402 | Stdio server named `local-tool` with `["npx", "-y", "approved-package"]` | Allowed: matches command |
403 | Stdio server named `local-tool` with `["node", "server.js"]` | Blocked: command entries exist but doesn't match |
404 | Stdio server named `github` with `["node", "server.js"]` | Blocked: stdio servers must match commands when command entries exist |
405 | HTTP server named `github` | Allowed: matches name |
406 | HTTP server named `other-api` | Blocked: name doesn't match |
407407</Accordion>
408408
409409<Accordion title="Name-only allowlist">
from line 416
416416 }
417417 ```
418418
419 | Server | Result |
420 | :-------------------------------------------------- | :------------------------------- |
421 | Stdio server named `github` with any command | Allowed: no command restrictions |
419 | Server | Result |
420 | :- | :- |
421 | Stdio server named `github` with any command | Allowed: no command restrictions |
422422 | Stdio server named `internal-tool` with any command | Allowed: no command restrictions |
423 | HTTP server named `github` | Allowed: matches name |
424 | Any server named `other` | Blocked: name doesn't match |
423 | HTTP server named `github` | Allowed: matches name |
424 | Any server named `other` | Blocked: name doesn't match |
425425</Accordion>
426426
427427<Accordion title="Allowlist with denylist override">
from line 436
436436 }
437437 ```
438438
439 | Server | Result |
440 | :----------------------------------------------- | :-------------------------------------------------------- |
441 | HTTP server at `https://mcp.example.com/api` | Allowed: matches allowlist URL pattern, no denylist match |
442 | HTTP server at `https://staging.example.com/api` | Blocked: matches both, but the denylist takes precedence |
443 | HTTP server at `https://other.com/mcp` | Blocked: doesn't match the allowlist |
439 | Server | Result |
440 | :- | :- |
441 | HTTP server at `https://mcp.example.com/api` | Allowed: matches allowlist URL pattern, no denylist match |
442 | HTTP server at `https://staging.example.com/api` | Blocked: matches both, but the denylist takes precedence |
443 | HTTP server at `https://other.com/mcp` | Blocked: doesn't match the allowlist |
444444</Accordion>
445445
446446### Restrict the allowlist to managed settings only
from line 463
463463
464464For what users see at startup when `managed-mcp.json` is deployed and the session also has `--mcp-config` servers, see [Exclusive control with managed-mcp.json](#exclusive-control-with-managed-mcp-json). Use this table to recognize the other reports and to tell users what to expect before you roll out a change:
465465
466| Restriction | What the user sees |
467| :-------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------- |
468| `managed-mcp.json` is present and the user runs `claude mcp add` | `Cannot add MCP server: enterprise MCP configuration is active and has exclusive control over MCP servers` |
469| The server is on a denylist and the user runs `claude mcp add` | `Cannot add MCP server "<name>": server is explicitly blocked by enterprise policy` |
470| The server isn't on the allowlist and the user runs `claude mcp add` | `Cannot add MCP server "<name>": not allowed by enterprise policy` |
471| The user runs `claude mcp remove` on a server from `managedMcpServers` | `MCP server "<name>" is provided by your organization (managed settings) and cannot be removed locally.` |
472| A previously configured server is now blocked by policy | The server disappears from `/mcp` and `claude mcp list` |
466| Restriction | What the user sees |
467| :- | :- |
468| `managed-mcp.json` is present and the user runs `claude mcp add` | `Cannot add MCP server: enterprise MCP configuration is active and has exclusive control over MCP servers` |
469| The server is on a denylist and the user runs `claude mcp add` | `Cannot add MCP server "<name>": server is explicitly blocked by enterprise policy` |
470| The server isn't on the allowlist and the user runs `claude mcp add` | `Cannot add MCP server "<name>": not allowed by enterprise policy` |
471| The user runs `claude mcp remove` on a server from `managedMcpServers` | `MCP server "<name>" is provided by your organization (managed settings) and cannot be removed locally.` |
472| A previously configured server is now blocked by policy | The server disappears from `/mcp` and `claude mcp list` |
473473| A server becomes blocked while a session is running, and the user selects **Reconnect** or turns it back on in `/mcp` | [`MCP server <name> is blocked by enterprise managed policy`](/docs/en/errors#mcp-server-is-blocked-by-enterprise-managed-policy) |
474474
475475When a server silently disappears, the user gets no signal that policy is the reason, so tell affected users which servers are blocked when you roll out a new restriction.
from line 482
482482
483483Every file and setting this page covers, what it controls, and how to deliver it:
484484
485| Surface | What it controls | Where it lives | How to deliver |
486| :--------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
487| `managed-mcp.json` | Fixed server set, exclusive control | System path: `/Library/Application Support/ClaudeCode/`, `/etc/claude-code/`, or `C:\Program Files\ClaudeCode\` | MDM, GPO, fleet management, or any process with administrator privileges. Cannot be set through server-managed settings |
488| `managedMcpServers` | Remote servers provided to every user alongside their own | Managed settings sources only; the setting has no effect elsewhere | A [managed settings source](/docs/en/admin-setup#decide-how-settings-reach-devices): server-managed settings, a gateway policy, `managed-settings.json`, MDM profile, or HKLM registry |
489| `allowedMcpServers` | Allowlist of permitted servers | Any [settings scope](/docs/en/settings#where-settings-live); [How a server is evaluated](#how-a-server-is-evaluated) says how lists from several scopes and managed sources combine | For enforcement, a [managed settings source](/docs/en/admin-setup#decide-how-settings-reach-devices): server-managed settings, `managed-settings.json`, MDM profile, or registry |
490| `deniedMcpServers` | Denylist of blocked servers | Any settings scope; [How a server is evaluated](#how-a-server-is-evaluated) says how lists from several scopes and managed sources combine | Same as `allowedMcpServers` |
491| `allowManagedMcpServersOnly` | Locks the allowlist to managed sources only | Managed settings sources only; [Keys read from every admin source](/docs/en/managed-settings#keys-read-from-every-admin-source) says which managed sources can turn it on. The setting has no effect in other scopes | Same as `allowedMcpServers` |
492| `allowAllClaudeAiMcps` | Loads the claude.ai connectors Claude Code fetches itself alongside `managed-mcp.json`. [A `managed-mcp.json` on the host that runs a cloud session still suppresses that session's connectors](#allow-claude-ai-connectors-alongside-the-managed-set) | Managed settings sources only; the setting has no effect elsewhere | Same as `allowedMcpServers` |
485| Surface | What it controls | Where it lives | How to deliver |
486| :- | :- | :- | :- |
487| `managed-mcp.json` | Fixed server set, exclusive control | System path: `/Library/Application Support/ClaudeCode/`, `/etc/claude-code/`, or `C:\Program Files\ClaudeCode\` | MDM, GPO, fleet management, or any process with administrator privileges. Cannot be set through server-managed settings |
488| `managedMcpServers` | Remote servers provided to every user alongside their own | Managed settings sources only; the setting has no effect elsewhere | A [managed settings source](/docs/en/admin-setup#decide-how-settings-reach-devices): server-managed settings, a gateway policy, `managed-settings.json`, MDM profile, or HKLM registry |
489| `allowedMcpServers` | Allowlist of permitted servers | Any [settings scope](/docs/en/settings#where-settings-live); [How a server is evaluated](#how-a-server-is-evaluated) says how lists from several scopes and managed sources combine | For enforcement, a [managed settings source](/docs/en/admin-setup#decide-how-settings-reach-devices): server-managed settings, `managed-settings.json`, MDM profile, or registry |
490| `deniedMcpServers` | Denylist of blocked servers | Any settings scope; [How a server is evaluated](#how-a-server-is-evaluated) says how lists from several scopes and managed sources combine | Same as `allowedMcpServers` |
491| `allowManagedMcpServersOnly` | Locks the allowlist to managed sources only | Managed settings sources only; [Keys read from every admin source](/docs/en/managed-settings#keys-read-from-every-admin-source) says which managed sources can turn it on. The setting has no effect in other scopes | Same as `allowedMcpServers` |
492| `allowAllClaudeAiMcps` | Loads the claude.ai connectors Claude Code fetches itself alongside `managed-mcp.json`. [A `managed-mcp.json` on the host that runs a cloud session still suppresses that session's connectors](#allow-claude-ai-connectors-alongside-the-managed-set) | Managed settings sources only; the setting has no effect elsewhere | Same as `allowedMcpServers` |
493493
494494## Related resources
495495
No line in this hunk matches that.