DEV Community

Ahab
Ahab

Posted on Originally published at indieseek.co

Claude Code 2.1.259 managed MCP servers: keep unattended headless runs fail-closed.

Originally published at IndieSeek.

Claude Code 2.1.259 managed MCP servers: keep unattended headless runs fail-closed

Quick answer

Claude Code 2.1.259 adds two controls that fit the same automation problem. Organizations can distribute remote HTTP or SSE servers through the managed managedMcpServers setting, and unattended headless hosts can use --permission-prompts none so an action that would have opened a prompt is denied instead. The active permission mode—including Auto mode—still makes its normal decisions first.

Do not treat either control as blanket approval. Managed MCP distribution decides which server definitions arrive; permission policy decides which tools may run; --permission-prompts none only changes the final prompt fallback. Roll out all three layers separately, record the effective configuration, and make a denied write the success case for your first canary.

Who this is for

This guide is for platform teams and indie developers running Claude Code from CI, scheduled jobs, remote workers, or an SDK host where nobody can answer a terminal prompt. It assumes you need a small approved set of internal remote tools without giving every job ambient authority.

If you first need to reduce what a shared-machine evaluation can reach, read the Claude Code restricted-mode checklist. If your risk is broad shell matching, use the Bash wildcard permission audit. Neither replaces MCP server identity, credentials, or tool-level permission rules.

What changed in 2.1.259

Anthropic published Claude Code 2.1.259 on September 2, 2026. The stable release adds managedMcpServers as a managed setting. Administrators can supply remote HTTP/SSE entries using the same entry shape as .mcp.json; entries that name a local command are skipped. That transport boundary matters: this new setting is not a way to distribute arbitrary stdio launch commands.

The release also adds --permission-prompts none for unattended headless hosts. When the active permission mode cannot approve or deny an action and would normally ask a person, Claude Code denies it automatically. This is different from bypassPermissions, and it does not convert an Ask rule into an Allow rule.

Two adjacent changes deserve migration tests. A malformed managed-settings source now makes Claude Code refuse to start and names the invalid source. Also, allowedMcpServers now governs only servers users add. If an older allowlist had been filtering a literal managed-mcp.json server, that server can load after upgrade; Anthropic directs administrators to deniedMcpServers when it must remain blocked.

The release tag resolves to commit f173a697aa6486945f1b9c4aa9ce5383d2c87db6. The local client used for this article was still 0.2.36, so the configuration below is an operator-ready rollout design derived from the official 2.1.259 release and current docs, not a claim that this machine executed the new binary.

Separate the three control planes

Control plane Primary question Safe evidence
Server delivery Which remote MCP definitions reach the session? Effective managed source, exact URL, connection status
Tool authority Which server tools can be invoked? Deny/ask/allow rules, permission mode, credential scope
Prompt fallback What happens when a decision still needs a person? Allowed call proceeds; prompt-required call is denied, never hung

This model prevents a common mistake: seeing an MCP server connected and assuming its tools are approved. Connection is inventory, not authorization. A token also has its own server-side scope, so an allowed tool with an overpowered credential can still be too broad.

Build a minimal managed remote set

Start with one read-only remote server in managed settings. The new setting uses .mcp.json-style server entries:

{
  "managedMcpServers": {
    "incident-readonly": {
      "type": "http",
      "url": "https://mcp.example.com/readonly"
    }
  },
  "permissions": {
    "allow": ["mcp__incident-readonly__get_status"],
    "deny": ["mcp__incident-readonly__mutate_*", "Bash"]
  }
}
Enter fullscreen mode Exit fullscreen mode

Treat this as a shape template, not a copy-paste production secret. Put authentication in the supported credential mechanism, scope the server token to read-only, and verify the effective settings on the exact host image. Managed file paths are /Library/Application Support/ClaudeCode/managed-settings.json on macOS, /etc/claude-code/managed-settings.json on Linux/WSL, and C:\Program Files\ClaudeCode\managed-settings.json on Windows.

A six-step unattended rollout

1. Snapshot the old effective state

Record the Claude Code version, managed-settings source, any managed-mcp.json, every allowed or denied MCP identity, permission mode, server credential scope, and the runner image digest. Keep the old binary and configuration together as one rollback unit.

2. Reconcile the allowlist semantic change

For every server in managed-mcp.json, ask whether an existing allowedMcpServers entry was the only reason it stayed off. Add an explicit deniedMcpServers identity before upgrading when the answer is yes. Prefer URL or command identity over display name for enforcement.

3. Validate managed delivery interactively

Upgrade one disposable host. Confirm startup succeeds, the correct managed source is visible, local-command entries are skipped, only the expected HTTP/SSE server connects, and no user or project setting widens the result. Intentionally break a copy of the managed file and verify startup refuses with the source named.

4. Prove tool-level permissions

Run one allowed read, one denied write, one unknown tool, and one call that would normally ask. Preserve the tool name, sanitized input, permission decision, server response class, and session ID. Do not record credentials or sensitive response bodies.

5. Add the no-prompt fallback

Run the headless job with --permission-prompts none only after the interactive matrix passes. Use structured output and inspect the initial system event. Current Headless documentation exposes mcp_servers plus mcp_server_errors; fail CI when the error array is non-empty rather than accepting a clean process exit with a missing server.

claude -p \
  --permission-prompts none \
  --output-format stream-json \
  --verbose \
  "Read the incident status and make no changes"
Enter fullscreen mode Exit fullscreen mode

6. Promote from a recorded acceptance matrix

Canary Expected result
Approved remote read tool Runs and returns the expected schema
Write tool matched by deny Blocked before side effect
Tool that would prompt Denied automatically; job does not hang
Invalid managed settings Client refuses to start and identifies the source
Command-based managedMcpServers entry Skipped; no local process launches
Disconnected server during tool listing Startup reports the error, not an empty connected server
Non-allowlisted user-added server Follows the new user-added allowlist policy
Explicitly denied fixed managed server Remains blocked after upgrade

Promote one runner group at a time. Roll back the no-prompt flag first if observability is insufficient, then the managed server set, then the binary. Never replace a deny with automatic approval just to keep a scheduled job green.

Copyable acceptance record

claude_code_version: 2.1.259
release_tag_commit: f173a697aa6486945f1b9c4aa9ce5383d2c87db6
managed_source: file
managed_remote_servers: [incident-readonly]
local_command_entries_loaded: false
permission_mode: default
permission_prompts: none
credential_scope: read-only
mcp_server_errors: []
allowed_read_passed: true
denied_write_blocked: true
prompt_required_denied: true
fixed_server_deny_migration_checked: true
rollback_binary_available: true
Enter fullscreen mode Exit fullscreen mode

Building something? Take a 60-sec game break. Score to rank your product or profile on tapto.top and get more exposure—free, no signup.

Common mistakes

  • Treating a delivered MCP definition as permission to use every tool.
  • Putting a local command entry under managedMcpServers and assuming it launched.
  • Using --permission-prompts none as if it were bypassPermissions.
  • Forgetting the 2.1.259 allowedMcpServers change for fixed managed servers.
  • Checking only the process exit code and ignoring mcp_server_errors.
  • Expanding credential scope to hide an authorization failure.

FAQ

Does --permission-prompts none approve tools automatically?

No. The active permission mode still decides first. Only a call that would otherwise prompt is converted to a denial.

Can managedMcpServers launch a local stdio command?

The 2.1.259 release says command-named entries are skipped. Use it for the remote HTTP/SSE boundary described by the release.

Is managedMcpServers the same as managed-mcp.json?

No. The new value is a managed setting for distributing remote entries. The existing system-level managed-mcp.json mechanism is a fixed server deployment with different behavior. Audit both when upgrading.

Is a connected server proof that the job is safe?

No. Verify tool permissions, server-side credential scope, prompt fallback, structured startup errors, and the absence of side effects.

Sources

Top comments (0)