Skip to content

PreToolUse hook permissionDecision 'deny' not enforced for MCP server tool calls #33106

@serrurco

Description

@serrurco

Bug Description

PreToolUse hooks that return permissionDecision: "deny" are not enforced when the target tool is an MCP server tool. The hook fires correctly and returns a valid deny response, but the MCP tool call proceeds anyway.

Reproduction Steps

  1. Register a PreToolUse hook in ~/.claude/settings.json targeting an MCP tool:
{
  "hooks": {
    "PreToolUse": [
      {
        "hooks": [
          {
            "command": "/path/to/hook.sh",
            "type": "command"
          }
        ],
        "matcher": "mcp__my_server__my_tool"
      }
    ]
  }
}
  1. The hook script reads stdin and returns a deny decision:
#!/bin/bash
INPUT=$(cat)
echo "BLOCKED: reason here"
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"reason here"}}'
exit 0
  1. When Claude calls the MCP tool, the hook fires and returns deny, but the MCP tool call is executed anyway.

Expected Behavior

The MCP tool call should be blocked, and the model should see the deny reason — identical to how PreToolUse deny works for built-in tools (Bash, Read, Write, etc.).

Actual Behavior

The hook fires, returns permissionDecision: "deny", but the MCP tool call proceeds and succeeds. The deny decision is effectively ignored.

Context

This was discovered while running multiple Claude Code instances in tmux panes with an identity enforcement hook. The hook correctly detects when an agent tries to send a message as a different identity via an MCP-based messaging server, returns deny, but the message is sent anyway.

Verified:

  • Hook script works correctly when tested manually (echo '...' | hook.sh)
  • Hook IS registered with the correct matcher pattern
  • Built-in tool PreToolUse deny IS enforced (e.g., Bash hooks work)
  • MCP tool PreToolUse deny is NOT enforced

Environment

  • Claude Code CLI
  • Linux
  • MCP server type: HTTP ("type": "http")

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:hooksarea:mcpbugSomething isn't workinghas reproHas detailed reproduction stepsplatform:linuxIssue specifically occurs on LinuxstaleIssue is inactive

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions