AI coding agent admin guide·verified October 21, 2026

cursor enterprise hooks example

Deploy a Cursor hooks.json to every machine that blocks dangerous shell commands and MCP calls and fails closed. Schema verified October 2026.

the short answer

Deploy an enterprise hooks.json to the system path on every machine (/Library/Application Support/Cursor/hooks.json on macOS, /etc/cursor/hooks.json on Linux, C:\ProgramData\Cursor\hooks.json on Windows) with beforeShellExecution and beforeMCPExecution hooks that call your policy scripts. Set failClosed: true, because crashes and timeouts fail open by default. Enterprise plans can also distribute team hooks from the dashboard.

Enterprise path
macOS /Library/Application Support/Cursor/hooks.json
Default on failure
Crashes, timeouts and non-2 exits fail open, unless failClosed: true
Deny response
{"permission":"deny","user_message":"...","agent_message":"..."}
Team hooks
Dashboard, Enterprise only, sync about every 30 minutes
Run Mode allowlist
Documented as best-effort, not a security boundary

The Hooks File

{
  "version": 1,
  "hooks": {
    "beforeShellExecution": [
      { "command": "/opt/company/cursor-shell-policy.sh", "timeout": 10, "failClosed": true }
    ],
    "beforeMCPExecution": [
      { "command": "/opt/company/cursor-mcp-policy.sh", "timeout": 10, "failClosed": true }
    ]
  }
}

Shell Policy Script

#!/bin/bash
# beforeShellExecution: reads {"command", "cwd", ...} on stdin.
cmd=$(jq -r '.command // ""')
if printf '%s' "$cmd" | grep -Eq 'terraform[[:space:]]+destroy|git[[:space:]]+push.*--force|rm[[:space:]]+-rf[[:space:]]+/'; then
  printf '%s' '{"permission":"deny","user_message":"Blocked by company policy","agent_message":"This command is not allowed. Propose the change in a PR instead."}'
  exit 0
fi
printf '%s' '{"permission":"allow"}'

MCP Policy Script

Field names are snake_case: user_message and agent_message. Exit code 2 also denies; invalid JSON blocks. The MCP hook receives tool_name, tool_input and mcp_server_name; its command field, present only for stdio servers, is the server’s launch command, not the tool call. Both scripts need jq on every machine: with failClosed: true, a missing dependency blocks every call, so ship it with the scripts.

Failproof can run here too: the form failproofai config writes is failproofai --hook preToolUse --cli cursor in ~/.cursor/hooks.json, at user scope and without failClosed. For enforcement the user cannot remove, put that entry in the system hooks.json with failClosed: true. These are the pre-tool command forms failproofai config writes into each agent’s hook file: user scope, except Codex, which it writes to the managed /etc/codex/config.toml when it can run as root. They cover only the pre-tool gate. failproofai config also registers post-tool output redaction, prompt, stop and session events, so keep its install alongside any system entry. Placing them in the system or managed locations below, and keeping them there with MDM, is your configuration rather than a documented Failproof install path; talk to us about a managed deployment.

#!/bin/bash
# beforeMCPExecution: reads {"tool_name", "tool_input", "mcp_server_name", ...} on stdin.
input=$(cat)
server=$(printf '%s' "$input" | jq -r '.mcp_server_name // ""')
tool=$(printf '%s' "$input" | jq -r '.tool_name // ""')
case "$server:$tool" in
  github:*|docs:*) printf '%s' '{"permission":"allow"}' ;;
  *) printf '%s' '{"permission":"deny","user_message":"MCP server not approved","agent_message":"This MCP tool is not on the company allowlist."}' ;;
esac

Cursor’s Other Admin Controls

ControlWhereNote
Run Mode (Auto-review, Allowlist, Run Everything)Team dashboard policy (Cursor 3.6+)Allowlist is best-effort
terminalAllowlist, mcpAllowlist, autoRun~/.cursor/permissions.json, deployable by MDMUser-writable, and concatenated with a per-repo .cursor/permissions.json, so users and repositories can extend it unless the team dashboard sets that category
MCP allowlistTeam dashboard, MCP Configuration (Enterprise)Matches full command string or URL
Privacy ModeEnforced at team level; AllowedTeamId as MDM backstopOn by default for Enterprise

FAQ

Can developers remove the enterprise hooks?

The system path needs admin rights to change. All matching hooks run: enterprise, team, project and user.

Do hooks see the agent’s prompts?

A beforeSubmitPrompt hook receives the prompt and can stop it with {"continue": false}.

Does `preToolUse` support ask?

Cursor documents ask as not enforced for preToolUse; use deny or allow.

Sources

Checked against the sources below on October 21, 2026. Harness settings, hook capabilities and cloud features change between versions.

  1. Cursor docs: Hooks
  2. Cursor docs: Enterprise deployment patterns
  3. Cursor docs: Model and integration management
  4. Cursor docs: Compliance and monitoring
  5. Failproof AI docs: Agent harnesses and enforcement capability