Skip to main content
Glama
opera-houdini-mcp

opera-houdini-mcp

by ChengZiiii

opera-houdini-mcp

License: MIT Python MCP Upstream

opera-houdini-mcp 是 capoomgit/houdini-mcp 的独立增强 fork,定位为可作为 git submodule 嵌入到任意 Houdini 插件库的 MCP server。MIT 协议,与上游完全兼容,额外提供 Tier 1 工具集、execute_code 安全护栏、零新增 pip 依赖。

当前上游基线:capoomgit/houdini-mcp @ de4fd93(2026-07-17 同步) 同步策略:cherry-pick only,禁止 merge 集成方式:作为 git submodule 嵌入到消费方 Houdini 项目(见 §3)


目录

  1. Features

  2. Architecture

  3. Embedding as a git submodule

  4. Tier 1 工具清单

  5. 自进化知识库

  6. RAG 文档检索与版本化索引

  7. Console 日志与命令审计

  8. AI 调用引导

  9. execute_code 安全模型

  10. AI 调用 hou API 的硬约束

  11. Configuration

  12. Upstream Sync Policy

  13. Testing

  14. Troubleshooting

  15. Edge Cases & 集成陷阱

  16. Contributing

  17. Security

  18. License & Acknowledgement


Related MCP server: Houdini MCP Server

Features

  • 176 个已注册 MCP 工具(feat-mcp-console-log-audit 后口径:houdini_mcp_server.py 中活动的 @mcp.tool 装饰器数,即 AI 工具 tools/list 可见数(174 + get_console_log / clear_console_log);另有 9 个工具的装饰器按 slim-mcp-toolset 计划注释停用——6 个 OPUS 资产 + 3 个 base64 渲染——不计入)

  • 13 个 Tier 1 工具 — 场景 CRUD / 节点发现 / 图编辑 / 错误扫描(含 warnings)/ 几何摘要 / 材质 / 截图 / 文档查询 / 缓存管理 / 诊断,独立模块化

  • execute_code 三档安全 policy — read-only / normal / privileged × dangerous / heavy / mutation 三类黑名单(正则 + AST 别名双检)

  • 双开关 bypass — 任何 dangerous / heavy / privileged 操作都需「请求端参数 + 服务端 HOUDINI_MCP_ALLOW_BYPASS=1」同时开启

  • 零新增 pip 依赖 — get_houdini_help 用 stdlib html.parser 替代 beautifulsoup4,维持 mcp[cli]==1.12.2 + requests + python-dotenv 三件套

  • 结构化 audit — 每次 execute_code 响应附 _audit 块(policy / dangerous_hits / heavy_hits / mutation_hits / bypass_used / elapsed_ms / undo_group)

  • local-help-first — get_houdini_help / verify_hou_api 优先打 Houdini 本地 help server(127.0.0.1:48626),失败自动回退在线 SideFX

  • 自进化知识库 — 6 个 bridge-local 知识工具(search_lessons / save_lesson / read_lesson / knowledge_stats / capture_workflow_snapshot / save_recipe)+ 自动错误捕获 hook(零上下文成本);多 root(个人库自动发现 + 团队库注册表声明,默认只读);无嵌入模型(BM25 + 指纹 + 统计,全 stdlib)


Architecture

flowchart LR
    A[AI Agent<br/>Claude Desktop / Cursor / ...] -->|stdio / MCP JSON| B[houdini_mcp_server.py<br/>bridge]
    B -->|TCP 127.0.0.1:9876| C[server.py<br/>HoudiniMCPServer]
    C -->|hou API| D[Houdini main thread<br/>H21+ / Python 3.11+]
    D -.->|hou.helpServerUrl| E[Local help server<br/>127.0.0.1:48626]
    E -.->|F1 失败 fallback| F[SideFX online docs]
    C -->|RAG index build| G[scripts/build_rag_index.py]

关键约束:

  • server.py 必须运行在 Houdini 主进程内(hou 是 C 扩展,跨进程 import 会 hang)

  • bridge(houdini_mcp_server.py)与 server 通过 TCP 127.0.0.1:9876 通信,每次 tool call 短连接

  • AI 工具看到的 MCP tool 列表来自 bridge 端(mcp[cli] SDK),实际 hou 调用发生在 Houdini 进程内


Embedding as a git submodule

1. 添加 submodule

# 在你的 Houdini 插件库根目录
git submodule add https://github.com/ChengZiiii/opera-houdini-mcp.git external/houdinimcp
git submodule update --init --recursive

2. 隔离 Python 环境

opera-houdini-mcp 与你项目里的其他工具运行环境解耦。建议目录布局:

<your-project>/
├── external/
│   ├── houdinimcp/                  # 本仓库(submodule)
│   ├── houdinimcp-env/              # 本仓库专用的 venv(python/ + pylibs/)
│   ├── <other-tool>/                # 你的其他第三方工具
│   └── <other-tool>-env/            # 各工具独立环境,互不冲突

<dirname>-env/ 不要提交进 git。env 目录名 = package 目录名 + -env,自动派生,详见 Configuration。如果你把 submodule 改名为 external/opera-houdini-mcp/,env 自动变成 external/opera-houdini-mcp-env/,跟着 rename 一下就行。

环境初始化细节(python/ 解释器 + pylibs/ 依赖)由消费方项目侧决定,可参考 pyproject.toml 的 dependencies 三件套自行装配,或用 uv pip install -p <venv-python> mcp[cli]==1.12.2 requests python-dotenv 一行命令起步。

3. 启动 server

从你的项目代码里直接 import houdinimcp 包:

import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "external"))

from houdinimcp import start_server, stop_server, is_server_running

# 启动(默认 127.0.0.1:9876)
start_server()

if is_server_running():
    print("opera-houdini-mcp is up")

houdinimcp 包对外暴露的完整 API:

函数

用途

start_server(host='127.0.0.1', port=9876)

启动 TCP server(幂等,重复调用早退)

stop_server()

停止 server

restart_server(host, port)

stop + start

is_server_running() -> bool

查询状态

initialize_plugin()

一次性初始化 hou.session 标志位

4. 配置 AI 工具

任一兼容 MCP 的客户端(Claude Desktop / Cursor / ZCode / OpenCode / Codex):

{
  "mcpServers": {
    "houdini": {
      "command": "uv",
      "args": [
        "run",
        "python",
        "<your-project>/external/houdinimcp/houdini_mcp_server.py"
      ]
    }
  }
}

MCP JSON key 固定为 houdini(mcpServers.houdini / mcp.houdini / mcp_servers.houdini 三种形式都接受),与上游完全兼容,老用户配置零改动。

5. 升级 submodule 消费者

git submodule update --remote external/houdinimcp
git submodule sync

无需重装 env —— 运行环境独立放在 external/<工具名>-env/ 下,与源码完全解耦。


Tier 1 工具清单

以独立 PR 形式合入。完整计划与进度见 CHANGELOG.md。

类别

工具

说明

场景

get_scene_info

增强版场景元信息(houdini_version / node_count)

场景

save_scene / load_scene / new_scene

场景 CRUD,自动失效缓存

节点发现

list_node_types

按 category 过滤 + name 模糊匹配 + 分页

节点发现

list_children

递归子树 + compact 模式 + 分页

节点发现

find_nodes

glob + 类型过滤,Houdini 端单次扫描

图编辑

reorder_inputs / layout_children / set_node_position / set_node_color / create_network_box

节点位置/颜色/网络盒

节点信息

get_node_info

增强:errors / cook_state / compact / input details

错误扫描

find_error_nodes

默认含 warnings,单次 allSubChildren 扫描

几何

get_geo_summary

counts / bbox / attributes / groups + 大几何降级

材质

create_material / assign_material / get_material_info

50+ 参数白名单 + texture 引用识别

HScript

execute_hscript

包装 hou.hscript

安全代码

execute_code

三档 policy + bypass 双开关 + 结构化 audit

安全代码

get_last_scene_diff

仅 mutation 模式提供前后场景快照

截图

capture_pane_screenshot / render_node_network / list_visible_panes / capture_multiple_panes

pane 截图,响应走 apply_response_cap

渲染

render_single_view / render_quad_views / render_specific_camera

路径版渲染(落盘 image_path);render_viewport_base64 / render_quad_views_base64 / render_specific_camera_base64 已注销注册(slim-mcp-toolset;恢复 = 取消对应 @mcp.tool() 注释);缺 OGL 3.3 环境经 render policy redirect 到视口截图

渲染 policy

start_render / monitor_render

ROP 同步渲染(四层防御 + consent token)+ husk/mantra OS 进程 best-effort 监控(bridge-only)

文档

get_houdini_help

本地 help server 优先 + 在线 SideFX 回退(stdlib urllib + html.parser);返 _source / _fallback_reason

文档

verify_hou_api

python_hou 默认 + _ai_hint 合成,AI-friendly wrapper over get_houdini_help

诊断

check_connection / ping_houdini

不持久化连接的 ping

缓存

manage_cache

stats / invalidate / warmup

知识库

get_best_practices

fork 人工审查 advisory recipes(bridge-local,不建立 Houdini 连接)

知识库

search_docs / get_doc / parse_hip_offline

BM25 离线文档检索 / 全文 / 离线 .hip 解析

知识库

search_lessons / save_lesson / read_lesson / knowledge_stats / capture_workflow_snapshot / save_recipe

自进化知识沉淀:跨 root BM25 融合检索 / 沉淀 / 全文 / 统计 + 工作流快照 / recipe 写入


自进化知识库

agent 操作 Houdini 的试错经验跨 session 持久化为可检索 lesson(模块 _lessons.py + _lessons_search.py,纯 stdlib、无嵌入模型)。触发时机:遇到报错、重试第 2 次 仍未解决、或遇到不认识的 API/参数时,先 search_lessons 检索既往经验;命中后用 read_lesson 拉全文;解决问题后用 save_lesson 沉淀。lesson 是 advisory,不替代 verify_hou_api / get_houdini_help / get_best_practices。

自动捕获(零上下文成本):bridge 在响应出口检测 status=error 响应,把错误 事件以 append-only 方式写入个人库 inbox/events.jsonl(同指纹去重、≥3 次自动生成 draft 骨架并在检索时提示「已踩 N 次,请补充 fix」)。

存储位置(全部在个人目录 ~/.opera-houdini-mcp/,不入仓库 git):

~/.opera-houdini-mcp/
├── config.json              # 注册表(仅声明额外团队 root,个人库自动发现)
├── knowledge/
│   ├── lessons/*.md         # draft + published lesson(9 字段 + id/status/strength/root/时间戳)
│   ├── recipes/BEST_PRACTICES.md   # 个人人工 recipes(可空)
│   └── inbox/events.jsonl   # 自动捕获原始事件
└── cache/index/<root-name>/ # 各 root BM25 索引缓存

团队库注册(config.json,可选):path 接受三种形式——${VAR} 环境占位符、 相对路径(相对 ~/.opera-houdini-mcp/)、或绝对路径(Windows 盘符 C:\ / C:/、 POSIX 前导 /、UNC \\server\share、前导 \)。绝对路径支持团队协作中各成员 NAS 映射盘符不同的场景——config.json 是本机配置(位于 ~/.opera-houdini-mcp/,每台 机器各一份),各成员各自写自己盘符的绝对路径即可,无需统一环境变量,无跨机器误导。 writable 默认 false(AI 只读,晋升人工把关);占位符未定义 → unconfigured 静默跳过,路径不可达(绝对/相对路径指向的目录不存在、或占位符已定义但目录不可读) → unavailable 跳过并附 _warning,均不影响个人库。含 ${ 但非纯占位符的混合 形式(如 ${VAR}/sub)仍被拒绝。

[
  { "name": "team_knowledge", "path": "${TEAM_SHARE}/houdini/knowledge", "priority": 0.8, "writable": false }
]

团队协作 NAS 示例(各成员盘符不同,各自在本机 config.json 写绝对路径;同事若 把同一 NAS 映射到其他盘符,则改成自己的盘符即可):

[
  { "name": "team_knowledge", "path": "Z:\\team\\houdini\\knowledge", "priority": 0.8, "writable": false }
]

RAG 文档检索与版本化索引

search_docs / get_doc(BM25 跨文档检索)面向「跨文档主题检索」,与 get_houdini_help / verify_hou_api(单条 API 结构化查询)互补。索引产物按 Houdini 版本隔离(versioned-rag-index):多版本共存互不覆盖,Houdini 升级后 自动为新版本构建全量索引。

双进程架构(检索与路由全部在 bridge 进程,env 不跨进程边界):

AI 客户端 ──stdio── bridge(houdini_mcp_server.py + _rag.py + _rag_lifecycle.py)
                      │  无 hou、无 HFS;LRU/BM25/预热都在此进程
                      │  版本路由:TCP 查 get_scene_info(hou_version + hfs_path)
                      │            → 进程内设 HOUDINI_MCP_RAG_INDEX_DIR
                      └──TCP 9876── server(server.py,Houdini GUI 进程,import hou)

目录布局(个人目录,不入 git):

~/.opera-houdini-mcp/rag/
├── 21.0.596/                # 每个 Houdini 版本一个目录,互不干扰
│   ├── index.v1.json        # 全量索引(H21:46 zip / 10,093 docs / 27.7 MB)
│   ├── build.status.json    # 构建状态(state/started_at/finished_at/pid/...)
│   └── eval/                # 评测报告落点(eval_rag.py 默认 out-dir)
├── 22.0.100/                # H22 升级后首次使用时自动构建
└── index.v1.json.legacy-5zip-20260909   # 旧 flat 索引封存(内容保留,不迁移)

生命周期(首次 RAG 工具调用时 lazy 触发,_rag_lifecycle.py):

  1. 版本路由:bridge 经 TCP 向 server 查 get_scene_info 取 houdini_version + hfs_path → 设 env 指向 rag/<ver>/(进程内一次, 粘滞)。server 不在线 → 回退 flat 解析序,30s 后重试;手工预设 env 则整体跳过。

  2. 封存:rag 根存在旧 flat 索引且版本目录无索引 → 改名 .legacy-5zip-20260909(内容保留;它是 5-zip 局部快照,迁移等于把 11% 覆盖合法化)。幂等,失败仅警告。

  3. 自动构建:版本目录无索引 → 独占 build.lock + 二次探测 → detached 无窗口子进程(bridge 内嵌 Python 3.12,CREATE_NO_WINDOW,零端口)跑 scripts/build_rag_index.py --source $HFS/houdini/help --output <verdir>; 状态文件 pid 探活 + 300s 龄期双判据防并发/自愈;H21 全量构建实测 ~7.5s。

  4. 预热:daemon 线程 load_index()(27.7MB 加载 ~2.9s,绝不上事件循环—— FastMCP 同步工具直接跑在事件循环上);构建完成后 watcher 自动 re-preheat。

envelope 语义(只加字段不改签名,现有消费者零影响):构建中 → rag_index_missing + building: true + eta_hint(本轮回退 get_houdini_help);预热未完 → rag_index_warming_up + warming_up: true (快速返回,不阻塞 bridge)。

eval 门禁(scripts/eval_rag.py + scripts/rag_gold_set.json,随 submodule 入库的 scripts/rag_baseline.json 为 H21 基线:MRR 0.4040 / hit@10 0.70):

# 对任意索引评测(报告默认落 <index 目录>/eval/,Markdown+JSON)
python scripts/eval_rag.py --index ~/.opera-houdini-mcp/rag/21.0.596/index.v1.json

# 与基线对比(可比性指纹判定:gold hash 相同且 zip 差异仅新增才可比)
python scripts/eval_rag.py --index <idx> --baseline scripts/rag_baseline.json

# 新版本索引定新基线
python scripts/eval_rag.py --index <idx> --write-baseline scripts/rag_baseline.json

门禁双层判据(整体 MRR 降幅 > 0.05 红 + RR 降幅 > 0.3 条目占比 ≥ 25% 红)+ gold_missing 守卫(> 2 条或 > 10% 红)+ 双向告警(MRR 异常升高黄灯,污染/ 分母逃逸形态);告警不阻断构建。注意:5-zip 旧索引的 MRR 与全量不可比 (分母逃逸,实测 14/30 条 gold_missing 时 MRR 反而虚高)。

手工构建(不依赖 bridge 自动链):

python scripts/build_rag_index.py --source "$HFS/houdini/help" --version-dir 21.0.596
# 默认 zip 集 = help 目录全部 *.zip 减排除清单(images);--zips 可覆盖

Console 日志与命令审计(feat-mcp-console-log-audit)

两个旁路能力:AI 排障取证(console 日志)+「AI 让 Houdini 干了什么」的事后追溯(命令审计)。

Console 日志(server 侧)

  • get_console_log(READ_ONLY):读 Houdini 进程内 Python 层 console 环形缓冲。 参数 offset / limit(分页)、tail(末尾 N 条)、last_seconds(时间窗,优先于 tail)。 envelope {status, lines, offset, limit, total, filter_mode, truncated} 过 apply_response_cap; 每行 {ts, ts_iso, stream, text}(stream 区分 stdout / stderr)。

  • clear_console_log(NO_UNDO):清空缓冲,返回清空前条数。

  • 覆盖边界:tee 只包装 Python 层 sys.stdout / sys.stderr(print、Python traceback、 execute_code 捕获输出自动同步入缓冲);不覆盖 Houdini 原生 C++ 层输出与独立 hython 进程输出。

  • 典型用法:AI 遇到报错时截图(视觉证据)+ get_console_log(last_seconds=120)(文本证据)联合定位。

  • 关闭开关:HOUDINI_MCP_CONSOLE_LOG=0 时启动完全跳过 tee 安装(缓冲恒空,两工具仍可调但无数据)。

命令审计(bridge 侧 JSONL)

  • bridge 进程内每次 MCP 工具调用(全部工具,含 bridge-local 与只读查询)在结束时 append 一行 JSON 到 $TEMP/houdini_mcp/audit/audit-<yyyymmdd>-<seq>.jsonl; 字段:ts(ISO8601 毫秒)/ session_id(bridge 进程 UUID4)/ tool / ok(响应 status == "success" 判定;str 响应按成功记)/ duration_ms / args(≤256 截断), 失败附 error_code / error_message。

  • 分段与保留:空闲超 15 分钟开新段(seq 续接当日最大,重启不覆盖);保留上限 30 段,超限删最旧。

  • 旁路语义:落盘失败(磁盘满 / 权限)仅进程内 warning,绝不影响工具调用;审计内容不注入任何响应。

  • 隐私边界:args 摘要可能含用户本机路径,本机单用户信任边界内不脱敏;文件仅供人工与离线分析。

  • v1 只记录不重放:不提供任何重放/回放工具(读回、重执行历史命令);重放为未来扩展,引入时另立 change。

env

环境变量

默认

作用

HOUDINI_MCP_CONSOLE_LOG_LINES

4000

console 环形缓冲行数

HOUDINI_MCP_AUDIT_DIR

$TEMP/houdini_mcp/audit

审计目录覆盖

HOUDINI_MCP_AUDIT_KEEP

30

审计保留段数

HOUDINI_MCP_AUDIT_SEGMENT_MIN

15

审计分段间隔(分钟)


AI 调用引导(feat-mcp-tool-guidance)

把「引导 AI 正确使用这套 MCP」内建到协议元数据与返回文本本身(用户工作区外 AGENTS.md 不可控,MCP 必须自带行为契约)。四个机制:

Tool annotations(三分类映射)

  • _tool_annotations.py 在 bridge 启动时后处理全部工具的 annotations: 以 server 命令三分类为锚——READ_ONLY 工具 readOnlyHint=true(含 idempotentHint=true);破坏性语义(节点删除 / 场景载入新建 / execute_code 变更档 / 磁盘清写类,12 个)destructiveHint=true;其余变更类显式 readOnlyHint=false, destructiveHint=false。

  • 对账测试双向守卫:annotations 注册表 ↔ server 三分类集合(含 7 对 bridge 工具名 ↔ server 命令名改名映射),任一侧增删都会红。

  • 规范语义:annotations 是对客户端的提示而非安全边界;权威执行层仍是 server 三分类 + render policy。

instructions 行为契约

initialize 响应的 instructions(≤1200 字符)承载四要点:专用工具优先 / execute_code 最后手段、写 hou API 前先 verify_hou_api、遇错或第 2 次重试 失败先查 search_lessons / get_best_practices、渲染走 start_render + 截图取证用 capture_pane_screenshot。

execute_code 失败引导(_ai_hint / _hint)

  • 返回文本含 hou.* 异常模式(Traceback / Stderr 段)时,末尾追加 _ai_hint: 行——列出提取到的 API 名(去重 ≤3)+ verify_hou_api / get_houdini_help 指引;无 hou.* 模式不追加(零噪音)。

  • 会话内 execute_code 调用达到阈值(默认 5)后每次返回追加 _hint: 行, 提示 set_parameters / create_wrangle / connect_nodes / batch 替代。 HOUDINI_MCP_EXEC_HINT_THRESHOLD=0 关闭。

  • hint 为文本行追加(返回仍为 str,不改 envelope 形态)。

描述瘦身与 lint

全部工具 description 两层拆分:调用方信息(何时用 / 参数 / 边界 / 失败先查 什么)留 docstring;实现备忘(PR 编号 / 设计史 / 路径怪癖)搬家到函数体注释。 tests/test_tool_description_lint.py 守卫:pattern 禁令(PR \d / issue 号 / change 代号 / §)+ 长度上限(默认 ≤1200 字符)+ help 类首行触发时机 + 备忘搬家抽查(20 工具跨五批)。


execute_code 安全模型

Policy

mutation

dangerous

heavy_geometry

import hou

默认 bypass

read-only

拒绝(命中 mutation 正则/AST)

拒绝

拒绝

拒绝

—

normal(默认)

允许

拒绝(除非 allow_dangerous=True)

拒绝(除非 allow_heavy_geometry=True)

提示

仅在客户端显式开启

privileged

允许

允许(必须同时开启 allow_dangerous=True 和 HOUDINI_MCP_ALLOW_BYPASS=1)

允许(必须同时开启 allow_heavy_geometry=True 和 HOUDINI_MCP_ALLOW_BYPASS=1)

允许

必须服务端环境变量

双开关原则:任何 dangerous / heavy / privileged 操作都需要「请求端参数 + 服务端环境变量」同时开启。服务端不开环境变量,再多客户端请求也无效。

Audit:每次 execute_code 调用都会在响应里附 _audit 块(policy / dangerous_hits / heavy_hits / mutation_hits / bypass_used / elapsed_ms / undo_group / exception)。

超时:执行超时不会自动 hou.undos.performUndo(),避免误回滚正常操作。客户端需根据 _audit.elapsed_ms 自行决定。


AI 调用 hou API 的硬约束

任何 AI agent 通过 execute_code 调用 hou API 之前 MUST 先 verify。hou 是 C 扩展,跨 major version 间会重命名 / 废弃 / 新增方法。假定跨版本 hou API 等价 = bug 风险(hang / type-check 失败 / 行为不一致)。

正确工作流:

  1. 调 verify_hou_api('Class.method') 先看 _ai_hint,绝不直接把假设的 hou API 写进 execute_code 的 code 参数

  2. 若返 status="success", methods=[](API 不存在),改用其他等价 API(例如在 SOP 子节点设 display/render flag,而不在 OBJ 容器调不存在的 setDisplayNode)

  3. 若返 status="success" 且 _ai_hint 提到 thread 安全 caveat(如 ObjNode.setInput 需 input_index + item + output_index 三参),谨慎评估是否值得在 worker thread 冒险

三级 fallback(F0 → F1 → F2 → F3)

按优先级从高到低:

  • F0 — 判断 hou 版本:verification 第一步必须先 hou.version() 确认 major version,因为 hou API 在跨 major 时会重命名 / 废弃 / 新增

  • F1 本地 hou help(优先,无网络依赖,最快):调 verify_hou_api(item_name=...);若需进一步信息,hou.node(path).help()(已存在节点)或 execute_code 跑 help(hou.<Class>.<method>)

  • F2 联网 SideFX 文档(F1 拿不到时):verify_hou_api(item_name="<Class>.<method>", help_type="python_hou") 走 stdlib urllib.request 抓 https://www.sidefx.com/docs/houdini/hom/hou/<name>.html;不引入新 pip 依赖

    • local-help-first(自动):get_houdini_help / verify_hou_api 优先打 Houdini 本地 help server(默认 http://127.0.0.1:48626/),本地不可达 / 超时 / 白屏(HTTP 200 但内容无效)时自动回退在线。返回 _source 字段("local" / "online" / "")告知实际命中方,_fallback_reason 说明回退原因。健康缓存:本地失败后 60s cooldown 内跳过本地直查在线(fix-mcp-help-cap-protocol:本地 HTTP 404 不进 cooldown——页面不存在是合法答案,直接回退在线;cooldown 仅由 timeout / 5xx / 网络错 / 白屏触发)。Class.method 点号名(python_hou)自动拆分为类页面 + 方法精确匹配,不再直接拼 URL 导致双 404

  • F3 让用户开梯子(F2 返 status="error" 且 reason 含网络关键字时):AI agent 必须在输出里显式写出"⚠ SideFX 文档站不可达,请检查网络/梯子,或在 Houdini 内用 hou.helpServerUrl() 查本地帮助"

跨工具说明:底层 = get_houdini_help;AI-friendly wrapper = verify_hou_api。建议优先用 verify_hou_api 调 hou API,get_houdini_help 用于 SOP/OBJ 节点本身或 vex_function 查询。

详细复盘 / postmortem(含 2026-07-21 ObjNode.setInput hang 案例)见 CHANGELOG.md。


Configuration

环境变量

默认

作用

适用工具

HOUDINI_MCP_ALLOW_BYPASS

未设

privileged policy 启用开关(不设则任何 bypass 请求都失败)

execute_code

HOUDINI_MCP_ALLOW_NEW_SCENE

未设

new_scene 放行开关(服务端/Houdini 进程内读取;未设或非 truthy 时默认禁用,防 AI 自主清空用户场景;1/true/yes/on 显式放行)

new_scene

HOUDINI_MCP_ENV_DIR

见下方约定

embedded env 目录绝对路径覆盖;未设时从 package 目录名自动派生(<dirname>-env/,与 package 平级)

_env_dir()(3 处 prod + 2 处 test)

HOUDINI_MCP_LOCAL_HELP_URL

http://127.0.0.1:48626/

本地 help server base URL

get_houdini_help / verify_hou_api

HOUDINI_MCP_LOCAL_HELP_TIMEOUT

8.0

本地探测短超时(秒,clamp [0.5, 60.0];fix-mcp-help-cap-protocol:2.5→8.0,H21 本地 ~1MB 页面实测需 6-8s)

get_houdini_help / verify_hou_api

HOUDINI_MCP_LOCAL_HELP_COOLDOWN

60

本地失败后 cooldown 窗口(秒,clamp [0.0, 600.0])

get_houdini_help / verify_hou_api

HOUDINI_MCP_LOCAL_HELP_DISABLE

未设

1 / true / yes / on 时完全禁用 local-first,退化到"仅在线"

get_houdini_help / verify_hou_api

HOUDINI_MCP_RAG_INDEX_DIR

bridge 路由时自动设为 ~/.opera-houdini-mcp/rag/<ver>/

RAG 索引目录覆盖;bridge 首次 RAG 调用时查 Houdini 版本自动指向版本目录(versioned-rag-index);手工预设则整体跳过路由。未设且路由失败时解析序 home 目录(存在即用)→ 旧 fork 模块目录(兼容)。索引由 scripts/build_rag_index.py 生成(默认自动构建,手动命令见「RAG 文档检索与版本化索引」章节)

search_docs / get_doc

HOUDINI_MCP_CONSOLE_LOG

未设(开)

0 时 Houdini server 启动完全跳过 console tee 安装(get_console_log 恒空)

get_console_log / clear_console_log

HOUDINI_MCP_CONSOLE_LOG_LINES

4000

console 环形缓冲行数

get_console_log

HOUDINI_MCP_AUDIT_DIR

$TEMP/houdini_mcp/audit

审计 JSONL 目录覆盖

全部工具(bridge 审计)

HOUDINI_MCP_AUDIT_KEEP

30

审计保留段数

全部工具(bridge 审计)

HOUDINI_MCP_AUDIT_SEGMENT_MIN

15

审计分段间隔(分钟)

全部工具(bridge 审计)

HOUDINI_MCP_EXEC_HINT_THRESHOLD

5

execute_houdini_code 会话计数达阈值后每次返回附 _hint: 专用工具指引行;0 关闭

execute_houdini_code

RAPIDAPI_KEY

未设

OPUS 资产库 API key

_opus.py

RAPIDAPI_HOST

opus5.p.rapidapi.com

OPUS API host

_opus.py

RAPIDAPI_HOST_URL

https://opus5.p.rapidapi.com/

OPUS API base URL

_opus.py

HOUDINI_MCP_ENV_DIR 派生约定:

package at  <parent>/<dirname>/                 env 派生为  <parent>/<dirname>-env/

examples:
  opera-houdini-mcp/                            opera-houdini-mcp-env/
  external/houdinimcp/                          external/houdinimcp-env/
  external/mcp/                                 external/mcp-env/
  D:/我的项目/external/houdinimcp/              D:/我的项目/external/houdinimcp-env/
  • 相对路径的 override 会被静默忽略(fallback 到默认派生),因为 bridge 进程的 cwd 取决于 AI 工具怎么 spawn 它(Claude Desktop / Cursor / ZCode 各不相同),相对路径不可靠

  • 99% 的场景不需要设这个变量,保持默认派生即可

OPUS 集成(可选)

OPUS 提供大量家具 / 环境程序化资产。订阅步骤:

  1. 注册 RapidAPI 账号

  2. 订阅 OPUS API

  3. 复制本地配置文件:

cp urls.env.example urls.env  # urls.env 已在 .gitignore
  1. 编辑 urls.env 填入 key:

RAPIDAPI_HOST_URL=https://opus5.p.rapidapi.com/
RAPIDAPI_HOST=opus5.p.rapidapi.com
RAPIDAPI_KEY=<your-key>

不设 key 时 server 仍可启动,仅 OPUS 工具被禁用。OPUS 集成是可选的。


Upstream Sync Policy

字段

值

上游仓库

capoomgit/houdini-mcp

同步基线

de4fd93(2026-07-17)

同步方式

cherry-pick only(禁止 merge)

提交规范

标题前缀 [opera],正文引用上游 PR 号(如 [upstream PR #42])

同步窗口

手动触发,每次有上游合入后 7 天内

为什么禁止 merge:保持 opera 自身的提交图干净可审计,区分"上游原样"与"opera 独有"的改动点。

贡献到上游:opera 独有的改进建议优先以 PR 形式回提给 capoomgit/houdini-mcp,合入后再 cherry-pick 回来。这样全社区都能受益。


Testing

# 全量回归(推荐入口;2026-09-26 口径:74 个测试文件 / 2298 passed / 0 failed)
cd external/houdinimcp
pytest tests/

# 单文件示例
pytest tests/test_rag_lifecycle.py tests/test_rag_versioned.py

防泄漏护栏(fixture 自动生效,无需手工设 env):tests/conftest.py 的 autouse fixture 默认把桥端口钉到死端口,测试不会穿透真机 9876;确需真机的手动 e2e 必须显式 opt-in(HOUDINI_MCP_TEST_ALLOW_LIVE=1 pytest tests/h21_live_*.py)且 先征得用户同意。注意 search_docs / get_doc 有遗留必填参数 ctx(体内未用, 调用时传空串即可)。

测试基线:Houdini 21.0 + Python 3.11。详细 fixture / 共享 helper 见 tests/conftest.py 与 tests/_e2e_helpers.py;历史专项回归 tests/phase5_full_regression.py 保留可用。


Troubleshooting

现象

排查

修复

AI 连不上 9876

netstat -an | findstr 9876

关防火墙,或在 shelf 重新 Start MCP

License 相关

Houdini license server 状态

hkey -n 看 license,Houdini 21 试用版过期需要重新申请

升级后工具找不到

Houdini 还加载着旧 plugin

在 shelf 点 Stop MCP → 重启 Houdini → 点 Start MCP

get_houdini_help 失败

本地 help server(127.0.0.1:48626)是否可达 + 网络是否能访问 www.sidefx.com

看 _source / _fallback_reason:online + local_* 说明本地挂了已自动回退在线;两边都挂设 HOUDINI_MCP_LOCAL_HELP_DISABLE=1 走纯在线,详见 _help.py

execute_code 永远 bypass_used=false

服务端 HOUDINI_MCP_ALLOW_BYPASS 未设

服务端 export HOUDINI_MCP_ALLOW_BYPASS=1 并重启 server

import houdinimcp 找不到

external/ 不在 sys.path

按 Embedding §3 把 external/ 加进 sys.path


Edge Cases & 集成陷阱

改 package 目录名

env 路径自动从 package 目录名派生(<dirname>-env/)。改了 package 目录名要同步改 env 目录名,或用 HOUDINI_MCP_ENV_DIR 指过去。env 内的 Python + 依赖无需重装,纯文件系统 rename 即可:

mv external/houdinimcp external/opera-houdini-mcp
mv external/houdinimcp-env external/opera-houdini-mcp-env   # 跟着改

多个项目共享一个 env

每个项目派生的 env 路径按各自 package 目录名走,默认不会共享。多项目共享:

export HOUDINI_MCP_ENV_DIR=/shared/envs/opera-houdini-mcp-env

建议绝对路径。相对路径的 override 会被静默忽略(bridge 进程的 cwd 取决于 AI 工具怎么 spawn,跨进程不稳定)。

Windows 目录大小写

Windows 不区分大小写但 git checkout 保留原始大小写。如果你在 Windows 上 clone 后看到 Houdinimcp/ 而代码 baseline 用 houdinimcp/,basename 派生会按实际拼写走,可能导致 env 路径大小写不一致:

# 强制 git 严格大小写敏感
git config core.ignorecase false
# 如已 checkout 成错误大小写,重命名
Rename-Item external/Houdinimcp external/houdinimcp

env 跨 OS 不通用

env 内嵌的 Python 是平台相关 wheel(cp311-cp311-win_amd64 这种)。Windows env 拷到 Linux 跑不了,反之亦然。跨 OS 迁移必须重装。

改 env 路径不需要重装依赖

env 改名、移位置、改 owner,依赖本身可以原地保留:

mv external/houdinimcp-env /new-location/my-env
export HOUDINI_MCP_ENV_DIR=/new-location/my-env

无需 pip install,无需重下 Python 包。

git worktree / 多分支并行

每个 worktree 派生独立 env,不会互窜。共享 env 见上方「多个项目共享一个 env」。

权限与只读 env

env 目录存在但不可写(网络盘权限、只读 checkout)时,_consent_dir() 的 os.makedirs 兜底会抛 PermissionError。安装时确保 env 所在目录对运行用户可写。

pip install -e . 会污染全局

不要把 opera-houdini-mcp 装到全局 Python。env 是隔离的,依赖会随 env 走;全局装会污染系统 Python,且后续覆盖会破坏 env 完整性。


Contributing

  1. Fork → 建分支 → commit(标题前缀 [opera],正文引用对应上游 PR 号如有)

  2. pytest tests/ 全绿

  3. PR 描述里说明:

    • 改动的 Tier 1 工具编号(如果适用)

    • 是否新增 pip 依赖(不允许,除非有充分理由并单独标注)

    • 是否动到不变量(见下)

  4. 等 CI / 维护者 review

不变量清单(动到任一需先在 issue 里讨论)

不变量

值

监听端口

127.0.0.1:9876

pip 依赖基线

mcp[cli]==1.12.2 + requests + python-dotenv

MCP JSON key

mcpServers.houdini / mcp.houdini / mcp_servers.houdini

公共 API

start_server / stop_server / restart_server / is_server_running / initialize_plugin


Security

  • execute_code 是 LLM 驱动 Python 执行入口,三档 policy + 双开关 + 结构化 audit 是当前安全基线

  • 漏洞报告:通过 GitHub Issue 的 Private vulnerability reporting 渠道(不要在公开 issue 里贴 PoC),或直接联系维护者


License & Acknowledgement

本仓库全部代码沿用上游 MIT License。opera-houdini-mcp 本身的改动部分同样以 MIT 协议发布。

Houdini-MCP 的最初设计参考了 blender-mcp,感谢他们的贡献。opera-houdini-mcp 是 capoomgit/houdini-mcp 的独立 fork,遵循 MIT 协议,原版权归 Capoom 2025 所有。提交通过 cherry-pick 而非 merge 同步上游。

Available Tools

174 tools
assign_materialA

把 material_path 处的材质绑定到 geometry_path 处的几何节点。

参数说明:
- geometry_path: SOP / OBJ 几何节点路径
- material_path: 材质节点路径
- group: 可选,指定要绑定到的 group 名(如 primitive / point group);
  传 None 时整节点绑定,传具体名字时仅绑定到该 group

返回 dict 包含 geometry_path / material_path / group / success;
绑定失败时函数会抛 ValueError,bridge 不会再以 success:True 形式
静默吞错。

Inputs: ctx (required), geometry_path (required), material_path (required), group.

batchA

按顺序执行一批既有 Houdini command。

batch 只做一次 TCP relay;bridge 先完整预检 render policy,任何 redirect / interrupt / blocked response 都不会触发连接或前序 mutation。 Houdini 端按 mutating segment 合并 undo;batch 不提供事务回滚,结果逐项 报告。默认最多 50 项,上限可由环境变量调整并 clamp 到 1..200。

Inputs: operations (required), continue_on_error.

capture_multiple_panesA

批量截图多种 pane 到 save_dir(不存在会自动创建)。

pane_types 是 pane 类型名列表;返回与 pane_types 等长的 result 列表,
每条 {pane_type, save_path, success, error} 独立报告。任意一种 pane
抛异常不影响其他 pane。响应过 apply_response_cap。

Inputs: ctx (required), save_dir (required), pane_types (required).

capture_pane_screenshotA

截图指定类型 pane(NetworkEditor / SceneViewer / Compositor / ChannelEditor 等 30 种)。

pane_type_name 必须是 hou.paneTabType 的合法属性名。save_path 为 None
时不落盘,size_bytes 改用 QBuffer 估算。fit_contents=True 时先按
pane 类型调用 homeAll() / curViewport().home() 把可视范围对齐。
响应走 apply_response_cap。无 PySide 环境返回 _warning dict。

Inputs: ctx (required), pane_type_name (required), save_path, fit_contents.

capture_sceneviewer_flipbook_viewsA

采集 SceneViewer 的 Top / Front / Right flipbook,可显式请求 Perspective。

views=None 时严格按 top、front、right 顺序采集;传入 views 时保留调用方
顺序且不允许重复或未知视图。每张图由 Houdini 内部 flipbook 生成并校验
PNG IHDR,返回结构化的逐视图结果与 state_restored 状态。

Inputs: ctx (required), views, save_dir, pane_name, +2 more.

capture_workflow_snapshotA

把用户选中(或 node_path 指定)的节点子网络捕获为结构化工作流快照 (add-workflow-knowledge-capture,readOnly relay,不修改场景)。

触发时机(advisory):用户完成 HDA / 节点流 / VEX 工作流后说"沉淀这些
知识"时,agent 先调用 get_selection 定位,再调本工具取快照,组织为
recipe(用法文档,走 save_recipe)或 lesson(经验,走 save_lesson)。
本工具是 advisory,不替代 verify_hou_api / get_houdini_help /
get_best_practices,也不替代目标 Houdini 版本的 live verification。

参数说明:
- node_path: 可选;省略时取当前节点选择(空选择返回 no_selection
  结构化错误,不静默回退);指定时捕获以该节点为根的闭包子网络。
- include_vex: 可选,默认 True;包含 Attribute Wrangle 的 VEX snippet。
- max_nodes: 可选,默认 50;闭包节点硬上限,超限截断并标记 truncated。
- include_hda_internals: 可选,默认 False;True 时满足展开判定的节点
  内部子网并入同一 BFS 遍历(受同一 max_nodes 预算与 truncated
  语义)。展开判定(H21 实测收敛):children() 非空 且(用户资产
  ——库文件非 $HFS otls;或官方 HDA 带 Editable Nodes 声明——
  definition().hasSection("EditableNodes"),如 rbdbulletsolver1
  的 dopnet/forces 子网络;或非 HDA 普通容器 subnet/geo)。
  官方无声明的封装 HDA(rbdconstraintproperties / rbdconfigure
  等)默认**不拆解**;官方空壳节点(attribwrangle 等 children
  恒空)不展开。**不能用 isEditable() 判定**(实例锁定态
  isEditable False 但 children 完全可读,且大 HDA 上定义比较可能
  极慢)。研究用户自制 HDA 原理(内部 VEX / 约束 / 子网结构)时
  启用,并可视需要上调 max_nodes(大资产内部节点多,如 500)。

返回结构:{status:success, root, node_count, truncated, hip_file,
nodes, sticky_notes, connections},超限截断时 truncated=true;API
降级附 _warning。节点表每项含资产级标识 type_full(nameWithCategory,
API 缺失降级 type)与 is_hda(**用户数字资产实例**:definition() 非 None
且库文件非 $HFS/houdini/otls 内建库——H21 上 attribwrangle 等 HDA 化
内建类型也有 definition,纯 definition 判定会误标),hda 字段
为 {type_name, version(可选), definition_source: embedded|external},
**绝不输出 library_path 或任何本机路径**(跨机器复现误导源);顶层
hip_file 只取 basename(隐私安全)。快照只含节点表(path/name/type/
type_full/is_hda/comment/非默认参数/vex/hda/errors/warnings)+
sticky note + 连线,**不含几何数据**,readOnly 不修改场景,纯规则
读取**不调用 LLM / 嵌入模型**。错误为 status=error + error={code,
message,details}(no_selection / invalid_node_path /
selection_read_failed / capture_connection_error)。整体过
apply_response_cap。

方法论沉淀协议(advisory,非强制):沉淀目标是工作流的**原理 / 设计
意图 / 为什么这么搭**,不是节点名与参数的复制粘贴;参数仅在用户要求
或直接影响复现时收录。正文索引用 type_full / hda 资产标识,实例名仅
辅助;**禁止本机路径入正文**(HDA 库路径 / hip 完整路径,团队知识库
跨机器误导源),资产只用全名 + 版本索引。自制 HDA 先
include_hda_internals=True 研究内部原理再组织为 recipe。

Inputs: ctx (required), max_nodes, node_path, include_vex, +1 more.

check_connectionA

检查 Houdini 端连接信息(PR 16 连接诊断)。

返回 dict 包含 hou_version / hou_build / hip_file / hip_file_basename /
is_untitled / node_count / desktop_count / _status 八个字段。返回结构
与 server.py 中 HoudiniMCPServer.check_connection 保持一致。仅做只读
查询,不会修改 .hip 文件、节点或网络;适合 AI agent 在长会话开头调用
一次以获取当前 Houdini 版本与场景规模。

Inputs: ctx (required).

clear_cacheA

清运行态 cache(remove_disk_file=True 时同步删磁盘文件)。副作用不可 undo。

Inputs: ctx (required), node_path (required), remove_disk_file.

connect_nodesA
Wire one node's output into another node's input. Both nodes must live in
the same network. input_index selects which input of to_path to connect
(0-based); output_index selects which output of from_path to use.

Inputs: to_path (required), from_path (required), input_index, output_index.

cook_nodeB

Force-cook a node and report whether it cooked cleanly, with errors, warnings and cook time. The definitive way to verify a node works.

Inputs: path (required).

copy_nodeA

复制节点到 dest_parent 下(add-node-parameter-vex-tools,MUTATING)。

使用 ``hou.copyNodesTo``;预检目标 category 与同名冲突。
``name`` 可选,None 时由 hou 决定。响应过 ``apply_response_cap``。

Inputs: ctx (required), src_path (required), dest_parent (required), name.

create_chop_nodeC

CHOP parent 下创建节点。参数:parent_path/node_type 必填,node_name 可选。

Inputs: ctx (required), node_type (required), parent_path (required), node_name.

create_cop_nodeA

在 Copernicus parent 下创建节点(add-cops-tools,MUTATING)。

校验 parent 可编辑且 child category 为 "Cop",node_type 必须在 Cop
registry 中存在;单 undo group。``node_name`` 可选。

Inputs: ctx (required), node_type (required), parent_path (required), node_name.

create_lop_nodeA

在可编辑 LOP parent 下创建节点(add-usd-solaris-tools,MUTATING)。

``node_type`` 必须在 ``hou.lopNodeTypeCategory().nodeTypes()`` 探针中
存在;单 undo group;失败 destroy 半成品。响应过 server 端
``apply_response_cap``。

Inputs: ctx (required), node_type (required), parent_path (required), node_name.

create_materialC

在 Houdini 中创建一个材质节点并返回节点信息。

参数说明:
- material_type: 材质节点类型,如 "principledshader"、"vopsurface"
- name: 可选,节点名;缺省时由 Houdini 自动命名
- parent_path: 可选,父节点路径,默认 "/mat";不存在时回退到 /mat
- parameters: 可选,dict 按 parm 名设置参数值;不存在的 parm 名会
  静默跳过(不影响调用)

返回 dict 包含 path / type / name / parameters_set 四项,
parameters_set 列出已尝试设置的 parm 名(含静默跳过的)。

Inputs: ctx (required), material_type (required), name, parameters, +1 more.

create_material_networkA

在 parent 下创建 matnet(add-scene-context-selection-materials,MUTATING)。

验证 parent 存在、未锁定、childTypeCategory 为 Sop 后调
``createNode("matnet", name)``;错误结构化区分
``parent_not_found / parent_locked / unsupported_parent_
category / node_type_unavailable``。此 tool 归
``MUTATING_COMMANDS``,server handler 通过
``hou.undos.group`` 入 undo group。响应过 server 端
``apply_response_cap``。

Inputs: ctx (required), parent_path (required), name.

create_network_boxA

在父节点下创建 network box(network editor 中的分组框)。

参数说明:
- parent_path: 父节点路径。
- name: 可选,box 名;缺省时由 Houdini 自动命名。
- node_paths: 可选,要包含到此 box 的节点路径列表;
  不存在的节点静默跳过,不抛错。

返回 dict 包含 path / name / nodes_in_box 三项;
父节点不存在时函数会抛 ValueError。

Inputs: ctx (required), parent_path (required), name, node_paths.

create_nodeC

Create a new node in Houdini.

Inputs: node_type (required), name, parent_path. Returns: result

create_render_nodeA

受限创建可分类 ROP 节点(design.md §"create_render_node")。

仅允许 ``ifd`` / ``opengl`` / ``karmarender``;创建后通过同一
白名单设置参数并校验 renderer 可识别。未知 node type 整体
error。响应过 ``apply_response_cap``。

Inputs: node_type (required), name, parameters, parent_path.

create_spare_parameterA

单项 spare 参数创建(add-node-parameter-vex-tools,MUTATING)。

通过 ``parmTemplateGroup()`` 复制 + 一次性
``setParmTemplateGroup()`` 提交。``data_type`` 接受 ``float / int /
string / toggle / menu``。``folder`` 可选。响应过
``apply_response_cap``。

Inputs: ctx (required), name (required), path (required), data_type (required), +8 more.

create_spare_parametersA

批量 spare 参数创建(add-node-parameter-vex-tools,MUTATING)。

``parameters`` 是 list of spec dict;先全量校验、失败零部分提交。
单次 ``setParmTemplateGroup()`` 完成。响应过 ``apply_response_cap``。

Inputs: ctx (required), path (required), parameters (required), folder.

create_takeC

创建 child take。参数:name: take 名;include_parms/parent_take 可选。

Inputs: ctx (required), name (required), parent_take, include_parms.

create_vex_expressionC

在 SOP parent 下创建 Attribute Wrangle (add-node-parameter-vex-tools,MUTATING)。

设置 ``snippet`` 与 ``runover``(point / primitive / vertex / detail /
number);单 undo group。父节点 category 非 Sop 时返回 error。响应过
``apply_response_cap``。

Inputs: ctx (required), code (required), parent_path (required), name, +1 more.

create_wrangleA
Create an Attribute Wrangle SOP with the given VEX snippet, optionally
wiring input_node into its first input. run_over: points, primitives,
vertices, detail or numbers. The node is cooked immediately and the
result includes a 'validation' report — check it for VEX compile errors
before building on top. On invalid input the node is removed, never left
half-configured.

Inputs: vex_code (required), parent_path (required), name, run_over, +1 more.

delete_keyframeA

删除指定帧的关键帧(PR 19,场景写,可 undo)。

``frame`` 必须为有限浮点(删除 sub-frame 精确点)。目标帧
不存在返回 status=error("no keyframe found at frame ..."),
不写。实际删除后再次读取 keyframes 列表验证已消失。

Inputs: ctx (required), path (required), frame (required), parameter (required).

delete_nodeB

Delete a node from the scene by path.

Inputs: path (required).

disconnect_node_inputA

Disconnect one input of a node (reports what it was connected to).

Inputs: path (required), input_index.

execute_houdini_codeA
Execute arbitrary Python code in Houdini's environment. LAST RESORT:
prefer the dedicated tools (connect_nodes, set_parameters, create_wrangle,
get_geometry_info, ...) — they validate input, report structured errors
and are undoable as a single step. Use this only for operations no
dedicated tool covers.

Args:
    code: Python source to exec inside Houdini.
    policy: "read-only" / "normal" / "privileged" (PR 4 safety policy).
    allow_dangerous: explicit per-call dangerous-code override (privileged only).
    allow_heavy_geometry: explicit per-call heavy-geometry override.
    capture_diff: when True, server snapshots scene state before & after.

Returns status, any stdout/stderr, and an optional audit block.

Inputs: code (required), policy, capture_diff, allow_dangerous, +1 more. Returns: result

execute_hscriptA

在 Houdini 中执行 HScript 命令字符串。

HScript 是 Houdini 的传统脚本语言(与 Python/HScript 两套接口并存),
适合执行 `ls`、`cd`、`opset` 等内建命令。调用结果以 stdout / stderr
形式返回。

参数说明:
- code: HScript 命令字符串(如 "cd /obj; ls")。空字符串 / 纯空白
  会被服务端拒绝并返回错误。

返回字符串包含 stdout / stderr 两段;连接或服务端出错时返回
"Error (...): ..." 形式的提示。

Inputs: ctx (required), code (required).

explain_nodeB

单节点结构化摘要(add-scene-context-selection-materials,READ_ONLY)。

字段:``path / name / type / category / input_count /
output_count / inputs / outputs``;``include_params=True`` 时
附 ``non_default_parameters``(最多 ``max_params`` 条)。仅读
不修改场景。响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required), max_params, include_params.

export_chop_to_parmD

建立 chop() 通道引用。参数:chop_path/channel/target_path/target_parm。

Inputs: ctx (required), channel (required), chop_path (required), target_parm (required), +3 more.

find_error_nodesA

扫描场景中的错误与警告节点。

从 root_path 出发,单次调用 node.allSubChildren() 收集所有后代节点,
返回 errors 与 warnings 双列表。include_warnings 默认 True(PR 11 行为);
max_warnings 限制警告条目数(超过返 _warnings_truncated 标记);
max_errors 限制错误条目数(None 表示不限)。适合场景构建完成后做
一次性体检,比逐节点 cook_node 更快。

Inputs: ctx (required), root_path, max_errors, max_warnings, +1 more.

find_nearest_pointA

最近点查询:Point | None 双路径 (add-geometry-export-and-measure,NO_UNDO)。

- ``position`` 必须是 ``[x, y, z]``。
- ``max_distance`` 默认 1.0,作为 ``geo.nearestPoint`` 的
  ``max_radius``。
- Point 返回 ``{point_index, point_position, distance}``;None
  返回三字段均 null。响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), position (required), node_path (required), max_distance.

find_nodesB

Find nodes under root_path matching a glob / substring pattern or node_type. Default root_path is "/".

PR 6: relays to server-side disc.find_nodes.

Inputs: limit, cursor, pattern, node_type, +1 more.

frame_allB

viewport.frameAll()(add-viewport-control-tools,NO_UNDO)。

仅调整视图,**不**截图。响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required).

frame_selectionC

viewport.frameSelected()(add-viewport-control-tools,NO_UNDO)。

仅调整视图,**不**截图。响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required).

geo_exportA

translator 驱动的原子几何导出 (add-geometry-export-and-measure,NO_UNDO)。

- ``format`` 接受 ``bgeo / bgeo.gz / bgeo.lzma / bgeo.bz2 / geo``
  (H21+ 实机 ``geo.saveToFile`` 验证)。
- ``output_path`` 扩展名必须与 format 匹配;不匹配返回
  ``extension_mismatch``。
- 临时文件 ``fsync`` + ``os.replace`` 原子覆盖;``overwrite=False``
  且目标存在返回 ``target_exists``;失败清理临时文件。
- 落盘副作用不进 Houdini undo group;响应过 server 端
  ``apply_response_cap``。

Inputs: ctx (required), format (required), node_path (required), output_path (required), +1 more.

get_attrib_valuesC

按 owner/storage/tuple-size 分派读取属性,原生分页 (add-geometry-export-and-measure,NO_UNDO)。

- ``attrib_class`` 接受 ``point / prim / vertex / detail``。
- 返回 ``{values, offset, limit, total, next_offset, storage,
  tuple_size}``。响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), attribute (required), node_path (required), limit, +2 more.

get_best_practicesA

查询 fork 人工审查的 BEST_PRACTICES advisory recipes(bridge-local)。

本工具 **不建立 Houdini TCP 连接**,直接在 bridge 进程内加载并查询
BEST_PRACTICES.md。recipe 是 advisory,不替代 verify_hou_api /
get_houdini_help,也不替代目标 Houdini 版本的 live verification。

参数说明:
- query: 可选,对 problem/symptom/fix/category/source 做 casefold
  子串匹配。
- category: 可选,精确匹配 category 字段。
- id: 可选,精确匹配 recipe id(如 "BP-001")。
多个参数组合为 AND。

返回统一 envelope:status(success/error)、practices(实际返回列表)、
total_indexed(过滤前索引数)、matched_count(过滤命中数)、
returned_count(cap 后实际返回数,恒等于 len(practices))、truncated
(matched > returned 时为 true)。error 时 error={code,message,details},
且 practices 为空、三个 count 为 0。响应整体过 apply_response_cap。

Inputs: ctx (required), id, query, category.

get_bounding_boxB

解包几何 6 元 bounds 为 {min,max,size,center} (add-geometry-export-and-measure,NO_UNDO)。

使用 ``geo.intrinsicValue("bounds")`` 的
``(xmin, xmax, ymin, ymax, zmin, zmax)`` 标准布局。响应过 server
端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required).

get_cache_statusA

读取 cache 节点 status 摘要;未知类型返回 unsupported_cache_type。只读。

Inputs: ctx (required), node_path (required).

get_chop_dataC

有界读取 CHOP 采样。参数:node_path,sample/frame/time/start/end 选一。

Inputs: ctx (required), node_path (required), end, time, +5 more.

get_cook_chainA

有界 DFS 上游 cook chain(add-scene-context-selection-materials,READ_ONLY)。

从 ``node_path`` 沿 ``inputs()`` 关系向上递归;path-based
visited 在入栈前判定,菱形 / 环自动去重。``max_nodes`` 是
HOM 访问预算硬约束;触发时 ``truncated=True``。响应过
server 端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required), max_depth, max_nodes.

get_cop_geometryA

读取 Copernicus output geometry 摘要(add-cops-tools,NO_UNDO)。

调 ``geometry``/``geometryAtFrame``,只返回 point/prim/vertex counts、
bbox、有界 attrib 摘要;不序列化完整几何。``frame`` 可选,指定时走
AtFrame 变体。

Inputs: ctx (required), node_path (required), frame, output_index.

get_cop_infoA

读取 Copernicus 节点信息(add-cops-tools,NO_UNDO)。

返回 input/output data types、outputCableStructure 与每个 output 的
cable metadata(反射探针如实汇报 wire surface)。可能触发 COP cook;
响应经过 ``apply_response_cap``。

Inputs: ctx (required), node_path (required).

get_cop_layerA

读取 Copernicus ImageLayer metadata(add-cops-tools,NO_UNDO)。

先调 ``layer``/``layerAtFrame``;不可得时从 ``cable`` 反射 wire 选择
ImageLayer(响应披露 ``cable_fallback_used``)。只返回 resolution/
storage/bounds,不返回原始像素。

Inputs: ctx (required), node_path (required), frame, output_index.

get_cop_vdbA

读取 Copernicus NanoVDB/grid metadata(add-cops-tools,NO_UNDO)。

先调 ``vdb``/``vdbAtFrame``;不可得时从 ``cable`` 反射 wire 选择
NanoVDB。只返回 grid_name/storage/bounds 等有界 metadata,不返回体素。

Inputs: ctx (required), node_path (required), frame, output_index.

get_current_takeA

读取当前 take,返回 name/path/parent。只读。

Inputs: ctx (required).

get_docA

按相对路径取回已索引文档的全文(bridge-local,无 Houdini 连接)。

本工具 **不建立 Houdini TCP 连接**,``path`` 只与已校验索引中的规范
化 POSIX 相对 path 做精确匹配,全文从 JSON 内嵌 content 返回,
**绝不拼接源文件系统路径或回读索引外文件**(含 ``..`` 遍历串)。
与 ``get_houdini_help`` / ``verify_hou_api`` 互补:那两个面向在线
结构化字段查询,本工具面向已索引离线文档的整篇读取。

参数说明:
- path: 索引中文档的 POSIX 相对路径(如 ``nodes/sop/box.html``),
  可先用 search_docs 取得。

返回统一 envelope:status(success/error)、path、title、length、
content(全文,过 apply_response_cap)、returned(1 命中 / 0 未命中)。
path 不存在或非法返回 rag_doc_not_found;索引缺失 / 损坏分别返回
rag_index_missing / rag_index_unavailable。

Inputs: ctx (required), path (required).

get_dop_fieldB

读取 DOP data/record 字段(add-dops-tools,READ_ONLY)。

volume/VDB 字段不返回原始体素,只返回可廉价取得的 resolution /
bbox/min/max/average;不可得值标记 ``unavailable``。

Inputs: ctx (required), dop_path (required), data_name (required), field_name (required), +3 more.

get_dop_objectA

通过 findObject 查询单个 DOP object(add-dops-tools,READ_ONLY)。

``max_data`` 限制 data 摘要数量;不返回无界 record 内容。

Inputs: ctx (required), dop_path (required), object_name (required), max_data.

get_dop_relationshipsB

分页读取 DOP relationships(add-dops-tools,READ_ONLY)。

每个关系的对象名受 ``max_objects`` 硬上限约束;响应经过
``apply_response_cap``。

Inputs: ctx (required), dop_path (required), limit, offset, +1 more.

get_expressionC

读取 parm 表达式(add-node-parameter-vex-tools,READ_ONLY)。

返回 ``{expression}``,空表达式时 ``expression: None``。响应过
``apply_response_cap``。

Inputs: ctx (required), path (required), parameter (required).

get_frameA

读取当前帧 / 时间 / fps / 三组 range / increment,全部 float(PR 19)。

返回 dict 字段:frame / time / fps / frame_range /
playback_range / frame_increment;任一 hou 调用抛异常时降级为
status=error 而非向调用方抛异常。仅读取时间线状态,不修改场
景或参数(READ_ONLY_COMMANDS)。响应整体过 server 端
``apply_response_cap`` 截断大 payload(虽然规模小,仍保持
defense-in-depth)。

Inputs: ctx (required).

get_geometry_dataA
Read actual attribute values from geometry, paginated (limit capped at
500 — use start to page through large geometry). element: 'points' or
'primitives'. attributes: names to read (default: P for points); call
get_geometry_info first to see what exists.

Inputs: path (required), limit, start, element, +1 more.

get_geometry_infoA
Summarize a node's geometry: point/primitive/vertex counts, bounding box,
attribute listings per class, and group names. Accepts a SOP path or a
geometry container (its display SOP is used). Use this to verify what a
network actually produced instead of judging from a render.

Inputs: path (required).

get_geo_summaryA

获取几何节点的轻量级概要信息。

返回 SOP 节点的 point / primitive / vertex 计数、bbox 6 元、attributes /
groups 列表(带 name/type/size),以及前 sample_size 个点的属性采样。
point_count 超过 max_points_for_full 时自动降级 — 跳过 sample_points 与
详细 attributes/groups,避免大几何撑爆 MCP。比 get_geometry_info 更轻,
比 get_geometry_data 更结构化。适用于“先看看节点生成了什么规模的几何”。

Inputs: ctx (required), node_path (required), sample_size, max_points_for_full.

get_group_membersA

分页读取 group 成员 (add-geometry-export-and-measure,NO_UNDO)。

- ``offset / limit`` 必填;``limit`` 默认 1000。
- vertex 成员 ``{prim_index, vertex_index, point_index}``;
  edge 成员 ``[min_point, max_point]`` 排序端点对。
- 返回 ``{values, offset, limit, total, next_offset}``。响应过
  server 端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required), group_name (required), group_type (required), +2 more.

get_groupsA

返回四类 groups(point / prim / vertex / edge)name 列表 (add-geometry-export-and-measure,NO_UNDO)。

edge groups 在 H21+ 通过 ``geo.edgeGroups()`` 公开。响应过
server 端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required).

get_hda_section_contentA

分页读取 section 正文(add-hda-management-tools,READ_ONLY)。

``encoding`` 显式必填 ``utf8`` / ``base64``;两种模式均以
``binaryContents()`` 一次拿到的 raw bytes 为唯一分页真相。
响应过 ``apply_response_cap``。

Inputs: section (required), encoding (required), node_type (required), limit, +1 more.

get_hda_sectionsC

枚举 sections metadata(add-hda-management-tools,READ_ONLY)。

每项含 ``name / size / protected / binary / utf8``;``utf8``
严格探测;``binary`` 固定 true。响应过 ``apply_response_cap``。

Inputs: node_type (required).

get_houdini_eventsA

分页拉取 Houdini 进程级事件;cursor 由上一页响应返回。

Inputs: ctx (required), limit, cursor.

get_houdini_helpA

从 SideFX 在线文档查询 Houdini 节点、VEX 函数或 hou 方法的帮助(PR 15)。

help_type 支持 11 种:"sop" / "obj" / "dop" / "cop2" / "chop" /
"vop" / "lop" / "top" / "rop" / "vex_function" / "python_hou"。
item_name 是节点名 / VEX 函数名 / hou 方法名。timeout 是 HTTP 请求
超时秒数(默认 10)。返回 dict 包含 title / summary / parameters /
inputs / outputs / methods / status 等字段,HTML 解析使用 stdlib
html.parser(零新增 pip 依赖)。HTTP 4xx / 5xx / 网络错误 / 超时
全部降级为 status=error,不抛异常。响应整体过 apply_response_cap。

Inputs: ctx (required), help_type (required), item_name (required), timeout.

get_keyframesA

读取 parm 的全部关键帧(PR 19,只读)。

返回 list 中每项 ``{"frame": float, "value": float}``,不
做 ``int()`` 截断;空关键帧列表返回 ``keyframes=[]``。本
工具仅查询状态(READ_ONLY_COMMANDS),不会修改场景或参数。

Inputs: ctx (required), path (required), parameter (required).

get_last_modified_primsC

最近修改信息不可证明时返回 unsupported (add-usd-solaris-tools,NO_UNDO)。

USD composed stage 无法提供可证明的 last-modified 排序;不伪造。响应
过 server 端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required).

get_last_scene_diffA

Return the last execute_code (capture_diff=True) scene before/after diff.

The Houdini-side server caches the most recent serialize_scene_state pair;
this tool fetches and pretty-prints the diff so the agent can verify what
a privileged execution actually changed in the scene.

Inputs: no named parameters. Returns: result

get_material_infoA

获取材质节点的详细信息。

返回 dict 包含 path / type / name / parameters / texture_references
五项。parameters 仅保留 _materials.MATERIAL_PARM_WHITELIST 中列出的
50+ parm,过滤后键集合稳定跨材质类型一致;texture_references 列出
eval 值匹配已知贴图后缀(.png / .jpg / .jpeg / .exr / .hdr / .tif /
.tiff / .rat / .tex)的 parm。

Inputs: ctx (required), material_path (required).

get_network_overviewA

有界 BFS 遍历 parent 节点的网络拓扑(add-scene-context-selection-materials,READ_ONLY)。

``max_depth`` 控制 BFS 深度(0 = 仅 parent_path),
``max_nodes`` 限制 HOM 访问节点预算;返回 ``nodes / edges /
visited_count / truncated / truncation_reason``。节点去重
使用 path-based visited,环 / 共享祖先仅记一次。响应过 server
端 ``apply_response_cap``。

Inputs: ctx (required), parent_path (required), max_depth, max_nodes.

get_node_infoA

获取节点的详细信息。

参数说明:
- node_path: 目标节点路径。
- include_errors: 可选,是否包含 errors / warnings 字段,默认 True。
- force_cook: 可选,读取前是否调 node.cook(force=True),默认 False。
- include_input_details: 可选,是否包含每个 input 的详细连接
  (用 node.inputConnectors() 一次性取),默认 False。
- compact: 可选,是否仅返精简字段 path/type/counts(不含 parameters /
  errors / warnings),默认 False。

返回 dict:compact=True 时仅含 path / type / children_count / input_count
/ output_count 五项;否则包含完整字段(详见 _node_info.get_node_info)。
节点不存在时函数会抛 ValueError,bridge 透传 error envelope 不静默吞错。

Inputs: ctx (required), node_path (required), compact, force_cook, +2 more.

get_parameterA

读取 parm 当前值/类型/表达式/时间依赖 (add-node-parameter-vex-tools,READ_ONLY)。

返回 ``{value, type, expression, is_time_dependent}``;无 expression
时 ``expression: None``。响应过 ``apply_response_cap``。

Inputs: ctx (required), path (required), parameter (required).

get_parameter_schemaA
Describe a node's parameters: names, labels, types, tuple sizes, current
values, defaults, numeric ranges and menu options. Use this to discover
valid parameter names/values before calling set_parameters. Filter with a
glob pattern (e.g. "*scale*", matched against name and label); paginate
with offset/limit when a node has many parameters.

Inputs: path (required), limit, offset, pattern.

get_prim_intrinsicsA

仅查询指定 prim_index 的 intrinsics (add-geometry-export-and-measure,NO_UNDO)。

``names`` 可选子集过滤;越界返回结构化 error。响应过 server
端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required), prim_index (required), names.

get_render_settingsA

读取 node_path 的白名单 parm 值(design.md §"设置白名单")。

仅返回 ``ifd`` / ``opengl`` / ``karmarender`` 实际存在且数据安全的
parm;script / callback / command / executable 类型拒绝。整体
过 ``apply_response_cap``。

Inputs: node_path (required).

get_scene_infoB

Ask Houdini for scene info. Returns JSON as a string.

Inputs: no named parameters. Returns: result

get_scene_summaryA

全场景 category counts + 时间线(add-scene-context-selection-materials,READ_ONLY)。

``max_nodes`` 控制 HOM 遍历预算;返回 ``total_nodes /
category_counts / frame / fps / start_frame / end_frame /
truncated / truncation_reason``。不返回完整节点列表,只聚合
category 分布。响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), max_nodes.

get_selectionA

读取当前节点选择(add-scene-context-selection-materials,READ_ONLY)。

固定走 ``hou.selectedNodes()``,不接受 ``selectedItems()``;
因此不混入 network box / note / dot。返回 ``selected / count``,
每项 ``path / type / category``。响应过 server 端
``apply_response_cap``。

Inputs: ctx (required).

get_sim_memory_usageB

读取 DOP simulation 内存(add-dops-tools,READ_ONLY)。

使用 ``DopSimulation.memoryUsage()``,返回值明确标记 bytes;响应
经过 ``apply_response_cap``。

Inputs: ctx (required), dop_path (required).

get_simulation_infoA

读取 DOP simulation 元数据(add-dops-tools,READ_ONLY)。

返回 frame/time/timestep/object_count;只使用有界 DopSimulation
查询。响应经过 server 端 ``apply_response_cap``。

Inputs: ctx (required), dop_path (required).

get_usd_attributeB

单个属性值 + 类型名(add-usd-solaris-tools,NO_UNDO)。

从 composed stage 读取 attribute 在 ``time`` 的值。响应过 server 端
``apply_response_cap``。

Inputs: ctx (required), attribute (required), node_path (required), prim_path (required), +1 more.

get_usd_compositionC

composition arc 摘要(add-usd-solaris-tools,NO_UNDO)。

使用 ``Usd.PrimCompositionQuery`` 若可用;否则返回 unsupported。响应
过 server 端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required), prim_path (required), max_arcs.

get_usd_prim_statsC

prim active / loaded / defined / abstract / instance + 属性计数 (add-usd-solaris-tools,NO_UNDO)。

响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required), prim_path (required).

get_usd_variantsD

variant set 名称与当前选择(add-usd-solaris-tools,NO_UNDO)。

响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required), prim_path (required).

get_viewport_infoA

返回当前 SceneViewer viewport schema(add-viewport-control-tools,NO_UNDO)。

字段:camera / viewport_type / display_set / shaded_mode /
hydra_renderer。无 GUI / 无 pane 返 ``viewport_unavailable``
warning。响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required).

get_wrangle_codeB

读取 Attribute Wrangle SOP 的 snippet (add-node-parameter-vex-tools,READ_ONLY)。

返回 ``{path, name, type, code}``。响应过 ``apply_response_cap``。

Inputs: ctx (required), path (required).

hda_createA

从节点创建 HDA(add-hda-management-tools,MUTATING)。

先 ``canCreateDigitalAsset()``,再
``createDigitalAsset(name=, hda_file_name=, description=)``。
``label`` 可选,作为 description。响应过 ``apply_response_cap``。

Inputs: name (required), node_path (required), save_path (required), label.

hda_getA

读取 definition metadata(add-hda-management-tools,READ_ONLY)。

``node_type`` 仅接受 ``hou.NodeType.nameWithCategory()`` 完整
类别名(如 ``Sop/box``);短名称 / 未知 / 歧义均返回稳定
error。响应过 ``apply_response_cap``。

Inputs: node_type (required).

hda_installA

安装 HDA 库(add-hda-management-tools,NO_UNDO)。

落盘 + 全局 HDA registry 副作用,**不**可由 Houdini undo 恢复。
响应过 ``apply_response_cap``。

Inputs: file_path (required).

hda_listA

枚举已加载 HDA(add-hda-management-tools,READ_ONLY)。

使用 ``hou.hda.loadedFiles()`` + ``hou.hda.definitionsInFile()``
按 ``(libraryFilePath, nameWithCategory())`` 去重。响应过
server 端 ``apply_response_cap``。``category`` 可选透传过滤。

Inputs: category.

inspect_usd_layerD

layer 自定义元数据 / sublayer 路径(add-usd-solaris-tools,NO_UNDO)。

响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required), max_layers.

knowledge_statsA

查看各知识库 root 状态与计数(只读状态报告)。

触发时机:需要了解知识库状态、确认写入是否生效或排查检索范围时调用。
查看各 root 状态(ok/unconfigured/unavailable)与 lessons/inbox/
recipes 计数;unconfigured 静默、unavailable 会带 _warning。本工具是
只读状态查询,不替代 verify_hou_api / get_houdini_help /
get_best_practices,也不替代目标 Houdini 版本的 live verification。

参数说明:
- scope: 可选 root 名;缺省/"all" 报告全部 root。

返回:{status:success, roots:[{name, state, path, priority, writable,
lesson_count, draft_count, published_count, inbox_count,
recipes_count}]};未知 scope → status=error + error.code=
ls_unknown_root。整体过 apply_response_cap。

Inputs: scope.

layout_childrenA

布局父节点下的子节点(按间距参数手动 setPosition,跨 Houdini 版本可移植)。

参数说明:
- parent_path: 父节点路径(PR 9 推荐命名)。
- parent: 旧版别名;若同时传 parent_path 与 parent,以 parent_path 为准。
- horizontal_spacing: 水平间距(Houdini units),缺省 2.0。
- vertical_spacing: 垂直间距,缺省 1.5。
- direction: "horizontal"(默认)或 "vertical"。

返回 dict 包含 parent_path / children_count / direction / spacing
四项。后向兼容:现有调用 layout_children(ctx, parent) 仍 work。

Inputs: ctx (required), parent, direction, parent_path, +2 more.

layout_networkC

Auto-layout all children of a network node for a tidy graph.

Inputs: path (required).

list_cachesA

枚举白名单 File Cache 节点(BFS,受 max_nodes 限制)。只读。

Inputs: ctx (required), max_nodes, parent_path.

list_childrenA

List the children of node_path. With recursive=True walk the subtree up to max_depth. compact=True returns only {path, type, children_count}.

PR 6: relays to server-side disc.list_children.

Inputs: limit, cursor, compact, max_depth, +3 more.

list_chop_channelsB

枚举 CHOP 通道(track)名与采样范围。参数:node_path,output_index 可选。

Inputs: ctx (required), node_path (required), output_index.

list_cop_node_typesA

枚举 Copernicus node type registry(add-cops-tools,READ_ONLY)。

默认枚举 "Cop" category(H21+ Copernicus);``"Cop2"`` 显式拒绝为
legacy。只查询 registry,不触发 COP cook 或写入。

Inputs: ctx (required), category.

list_dop_objectsA

分页列出 DOP objects(add-dops-tools,READ_ONLY)。

每项仅返回 name/object_id 与有界 data/record type 摘要;不展开
模拟数据。响应经过 ``apply_response_cap``。

Inputs: ctx (required), dop_path (required), limit, offset.

list_lightsC

灯光识别:优先 UsdLux.LightAPI,再具体 schema IsA (add-usd-solaris-tools,NO_UNDO)。

不依赖 ``UsdLux.Light`` 基类;缺少 API 时返回 capability warning。响应
过 server 端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required), max_lights.

list_materialsA

枚举 parent 下材质节点(add-scene-context-selection-materials,READ_ONLY)。

验证 parent 存在且 childTypeCategory 为 Sop(Houdini 21
真实材质节点归属);每项 ``path / name / node_type / category``,
稳定按 path 排序。响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), parent_path.

list_material_typesA

枚举材质 category 下的 node types(add-scene-context-selection-materials,READ_ONLY)。

``category`` 仅接受 ``Vop`` / ``Shop``;使用对应 category 的
``nodeTypes()``,稳定排序返回 ``name / node_type / category /
description``,``node_type`` 走 ``nameWithCategory()`` 完整
类别名。未知 / 不支持 category 返 ``unsupported_category``。
响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), category.

list_node_typesB

List Houdini node types with optional category / name filter, paginated.

PR 6: relays to server-side disc.list_node_types, which populates the
NodeTypeCache on first call and reuses it across invocations.

Inputs: limit, cursor, category, name_filter.

list_render_nodesA

枚举 parent_path 下可分类 ROP 节点(ifd / opengl / karmarender)。

响应字段:``parent_path / count / nodes``,每节点含
``name / path / type / renderer``。未知 ROP type 仍列出但
``renderer=""``。整体过 ``apply_response_cap``。

Inputs: parent_path.

list_takesA

枚举全部 takes,返回 name/path/parent/current 列表。只读不改场景。

Inputs: ctx (required).

list_usd_primsB

受 max_depth / max_prims 限制的 prim 遍历 (add-usd-solaris-tools,NO_UNDO)。

返回 prim 路径 / 名称 / 类型 / 深度列表。响应过 server 端
``apply_response_cap``。

Inputs: ctx (required), node_path (required), max_depth, max_prims.

list_visible_panesA

列出当前所有 desktop 中可见的 pane tab。

返回 {desktop, pane_type, name, is_current} 四元组列表;is_current
标记该 desktop 当前激活的 pane。只读操作,响应过 apply_response_cap。

Inputs: ctx (required).

load_sceneA

Load a .hip file as the current Houdini scene.

Server-side also calls cmn.invalidate_all_caches() so downstream caches
(NodeTypeCache coming in PR 6) reset on scene switch.

Inputs: file_path (required).

lock_parameterC

切换 parm 锁定状态(add-node-parameter-vex-tools,MUTATING)。

``locked`` 接受 bool;单 undo group。响应过 ``apply_response_cap``。

Inputs: ctx (required), path (required), locked (required), parameter (required).

lop_importA

创建 Reference 或 Sublayer LOP(add-usd-solaris-tools,MUTATING)。

创建 / 连接 / 配置是单 undo group 的连续步骤;失败 destroy 半成品。
**不**直接修改 stage layer stack;adapter 不可用时返回 unsupported。
``import_type`` 接受 ``reference`` / ``sublayer``。响应过 server 端
``apply_response_cap``。

Inputs: ctx (required), file_path (required), parent_path (required), node_name, +2 more.

lop_layer_infoB

layer stack 摘要(add-usd-solaris-tools,NO_UNDO)。

读取 root / session / sublayer 的 identifier / real path / sublayer
数,受 ``max_layers`` 限制。响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), node_path (required), max_layers.

lop_prim_getA

单个 prim 的 type / active / loaded / kind + 有界属性 (add-usd-solaris-tools,NO_UNDO)。

``prim_path`` 必填(USD path,如 ``/Asset``)。响应过 server 端
``apply_response_cap``。

Inputs: ctx (required), node_path (required), prim_path (required), max_attributes.

lop_stage_infoB

composed stage 级元数据(add-usd-solaris-tools,NO_UNDO)。

从 ``LopNode.stage()`` 读取 upAxis / metersPerUnit /
framesPerSecond / defaultPrim 与有界 prim 计数。响应携带 capability
探针(Houdini 版本 / USD 版本 / feature flags)并过 server 端
``apply_response_cap``。

Inputs: ctx (required), node_path (required), max_prims.

manage_cacheA

Manage the Houdini-side NodeTypeCache.

action="stats"     -> return cache hits/misses/size/last_populated_at
action="invalidate"-> clear all registered caches (calls
                      cmn.invalidate_all_caches under the hood)
action="warmup"    -> pre-populate the NodeTypeCache

PR 6: relays to server-side disc.manage_cache. ValueError on unknown
action surfaces as an error dict with origin="houdini".

Inputs: action.

monitor_renderA

在 bridge 进程 best-effort 观察 husk / mantra OS 进程。

不读 hou、不发 TCP;通过 stdlib ``subprocess`` 调 PowerShell CIM
(Windows)或 ``ps``(POSIX),按 executable basename
(``husk`` / ``husk.exe`` / ``mantra`` / ``mantra.exe`` /
``mantra-bin`` / ``mantra-bin.exe``)过滤;不把命令行任意
substring 当 renderer。PID / name 必填;CPU / memory 可得为
float,不可得为 ``null`` 并在 ``_warning`` 列明
``cpu_unavailable`` / ``memory_unavailable``。命令缺失、权限
不足或解析失败返 ``status=success``、空 / 部分结果与 warning,
不抛异常。响应整体过 ``apply_response_cap``。

本工具 **bridge-only**,不进入 server registry 或三个 server
分类集合。

Inputs: no named parameters.

move_nodeC

移动节点到 dest_parent 下(add-node-parameter-vex-tools,MUTATING)。

使用 ``hou.moveNodesTo``;预检目标 category。响应过
``apply_response_cap``。

Inputs: ctx (required), src_path (required), dest_parent (required).

new_sceneA

Reset Houdini to an empty scene (suppress_save_prompt=True).

默认禁用:未设置 HOUDINI_MCP_ALLOW_NEW_SCENE(或非 truthy)时返回错误,
禁止 AI 自主清空用户场景;需显式放行时由用户设置
HOUDINI_MCP_ALLOW_NEW_SCENE=1。
Server-side also calls cmn.invalidate_all_caches().

Inputs: no named parameters.

parse_hip_offlineA

离线 best-effort 解析 .hip/.hiplc/.hipnc(bridge-local,无 Houdini 连接)。

本工具 **不建立 Houdini TCP 连接、不 import hou**,直接在 bridge 进程
内按真实 legacy cpio/odc entry 流式读取 archive(magic 070707、76 字节
header),best-effort 提取节点 type、def comment/position/connections、
可选 parm 序列化原始值、postit 文本与 netbox label,并对不可信输入施加
file/entry/section/total/node 五类硬限额(``max_depth`` 仅裁输出树)。

与 ``serialize_scene`` / ``get_node_info`` 互补:那两个面向**在线** Houdini
连接的实时节点树查询;本工具面向**离线**文件审计(如查看一个 .hip 里
有哪些节点/连线,而不必启动 Houdini)。

参数说明:
- file_path: ``.hip``/``.hiplc``/``.hipnc`` 文件路径;其他扩展名返回
  ``unsupported_extension``。
- include_params: 可选,True 时每节点附 ``parameters``(archive 中序列化
  的原始 parm 文本,**不求值、不比较默认、不保证动画/表达式完整**)。
- max_depth: 可选,输出 ``structure`` 树深度,clamp 到 ``[1,64]``;
  flat ``nodes``/``connections`` 不受影响。

返回统一 envelope:``status``(success/error)、``file_path``、
``save_version``(从 ``.variables`` 的 ``_HIP_SAVEVERSION`` 明确提取,
不可得为 null)、``nodes``(flat)、``connections``、``postits``、
``netboxes``、``structure``(depth-clipped 树)、``metadata``(含
complete_entries/bytes_consumed/trailer_seen/duplicate_entries/
skipped_sections/limits)。error 形如
``error:{code,message,details}`` 并尽可能附 partial(trailer_seen=false,
不含截断 body)。error code:unsupported_extension / invalid_archive /
corrupt_archive / truncated_archive / resource_limit_exceeded /
hip_not_found / hip_io_error。success 与 error-partial 均**过**
``apply_response_cap``。

Inputs: ctx (required), file_path (required), max_depth, include_params.

pdg_cancelA

cancel 正在运行的 cook;对已终态 handle 幂等返回 cancelled。cancel 不可 undo。

Inputs: ctx (required), node_path (required), cook_id.

pdg_cookA

启动 PDG/TOPs cook 并返回进程内 handle。blocking=True 时阻塞轮询至终态或超时;handle 进程内有效,server 重启失效。

Inputs: ctx (required), node_path (required), blocking, timeout_seconds.

pdg_dirtyB

dirty work items,默认不删除磁盘输出。改变 scheduler 运行态,不可 undo。

Inputs: ctx (required), node_path (required).

pdg_statusA

查询 TOP cook 状态与 work item 计数。可选 cook_id 校验其归属;未知/过期返回结构化错误。

Inputs: ctx (required), node_path (required), cook_id.

pdg_workitemsA

读取已生成 work item 摘要(index/name/state)。PDG 未生成时返回空列表;受 status_filter 与 max_items 限制。

Inputs: ctx (required), node_path (required), max_items, status_filter.

ping_houdiniA

轻量级 Houdini 端 ping,验证响应时间(PR 16 连接诊断)。

参数说明:
- timeout: 最长等待秒数(默认 5),超过则 within_timeout=False

返回 dict 包含 pong / elapsed_ms / within_timeout / hou_version 四项;
hou 抛异常时返 pong=False 并带 error 字段。该 ping 不持久化新连接,
只在既有 hou 上下文里调用一次 hou.version();适合作为健康检查或
网络抖动场景下的快速探测。注意:与 bridge 协议的 "ping" 命令不同,
后者只验证 socket / 帧协议,本工具测量 Houdini 端的实际响应时间。

Inputs: ctx (required), timeout.

playbar_controlA

playbar 播放 / 步进 / 跳转(PR 19,运行态时间线写,no-undo)。

``action`` 取值:
- ``play`` / ``reverse`` / ``stop``:直接调 SideFX HOM 同名方法。
- ``step_forward`` / ``step_backward``:仅通过
  ``hou.setFrame(current ± hou.playbar.frameIncrement())``
  路径并 clamp 到当前 playback range 闭区间,**不引入其
  他 step helper**(increment 非有限正数 / range 不可用
  → error 且 **不**调 hou.setFrame)。
- ``goto_start`` / ``goto_end``:直接设 playback range 端点。

整个 action 集在 NO_UNDO_COMMANDS 中,batch dispatcher 在
该命令前关闭 undo segment,保证不进入 ``hou.undos.group``。

Inputs: ctx (required), action (required).

read_lessonA

按 id 拉取单条 lesson 的完整 markdown 全文(含 front matter 与三段正文)。

触发时机:search_lessons 命中后按需拉全文;draft 也可读。本工具只读
advisory 内容,不替代 verify_hou_api / get_houdini_help /
get_best_practices,也不替代目标 Houdini 版本的 live verification。

参数说明:
- id: lesson id(如 L-20260802-001),由 search_lessons 返回。

返回:{status:success, id, root, lesson_status, markdown}(markdown 为
规范格式,可 round-trip);id 不存在 → status=error + error.code=
ls_lesson_not_found(提示先 search_lessons 获取 id)。整体过
apply_response_cap。

Inputs: id (required).

reload_hdaB

重载 HDA 库(add-hda-management-tools,NO_UNDO)。

落盘 + registry 副作用,**不**可由 Houdini undo 恢复。

Inputs: file_path (required).

rename_nodeB

重命名节点(add-node-parameter-vex-tools,MUTATING)。

预检同名冲突;返回新 path / old_name / new_name。响应过
``apply_response_cap``。

Inputs: ctx (required), path (required), new_name (required).

render_node_networkA

定位到节点所在 NetworkEditor pane,cd 到节点,再截图。

node_path 必须存在;fit_contents=True 时截图前调用 homeAll() 把可视
范围对齐到节点子树。save_path=None 时不落盘(size_bytes 改用 QBuffer
估算)。响应过 apply_response_cap。

Inputs: ctx (required), node_path (required), save_path, fit_contents.

render_quad_viewsA
IMPORTANT (fork-render-policy-redirect-and-consent):
    在用户机 H21 缺 OGL 3.3 环境下,本工具的 opengl renderer 已被 fork
    强制 redirect 到 ``capture_pane_screenshot(SceneViewer)``;karma_cpu
    / karma_xpu 需带 ``consent_token`` 重调。详见 ``_render_policy.py``。

Render 4 canonical views from Houdini and return a structured result dict.

Returns a dict (4 views × {image_path, size_bytes, ...}) instead of a
string. See render_single_view docstring for the dict-vs-str Pydantic
background. The legacy bridge command name is `render_quad_view`
(singular) — kept for backward compatibility with the server-side
handler dictionary in opera-houdini-mcp/server.py.

Inputs: render_path, karma_engine, consent_token, render_engine.

render_single_viewA
IMPORTANT (fork-render-policy-redirect-and-consent):
    在用户机 H21 缺 OGL 3.3 环境下,本工具的 opengl renderer 已被 fork
    强制 redirect 到 ``capture_pane_screenshot(SceneViewer)``(不再
    触发 opengl output node 链路,避免 Houdini 主线程死锁);karma_cpu /
    karma_xpu renderer 需带 ``consent_token`` 重调,token 在首次调用返
    回的 ``_interrupt`` 字段中获得。详见 ``_render_policy.py``。

Render a single view inside Houdini and return a structured result dict.

Returns a dict (carrying renderer / image_path / size_bytes / etc.)
instead of a string. Pydantic-typed MCP output models reject dicts
when the return annotation is `str`; this tool is the one that broke
live with `1 validation error for render_single_viewOutput / result
Input should be a valid string [type=string_type, input_type=dict]`.
Server-side always returns a dict; we forward it verbatim and only
fall back to an error envelope on exception.

Inputs: rotation, render_path, karma_engine, orthographic, +2 more.

render_specific_cameraA
IMPORTANT (fork-render-policy-redirect-and-consent):
    在用户机 H21 缺 OGL 3.3 环境下,本工具的 opengl renderer 已被 fork
    强制 redirect 到 ``capture_pane_screenshot(SceneViewer)``;karma_cpu
    / karma_xpu 需带 ``consent_token`` 重调。详见 ``_render_policy.py``。

Render from a specific camera path in the Houdini scene.

Returns a structured dict (renderer / image_path / size_bytes) instead
of a string. See render_single_view docstring for the dict-vs-str
Pydantic background.

Inputs: camera_path (required), render_path, karma_engine, consent_token, +1 more.

reorder_inputsA

重新排列节点的输入顺序。

参数说明:
- node_path: 目标节点路径。
- new_order: list of input_index,按新顺序排列(如 [2, 0, 1] 表示把
  原 input 2 移到 input 0,依此类推)。空 list 表示全部断开。
- order: 旧版别名;若同时传 new_order 与 order,以 new_order 为准。

返回 dict 包含 path / old_order / new_order / success 四项;
节点不存在时函数会抛 ValueError,bridge 不会再以 success:True 形式
静默吞错。

Inputs: ctx (required), node_path (required), order, new_order.

reset_simulationA

时间线优先重置 DOP 模拟(add-dops-tools,NO_UNDO)。

先移动到 reset frame 并 force cook;可选 force-reset 仅在真实签名
探针和对应 Houdini 版本 live gate 同时允许时执行。cache 清空/重建
不可由 HIP undo 恢复,owned simulation 权限失败返回结构化 warning。

Inputs: ctx (required), dop_path (required), reset_frame.

revert_parameterA

恢复 parm 至默认值(add-node-parameter-vex-tools,MUTATING)。

走 ``parm.revertToDefaults()``,单 undo group。响应过
``apply_response_cap``。

Inputs: ctx (required), path (required), parameter (required).

save_lessonA

把解决一个 Houdini 问题的经验沉淀为 lesson(写入个人库 draft 状态)。

触发时机:agent 在解决一个 Houdini 问题后主动沉淀经验。写入个人库
draft 状态,不立即进入检索索引;同 symptom 再次出现会自动累积
strength(只累积不覆盖)。团队 root 默认只读,写入返回
root_not_writable。沉淀的是 advisory 经验,不替代 verify_hou_api /
get_houdini_help / get_best_practices 与目标 Houdini 版本 live
verification。

主动沉淀工作流(advisory 行为注解,非强制协议):用户完成 HDA / 节点流
/ VEX 工作流后说"沉淀这些知识"时,agent SHALL 依次:get_selection 定位
→ capture_workflow_snapshot 取快照 → 组织为 recipe(用法文档,走
save_recipe)或 lesson(经验,走本工具)→ 写入后向用户汇报写入的
id / root / 状态。

加深与研究方法论(advisory 引导,非强制):用户要求"加深 / 改造 / 优化"
既有沉淀时,agent SHALL 先 search_lessons 定位既有 id,再用
capture_workflow_snapshot(自制 HDA 带 include_hda_internals=True)
重新研究,最后 save_recipe(recipe_id=...) 原地更新(recipe 通道),
**不得新增重复知识**。沉淀目标是原理 / 设计意图 / 为什么(方法论优先),
参数按需收录(用户显式要求除外);正文索引用资产级标识(type_full /
hda 资产全名 + 版本),实例名仅辅助,**禁止本机路径入正文**。

参数说明:
- problem / symptom / fix / category / affected_versions: 必填。
- severity: 必填,取值 low / medium / high / critical。
- verified_versions: 可选;缺省 "unknown"。
- root: 可选 root 名;缺省 personal(唯一可写 root)。

返回:新 lesson → {status:success, lesson_id, lesson_status:"draft",
strength:1, root};同 fingerprint 已存在 → strength 递增且内容保留。
错误为 status=error + error={code,message,details}(非法 severity →
ls_write_error 并列出合法值;只读团队 root → root_not_writable)。

Inputs: fix (required), problem (required), symptom (required), category (required), +4 more.

save_recipeA

把一条用法/流程知识写入指定 root 的 recipes 文件 (add-workflow-knowledge-capture,write,bridge-local 不连接 Houdini)。

触发时机(advisory):用户完成工作流后说"沉淀这些知识"时,agent 先用
get_selection 定位,再调 capture_workflow_snapshot 取快照;用法/流程
文档("怎么用这个 HDA""这个网络怎么搭")走本工具 save_recipe(写入即被
search_lessons 检索,无 draft 门槛),错误经验走 save_lesson(draft
门槛 + 指纹累积)。本工具是 advisory,不替代 verify_hou_api /
get_houdini_help / get_best_practices,也不替代目标 Houdini 版本的
live verification。

参数说明:
- title / problem / symptom / fix / category / severity /
  affected_versions: 必填;title 渲染为块上方 ``> title`` 注释行。
- severity: 必填,recipes severity 合法取值 low / medium / high
  (3 值,与 lesson 的 4 值不同)。
- verified_versions: 可选;缺省 "unknown"。
- recipe_id: 可选;引用**既有** ``### BP-NNN`` 块 id(格式
  ``BP-\d{3}``,非自定义新 id)。提供时**原地替换**该块 9 字段、
  不新增块(首块 ``> title`` 行同步更新),响应 action=updated;
  未提供时维持自增追加,响应 action=created。
- root: 可选 root 名;缺省 personal(唯一默认可写 root)。

返回:{status:success, recipe_id, root, severity, source,
immediately_searchable:true, action:created|updated};recipe_id 为
BP-NNN 自动生成(扫描既有块最大序号 + 1),**不接受自定义 id**;团队
root 写入 source 自动附 ``@<用户名>``(系统标注)。错误为 status=error
+ error={code,message,details}(非法 severity → ls_write_error 并列出
合法值;recipe_id 格式非法 → ls_write_error;引用不存在的 id →
ls_recipe_not_found 且 message 附既有 id 列表;只读团队 root →
root_not_writable;未知/不可用 root → ls_unknown_root)。整体过
apply_response_cap。

方法论沉淀协议(advisory,非强制):
- 沉淀内容是工作流的**原理 / 设计意图 / 方法论**(为什么这么搭),
  不是节点名与参数的复制粘贴;参数仅在用户要求或直接影响复现时收录。
- 正文索引用资产级标识(capture_workflow_snapshot 的 type_full / hda
  资产全名 + 版本),实例名仅辅助。
- **禁止本机路径入正文**:不写 HDA 库路径 / hip 完整路径(团队知识库
  跨机器误导源)。
- 改造 / 加深既有知识时先 search_lessons 定位既有 id,再传 recipe_id
  **原地更新**,**不得新增一条重复知识**。

Inputs: ctx (required), fix (required), title (required), problem (required), +7 more.

save_sceneA

Save the current Houdini scene to file_path.

file_path 省略(None/"")时保存到当前 hip 路径(hou.hipFile.path());
会话 untitled(无 hip 路径)时返回错误而非弹出模态保存对话框。
Returns JSON like {"saved": true, "file_path": "..."} or an error string.

Inputs: file_path.

search_docsA

跨 Houdini 文档做 BM25 检索(bridge-local,无 Houdini 连接)。

本工具 **不建立 Houdini TCP 连接**,直接在 bridge 进程内加载并查询
本地 RAG 索引(``index.v1.json``)。与 ``get_houdini_help`` /
``verify_hou_api`` 互补:那两个面向单条 API / 节点的结构化查询
(local-help-first + 在线回退),本工具面向「跨文档主题检索」,
如「怎么搭 pyro 网络」「karma 采样设置」。

参数说明:
- query: 检索文本;tokenizer 会保留 hou.xxx() API 与 /obj/geo1 节点
  路径整体语义,下划线复合词同时按完整与拆分匹配。
- limit: 可选,返回条目上限,clamp 到 [1, 50],默认 10。

返回统一 envelope:status(success/error)、query、limit、matched
(response cap 前所有 BM25 正分文档总数)、returned(cap 后实际
results 长度,恒等于 len(results))、results(每条含 path / title /
score / 围绕首个命中位置的 snippet)。索引缺失返回
rag_index_missing;损坏 / 不兼容返回 rag_index_unavailable;命中
stale 缓存时附 _index_warning。响应整体过 apply_response_cap。

Inputs: ctx (required), query (required), limit.

search_lessonsA

跨全部可用知识库 root 检索既往经验(published lessons + root recipes)。

触发时机:agent 在 Houdini 操作遇到报错、重试第 2 次仍未解决、或遇到
不认识的 API/参数时,先调用本工具检索既往经验;命中后用 read_lesson
拉全文。本工具是 advisory,不替代 verify_hou_api / get_houdini_help /
get_best_practices,也不替代目标 Houdini 版本的 live verification。

主动沉淀工作流(advisory 行为注解,非强制协议):用户完成 HDA / 节点流
/ VEX 工作流后说"沉淀这些知识"时,agent SHALL 依次:get_selection 定位
→ capture_workflow_snapshot 取快照 → 组织为 recipe(用法文档,走
save_recipe)或 lesson(经验,走 save_lesson)→ 写入后向用户汇报写入的
id / root / 状态。

加深与研究方法论(advisory 引导,非强制):用户要求"加深 / 改造 / 优化"
既有沉淀时,agent SHALL 先调用本工具定位既有 recipe/lesson id,再用
capture_workflow_snapshot(自制 HDA 带 include_hda_internals=True)
重新研究,最后 save_recipe(recipe_id=...) 原地更新,**不得新增重复
知识**。沉淀目标是原理 / 设计意图 / 为什么(方法论优先),参数按需收录
(用户显式要求除外);正文索引用资产级标识(type_full / hda 资产全名 +
版本),实例名仅辅助,**禁止本机路径入正文**(HDA 库路径 / hip 完整
路径,团队知识库跨机器误导源)。

参数说明:
- query: 检索文本(可为空串 → 按新鲜度/priority 基线浏览)。
- category / severity: 精确过滤(severity: low/medium/high/critical)。
- node_type: doc 文本子串过滤(如 /obj/geo1、sop/attribwrangle)。
- houdini_version: affected_versions 子串过滤(如 H21.0)。
- scope: 可选 root 名(如 "personal")或 "all";缺省检索全部 root。

返回统一 envelope:status/query/top_k/matched/returned_count/truncated/
results(紧凑摘要,含 source_root)/draft_suggestions;unavailable root
附 _warning。错误为 status=error + error={code,message,details}
(未知 scope → ls_unknown_root)。整体过 apply_response_cap。

Inputs: query (required), scope, category, severity, +2 more.

serialize_sceneA

递归序列化 root_path 下的节点树为 dict。

只读操作,AI 用于场景结构对比 / 文档生成。
include_params=False 时每节点只含 path/type/name/children;
True 时增加 parameters dict。

Inputs: max_depth, root_path, include_params.

set_cop_flagsA

原子设置 Copernicus 白名单 flags(add-cops-tools,MUTATING)。

``flags`` 键只能是 display/export/template/selectable_template/
compress/bypass,值为 bool;未知键在任何写入前拒绝整次请求。单 undo group。

Inputs: ctx (required), flags (required), node_path (required).

set_current_networkB

NetworkEditor.cd(path)(add-viewport-control-tools,NO_UNDO)。

节点不存在返 ``node_not_found``;无 NetworkEditor pane 返
``viewport_unavailable`` warning。响应过 server 端
``apply_response_cap``。

Inputs: ctx (required), path (required).

set_current_takeB

切换当前 take。参数:name_or_path: take 名或路径,找不到/歧义时拒绝。

Inputs: ctx (required), name_or_path (required).

set_detail_attribA

创建 Attribute Create SOP,class=detail (add-geometry-export-and-measure,MUTATING)。

- 创建 + 连接 + 配置是单 undo group 的连续步骤;失败 destroy
  半成品。
- **不**调用 cooked ``node.geometry()`` 的写方法。
- ``attrib_type`` 接受 ``float / int / string / vector``。
- 响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), name (required), value (required), node_path (required), +2 more.

set_expressionA

写入 parm 表达式(PR 19,参数通道持久写,可 undo)。

``language`` 接受 ``hscript`` / ``python``,映射到对应
``hou.exprLanguage``;其他值(包括大小写变体)一律
status=error。该命令属于参数通道数据写
(MUTATING_COMMANDS),**不**归为只读或 no-undo;与其他
关键帧 / 范围写共用 undo group 策略。

Inputs: ctx (required), path (required), parameter (required), expression (required), +1 more.

set_frameA

设置当前帧(PR 19,运行态时间线写,no-undo)。

``frame`` 接受 int / float;拒绝 bool / NaN / ±inf / 非数值;
hou 接受 float 值并保留 sub-frame。任何 hou 异常降级为 error
dict。该命令在 NO_UNDO_COMMANDS 中,batch dispatcher 会在调
用前自动关闭当前 undo segment,确保不进入 ``hou.undos.group``。

Inputs: ctx (required), frame (required).

set_frame_rangeA

设置全局 frame range(PR 19,场景写,可 undo)。

``start`` / ``end`` 必须为有限浮点且 ``start <= end``;end
可 sub-frame。错误(如 start > end)返回 status=error 不写;
成功时由 hou.playbar.setFrameRange 持久化。

Inputs: ctx (required), end (required), start (required).

set_hda_section_contentA

allowlist 写入 section(add-hda-management-tools,MUTATING)。

``section`` 仅 ``Help`` / ``IconSVG`` 大小写敏感精确匹配允许;
其他全部 ``section_write_denied`` 且零写入。``content`` UTF-8
字节上限 65536。响应过 ``apply_response_cap``。

Inputs: content (required), section (required), node_type (required).

set_keyframeA

单关键帧写入(PR 19,场景写,可 undo)。

``path`` / ``parameter`` 必为非空字符串;``frame`` / ``value``
必须为有限浮点。value 创建 ``hou.Keyframe(float(value))`` 并
``keyframe.setFrame(float(frame))`` 后 ``parm.setKeyframe``。
字符串参数 / NaN / inf 等返回 status=error 不写。

Inputs: ctx (required), path (required), frame (required), value (required), +1 more.

set_keyframesA

批量关键帧写入(PR 19,场景写,可 undo)。

``keyframes`` 为 list,每项 dict 至少含 ``path`` /
``parameter`` / ``frame`` / ``value``;任一项无效则**整调
用**失败、零写入(在 server 上层预校验拒绝)。全部有效时
在单个 ``hou.undos.group`` 内逐项写入并返回 ``set_count`` /
``requested``。错误列表同样受 server 端 ``apply_response_cap``
截断保护。

Inputs: ctx (required), keyframes (required).

set_node_colorA

设置节点颜色(颜色分量自动 clamp 到 [0, 1])。

参数说明:
- node_path: 节点路径。
- r, g, b: 颜色分量;负值 clamp 为 0.0,>1 值 clamp 为 1.0。

返回 dict 包含 path / color / success 三项;
节点不存在时函数会抛 ValueError。

Inputs: b (required), g (required), r (required), ctx (required), +1 more.

set_node_flagsA

Set node flags (display/render/bypass/template). Only flags you pass are changed. Flags a node type doesn't support are reported as 'unsupported'.

Inputs: path (required), bypass, render, display, +1 more.

set_node_positionB

设置节点在 network editor 中的位置。

参数说明:
- node_path: 节点路径。
- x: x 坐标(Houdini units)。
- y: y 坐标。

返回 dict 包含 path / position / success 三项;
节点不存在时函数会抛 ValueError。

Inputs: x (required), y (required), ctx (required), node_path (required).

set_parameterB

写 parm 值(add-node-parameter-vex-tools,MUTATING)。

单 undo group;失败抛 error。响应过 ``apply_response_cap``。

Inputs: ctx (required), path (required), value (required), parameter (required).

set_parametersA
Set one or more parameters on a node in a single undoable call.
Values: scalar for single parms (e.g. {"scale": 2.0}), a list for parm
tuples (e.g. {"t": [0, 1, 0]}), and menu token or label strings for menu
parms. Unknown names fail per-parameter with did-you-mean suggestions —
check the "failed" list in the result. Use get_parameter_schema first if
unsure of names, types or valid menu values.

Inputs: path (required), parameters (required).

set_playback_rangeC

设置 playback range(PR 19,场景写,可 undo)。

校验同 ``set_frame_range``;调 ``hou.playbar.setPlaybackRange``。

Inputs: ctx (required), end (required), start (required).

set_render_settingsA

受限可撤销写入(design.md §"set_render_settings")。

完整预校验所有 key/value/parm 可写性/prospective engine 后快
照旧值;应用失败显式恢复快照旧值,**不**依赖 undo 自动 rollback。
全部成功 -> ``status=success``;恢复成功 ->
``status=error, error_code=render_settings_apply_failed,
restored=true``;任一恢复失败 ->
``status=error, error_code=render_settings_restore_failed,
restored=false`` + ``restore_errors``。响应过
``apply_response_cap``。

Inputs: node_path (required), parameters (required).

set_selectionB

覆盖节点选择(add-scene-context-selection-materials,NO_UNDO)。

全量预校验 ``node_paths``,任一无效 → 0 部分改变;clear 仅
走当前 ``selectedNodes()`` 的 ``setSelected(False)``,**不**
调 ``clearAllSelected()`` 避免影响 box / note / dot。UI /
viewport 运行态写,**不**能由 HIP undo 恢复;该命令归
``NO_UNDO_COMMANDS``,batch dispatcher 会在执行前关闭 undo
segment。响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), node_paths (required), clear_others.

set_usd_attributeB

创建白名单属性 authoring LOP(add-usd-solaris-tools,MUTATING)。

按其真实参数 schema author;adapter 或 value 无法无损映射时返回
``unsupported``,**禁止** fallback 到 composed stage mutation。
``attribute_type`` 接受 ``float / int / string / vector``。响应过
server 端 ``apply_response_cap``。

Inputs: ctx (required), value (required), attribute (required), prim_path (required), +3 more.

set_viewport_cameraA

设置 SceneViewer viewport camera(add-viewport-control-tools,NO_UNDO)。

``camera_path`` 必须是已存在节点;无效返 ``camera_not_found``。
仅 UI/view 写,**不**进 undo group。响应过 server 端
``apply_response_cap``。

Inputs: ctx (required), camera_path (required).

set_viewport_directionA

将白名单方向映射到 geometryViewportType 并调 changeType (add-viewport-control-tools,NO_UNDO)。

七方向 token:front/back/left/right/top/bottom/perspective。
不接受反射式 setter。响应过 server 端 ``apply_response_cap``。

Inputs: ctx (required), direction (required).

set_viewport_displayA

设置 viewport display set + shaded mode(add-viewport-control-tools,NO_UNDO)。

两个值均为 design.md D2 白名单 token;不接受反射式 setter
或不存在枚举。仅 UI/view 写,**不**进 undo group。响应过
server 端 ``apply_response_cap``。

Inputs: ctx (required), display_set (required), shaded_mode (required).

set_viewport_rendererA

LOP SceneViewer Hydra renderer 切换(add-viewport-control-tools,NO_UNDO)。

仅 LOP context 可用;非 LOP 返 ``viewport_unavailable`` warning。
``renderer`` 必须是 ``sceneViewer.hydraRenderers()`` 中存在的
identifier;不可用返 ``renderer_unavailable``。响应过 server
端 ``apply_response_cap``。

Inputs: ctx (required), renderer (required).

set_wrangle_codeA

Replace the VEX snippet on an existing wrangle node. With validate=True (default) the node is re-cooked and the result includes a 'validation' report with any VEX compile errors.

Inputs: path (required), vex_code (required), validate.

start_renderA

同步启动一次 ROP 渲染;四层防御见 _render_jobs.start_render。

Args:
    node_path: 真实 ROP 节点路径(如 ``/out/mantra1``)。
    policy_renderer: 必填提示,bridge Layer 1 用其初筛(``mantra`` /
        ``opengl`` / ``karma_cpu`` / ``karma_xpu``);不替换真实
        node 推断。
    frame_range: 可选 2 或 3 元 ``[start, end[, inc]]``,缺省走
        ROP 自身设置。
    consent_token: 可选,karma 路径重调时携带。

Returns:
    dict: 直接 relay server 响应;blocked 时为 redirect / interrupt /
    error 字典;正常完成时为 ``status=success`` 含
    ``state / elapsed / frame_range``。

Inputs: node_path (required), policy_renderer (required), frame_range, consent_token.

step_simulationA

推进 DOP 模拟(add-dops-tools,NO_UNDO)。

通过 ``hou.setTime(frameToTime(current + frames))`` 后
``dop_node.cook(force=True)``;拒绝 ``frames <= 0``,不恢复旧帧。
会触发依赖图 cook 与 DOP cache 生成/替换,**不**进入 undo group。

Inputs: ctx (required), dop_path (required), frames.

subscribe_houdini_eventsB

订阅事件类型;省略 types 时订阅当前支持的全部事件。

Inputs: ctx (required), types.

uninstall_hdaA

卸载 HDA 库(add-hda-management-tools,NO_UNDO)。

落盘 + registry 副作用,**不**可由 Houdini undo 恢复。

Inputs: file_path (required).

unsubscribe_houdini_eventsA

取消指定事件订阅;省略 types 时清空全部订阅。

Inputs: ctx (required), types.

update_hdaA

从实例更新定义(add-hda-management-tools,MUTATING)。

验证节点存在、拥有 definition、实例类型匹配后调
``definition.updateFromNode(node)``;**不**使用
``definition.save()``。响应过 ``apply_response_cap``。

Inputs: node_path (required).

validate_vexA

用真实 HFS/bin/vcc 编译 VEX(add-node-parameter-vex-tools,NO_UNDO)。

临时 ``.vfl`` + ``subprocess.run([vcc, ...], shell=False, timeout=10)``;
不调用 Python exec / eval / compile / execute_code / hou.hscript /
hou.vexLint / hou.text.vexSyntaxCheck;不执行编译产物。10 秒超时、
输出 64KB 上限、finally 清理源与产物。返回
``{valid, context, diagnostics: [{severity, line, column, message}]}``。
响应过 ``apply_response_cap``。

Inputs: ctx (required), code (required), context.

verify_hou_apiB

AI-friendly wrapper over get_houdini_help(PR 18)。

参数说明:
- item_name: 要查询的 hou API / 节点 / VEX 函数名,如
  "ObjNode.setDisplayNode" 或 "Node.setInput"。
- help_type: 可选,帮助类型,默认 "python_hou";其他支持值见
  get_houdini_help(sop / obj / dop / cop2 / chop / vop / lop /
  top / rop / vex_function)。
- timeout: 可选,HTTP 请求超时秒数,默认 10。

返回 dict 包含 title / summary / parameters / inputs / outputs /
methods / status 等字段,并在响应末尾附 `_ai_hint` 字段,给 AI
一个可直接使用的简短提示(命中方法签名 / F-C pattern /
SideFX 不可达 fallback)。响应整体过 apply_response_cap。

Inputs: ctx (required), item_name (required), timeout, help_type.

write_cacheB

真实落盘 cache 并返回结果。磁盘副作用不可 undo。

Inputs: ctx (required), node_path (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.7/5.0

    Scored across 174 tools

    Disambiguation2/5

    Many tools have overlapping purposes, such as get_geo_summary vs get_geometry_info, verify_hou_api vs get_houdini_help, and get_scene_info vs get_scene_summary. The sheer number of similarly named get_* and create_* tools makes it difficult for an agent to select the correct one without reading extensive descriptions.

    Naming Consistency2/5

    Tool names follow no single consistent pattern: some use verb_noun (set_parameters), some use prefix-based conventions (hda_list, pdg_cook, lop_prim_get), and others mix forms (uninstall_hda vs hda_install). This inconsistency increases cognitive load and makes predictions about tool names unreliable.

    Tool Count1/5

    With 174 tools, this server vastly exceeds the typical well-scoped range of 3-15 tools. The extreme count overwhelms agents and likely degrades selection accuracy, making it an extreme mismatch for a coherent MCP surface.

    Completeness5/5

    The server provides extensive CRUD/lifecycle coverage across Houdini's major domains: nodes, parameters, geometry, rendering, DOPs, COPs, CHOPs, LOPs, PDG, materials, HDAs, takes, caches, and even a knowledge base. No obvious dead ends or significant missing operations were found.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      An MCP server for SideFX Houdini that enables AI assistants to interactively control, construct, inspect, and visually verify 3D procedural scenes through tools like node creation, parameter editing, viewport capture, and rendering.
      MIT