【Claude Code 進階配置】#04 Hooks 與 MCP:事件驅動自動化與外部服務整合

測驗:Hooks 與 MCP — 事件驅動自動化與外部服務整合

共 5 題,點選答案後會立即顯示結果

1. 在 Claude Code 的 hooks 配置中,PreToolUse 事件的最常見用途是什麼?

  • A. 在 Session 結束時保存狀態
  • B. 自動格式化程式碼
  • C. 阻止危險指令的執行
  • D. 載入環境變數與恢復上下文

2. 請看下方的 hooks 配置片段,這段配置的功能是什麼?

{ “hooks”: { “PostToolUse”: [ { “matcher”: “Write|Edit”, “hooks”: [ { “type”: “command”, “command”: “npx prettier –write …” } ] } ] } }
  • A. 在寫入或編輯檔案前,先檢查檔案格式
  • B. 在寫入或編輯檔案後,自動用 Prettier 格式化
  • C. 在所有工具執行後,用 Prettier 格式化所有檔案
  • D. 在寫入或編輯檔案前,阻止不符合格式規範的操作

3. Hook 腳本回傳 exit 2 時,Claude Code 會怎麼處理?

  • A. 忽略錯誤並繼續執行
  • B. 顯示警告但不影響流程
  • C. 將 stdout 的內容回饋給 Claude
  • D. 阻止該動作,並將 stderr 的訊息回饋給 Claude

4. 如何區分 MCP 配置中的 stdio 類型與 HTTP 類型伺服器?

// 配置 A { “github”: { “command”: “npx”, “args”: [“-y”, “@modelcontextprotocol/server-github”] } } // 配置 B { “vercel”: { “type”: “http”, “url”: “https://mcp.vercel.com” } }
  • A. 有 "url" 的是 stdio 類型,有 "command" 的是 HTTP 類型
  • B. 兩者沒有區別,只是寫法不同
  • C. 有 "command" + "args" 的是 stdio(本機執行),有 "type": "http" + "url" 的是 HTTP(遠端服務)
  • D. 配置 A 是遠端服務,配置 B 是本機執行

5. MCP 工具在 hooks 的 matcher 中使用什麼命名格式?

  • A. mcp.伺服器名稱.工具名稱
  • B. mcp__伺服器名稱__工具名稱(雙底線分隔)
  • C. mcp-伺服器名稱-工具名稱(短橫線分隔)
  • D. mcp/伺服器名稱/工具名稱(斜線分隔)

一句話說明

Hooks 讓 Claude Code 在特定事件發生時自動執行腳本(像 Git hooks 那樣),MCP 讓 Claude Code 連接外部服務(GitHub、Supabase、Vercel 等);兩者結合,就能打造「AI 做完事,自動觸發下一步」的工作流。

前置知識

  • 已讀過本系列第 1-3 篇(Rules、Commands、Agents)
  • 知道 JSON 的基本語法
  • 聽過 CI/CD 的概念(「程式碼推上去後自動跑測試、自動部署」那種)

第一部分:Hooks — 事件驅動的自動化

Hooks 是什麼?

你可能用過 Git hooks — 在 git commit 之前自動跑 lint,在 git push 之前跑測試。Claude Code 的 Hooks 是同樣的概念:

當某個事件發生時,自動執行你指定的動作。

差別在於,Git hooks 只能掛在 Git 操作上,而 Claude Code hooks 能掛在 Claude 的整個工作流程上 — 從啟動 session、執行工具、到結束對話。

hooks 的生命週期

把 Claude Code 的工作流想像成一條時間線,hooks 就是你插在上面的「檢查站」:

Session 開始
  ↓
  ├── [SessionStart] ← 載入環境、初始化
  ↓
  使用者送出 prompt
  ├── [UserPromptSubmit] ← 可以攔截或加上下文
  ↓
  Claude 要用工具了
  ├── [PreToolUse] ← 工具執行「前」,可以阻止
  ↓
  工具執行完畢
  ├── [PostToolUse] ← 工具執行「後」,可以追加動作
  ↓
  Claude 準備停下來
  ├── [Stop] ← 可以阻止停下,讓它繼續做
  ↓
  Session 結束
  └── [SessionEnd] ← 清理、保存狀態
Code language: CSS (css)

所有事件類型一覽

你不需要全部記住,但看到配置時要能對照:

事件 什麼時候觸發 最常見的用途
SessionStart Session 啟動或恢復 載入環境變數、恢復上下文
UserPromptSubmit 使用者送出 prompt 驗證 prompt、加上下文
PreToolUse 工具執行前 阻止危險指令(最常用)
PostToolUse 工具成功執行後 自動格式化、跑型別檢查
PostToolUseFailure 工具執行失敗後 記錄錯誤、發通知
PermissionRequest 權限對話框出現時 自動同意/拒絕特定操作
Stop Claude 回答完畢 強制繼續(如檢查未完成)
SubagentStart 子代理啟動 注入上下文給子代理
SubagentStop 子代理結束 驗證子代理的輸出
PreCompact 上下文壓縮前 保存狀態快照
SessionEnd Session 結束 保存狀態、清理資源
Notification 送出通知時 自訂通知方式
TeammateIdle 團隊成員閒置 品質檢查
TaskCompleted 任務標記完成 驗證完成條件

讀懂 hooks 配置

hooks 配置放在 .claude/settings.json 中。結構是三層巢狀:

hooks 配置
  └── 事件類型(什麼時候觸發)
       └── Matcher 群組(過濾條件:哪些工具觸發)
            └── Hook 處理器(要做什麼事)

來看一個最小範例:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/block-rm.sh"
          }
        ]
      }
    ]
  }
}
Code language: JSON / JSON with Comments (json)

逐行翻譯:

"hooks": {                          // hooks 配置的開始
  "PreToolUse": [                   // 事件:在工具執行「前」
    {
      "matcher": "Bash",            // 過濾:只在 Bash 工具時觸發
      "hooks": [                    // 要做的事(可以有多個)
        {
          "type": "command",        // 類型:執行 shell 指令
          "command": ".claude/hooks/block-rm.sh"  // 跑這個腳本
        }
      ]
    }
  ]
}
Code language: JavaScript (javascript)

白話文:「每次 Claude 要執行 Bash 指令之前,先跑 block-rm.sh 這個腳本來檢查。

Matcher 怎麼運作?

Matcher 是正則表達式(regex),用來過濾「這個 hook 要對哪些工具生效」:

// 只對 Bash 工具生效
"matcher": "Bash"

// 對 Edit 或 Write 工具生效(用 | 代表「或」)
"matcher": "Edit|Write"

// 對所有 MCP 工具生效
"matcher": "mcp__.*"

// 對 memory 這個 MCP 伺服器的所有工具生效
"matcher": "mcp__memory__.*"
Code language: JavaScript (javascript)

不同事件的 matcher 過濾對象不同:

事件 matcher 過濾什麼 範例
PreToolUsePostToolUse 工具名稱 "Bash""Edit\|Write"
SessionStart 啟動方式 "startup""resume"
SessionEnd 結束原因 "clear""logout"
Notification 通知類型 "permission_prompt"

如果省略 matcher 或寫 "*",就是「全部都觸發」。

Hook 處理器的三種類型

Hook 有三種類型,看到 "type" 欄位就知道是哪一種:

1. Command(最常見)— 執行 shell 指令

{
  "type": "command",
  "command": ".claude/hooks/check-style.sh",
  "timeout": 30
}
Code language: JSON / JSON with Comments (json)

白話:「跑一個腳本,最多等 30 秒。」

2. Prompt — 讓 AI 判斷

{
  "type": "prompt",
  "prompt": "檢查這個操作是否安全:$ARGUMENTS",
  "timeout": 30
}
Code language: JSON / JSON with Comments (json)

白話:「把事件資訊丟給一個小 AI 模型,讓它判斷要不要放行。」

3. Agent — 讓 AI 用工具驗證

{
  "type": "agent",
  "prompt": "驗證所有單元測試都通過:$ARGUMENTS",
  "timeout": 120
}
Code language: JSON / JSON with Comments (json)

白話:「啟動一個子代理,它可以讀檔、搜尋,做完驗證再回報。」

Hook 腳本怎麼和 Claude Code 溝通

Hook 腳本透過 stdin(標準輸入)接收 JSON 資料,透過 exit codestdout 回傳結果:

Claude Code ──JSON──→ hook 腳本 ──exit code + stdout──→ Claude Code
Code language: JavaScript (javascript)

三種 exit code 的意思:

Exit Code 意思 效果
0 成功,放行 繼續執行
2 阻止 阻止該動作(stderr 回饋給 Claude)
其他 非阻塞錯誤 記錄錯誤但繼續

來看一個完整的 hook 腳本範例:

#!/bin/bash
# .claude/hooks/block-rm.sh
# 功能:阻止 Claude 執行 rm -rf 指令

# 從 stdin 讀取 JSON,取出 command 欄位
COMMAND=$(jq -r '.tool_input.command')

# 檢查指令是否包含 rm -rf
if echo "$COMMAND" | grep -q 'rm -rf'; then
  # 輸出 JSON 告訴 Claude Code:拒絕這個操作
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "危險指令 rm -rf 已被 hook 阻止"
    }
  }'
else
  exit 0  # 放行
fi
Code language: PHP (php)

逐段翻譯這個流程:

1. Claude 想執行 "rm -rf /tmp/build"
2. PreToolUse 事件觸發,matcher "Bash" 匹配成功
3. block-rm.sh 收到 JSON:{"tool_name": "Bash", "tool_input": {"command": "rm -rf /tmp/build"}}
4. 腳本發現 "rm -rf",回傳 deny
5. Claude Code 阻止執行,告訴 Claude 原因
Code language: JavaScript (javascript)

讀懂實戰配置

下面是一個真實專案的 hooks 配置片段。我會逐塊翻譯:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "node -e \"const i=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); const c=i.tool_input?.command||''; if(/^(npm run dev|yarn dev|python.*app\\.py)/.test(c) && !process.env.TMUX){process.stderr.write('請在 tmux 中執行 dev server');process.exit(2)}\"",
            "statusMessage": "檢查 dev server 環境..."
          }
        ]
      },
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "node -e \"const i=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); const p=i.tool_input?.file_path||''; if(/\\.(md|mdx)$/.test(p) && !/README|CHANGELOG/.test(p)){process.stderr.write('避免建立不必要的文件檔案');process.exit(2)}\"",
            "statusMessage": "檢查檔案路徑..."
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "node -e \"const i=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); const p=i.tool_input?.file_path||''; if(/\\.(js|ts|jsx|tsx)$/.test(p)){require('child_process').execSync('npx prettier --write '+p)}\"",
            "statusMessage": "自動格式化..."
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node scripts/hooks/check-console-log.js",
            "statusMessage": "檢查 console.log..."
          }
        ]
      }
    ],
    "SessionStart": [
      {
        "matcher": "startup",
        "hooks": [
          {
            "type": "command",
            "command": "node scripts/hooks/session-start.js",
            "statusMessage": "載入上下文..."
          }
        ]
      }
    ],
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node scripts/hooks/session-end.js",
            "statusMessage": "保存狀態..."
          }
        ]
      }
    ]
  }
}
Code language: JSON / JSON with Comments (json)

逐塊翻譯:

區塊 白話意思
PreToolUse + Bash 執行 Bash 前:如果是 dev server 指令但不在 tmux 裡,就阻止
PreToolUse + Write 寫檔前:如果是 .md 檔但不是 README/CHANGELOG,就阻止
PostToolUse + Write\|Edit 寫檔或編輯後:如果是 JS/TS 檔,自動跑 Prettier 格式化
Stop Claude 停下前:檢查修改的檔案裡有沒有忘記移除的 console.log
SessionStart + startup 新 session 啟動時:載入之前保存的上下文
SessionEnd Session 結束時:保存當前狀態

hooks 配置放哪裡?

位置 範圍 能分享嗎
~/.claude/settings.json 所有專案 不能,只在你的電腦
.claude/settings.json 單一專案 能,可 commit 進 repo
.claude/settings.local.json 單一專案 不能,被 gitignore

最佳實踐:團隊共用的 hook 放 .claude/settings.json,個人的放 .claude/settings.local.json


第二部分:MCP — 連接外部服務的協議

MCP 是什麼?

MCP 全稱 Model Context Protocol(模型上下文協議),是一個開放標準,讓 AI 工具(像 Claude Code)能連接到外部服務。

打個比方:

  • 沒有 MCP:Claude Code 只能讀寫你本機的檔案、跑 shell 指令
  • 有了 MCP:Claude Code 還能直接操作 GitHub PR、查 Supabase 資料庫、管理 Vercel 部署
你的問題: 「幫我看 PR #456 並提出改進建議」
    ↓
Claude Code ──MCP──→ GitHub 伺服器 → 取得 PR 內容
    ↓
Claude 分析 + 回覆
Code language: CSS (css)

MCP 配置長什麼樣?

MCP 配置可以放在 .mcp.json(專案根目錄,可 commit)或 ~/.claude.json(個人全域)。

最小範例:

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxxxxxxxxxx"
      }
    }
  }
}
Code language: JSON / JSON with Comments (json)

逐行翻譯:

"mcpServers": {                     // MCP 伺服器列表
  "github": {                       // 伺服器名稱(自己取的)
    "command": "npx",               // 用 npx 啟動
    "args": [                       // 啟動參數
      "-y",                         // 自動確認安裝
      "@modelcontextprotocol/server-github"  // GitHub MCP 套件
    ],
    "env": {                        // 環境變數
      "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxxxxxxxxxx"  // GitHub Token
    }
  }
}
Code language: JavaScript (javascript)

白話文:「用 npx 啟動 GitHub MCP 伺服器,用這個 token 來驗證身份。

兩種 MCP 伺服器類型

看到配置時,注意區分這兩種:

1. stdio 類型 — 本機執行的程式

{
  "github": {
    "command": "npx",
    "args": ["-y", "@modelcontextprotocol/server-github"],
    "env": {
      "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxx"
    }
  }
}
Code language: JSON / JSON with Comments (json)

特徵:有 commandargs。Claude Code 會在你電腦上啟動這個程式,透過 stdin/stdout 通訊。

2. HTTP 類型 — 遠端服務

{
  "vercel": {
    "type": "http",
    "url": "https://mcp.vercel.com"
  }
}
Code language: JSON / JSON with Comments (json)

特徵:有 "type": "http"url。Claude Code 透過網路連到遠端 MCP 伺服器。

讀懂完整的 MCP 配置

這是一個真實專案的 mcp-servers.json,包含多個常用服務:

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_PAT_HERE"
      },
      "description": "GitHub operations - PRs, issues, repos"
    },
    "supabase": {
      "command": "npx",
      "args": ["-y", "@supabase/mcp-server-supabase@latest", "--project-ref=YOUR_PROJECT_REF"],
      "description": "Supabase database operations"
    },
    "vercel": {
      "type": "http",
      "url": "https://mcp.vercel.com",
      "description": "Vercel deployments and projects"
    },
    "railway": {
      "command": "npx",
      "args": ["-y", "@railway/mcp-server"],
      "description": "Railway deployments"
    },
    "memory": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-memory"],
      "description": "Persistent memory across sessions"
    }
  }
}
Code language: JSON / JSON with Comments (json)

逐塊翻譯:

伺服器 類型 用途 需要什麼
github stdio 操作 PR、Issue、Repo GitHub Personal Access Token
supabase stdio 操作資料庫 Project Reference
vercel http 管理部署 OAuth 登入(透過 /mcp 指令)
railway stdio 管理部署 Railway Token
memory stdio 跨 session 記憶 不需要額外認證

MCP 的三個安裝 scope

claude mcp add 指令新增 MCP 伺服器時,--scope 決定配置放哪裡:

Scope 存放位置 誰能用 用途
local(預設) ~/.claude.json(專案路徑下) 只有你,只在這個專案 個人開發用
project .mcp.json(專案根目錄) 所有人(可 commit) 團隊共用
user ~/.claude.json(全域) 只有你,所有專案 個人常用工具

常用指令:

# 新增一個 HTTP 類型的 MCP 伺服器
claude mcp add --transport http github https://api.githubcopilot.com/mcp/

# 新增一個 stdio 類型,帶環境變數
claude mcp add --transport stdio --env GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxx github \
  -- npx -y @modelcontextprotocol/server-github

# 列出所有已配置的伺服器
claude mcp list

# 在 Claude Code 內查看狀態
/mcp
Code language: PHP (php)

環境變數展開

.mcp.json 支援環境變數,讓團隊共享配置但各自用自己的密鑰:

{
  "mcpServers": {
    "api-server": {
      "type": "http",
      "url": "${API_BASE_URL:-https://api.example.com}/mcp",
      "headers": {
        "Authorization": "Bearer ${API_KEY}"
      }
    }
  }
}
Code language: JSON / JSON with Comments (json)

翻譯:

${API_BASE_URL:-https://api.example.com}
↑ 如果 API_BASE_URL 環境變數有設定就用它,否則用預設值

${API_KEY}
↑ 必須設定這個環境變數,否則會報錯
Code language: JavaScript (javascript)

這樣 .mcp.json 可以安全地 commit 進 repo,每個人在自己的 .env 或 shell 裡設定自己的 key。


第三部分:Hooks + MCP 的協作

MCP 工具在 hooks 裡的名稱規則

當 MCP 伺服器連接上來,它提供的工具在 hooks 裡的命名格式是:

mcp__<伺服器名稱>__<工具名稱>
Code language: HTML, XML (xml)

例如:

mcp__github__search_repositories    ← GitHub 的搜尋 repo 工具
mcp__memory__create_entities        ← Memory 的建立實體工具
mcp__filesystem__read_file          ← Filesystem 的讀檔工具

所以你可以用 hooks 來監控或控制 MCP 工具的使用:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__github__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'GitHub 操作已記錄' >> ~/mcp-operations.log"
          }
        ]
      },
      {
        "matcher": "mcp__.*__write.*",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/validate-mcp-write.py"
          }
        ]
      }
    ]
  }
}
Code language: JSON / JSON with Comments (json)

翻譯:

規則 意思
mcp__github__.* 所有 GitHub MCP 工具操作前,記一筆 log
mcp__.*__write.* 任何 MCP 伺服器的寫入操作前,跑驗證腳本

實戰範例:commit 前自動安全檢查

這個範例結合 Hooks 來阻止危險的 git 操作:

配置(.claude/settings.json):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/git-safety.sh"
          }
        ]
      }
    ]
  }
}
Code language: JSON / JSON with Comments (json)

腳本(.claude/hooks/git-safety.sh):

#!/bin/bash
# 讀取 Claude 要執行的指令
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# 阻止強制推送到 main
if echo "$COMMAND" | grep -qE 'git push.*--force.*(main|master)'; then
  echo "禁止對 main/master 執行 force push" >&2
  exit 2
fi

# 阻止 hard reset
if echo "$COMMAND" | grep -q 'git reset --hard'; then
  echo "禁止 git reset --hard,請用更安全的方式" >&2
  exit 2
fi

# 提交前提醒檢查
if echo "$COMMAND" | grep -q 'git push'; then
  echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"ask","permissionDecisionReason":"即將 push,請確認變更內容"}}'
  exit 0
fi

exit 0
Code language: PHP (php)

流程解讀:

Claude 想執行 git push --force origin main
  ↓
PreToolUse 觸發 → matcher "Bash" 匹配
  ↓
git-safety.sh 收到指令
  ↓
發現 "force push" + "main"exit 2(阻止)
  ↓
Claude 收到錯誤訊息,不會執行
Code language: PHP (php)

注意三種回應方式:

# 1. 直接阻止
echo "原因" >&2
exit 2

# 2. 放行
exit 0

# 3. 讓使用者確認(彈出權限對話框)
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"ask","permissionDecisionReason":"理由"}}'
exit 0
Code language: PHP (php)

實戰範例:寫檔後自動跑測試(非同步)

有些 hook 不需要阻塞流程,可以在背景跑:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run-tests-async.sh",
            "async": true,
            "timeout": 300
          }
        ]
      }
    ]
  }
}
Code language: JSON / JSON with Comments (json)

關鍵是 "async": true

Claude 寫完檔案 → PostToolUse 觸發
                    ↓
              run-tests-async.sh 在背景跑
                    ↓
              Claude 繼續工作(不等測試跑完)
                    ↓
              測試跑完 → 結果在下一輪對話中回報
