---
title: "Claude Code v2.1.299: Stricter MCP Allow Rules, Fail-Closed Plugin Hooks, and Idle Compaction"
date: 2026-10-14
tags: ["claude-code","mcp","hooks","security","changelog","permissions"]
categories: ["Guides"]
summary: "Claude Code v2.1.299 (Oct 14) narrows MCP allow rules to the exact named server, makes plugin hooks that can't answer refuse the action, stops following redirects on connector proxies, and compacts idle 200K+ token sessions before the one-hour cache expires."
---


![Claude Code v2.1.299: Stricter MCP Allow Rules, Fail-Closed Plugin Hooks, and Idle Compaction](/images/claude-code-v2-1-299-mcp-allow-rules-fail-closed-hooks-idle-compaction.png)

Most Claude Code releases are a pile of conveniences. v2.1.299, [shipped today](https://code.claude.com/docs/en/changelog), 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:

```bash
# 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](/posts/claude-code-hooks-on-failure-block-fail-closed-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](/posts/claude-code-defaults-mcp-2026-07-28-what-breaks-for-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

- [Claude Code changelog, v2.1.296–2.1.299](https://code.claude.com/docs/en/changelog)

