↓ Skip to main content
  1. Articles/

Claude Code v2.1.299: Stricter MCP Allow Rules, Fail-Closed Plugin Hooks, and Idle Compaction

·1047 words·5 mins·
Florent Clairambault
Author
Florent Clairambault
CTO & software engineer — writing daily about spec-driven development and agentic coding

Claude Code v2.1.299: Stricter MCP Allow Rules, Fail-Closed Plugin Hooks, and Idle Compaction

Most Claude Code releases are a pile of conveniences. v2.1.299, shipped today, is mostly a pile of tightened screws. Read it as a security-and-cost release with a few UI extras attached. Several of the changes can silently alter what your existing config does, so it’s worth ten minutes before you roll it out to a team.

MCP allow rules now match exactly one server
#

This is the change most likely to bite. Per the changelog: “MCP allow rules match only the named server. mcp__a no longer covers a__b or a_.” The prescribed form is mcp__<server>__* with the full normalized server name. Agent tools: lists follow the same logic, and for a server whose name contains __ you write mcp__<whole name>__*.

The old behavior is the sort of prefix-matching that looks harmless until you have two servers whose names share a prefix. A rule written for mcp__github could plausibly have granted tools from a server named github__enterprise. That’s a permission leak by naming accident, and it’s good that it’s closed.

The practical consequence: rules that relied on the loose match will now stop matching and Claude will prompt (or deny, in non-interactive runs). A quick audit:

# find MCP rules in project and user settings
grep -rn '"mcp__' .claude/settings*.json ~/.claude/settings.json

For each hit, confirm it either ends in __* or names a specific tool on the exact server. Rewrite anything that was a bare prefix.

Plugin hooks fail closed
#

Two related changes land here. First: “A plugin hook that can’t receive an action, or can’t return its answer, now refuses the action rather than letting it through. If the tool already ran, its result is withheld.” Second, hooks and workflow scripts now reject returned values nested deeper than 28,000 levels (100,000 for workflow scripts).

This continues the direction we covered with onFailure: "block" in v2.1.295: a guard that errors out should not become an open door. If you run a policy hook that occasionally times out or crashes, expect it to start blocking work instead of waving it through. That is the correct behavior for a policy hook and an annoying one for a flaky hook, which tells you which of yours need fixing.

Also relevant for hook authors: UserPromptSubmit hooks now run before a skill or custom command expands, so a blocking hook also stops the embedded shell commands in that skill. And a skill’s own front-matter UserPromptSubmit hook first fires on the prompt after the one that invokes the skill.

No more redirect following on connector proxies
#

Requests to claude.ai’s connector proxy and to Anthropic-hosted MCP servers no longer follow HTTP redirects, and the same goes for MCP requests in cloud and self-hosted runner sessions going through the session’s MCP proxy. A connector’s own server is unaffected. Redirect-following on authenticated requests is a classic way to leak credentials to an unintended host; refusing them at the proxy layer is cheap hardening. If you ran a self-hosted setup that depended on a proxy redirect, it will break, and you’ll need to point at the final URL.

Related loading rule: skills and commands whose file or folder name contains hidden, direction-changing or blank-like characters, or < or >, are no longer loaded until renamed. That targets lookalike-filename tricks in shared skill repos, which matters given how many teams now pull skills from third parties.

Smaller hardening items from the same release:

  • The resume command printed at exit uses the session ID rather than the session name, so nothing in a name can execute when pasted.
  • The /ultrareview upload error no longer suggests git add ., which could stage untracked files such as .env.
  • In Cowork cloud sessions in auto mode, a PermissionRequest hook can no longer approve shell commands or subagents.

Idle compaction: a cost feature in disguise
#

The headline addition for budget owners: a terminal conversation over 200K tokens that sits idle for about 54 minutes is compacted before its one-hour prompt cache expires.

The logic is about cache economics. If you walk away from a large session and come back after the cache has lapsed, the next turn re-reads the entire context at uncached input prices. Compacting at the 54-minute mark means the first turn after your break pays for a smaller context. Controls:

  • CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS changes the 200K threshold.
  • "idleCompaction": false in settings.json turns it off.
  • Both require v2.1.290 or later.

The trade-off is that compaction is lossy. If you rely on the exact transcript state when you return from lunch, disable it for those sessions. For long-running spec-driven work where the spec lives in a file rather than the conversation, compaction costs you little, and that’s the argument for keeping state in files.

Smaller additions worth knowing
#

  • CLAUDE_CODE_DISABLE_FILE_MENTIONS: @ mentions pass the path only, and Claude reads the file with its tools instead of getting contents inlined.
  • --shutdown-drain-sec for claude self-hosted-runner orchestrator: on SIGTERM it stops polling and gives in-flight work that many seconds to finish. Useful for rolling deploys of runners.
  • --disallow-tools for claude plugin eval, to keep tools like Agent out of eval runs.
  • /usage now warns about max effort, workflows, always-on context and large tool results.
  • Cloud session and Remote Control MCP connectors negotiate protocol 2026-07-28 by default, with MCP_PROTOCOL_NEGOTIATION=legacy as the opt-out. See our earlier piece on what that does to your servers.
  • Mod authors get $.prompt.media, $.session.identity(), new Text options (size, weight, mono, tabular), and bold is deprecated in favor of weight.

Upgrade checklist
#

  1. Grep your settings for bare mcp__<name> allow rules and rewrite them to mcp__<name>__*.
  2. List the plugin hooks you run and decide, for each, whether “refuse on failure” is what you want. Fix the flaky ones.
  3. Check any self-hosted MCP proxy path for redirects.
  4. Decide on idle compaction per workflow, and set the threshold or turn it off.
  5. Rename any skills with odd characters in their paths.

What I couldn’t verify
#

I did not install v2.1.299 or test any of these behaviors; everything above comes from the changelog text. The page lists 16 improvements and 131 bug fixes in this release, and I read only the summary of those, not each item. The changelog doesn’t say how the idle timer is measured beyond “about 54 minutes”, nor whether compaction output differs from manual /compact.

Sources
#

Related