﻿---
title: "钩子要调 MCP，用 type mcp_tool，不要再包一层 shell"
summary: "server / tool / input 直接打到已连接的 MCP。服务器没起来不会拦操作。prompt 和 agent 类型会解析但跳过。"
category: hooks
level: advanced
surfaces: [cli]
tags: ["hooks", "mcp_tool", "MCP"]
canonical: /tips/mcp-tool-hook/
---

# 钩子要调 MCP，用 type mcp_tool，不要再包一层 shell

server / tool / input 直接打到已连接的 MCP。服务器没起来不会拦操作。prompt 和 agent 类型会解析但跳过。

生命周期钩子可以直接调 MCP，不必再写 `npx …` 包装。JSON 示例：

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "mcp_tool",
            "server": "scanner",
            "tool": "scan_patch",
            "input": { "patch": "${tool_input.command}" },
            "timeout": 30,
            "statusMessage": "Scanning edited files"
          }
        ]
      }
    ]
  }
}
```

`server` 必须是已经连上的 MCP 名。钩子不会替你启动或重连。`input` 里用 `${field.nested}` 从事件取值：整段占位保留 JSON 类型，嵌在字符串里就变成文本。

官方约束：

- 只跑 `command` 和 `mcp_tool`。`prompt` / `agent` 写了也不会执行
- `mcp_tool` 始终同步，不走工具批准，也不会再触发别的钩子
- 超时取钩子 `timeout` 和服务器 `tool_timeout_sec` 里较短的那个
- `SessionEnd` 不支持 `mcp_tool`；`SessionStart` 可能在 MCP 就绪前就跑，那时不会拦会话
- 工具返回 block 才会拦住操作。缺服务器、连不上、工具不存在、执行报错都不拦

不要把 `mcp_tool` 的 Stop 当成合规完成门。服务器没配或起不来时，`codex exec --json` 仍可能直接 `turn.completed`。讨论中的 failureMode 还没落地，不要抄进配置。真正的门继续用能 exit 2 / 返回 deny 的 `command` 钩子，并自己确认 MCP 已在 `/mcp` 里。

先 `codex mcp add` 再信任钩子。新开会话后 `/hooks` 应能看到 server 和 tool 字段。

## 来源

- [OpenAI · Hooks](https://learn.chatgpt.com/docs/hooks)
- [openai/codex#39858](https://github.com/openai/codex/issues/39858)
