Claude Code hooks not firing on an MCP tool: 6 causes

A PreToolUse hook that never fires on an MCP tool usually has a matcher problem: a bare server name, a plugin's scoped name, or a missing .*. Fixes for Sume.

5 min readSume
All posts

If a Claude Code hook does not fire on an MCP tool, the matcher is the first thing to check. Anthropic's hooks page says a matcher such as mcp__memory with no .* is compared as an exact string and matches no tool, and that tools from a plugin-bundled server have a longer scoped name that a bare-server matcher never matches. Both hit a Sume server the same way.

Everything about hooks below is from Anthropic's hooks reference and MCP page, read 2026-09-29. Sume appears only as the example server: the MCP quickstart adds it as sume, so its tools are named like mcp__sume__generate_video.

Which matcher matches a whole Sume server?

Append .* to the server prefix. The page says the .* is required, because a matcher made only of exact-match characters is compared as an exact string. These four cover the usual cases:

From Anthropic's hooks reference, read 2026-09-29.
MatcherMatches
mcp__sume__.*Every tool from a server named sume
mcp__sumeNothing: compared as an exact string
mcp__sume__generate_videoThat one tool (exact name, underscores only)
mcp__.*__write.*Any tool starting with write on any server

Why does my hook work on a manual server but not a plugin's?

A plugin-bundled server gets a scoped segment. The form is mcp__plugin_<plugin-name>_<server-name>__<tool>, with any character outside A-Z, a-z, 0-9, _ and - replaced by _. For a plugin named sume-media that bundles a server keyed sume, the matcher is mcp__plugin_sume-media_sume__.*. The same scoped name is needed in a handler's if field, permission rules, a skill's allowed-tools and a subagent's tools.

An mcp_tool hook that calls a plugin's server names it plugin:<plugin-name>:<server-name>, not the bare key.

What other causes are there?

Work down this list before rewriting the hook. Each item is a documented behavior.

  • Server name with a hyphen: on Claude Code earlier than v2.1.195 a bare hyphenated prefix is read as an unanchored regex and can match more than you meant. The mcp__<server>__.* form works on every version.
  • Exit code 1 instead of 2: without valid JSON on stdout, exit 1 is a non-blocking error and the tool call goes ahead. Exit 2 blocks.
  • Hook script not found or not executable: the shell exits with a code like 127, which is non-blocking, so a mistyped path leaves a gate silently disabled.
  • Timeout: a hook that reaches its timeout is cancelled and does not block the call.
  • Wrong event: PreToolUse does not fire for files you reference with @, and mcp_tool hooks on SessionStart at launch are skipped because MCP servers are not up yet.
  • Hooks turned off: disableAllHooks: true in a settings file disables them, and a project's false overrides a user-level true.

How do I see what Claude Code actually loaded?

Type /hooks for a read-only browser of configured hooks. It lists each event with a count, and the detail view shows the matcher, type and source file, labeled User, Project, Local, Plugin or Session. If the hook you expect is missing there, the problem is the settings file, not the matcher.

The last part of the name is the tool id. Call tools_list on the server to see the ids; Sume's tools and gates docs say live tool ids use underscores, for example generate_video and jobs_wait.

Does a matching hook override my permission rules?

No. Anthropic's permissions page says deny and ask rules are evaluated whatever a PreToolUse hook returns, so a hook's allow cannot turn a denied Sume tool back on. For the allow-rule side, see Claude Code: allow MCP tools without approving every call.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume