内容
# glm-worker-mcp
一个让 **Claude** 进行协调,**GLM-5.2 worker** 执行有界限的、机械的文件工作的工作服务器。Claude 通过一个工具调用委托子任务;GLM 运行自己的多回合循环,调用 **仅限文件** 的工具集,并返回结构化的、可验证的结果清单。目标是:将大量的 token 调用量转移到更便宜的模型,同时让 Claude 保留规划和验证能力。
与 deepseek-worker-mcp(一个 sibling 本地项目)具有相同的规格,但后端使用 GLM-5.2(z.ai)。
## 安全模型
工作服务器 **没有 shell 和代码执行能力** —— 仅限于读取、写入、编辑、全局搜索和 grep。由于没有任何代码执行,路径隔离(`resolve()` + `relative_to(workspace)`)是一个 **完整的文件系统边界**:没有编写脚本然后运行的逃脱方式,这是基于黑名单的沙盒容易出现漏洞的攻击向量。指向工作空间外部的符号链接会被过滤。
**您需要承担的剩余风险**:工作服务器读取的文件内容会被发送到 z.ai 的 API(`api.z.ai`)。请勿将敏感信息指向不希望传输的路径。`denylist`(默认为 `[".git"]`)会拒绝匹配的路径 —— 您可以通过添加秘密模式(例如 `.env*`、`*.pem`)来扩展它;显式设置 `"denylist": []` 则完全禁用。
## 安装
```powershell
# Windows
./install.ps1
```
```bash
# macOS / Linux
./install.sh
```
**需要 Python 3.10+**。安装程序会创建 `.venv`,安装软件包,编写 `~/.glm-mcp/config.json` 配置模板(询问您的密钥来自哪个平台 —— z.ai 或 bigmodel.cn —— 并提示输入密钥),将服务器注册到 Claude Code (`claude mcp add glm -s user`),并部署 `glm-worker` 技能和 `glm` 代理类型(`~/.claude/agents/glm.md`,用于将子代理分发到工作服务器)。重启 Claude Code 以加载两者。
## 配置 —— `~/.glm-mcp/config.json`
```json
{
"api_key": "...",
"model": "glm-5.2",
"max_turns": 50,
"workspace": "",
"allowed_tools": ["Read", "Write", "Edit", "Glob", "Grep"],
"denylist": [".git"],
"base_url": "https://api.z.ai/api/paas/v4",
"thinking": true,
"reasoning_effort": "max"
}
```
- `base_url` 根据平台而定:`https://api.z.ai/api/paas/v4`(z.ai,国际)或 `https://open.bigmodel.cn/api/paas/v4`(bigmodel.cn,中国大陆)—— 安装程序会询问。
两者都是按需付费的端点;Coding-Plan 密钥需要使用 `/api/coding/paas/v4` 变体。
- 环境变量覆盖:`GLM_API_KEY`(或 `ZAI_API_KEY` / `ZHIPUAI_API_KEY`)、`GLM_WORKSPACE`、`GLM_MODE`。
- 空 `workspace` 跟随 Claude Code 的启动目录(当前工作目录)。
- `allowed_tools` 与仅限文件的工具集相交 —— **Bash 永远无法启用**。
- `thinking` 启用 GLM-5.2 的思维链(`reasoning_content`);默认为 `reasoning_effort: "max"`。努力级别:`high` / `max`(GLM-5.2 仅暴露这两个)。
设置 `thinking: false` 或传递 `thinking="off"` 以节省纯机械工作的 token。GLM 的服务器端默认为开启思维,因此 "off" 会被显式发送为 `{"thinking": {"type": "disabled"}}`。
## 使用
在 Claude Code 会话中,只需描述一个有界限的机械任务;`glm-worker` 技能会指导 Claude 何时调用工具。或者检查健康状况:让 Claude 调用 `ping`。
每次调用的覆盖参数:`delegate_to_glm(task, context, model="glm-5.2[1m]", workspace="./src", thinking="off")`(每个参数都与默认值不同;`reasoning_effort` 在 `thinking="off"` 时被忽略)。
### 开启/关闭委托
- **软(指令)**:告诉 Claude *"自己做这个,不要委托"* / *"委托给 glm"*。即时生效,适用于对话中。
- **硬,在线(无需重启)**:让 Claude *"关闭 glm"* / *"开启"* —— 它会调用 `glm_set_mode` 工具(`on` / `off` / `auto`)。会话范围:覆盖持续到更改或服务器重启,然后恢复为启动默认值。`ping` 显示有效模式。
- **启动时**:使用 `GLM_MODE=off` 启动 Claude,使会话默认为关闭。
### 可选:自动将子代理工作路由到 GLM
技能涵盖 Claude 内联委托的子任务。要使 Claude 也自动将合格的 **子代理** 阶段路由到 `glm` 代理 —— 无需逐任务询问 —— 请将以下内容粘贴到您的全局 `~/.claude/CLAUDE.md`(或项目 `CLAUDE.md` 以将其范围限定为一个仓库):
```markdown
## 子代理/工作流 → GLM 路由
当为机械/批量阶段生成子代理时,您可以将其路由到 GLM-5.2 代理子代理而不是默认的 Claude 子代理 —— 通过以下任意一种方式:
代理工具:subagent_type: 'glm' # 机械/批量 -> GLM
工作流: agent(prompt, {agentType: 'glm'}) # 机械/批量 -> GLM
工作流: agent(prompt, {schema: VERDICT}) # 验证/判断/推理 -> Claude(默认)
**仅当满足以下所有条件时,才路由到 `glm` 代理:** 有界限、仅限文件(只需要 Read/Write/Edit/Glob/Grep)、高容量、机械/低变异性(转换是规则形状的,不是开放式的),并且具有廉价的 Claude 端验证门控。示例:批量提取、通过提供的词汇/映射的机械翻译(不是自由/习语翻译,这是推理)、跨多个文件的模式重构、从模板生成的代码、文件输出 ETL。
**仅限文件并不意味着无推理。** 如果逐项工作需要判断、分类、消歧义或设计决策,请将其保留在 Claude 上,即使它只触及文件。始终保留在默认 Claude 子代理上:验证、判断、合成、规划和需要 shell、web、代码执行或非琐碎推理的任何操作。
**永远不要将审计/审查/漏洞搜索路由到 GLM —— 没有例外。** 一致性审计、代码审查、开放式漏洞搜索和多类别分析是推理工作。"Claude 子代理不可用"(会话限制、配额)不是路由到 GLM 的理由。无论如何,请勿进行审查。`glm` 代理也拒绝这些任务形状。
**分片 + 增量输出。** 工作服务器有硬性回合上限(默认 50;每个读取/编辑/全局搜索都是一个回合)。将每个委托的大小控制在大约 <40 回合(大约 ≤10 个文件/分片)以内,并在并行中分发分片。任何生成输出文件的任务必须指示:首先创建文件,然后在每个文件/项目更新后更新 —— 永远不要在最后一次写入。
```
未自动安装:CLAUDE.md 是个人配置,自动路由是用户应有意选择启用的策略。
### 可选:使用钩子强制自动路由
上面的 CLAUDE.md 模块是建议性的 —— Claude 仍可能忘记路由合格的任务。要使路由 **强制**,请在 `~/.claude/settings.json` 中添加两个 `PreToolUse` 提示钩子(合并到现有的 `hooks` 对象中;不会自动安装)。每个钩子在工具调用前运行一个小型 LLM 分类器:
- **`Agent` 网关** —— 每个 Agent 工具调度都会进行分类。限定为机械/批量任务的通用代理类型会被拒绝,并附有指令以重新调度为 `subagent_type: 'glm'`。推理工作(审查、审计、验证、规划、需要 shell/web/测试)和命名代理类型(Explore、Plan、...)会直接通过。
- **`Workflow` 网关** —— 在运行前会检查整个工作流脚本。如果机械/批量 `agent()` 阶段缺少 `agentType: 'glm'`,则调用会被拒绝,并附有重写检查清单(将阶段路由到 glm,分片 ≤10 个文件,增量输出,关闭失败的 Claude 验证阶段)。
两个网关都允许失败并继续 (`continueOnBlock: true`),因此拒绝会将原因反馈给 Claude 进行重新调度,而不是终止回合。
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Workflow",
"hooks": [
{
"type": "prompt",
"prompt": "您是 Workflow 脚本的路由网关。钩子输入:$ARGUMENTS\n\n输入的 tool_input.script 是一个 JavaScript 工作流,它通过 agent(prompt, opts) 生成子代理。请根据以下规则决定机械批量阶段是否正确路由到 GLM 工作服务器。\n\n如果以下条件成立,则回答 ok=true(让工作流继续运行):\n- tool_input 没有脚本字段(通过 scriptPath 或 name 调用 —— 无法检查;允许)\n- 脚本中没有机械/批量阶段。机械/批量 = 有界限、规则形状、仅限文件工作:批量提取、通过提供的词汇/映射的机械翻译、跨多个文件的模式重构、从模板生成的代码、文件输出 ETL\n- 每个机械/批量 agent() 调用已传递 agentType: 'glm',并且每个此类阶段都后跟 Claude 验证阶段(没有 agentType: 'glm' 的 agent(),或显式结果检查代码)以将错误/OFF/空结果视为失败\n- 所有 agent() 调用都是推理工作:验证、判断、合成、规划、调试、研究、分析、分类、消歧义、设计决策或需要 shell/web/代码执行 — 这些必须留在默认 Claude 代理上\n- 您不确定\n\n仅当脚本明显包含一个或多个机械/批量 agent() 阶段未路由到工作服务器时,回答 ok=false(阻止以便编排器重写脚本)。\n\n如果阻止,您的原因必须是以下内容:\"工作流具有符合 GLM 条件的机械阶段未路由到工作服务器。请重写脚本:(1)为每个机械/批量 agent() 调用添加 agentType: 'glm';(2)分片到约 <=10 个文件/分片;(3)每个 glm 任务必须先创建输出文件,然后在每个项目更新后更新;(4)在每个 glm 阶段后跟随一个关闭失败的 Claude 验证阶段(错误/OFF/空清单 = 失败阶段,过滤掉);(5)将验证/判断/合成阶段保留在默认 Claude 代理上;(6)确认 mcp__glm__ping 报告 mode=on,然后重新提交。\"\n\n如果阻止,您的原因必须是以下内容:\"工作流具有符合 GLM 条件的机械阶段未路由到工作服务器。请重写脚本:(1)为每个机械/批量 agent() 调用添加 agentType: 'glm';(2)分片到约 <=10 个文件/分片;(3)每个 glm 任务必须先创建输出文件,然后在每个项目更新后更新;(4)在每个 glm 阶段后跟随一个关闭失败的 Claude 验证阶段(错误/OFF/空清单 = 失败阶段,过滤掉);(5)将验证/判断/合成阶段保留在默认 Claude 代理上;(6)确认 mcp__glm__ping 报告 mode=on,然后重新提交。\""
"continueOnBlock": true,
"timeout": 45,
"statusMessage": "检查工作流 GLM 路由..."
}
]
},
{
"matcher": "Agent",
"hooks": [
{
"type": "prompt",
"prompt": "您是子代理调度的路由网关。钩子输入:$ARGUMENTS\n\n根据以下规则决定此 Agent 调度是否应重路由到 GLM 批量工作服务器。\n\n如果以下任意条件成立,则回答 ok=true(让调度继续不变):\n- tool_input.subagent_type 已经是 \"glm\"\n- tool_input.subagent_type 命名为专用代理(Explore、Plan、claude-code-guide、statusline-setup、code-reviewer,以 \"caveman:\" 或 \"cavecrew\" 开头的任意名称)—— 即任何其他名称\n- 任务涉及任意推理工作:审查、审计、漏洞搜索、一致性检查、验证、判断、合成、规划、调试、研究、分析、分类、消歧义、设计决策或需要 shell/web/代码执行\n- 任务需要 shell、web 访问、代码执行、git 或测试\n- 任务是开放式、低容量或非规则形状的\n- 您不确定\n\n仅当以下所有条件成立时,回答 ok=false(阻止以便编排器重调度到 GLM):\n- 有界限、机械、规则形状的工作,变异性低\n- 仅限文件:只需要 Read/Write/Edit/Glob/Grep\n- 高容量/批量:批量提取、通过提供的词汇/映射的机械翻译、跨多个文件的模式重构、从模板生成的代码、文件输出 ETL\n- 输出的廉价 Claude 端验证是可能的\n\n如果阻止,您的原因必须是以下内容:\"符合 GLM 条件的机械任务。重调度为 subagent_type 'glm'。在调度前:确认 mcp__glm__ping 报告 mode=on;分片到约 <=10 个文件/调度;指示工作服务器先创建输出文件,然后在每个项目更新后更新;之后运行一个关闭失败的 Claude 验证阶段(错误/OFF/空清单 = 失败阶段)。\""
"continueOnBlock": true,
"timeout": 30,
"statusMessage": "检查 GLM 路由资格..."
}
]
}
]
}
}
```
注意:
- 需要部署 `glm` 代理类型 (`~/.claude/agents/glm.md` —— 安装程序会执行此操作)并且上述 CLAUDE.md 模块提供规则,拒绝消息会引用。
- 分类器在每次调用时运行在小型快速模型上;成本相对于错误路由的批量阶段可以忽略不计。
- 已知盲点:通过 `scriptPath`/`name` 调用工作流会未经检查(脚本文本不在钩子输入中),而拒绝是指令而非重写 —— 编排器模型执行重调度。CLAUDE.md 模块仍然涵盖两者。
- Claude Code 热加载 `~/.claude/settings.json` 如果它在会话启动时存在;否则打开 `/hooks` 一次或重启以加载网关。
## 结果清单
每次委托返回工作服务器的摘要以及:
- **更改的文件** (写入/编辑,带计数)
- 工作服务器做出的 **假设**
- **无法执行** (跳过/失败)
- **指标** (模型、回合、工具调用、token、持续时间)
始终通过读取更改文件的样本/运行测试来验证,然后再声明成功。
## 测试
```powershell
.venv\Scripts\python -m pytest tests/ -q
```
```bash
.venv/bin/python -m pytest tests/ -q
```
默认情况下离线运行。要对 `glm-5.2` 运行实时烟雾测试:
```powershell
$env:GLM_LIVE = "1"; .venv\Scripts\python -m pytest tests/test_live_smoke.py -q
```
```bash
GLM_LIVE=1 .venv/bin/python -m pytest tests/test_live_smoke.py -q
```
(需要设置 `GLM_API_KEY` 或 `ZAI_API_KEY`,否则会回退到跳过)