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"]
}
}
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"
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
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
commandentry undermanagedMcpServersand assuming it launched. - Using
--permission-prompts noneas if it werebypassPermissions. - Forgetting the 2.1.259
allowedMcpServerschange 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.
Top comments (0)