Code language: JavaScript (javascript)

第四部分:安全考量

Hook 腳本的安全最佳實踐

hooks 以你的使用者權限執行,等同於你在終端機跑任何指令。注意以下幾點:

必做:
- 永遠用引號包變數:"$VAR" 而非 $VAR
- 用絕對路徑或 "$CLAUDE_PROJECT_DIR" 指定腳本位置
- 檢查 .. 防止路徑穿越(path traversal)
- 避免處理 .env、.git/、金鑰等敏感檔案

知道就好:
- hooks 在 session 啟動時快照,中途修改不會立刻生效
- 中途被修改的 hooks 會觸發警告,需要在 /hooks 選單中審核
- 企業版可以用 allowManagedHooksOnly 限制只用管理員核准的 hooks
Code language: PHP (php)

MCP 伺服器的安全注意事項

必做:
- 不要把 API key 直接寫在 .mcp.json 裡(用環境變數)
- 第三方 MCP 伺服器未經 Anthropic 驗證,自行評估風險
- 別開太多 MCP 伺服器(官方建議不超過 10 個,以免佔用上下文窗口)

知道就好:
- MCP Tool Search 功能:當工具太多時,Claude Code 會自動按需載入
- 可用 MAX_MCP_OUTPUT_TOKENS 限制 MCP 輸出大小
- 專案層級的 .mcp.json 首次使用會要求確認
Code language: CSS (css)

Vibe Coder 檢查點

當你在專案裡看到 hooks 和 MCP 配置時,按這個順序確認:

看到 hooks 配置時:

1. 看「事件類型」→ 這是在什麼時候觸發的?
2. 看「matcher」→ 針對哪個工具或條件?
3. 看「type」→ 是 command(跑腳本)、prompt(AI 判斷)還是 agent(AI 用工具驗證)?
4. 看腳本內容 → exit 2 代表阻止,exit 0 代表放行
5."async": true 嗎?→ 是的話就是背景執行,不阻塞
Code language: PHP (php)

看到 MCP 配置時:

1."command" + "args" → 本機執行的 stdio 伺服器
2."type": "http" + "url" → 遠端 HTTP 伺服器
3."env" → 需要設定環境變數(通常是 API key)
4. 有 ${VAR} → 用環境變數展開,實際值在你的 shell 環境中
Code language: PHP (php)

常見配置模式速查

最後整理幾個你最可能遇到的配置模式:

模式 1:阻止危險操作

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{"type": "command", "command": "scripts/block-dangerous.sh"}]
    }]
  }
}
Code language: JSON / JSON with Comments (json)

模式 2:自動格式化

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Write|Edit",
      "hooks": [{"type": "command", "command": "npx prettier --write $(jq -r '.tool_input.file_path')"}]
    }]
  }
}
Code language: JSON / JSON with Comments (json)

模式 3:Session 狀態管理

{
  "hooks": {
    "SessionStart": [{
      "matcher": "startup",
      "hooks": [{"type": "command", "command": "scripts/load-context.js"}]
    }],
    "SessionEnd": [{
      "hooks": [{"type": "command", "command": "scripts/save-state.js"}]
    }]
  }
}
Code language: JSON / JSON with Comments (json)

模式 4:MCP 外部服務

{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/"
    }
  }
}
Code language: JSON / JSON with Comments (json)

模式 5:AI 品質閘門

{
  "hooks": {
    "Stop": [{
      "hooks": [{
        "type": "prompt",
        "prompt": "檢查所有任務是否完成:$ARGUMENTS。回傳 {\"ok\": true} 或 {\"ok\": false, \"reason\": \"原因\"}",
        "timeout": 30
      }]
    }]
  }
}
Code language: JSON / JSON with Comments (json)

小結

概念 一句話
Hooks 在 Claude Code 工作流的特定時間點自動執行腳本
Hook 事件 14 種事件涵蓋整個 session 生命週期
Matcher 用正則表達式過濾「對哪個工具觸發」
Hook 類型 command(跑腳本)、prompt(AI 判斷)、agent(AI 驗證)
Exit code 0 = 放行、2 = 阻止、其他 = 非阻塞錯誤
MCP 讓 Claude Code 連接外部服務的開放協議
MCP 類型 stdio(本機程式)vs HTTP(遠端服務)
Scope local(個人+專案)、project(團隊共享)、user(個人全域)
Hooks + MCP 用 hooks 監控/控制 MCP 工具,工具名稱格式 mcp__伺服器__工具

下一篇,我們將進入系列最終章:專案模板與整合實戰,把 Rules、Commands、Agents、Hooks、MCP 全部串起來,看一個完整的 Claude Code 專案配置長什麼樣。

進階測驗:Hooks 與 MCP — 事件驅動自動化與外部服務整合

測驗目標:驗證你是否能在實際情境中應用所學。
共 5 題,包含情境題與錯誤診斷題。

1. 你的團隊希望 Claude Code 在每次寫入 JS/TS 檔案後自動跑 ESLint,但不要阻塞 Claude 的工作流程。你應該怎麼配置? 情境題

  • A. 用 PreToolUse + matcher "Write",在寫入前跑 ESLint
  • B. 用 PostToolUse + matcher "Write|Edit",同步執行 ESLint
  • C. 用 PostToolUse + matcher "Write|Edit",加上 "async": true
  • D. 用 Stop 事件,在 Claude 停下時統一跑 ESLint

2. 你想讓團隊共用一套 MCP 配置(包含 GitHub 和 Vercel),但每個人用自己的 API key。最佳做法是什麼? 情境題

  • A. 每個人各自用 claude mcp add --scope local 手動新增,不共享配置
  • B. 在 .mcp.json 中用 ${API_KEY} 環境變數展開,commit 進 repo,各自在本機設定環境變數
  • C. 把 API key 直接寫在 .mcp.json 裡,commit 進 repo 方便團隊使用
  • D. 用 --scope user 把配置寫進 ~/.claude.json,再把這個檔案分享給團隊

3. 你想讓 Claude Code 在每次使用 GitHub MCP 工具前都記錄一筆 log,但不影響 Supabase 等其他 MCP 工具。matcher 應該怎麼寫? 情境題

{ “hooks”: { “PreToolUse”: [ { “matcher”: “???”, “hooks”: [ { “type”: “command”, “command”: “echo ‘GitHub MCP used’ >> ~/mcp.log” } ] } ] } }
  • A. "matcher": "github"
  • B. "matcher": "mcp__.*"
  • C. "matcher": "mcp.github.*"
  • D. "matcher": "mcp__github__.*"

4. 小華寫了一個 hook 腳本,想要在 Claude 執行 rm -rf 時阻止操作。但測試時發現 Claude 仍然成功執行了危險指令。請看下方腳本,問題最可能出在哪裡? 錯誤診斷

#!/bin/bash COMMAND=$(jq -r ‘.tool_input.command’) if echo “$COMMAND” | grep -q ‘rm -rf’; then echo “危險指令已被阻止” exit 1 fi exit 0
  • A. jq 指令寫錯了,應該用 jq -r '.command'
  • B. grep -q 無法匹配含空格的字串
  • C. 阻止操作應該用 exit 2 而非 exit 1,且錯誤訊息應輸出到 stderr
  • D. 腳本缺少 chmod +x 執行權限

5. 小明想在專案中配置 GitHub MCP 伺服器供團隊使用,但隊友回報連不上。請看配置檔,最可能的問題是什麼? 錯誤診斷

// .mcp.json(已 commit 進 repo) { “mcpServers”: { “github”: { “command”: “npx”, “args”: [“-y”, “@modelcontextprotocol/server-github”], “env”: { “GITHUB_PERSONAL_ACCESS_TOKEN”: “ghp_a1b2c3d4e5f6g7h8” } } } }
  • A. npx 指令不支援 MCP 伺服器,應該改用 node
  • B. Token 不應該寫死在 .mcp.json 裡;應改用 ${GITHUB_PERSONAL_ACCESS_TOKEN} 環境變數展開,每個人在本機設定自己的 token
  • C. .mcp.json 不支援 stdio 類型,必須改用 HTTP 類型
  • D. 缺少 "type": "stdio" 欄位,導致 Claude Code 無法辨識伺服器類型

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *