[DOCS] Managed MCP allowlist and denylist docs omit `${VAR}` reference matching behavior

Status Fixed / completed
Maintainer reply ✓ Yes — bcherny
Activity 3 comments · opened Jun 6, 2026 · closed Aug 17, 2026
💡 Likely answer: A maintainer (bcherny, collaborator) responded on this thread — see the highlighted reply below.

Documentation Type

Unclear/confusing documentation

Documentation Location

https://code.claude.com/docs/en/managed-mcp

Section/Topic

allowedMcpServers / deniedMcpServers predicates that contain ${VAR} references

Current Documentation

The managed MCP page currently says:

"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"

It documents exact command matching and URL wildcard matching, and it separately says MCP configurations can use ${VAR} expansion for per-user credentials. The allowlist/denylist predicate section does not say how ${VAR} references inside policy entries are matched.

What's Wrong or Missing?

Claude Code v2.1.166 fixed managed-settings allowedMcpServers / deniedMcpServers predicates not matching when they use ${VAR} references. That implies ${VAR} references are a supported or at least recognized shape inside policy predicates.

The current docs tell administrators how URL, command, and name predicates match, but omit:

  • whether ${VAR} is valid in serverUrl and/or serverCommand predicates
  • when variable references are expanded
  • whose environment supplies the value
  • whether missing variables fail closed, warn, or leave the predicate unmatched
  • how this differs from ${VAR} expansion inside .mcp.json server definitions

Without this, administrators cannot safely write managed policies that depend on per-user or per-machine values, and they cannot reason about why a predicate with ${VAR} did or did not match.

Suggested Improvement

Add a subsection under "Match servers by URL, command, or name":

Policy predicates may include `${VAR}` references in supported fields. Claude Code resolves them before comparing configured servers against `allowedMcpServers` and `deniedMcpServers`. Document exactly which fields support references, which environment is used, and what happens when a variable is unset.

Add examples for both allowlist and denylist policy if supported:

{
"allowedMcpServers": [
{ "serverUrl": "https://${MCP_HOST}/mcp" }
],
"deniedMcpServers": [
{ "serverCommand": ["node", "${UNAPPROVED_MCP_PATH}"] }
]
}

If ${VAR} references are intentionally allowed only in server definitions and not policy predicates, update the docs to say that explicitly and explain the v2.1.166 behavior.

Impact

Medium - Makes feature difficult to understand

Additional Context

Affected Pages:

| Page | Line(s) | Context |
|------|---------|---------|
| https://code.claude.com/docs/en/managed-mcp | 121-151 | Defines allowlist/denylist predicate keys but not ${VAR} behavior |
| https://code.claude.com/docs/en/managed-mcp | 153-172 | Explains exact command and URL wildcard matching but not variable expansion |
| https://code.claude.com/docs/en/settings | 176, 199 | Lists allowedMcpServers and deniedMcpServers without variable-reference caveats |
| https://code.claude.com/docs/en/mcp | 496-510 | Documents MCP config environment expansion, which should be cross-referenced or distinguished |

Total scope: 3 pages affected.

Version reference: Claude Code v2.1.166 release notes state that managed-settings allowedMcpServers / deniedMcpServers predicates now match when they use ${VAR} references.

View original on GitHub ↗

3 Comments

coygeek · 3 months ago

Still relevant as of 2026-07-01.

The documentation gaps identified at filing are still present. At https://code.claude.com/docs/en/managed-mcp, the "Match servers by URL, command, or name" section (lines 130-174) still defines only exact-command matching and URL * wildcard matching for allowedMcpServers / deniedMcpServers predicates, with no mention of ${VAR} reference behavior in serverUrl or serverCommand. The only ${VAR} mention on that page (line 89) is scoped to .mcp.json server authentication, not policy predicates. The ${VAR} expansion reference at https://code.claude.com/docs/en/mcp (lines 386-400) covers only server-definition fields (command, args, env, url, headers) and does not cross-reference predicate matching. The allowedMcpServers and deniedMcpServers entries at https://code.claude.com/docs/en/settings (lines 208 and 234) carry no ${VAR} caveat either. The v2.1.166 fix recorded at https://code.claude.com/docs/en/changelog.md (line 418) makes this a supported predicate shape, but the docs still do not say which fields accept ${VAR}, when expansion happens, whose environment supplies the value, or what happens when a variable is unset. Please add a predicate-side ${VAR} subsection to the managed-mcp page and cross-reference it from the MCP expansion reference.

bcherny collaborator · 1 month ago

Thanks for flagging this — the managed MCP page now documents this. Under "Match servers by URL, command, or name" it explains that serverCommand and serverUrl policy entries expand ${VAR} / ${VAR:-default} before matching (and that serverName matches literally), and a new "How policy entries expand" subsection covers which environment each side reads, how allowedMcpServers and deniedMcpServers differ when a variable is missing or would change an entry's scope, and the recommendation to use literal values for entries you rely on for enforcement.

https://code.claude.com/docs/en/managed-mcp#how-policy-entries-expand

Closing as documented; reopen if something is still unclear.

🤖 Generated with Claude Code

github-actions[bot] · 8 days ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.