[BUG] `allowedMcpServers` from remote managed settings not enforced when the settings fetch is slow: MCP servers connect first and are never re-checked

Status Open
Reported on v2.1.280
Maintainer reply None cached
Activity 0 comments · opened Sep 23, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet. Closest: #93727 (same symptom class, closed without reproduction steps) and #70181 (the inverse precedence problem, remote settings overriding local managed rules). This report supplies the log sequence and a deterministic reproduction for the #93727 class.
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (2.1.280, the version pinned in our managed image; the autoupdater is disabled by policy)

What's Wrong?

When remote managed settings are slow to load, Claude Code connects MCP servers before the policy is applied, then logs Remote settings: Loading promise timed out, resolving anyway. Servers whose URLs are not in allowedMcpServers connect successfully, stay connected for the whole session, and their tools remain callable. When the policy is applied later, existing connections are not re-evaluated.

A server that was explicitly logged as blocked by enterprise policy before prefetch still went on to connect six seconds later.

The same configuration is blocked or allowed depending only on whether the remote-settings load beats MCP startup. Across roughly fifteen first-run sessions on identical container images the same day (same version, same policy), every session whose managed settings resolved within about 6 s of process start connected the unlisted servers, and every session that took 20 s or more blocked them, with one ambiguous case. In the blocked sessions, a server that is on the allowlist connected normally, so the allowlist works whenever it is loaded in time.

What Should Happen?

Any of:

  1. MCP server startup waits for managed-settings resolution when a remote source is configured; or
  2. on fetch timeout, security-relevant keys (allowedMcpServers, deniedMcpServers, permissions.deny) fail closed instead of "resolving anyway"; or
  3. when remote settings are applied after startup, live MCP connections are re-evaluated against allowedMcpServers and disconnected if no longer permitted.

At minimum, a server logged as blocked by enterprise policy before prefetch must not be allowed to connect.

Error Messages/Logs

# One interactive session, --debug-file, times UTC.
# Server A: plain-http MCP server, user scope, URL NOT on allowlist.
# Server B: https MCP server, local scope, URL NOT on allowlist.
08:52:11.899  [pre-warm claude -p process] Remote settings: Fetched successfully
08:52:11.913  [pre-warm] Remote settings: Applied for this non-interactive run; consent deferred — not persisting the disk cache as consented
08:52:12.424  [interactive] Acquired PID lock on running version: .../2.1.280
08:52:13.397  [STARTUP] MCP configs resolved in 4ms (awaited at +1519ms)
08:52:13.397  [WARN] MCP server blocked by enterprise policy before prefetch: <server A>
08:52:13.408  [MCP] --mcp-config servers running fully async (nonblocking)
08:52:13.408  [3P telemetry] Remote managed settings fetch settled, initializing telemetry
08:52:19.360  Remote settings: Fetched successfully
08:52:19.578  MCP server "<server B>": Starting connection with timeout of 30000ms
08:52:19.583  MCP server "<server A>": Starting connection with timeout of 30000ms
08:52:19.652  MCP server "<server A>": Successfully connected (transport: http) in 69ms     # flagged as blocked 6 s earlier
08:52:20.071  MCP server "<server B>": Successfully connected (transport: http) in 494ms    # not on allowlist, never flagged
08:52:48.868  Remote settings: Loading promise timed out, resolving anyway (load and fetch barriers)
09:09:07.505  Remote settings: Saved to ~/.claude/remote-settings.json
09:09:07.506  Remote settings: Applied new settings successfully                              # policy now in force; A and B still connected

# Fresh process in the same directory once the cache existed on disk:
[WARN] MCP servers blocked by enterprise policy before prefetch: <server A>, <server B>

Steps to Reproduce

The race needs two conditions: no consented settings cache on disk, and a slow settings fetch. Both can be forced.

  1. Use an org with remote managed settings that contain an allowedMcpServers list.
  2. Remove any cached copy so the session must fetch: rm -f ~/.claude/remote-settings.json ~/.claude/remote-settings-consent.json
  3. Add latency to outbound HTTPS so the settings fetch takes longer than MCP startup. Either of:
  • in a Linux container: tc qdisc add dev eth0 root netem delay 5000ms
  • or route through a delaying proxy (for example toxiproxy with a latency toxic of 5000 ms) and set HTTPS_PROXY to it
  1. Register a server whose URL is not on the allowlist:

claude mcp add --transport http probe https://<any-reachable-host-not-on-the-list>/mcp

  1. Start claude --debug-file /tmp/d.log and run /mcp.
  2. Observe: probe is connected. In the log, MCP server "probe": Successfully connected appears before Remote settings: Loading promise timed out, resolving anyway, and later Remote settings: Applied new settings successfully appears with probe still connected and its tools callable.
  3. Exit and start claude again with the cache now on disk. Observe MCP servers blocked by enterprise policy before prefetch: probe and probe absent from /mcp.

Note for anyone trying to work around it: pre-warming with a non-interactive claude -p does not help. It applies the settings for its own run but defers consent and does not persist the disk cache, so the first interactive session in a fresh environment always races.

Claude Model

N/A

Is this a regression?

Not sure

Last Working Version

Unknown

Claude Code Version

2.1.280 (Claude Code)

Platform

CLI

Operating System

Linux (x86_64 container, Node v26.3.0)

Terminal/Shell

bash, xterm-256color

Additional Information

Impact. An enterprise allowedMcpServers policy is bypassable by timing. A user, or an agent acting on injected instructions with shell access, can claude mcp add an arbitrary HTTP server and it connects whenever the settings fetch is slow. permissions.deny rules that live only in remote settings are absent during the same window (not exercised here, but the same load path). The environment where this is most likely is exactly where enterprise controls are relied on most: fresh ephemeral containers behind a corporate egress proxy, where every first session has no cache and a slow fetch.

Related issues. #93727 reported the same symptom class and was closed for lack of reproduction steps; the steps above reproduce it. #70181 describes the inverse precedence problem, remote settings overriding local managed-settings.json. #95020 reports claude mcp list ignoring allowedMcpServers. #94803 covers plugin-sourced servers under the enterprise policy. They point at the same area: policy resolution and MCP startup are not sequenced.

View original on GitHub ↗