fxhoudinimcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| LOG_LEVEL | No | Logging level | INFO |
| HOUDINI_HOST | No | Houdini host address | localhost |
| HOUDINI_PORT | No | Houdini hwebserver port | 8100 |
| MCP_TRANSPORT | No | MCP transport (stdio or streamable-http) | stdio |
| FXHOUDINIMCP_PORT | No | Port for the Houdini plugin to listen on | 8100 |
| FXHOUDINIMCP_AUTOSTART | No | Set to 0 to disable auto-start | 1 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| set_keyframeC | Set a single keyframe on a parameter. Args: node_path: Node path. parm_name: Parameter name. frame: Frame number. value: Value at this keyframe. slope: Tangent slope. accel: Acceleration. |
| set_keyframesA | Batch-set multiple keyframes on a parameter. Args: node_path: Node path. parm_name: Parameter name. keyframes: List of dicts with "frame", "value", and optionally "slope"/"accel". |
| delete_keyframeC | Delete a keyframe at a specific frame. Args: node_path: Node path. parm_name: Parameter name. frame: Frame number to delete. |
| get_keyframesC | Get all keyframes on a parameter. Args: node_path: Node path. parm_name: Parameter name. |
| set_frameC | Set the current frame in the timeline. Args: frame: Frame number. |
| get_frameA | Get the current frame and FPS. |
| set_frame_rangeC | Set the global frame range. Args: start: Start frame. end: End frame. |
| set_playback_rangeC | Set the playback range (green bar in the timeline). Args: start: Start frame. end: End frame. |
| playbar_controlC | Control playback: play, stop, or reverse. Args: action: One of "play", "stop", or "reverse". real_time: Enable or disable real-time playback. fps: Frames per second. |
| list_cachesC | List all cache-type nodes under a root path. Args: ctx: MCP context. root_path: Root path to search from. |
| get_cache_statusA | Frames on disk for a cache node, against the range it is set to write. This is what to poll after a background write_cache: Args: ctx: MCP context. node_path: Path to the cache node. |
| clear_cacheC | Delete cached files on disk for a cache node. Args: ctx: MCP context. node_path: Path to the cache node. frame_range: [start, end] frame range to limit deletion. |
| write_cacheA | Execute a cache node, and report whether a cache actually appeared. Foreground by default: Houdini shows its own progress dialog and the user can cancel. The call holds until the write finishes, however long that is; a client that hands a long call to a background task notifies you with the verdict when it lands. Do nothing else in Houdini meanwhile (every other call queues behind the write) and never poll the disk.
Args: ctx: MCP context. node_path: Path to the cache node. frame_range: [start, end] frame range to render. Overrides the node's $FSTART/$FEND expressions for this and later writes. background: Save from a separate Houdini process (File Cache's own "Save to Disk in Background") so Houdini stays usable, at the cost of the user seeing no progress there. Saves the hip first, returns at once with status "launched"; follow it with get_cache_status. Use it only when asked to keep working while a cache writes. A verified foreground write turns the node's Load from Disk on. |
| get_chop_dataC | Get CHOP node track data. Args: node_path: CHOP node path. channel_name: Specific channel to retrieve. start: Start sample index. end: End sample index. |
| create_chop_nodeB | Create a new CHOP node. Before using this, call list_node_types(context='Chop', filter='') to verify the correct node type. CHOPs has many dedicated nodes for motion and timing — noise, wave, spring, jiggle, lag, limit, filter, math, function, blend, shift, stretch, trim, cycle, speed, constraintlookatat, constraintpath — that may already do what you need. Args: parent_path: Parent network path. chop_type: CHOP node type to create. name: Node name override. |
| list_chop_channelsC | List all channels on a CHOP node. Args: node_path: CHOP node path. |
| export_chop_to_parmC | Export a CHOP channel to a parameter via a chop() expression. Args: chop_path: CHOP node path. channel_name: Channel to export. target_node_path: Target node path. target_parm_name: Parameter to receive the export. |
| execute_pythonA | Execute arbitrary Python code inside Houdini. LAST RESORT only. DO NOT use this to:
ONLY use this when no dedicated tool exists for the operation — i.e. hou.* API calls or Python-level state that no other tool exposes. The justification parameter is mandatory: name the dedicated tools you considered and why none covers this operation. Args: code: Python source code to execute. justification: Which dedicated tools you considered and why none covers this operation. return_expression: Python expression to evaluate after execution. |
| reload_pluginA | Re-import the plugin's Houdini-side code without restarting Houdini. For developing this server: after editing its handlers, this picks the edit up in the running session. The MCP server's own tool definitions are not reloaded; the client has to reconnect for those. |
| execute_hscriptC | Execute an HScript command in Houdini. Args: command: HScript command string to execute. |
| evaluate_expressionC | Evaluate an expression in Houdini and return its result. Args: expression: Expression string to evaluate. language: Expression language, "hscript" or "python". |
| get_env_variableC | Get a Houdini environment variable value. Args: var_name: Name of the environment variable. |
| get_file_referencesB | Every file path the scene references, with the parameter holding it and whether it exists. Args: ctx: MCP context. include_missing_only: Only report paths that are missing on disk. |
| set_update_modeA | Set Houdini's cook update mode, or read it when called with no mode. "manual" before a long build stops every parameter change from re-cooking; set "auto" back afterwards. Args: ctx: MCP context. mode: "auto", "on_mouse_up" or "manual". Omit to read. |
| get_network_overviewA | Get a compact overview of a network. Keep Args: path: Network path. depth: Recursion depth (default 2, keep ≤ 3). |
| get_cook_chainC | Trace the cook dependency chain for a node. Args: node_path: Node path. |
| explain_nodeC | Explain a node in human-readable form. Args: node_path: Node path. |
| get_selectionB | Get the current node selection. |
| set_selectionC | Set the node selection. Args: node_paths: Node paths to select. |
| get_scene_summaryC | Get a high-level summary of the scene. |
| compare_snapshotsC | Take or compare scene state snapshots. Args: action: "take" or "compare". snapshot_name: Snapshot name. |
| get_node_errors_detailedB | Get detailed error analysis for nodes. Args: node_path: Node to analyze, or scan from root_path if omitted. root_path: Root path to scan. |
| get_cop_infoC | Get information about a COP node. Args: node_path: Path to the COP node. |
| get_cop_geometryC | Get geometry representation from a COP node. Args: node_path: Path to the COP node. output_index: Output connector index. |
| get_cop_layerC | Get image layer data from a COP node. Args: node_path: Path to the COP node. output_index: Output connector index. |
| create_cop_nodeA | Create a COP node in the specified network. Before using this, call list_node_types(context='Cop', filter='') for Copernicus nodes (Houdini 20+), or context='Cop2' for legacy COPs. Copernicus is the modern image processing system and is preferred over COP2 (deprecated as of Houdini 20.5). COPs has many dedicated image-processing nodes — blur, sharpen, levels, contrast, over, multiply, luminance, premultiply, channelcopy, noise, ramp, fractalnoise, worleynoise, rasterizegeo, heighttonormal, sdfshape — that may cover the operation without needing a VEX COP or Python. Args: parent_path: Path to the parent COP network. cop_type: COP node type to create. name: Override node name. |
| set_cop_flagsC | Set flags on a COP node. Args: node_path: Path to the COP node. display: Display flag state. export_flag: Render/export flag state. compress: Compress flag state. |
| list_cop_node_typesB | List available COP node types. Args: filter: Substring filter for node type names. |
| get_cop_vdbC | Get VDB volumetric data from a COP node. Args: node_path: Path to the COP node. output_index: Output connector index. |
| get_simulation_infoC | Get DOP network simulation state. Args: node_path: DOP network node path. |
| list_dop_objectsC | List all DOP objects in a simulation. Args: node_path: DOP network node path. |
| get_dop_objectC | Get detailed data for a specific DOP object. Args: node_path: DOP network node path. object_name: DOP object name. |
| get_dop_fieldB | Read a specific field value from a DOP record. Args: node_path: DOP network node path. object_name: DOP object name. data_path: Dot-separated subdata path (e.g. "Geometry", "Forces/Gravity"). field_name: Field name to read. |
| get_dop_relationshipsC | List all relationships between DOP objects. Args: node_path: DOP network node path. |
| step_simulationC | Advance the simulation by a number of frames. Args: node_path: DOP network node path. steps: Number of frames to advance. |
| reset_simulationC | Reset the simulation to its initial state. Args: node_path: DOP network node path. |
| get_sim_memory_usageC | Get detailed memory breakdown for the simulation. Args: node_path: DOP network node path. |
| get_geometry_infoC | Get geometry summary for a SOP node. Args: node_path: Node path. output_index: Which output to read, for nodes with several (FLIP compress, Vellum solver, whitewater source): 0 is the first. |
| get_pointsA | Read point positions and attributes with pagination. Args: node_path: Node path. attributes: Attribute names to read. start: Start index. count: Max points per page (200 by default, about 14 KB; page on with start while has_more is true). group: Point group filter. |
| get_primsC | Read primitive data and attributes with pagination. Args: node_path: Node path. attributes: Attribute names to read. start: Start index. count: Max prims per page (200 by default; page on with start while has_more is true). group: Prim group filter. |
| get_attrib_valuesA | Read attribute values as a flat array with pagination. For spot-checking a few values prefer sample_geometry — it returns a representative spread of points with all their attributes in one call. Use get_attrib_values when you need a specific slice of one attribute. Values are element-major: for a float3 attribute every 3 consecutive values belong to one element. Check has_more and increment start to read subsequent pages. Args: node_path: Node path. attrib_name: Attribute name. attrib_class: "point", "prim", "vertex", or "detail". start: First element index to return. count: Max elements per page (default 200). |
| set_detail_attribB | Set a detail attribute on a SOP node. Appends an Attribute Create SOP after the node and moves the display flag to it; the result includes the new node's path. Args: node_path: Node path. attrib_name: Attribute name. value: Value to set. |
| get_groupsC | List all geometry groups on a SOP node. Args: node_path: Node path. |
| get_group_membersA | Get element indices in a geometry group, with pagination. Check has_more and increment start to read subsequent pages. Args: node_path: Node path. group_name: Group name. group_type: "point", "prim", or "edge". start: First element index to return. count: Max elements per page (default 5 000). |
| get_bounding_boxC | Get the bounding box of a SOP node's geometry. Args: node_path: Node path. |
| get_attribute_infoC | Get metadata for a geometry attribute. Args: node_path: Node path. attrib_name: Attribute name. attrib_class: "point", "prim", "vertex", or "detail". |
| sample_geometryC | Sample evenly distributed points from a SOP node's geometry. Args: node_path: Node path. sample_count: Number of points to sample. seed: Random seed. |
| get_prim_intrinsicsA | Get intrinsic values for primitives: one, many, or all of them. Read many prims in one call rather than one call per prim. Args: node_path: Node path. prim_index: One primitive index, or None for a summary. prim_indices: Several primitive indices, read in one call. prim_range: [start, end] (end inclusive) instead of a list. intrinsics: Only these intrinsics, e.g. ["bounds", "packedfulltransform"]. With none of the index arguments, they are read for every prim. |
| find_nearest_pointC | Find the nearest point(s) to a given position. Args: node_path: Node path. position: Query position as [x, y, z]. max_results: Max nearest points to return. |
| get_attrib_statsA | Aggregate statistics for numeric attributes: min, max, mean, sum. Use this to prove something is happening, rather than reading values. get_geometry_info names the attributes; get_attrib_values returns every value, which on a 60k-point cache tells you nothing you can read. Vector attributes also report per-component ranges, so a velocity field's per-axis extremes come back in the same call. Args:
node_path: SOP node path.
attribs: Attribute names. Omit for every attribute of the class. A
name written "age/life" is the ratio of two attributes, per
element (elements dividing by zero are counted, not used).
attrib_class: "point", "prim", "vertex" (uv and N usually live
there) or "detail".
frames: Measure at each of these frames: a row per node per frame,
frames cooked in increasing order, the current frame put back.
element_count is the point count and P's per-component min/max
the bounds, so a sim's count and spread over time is ONE call.
node_paths: Several nodes (variants) in the same call, instead of
node_path.
percentiles: e.g. [5, 50, 95] for the distribution (50 = median).
group: Only the elements in this group pattern, as a SOP group field
takes it: "grp", "@id>=0", "0-99"; space-separated parts add up.
Point and prim classes.
unique: Count distinct values of integer and string attributes
( |
| get_volume_infoA | Per-volume name, resolution, active voxels, value range, mean and sum. A primitive count cannot tell a correctly named non-empty density field from an empty one, which is the question worth asking before wiring a solver's sourcing. This is the SOP counterpart of get_cop_vdb. threshold or bins read the voxels (VDB: active ones) for percentiles, a histogram, the count over threshold and box_above_threshold, the world box of the voxels over it: where the smoke is, not where the grid is. Args: node_path: SOP node path holding volume or VDB primitives. max_volumes: Cap on volumes reported. threshold: Split the voxels at this value and box the ones above it. bins: Histogram bin count, or a list of bin edges. |
| sample_volumeA | Read named volume fields at world positions, or at another SOP's points. "What does the collision SDF read where the particles are" is one call with from_node, and adds no node to the scene. A VDB SDF reads its background (the band width) outside its narrow band, not the distance. Args: node_path: SOP holding the volumes. fields: Volume names (the name attribute), e.g. ["density"]. positions: [[x, y, z], ...] in world space. from_node: SOP whose points are the positions, instead of positions. limit: Values are returned up to this many positions; the summary always is. bins: Histogram bin count, or a list of bin edges, for the summary. threshold: Count the samples above this value. |
| compare_volumesA | How much of one field sits in each band of another field. "How much density is inside the collider" is field="density", against="surface" (an SDF), bands=[-1000, 0, 1000]: the first band's field_total is what is inside. Both are sampled on a grid over field's box. Args: node_path: SOP holding field. field: Volume to total, e.g. "density". against: Volume whose value picks the band, e.g. a collider SDF. against_node: SOP holding against, when not node_path. bands: Band count, or a list of band edges. |
| build_networkA | Build a whole node network in ONE atomic call — the PREFERRED way to construct anything of 3+ nodes (massively faster than node-by-node calls, and either the whole network builds or nothing does). Every node type, parameter name, and input reference is validated against the running Houdini BEFORE anything is created; errors come back with did-you-mean suggestions. Use dry_run=True to prove a plan when using unfamiliar node types. The result includes cooked evidence: per-node errors and the display node's geometry counts — read them instead of assuming success. Each node spec dict supports exactly these keys; an unknown one (in a spec or in an input entry) is a validation error with a did-you-mean, never a silently dropped request: type (required), name, parms (lists set whole parm tuples; a value written {"expr": "ch('../x')"} is set as an expression, with an optional "language": "hscript" | "python", also as one component of a list: "t": [{"expr": "$F"}, 0, 0]; a ramp takes the whole ramp as {"keys", "values", "basis"}), expressions (or its alias exprs: a block of parm name -> expression), inputs (list of source names — earlier spec names, existing children, or absolute paths; or dicts with index or input_name / source / source_output, where input_name is a connector name or label as get_node_card lists them and source_output an output index or name ("v", "P"); or {"indirect_input": n} to wire from connector n of the parent subnet itself), flags (display/render/bypass/template), color [r,g,b], comment, override_expression, run_callbacks. Parms are written in the order given. A string aimed at a numeric parameter is caught during validation and answered with the {"expr": ...} spelling, instead of failing mid-build and rolling the whole graph back. A literal in parms does not replace an expression the parm already
holds (a Ray SOP ships dir = @N.x): the dry run lists such parms in
Display: in a network that was empty, the last node gets the display
flag unless a spec sets one. A display flag asked of a node that has
none (a usdrender_rop) goes to its nearest input that has one, listed in
A LOCKED parm (karmarendersettings resolutiony while res_mode is
autoheight) takes nothing; such a spec is refused at validation, nothing
built, with There is no "children" key: build the subnet, then call build_network again with the subnet as parent_path. Nodes built inside a DOP network come with Args:
parent_path: Network to build inside (e.g. "/obj/geo1"). A missing
parent directly under /obj is created, as the container the
specs' context needs (geo for SOPs, lopnet for LOPs), and
removed again if the build fails; a dry run reports it as
|
| verify_networkA | Inspect every node in a network at once — errors, warnings, flags, and the display node's cooked geometry counts. Call this after building or modifying a network, the way an artist
middle-clicks nodes: if A node's errors are its LAST cook's verdict. A node that nothing has
cooked since its cause was fixed is reported Args: parent_path: Network to verify (e.g. "/obj/geo1"). force_cook: Cook the display node with force and recook every node that has errors, so the verdict is about the network as it is now. |
| get_node_cardA | Get the authoritative documentation card for a node type, straight
from the running Houdini: connectors in order ( Use this BEFORE setting parameters on a node type you have not used in this session — never guess parameter names. Unversioned names resolve to the newest version. A menu carries Args: node_type: Type name (e.g. "scatter", "rbdbulletsolver"). context: Category — "Sop", "Lop", "Vop" (MaterialX and other shader nodes inside a material network), "Dop", "Cop", "Chop", "Top", "Object", "Driver"; also "Cop2", "Shop", "VopNet". parm_filter: Substring filter for the parameter list. include_help: The node's help text (about 4 KB). Default: included for a whole card, left out when parm_filter asks for specific parameters. Pass True or False to decide. |
| find_expensive_nodesA | Profile cooking and rank the most expensive nodes — how a senior artist finds the slow node instead of guessing. Records a performance-monitor profile while force-cooking the display outputs under root_path. cook_ms is cumulative (parents include their children), so compare siblings to locate the hotspot. Args: root_path: Network to profile (a geo container, or "/" broadly). frame: Optionally jump to this frame before cooking. limit: Max nodes to return. |
| cook_frame_rangeA | Cook a node frame by frame and report what changed on each frame. This is how you advance a sequential solver and how you prove a simulation
is doing something. Frames are cooked in order, so a SOP solver, a DOP
network or an animated chain all accumulate correctly, and per-frame cook
time, errors, counts, bounding box and attribute aggregates come back in
ONE round trip instead of one per frame. Prefer this over set_frame in a loop, and over stepping by hand: a 100-frame check is one call rather than 100. The frame is left where the cook ended, ready to screenshot. No deadline: a heavy sim runs under Houdini's progress bar for as long as it
takes; wait for the verdict and call nothing else meanwhile. Stopped from
that bar, it answers Args: node_path: Node to cook; its output is what gets measured. start: First frame. Defaults to the playbar start. end: Last frame, inclusive. Defaults to the playbar end. step: Frame increment. Keep at 1.0 for any solver, since skipping frames gives it a discontinuous time step and invalid results. attribs: Point attributes to aggregate per frame (min/max/mean/sum). volumes: Also report per-volume name, resolution and value range. |
| get_cook_statusA | Whether a node has cooked, how often, and whether it is time dependent. Note the shape of the limitation: every command runs on Houdini's main thread, so a long cook blocks the bridge and cannot be polled while it runs. This answers the after-the-fact question instead -- did it really recook, is it time dependent, did it end in error -- plus whether the hip has unsaved changes. For asynchronous work use a ROP's background execution and get_render_progress. Args: node_path: Node to report on. |
| list_installed_hdasA | List installed HDA definitions, grouped by library file. A stock install loads thousands; pass a filter (namespace, name or path
fragment). Args: ctx: MCP context. filter: Substring filter for type names or file paths. limit: Maximum definitions returned. |
| get_hda_infoC | Get detailed information about an HDA definition. Args: ctx: MCP context. node_path: Node path. hda_file: HDA file path. type_name: HDA type name. |
| install_hdaB | Install an HDA file into the current session. Args: ctx: MCP context. file_path: HDA file path. force: Force reinstall even if already loaded. |
| uninstall_hdaC | Uninstall an HDA file from the current session. Args: ctx: MCP context. file_path: HDA file path. |
| reload_hdaC | Reload an HDA file from disk. Args: ctx: MCP context. file_path: HDA file path. |
| create_hdaC | Create a new HDA from an existing subnet node. Args: ctx: MCP context. node_path: Subnet node path. hda_file: Destination HDA file path. type_name: Operator type name. label: Human-readable label. version: Version string. |
| update_hdaA | Save the current node contents back to its HDA definition. The definition's library file is written by this call: Args: ctx: MCP context. node_path: Node path. |
| get_hda_sectionsC | List all sections in an HDA definition. Args: ctx: MCP context. node_path: Node path. |
| get_hda_section_contentC | Read the content of a specific section in an HDA definition. Args: ctx: MCP context. node_path: Node path. section_name: Section name. |
| set_hda_section_contentC | Write content to a specific section in an HDA definition. Args: ctx: MCP context. node_path: Node path. section_name: Section name. content: Section content. |
| list_hda_versionsC | Every installed definition of an HDA node's type: version, file, which is current. Args: ctx: MCP context. node_path: An HDA instance. |
| set_hda_interfaceA | Author an HDA's Type Properties interface in one call. Use this for the asset's TYPE interface — tab folders, strict ranges,
ordered menus, Hide/Disable When. Each entry of Example — a Controls tab whose Bevel disappears for a single stud: [{"name": "controls", "label": "Controls", "type": "folder", "children": [ {"name": "stud_count", "type": "int", "default": 4, "min": 1, "max": 8, "min_strict": True, "max_strict": True}, {"name": "bevel", "type": "float", "default": 0.02, "min": 0.0, "max": 0.1, "hide_when": "{ stud_count == 1 }"}, {"name": "material", "type": "menu", "menu_items": [["plastic", "Plastic"], ["metal", "Metal"]]}]}] It is edit_hda_interface with one insert per entry: names already in the
interface are refused before anything is written, and the reply is read
back off the definition — Args:
ctx: MCP context.
node_path: An instance of the HDA whose definition is edited.
parameters: Interface spec (see above). create_spare_parameters'
spelling (parm_name, parm_type, default_value) is accepted too.
replace: Start from an empty interface. Built-in parameters of the node
type cannot be removed: Houdini puts them back
( |
| edit_hda_interfaceA | Edit an HDA's EXISTING Type Properties interface in one atomic call: insert at a position, remove, hide/show, replace, modify, move. set_hda_interface only appends. Every op here works on the definition's parameter group; all ops are applied to a copy, the result is checked for component-name collisions, and it is written once — a failing op changes nothing. Read the interface first with get_parm_template_tree. Ops (dicts, applied in order): {"op": "insert", "spec": {...}, "after": name | "before": name | "in_folder": label or [labels]} — omit the position to append. spec is a set_hda_interface spec, plus types button (with "callback", Python by default), separator, label, vector, color, file, oppath; and fields naming_scheme (base1|xyzw|rgba|minmax| startend|uvw), default_expression (+ default_expression_language), hidden, join_with_next, callback, tags; folder_type "multiparm" for a multiparm block (children named "item#"). {"op": "remove", "name": name_or_folder_label} {"op": "hide" | "show", "name": ...} {"op": "replace", "name": ..., "spec": {...}} {"op": "modify", "name": ..., <label | help | default | default_expression | default_expression_language | min | max | min_strict | max_strict | hide_when | disable_when ("" clears) | hidden | join_with_next | menu_items | callback | naming_scheme | new_name | tags>} ("rename", "set_conditional", "set_default" are aliases) {"op": "move", "name": ..., "after" | "before" | "in_folder": ...} Names are template names (
Args: ctx: MCP context. node_path: An instance of the HDA whose definition is edited. ops: Operations, in order. dry_run: Validate and report the plan without writing. |
| search_helpA | Search the running Houdini's own documentation — concepts, workflows, VEX functions, expression functions, HOM API, and every effects manual SideFX ships. Version-exact, straight from the install. Use this BEFORE improvising: when unsure how a workflow is meant to be done ("pyro shaping", "vellum constraints"), what a VEX or expression function does, or what a Solaris/TOPs concept means. Follow up with get_help_page on a result path. Args: query: Search words (all must match a page). scope: Optional corpus, named after the archive. Every help archive in the install is searchable, which on a full 22.0 is 47 of them. The ones worth knowing by name: "nodes", "vex", "expressions", "hom", "solaris", "tops", plus the workflow manuals "pyro", "fluid", "vellum", "destruction", "grains", "crowds", "model", "copy", "assets", "render", "shade", "anim", "character", "ref", "shelf". Omit to search all. limit: Max results. |
| get_help_pageA | Fetch one page of Houdini's shipped documentation by path. Read the real reference instead of writing from memory — especially the VEX function pages (vex/functions/...) before any justified wrangle, and expression pages (expressions/...) before channel expressions. Args: path: As returned by search_help — e.g. "nodes/sop/scatter", "vex/functions/noise", "expressions/ch". |
| get_workflow_guideA | The server's written guide for a subject: what to build, in what order, which mistakes it exists to prevent, and the shipped help pages to read. Call this BEFORE designing a setup you have not built this session, and again the moment two attempts at the same symptom have failed. Each guide is distilled from that subject's SideFX manual. Args: topic: Help scope name or common alias: pyro, fluid (flip, water, whitewater), vellum (cloth), destruction (rbd), mpm (sand, snow), ocean, solaris, tops, model, copy, render, shade, character, crowds, heightfields, copernicus, assets, troubleshooting, dyno. description: What you are trying to build, for the guide's framing. |
| get_stage_infoA | Get USD stage info from a LOP node, or from a LOP network. Given a network such as "/stage", the answer is about what that network
displays: Args: node_path: LOP node or LOP network path (default "/stage"). |
| get_usd_primA | Get detailed info about a USD prim. Array attributes longer than 16 elements (points, faceVertexIndices,
primvars:st, ...) come back as a summary: size, element_type, the first 8
as Values are read at Args:
node_path: LOP node path.
prim_path: USD prim path.
full: Return array attributes in full instead of summarised.
traverse_instance_proxies: List the children that live on an
instanceable prim's prototype. Without it such a prim answers
|
| list_usd_primsA | List USD prims on a stage with filtering. Instanced geometry is invisible to the default walk: an instanceable prim has no children of its own, they belong to its prototype. Set traverse_instance_proxies to list the prims under it. Args: node_path: LOP node path. root_path: Root prim path to list from. prim_type: USD type filter (e.g. "Mesh", "Xform"). kind: Kind filter (e.g. "component", "group"). depth: Max traversal depth. traverse_instance_proxies: Descend into instanceable prims and list the prims under their prototypes. |
| get_usd_attributeA | Read a USD attribute value from a prim. A long array (over 16 elements) answers with A time-sampled attribute (a PointInstancer's Args:
node_path: LOP node path.
prim_path: USD prim path.
attr_name: Attribute name.
time: Time code (frame number). Omitted on a time-sampled attribute,
the current frame is used (the first sample outside the range).
full: Return the whole array as |
| get_usd_attributesA | Read the same attributes across many prims as one table. One row per prim and attribute: {prim, prim_type, name, type, value,
time_samples?} or, for a relationship, {prim, prim_type, name,
relationship: true, targets}. The call for "sourceName of every
RenderVar", "lpetag of every light", "the camera of the render
settings" -- instead of one get_usd_prim per prim. Args:
node_path: LOP node path.
prims: Prim paths or globs: |
| get_usd_world_transformA | World transform of USD prims at one or more frames. get_usd_prim gives local xformOps; this composes every parent, so an animated parent shows. Per prim and frame: translate, rotate (XYZ degrees), scale and the row-major matrix. Each frame recooks the stage there, so LOP-parm animation reads right, and the playbar is restored. Args: node_path: LOP node whose stage to read. prim_paths: Prim paths, e.g. ["/world/cam"]. frames: Frames to read at, at most 500. Default: the current frame. |
| get_usd_layersC | List all layers in a USD stage. Args: node_path: LOP node path. |
| get_usd_prim_statsA | Get prim counts by USD type under a root path. Instanced geometry counts once per prototype, not per instance:
Args: node_path: LOP node path. prim_path: Root prim path to gather stats from. traverse_instance_proxies: Count prims under instanceable prototypes. |
| get_last_modified_primsB | Get prims modified by the last LOP node cook. Args: node_path: LOP node path. |
| create_lop_nodeA | Create a new LOP node. Before using this, call list_node_types(context='Lop', filter='') to verify the correct node type. Solaris ships many specialized LOPs — sublayer, reference, materiallibrary, assignmaterial, karmarendersettings, editproperties, xform, prune, configurelayer, collection, addvariant — that may not be obvious from their names. Args: parent_path: Parent node path. lop_type: LOP node type (e.g. "sphere", "sublayer", "merge"). name: Node name. prim_path: USD prim path to set on the node. |
| set_usd_attributeB | Set a USD attribute value via an inline Python LOP. Args: node_path: LOP node path to connect after. prim_path: USD prim path. attr_name: Attribute name. value: Value to set. |
| get_usd_bound_materialA | The material each prim renders with, resolved the way the renderer
resolves it (ComputeBoundMaterials), and where the binding comes from:
Batched: pass every prim of interest in one call. Args: node_path: LOP node whose stage to read. prim_paths: Prim paths to resolve. purpose: "full" (default; what Karma renders, falling back to an all-purpose binding), "preview", or "all" (all-purpose bindings only). |
| get_usd_materialsA | List all USD materials on a stage. Each material reports surface_shaders keyed by render context: "surface" is the universal output, a UsdPreviewSurface for viewports and Storm, and "mtlx" is the MaterialX shader Karma renders. surface_shader is the mtlx one when present, so it agrees with get_material_info on the same material.
Args: node_path: LOP node path. |
| find_usd_primsB | Search USD prims by path pattern. Args: node_path: LOP node path. pattern: Glob pattern (supports *, **) or substring. traverse_instance_proxies: Search prims under instanceable prototypes too; the default walk never visits them. |
| get_usd_compositionB | Get composition arcs for a USD prim. Args: node_path: LOP node path. prim_path: USD prim path. |
| get_usd_variantsB | Get variant sets and selections for a USD prim. Args: node_path: LOP node path. prim_path: USD prim path. |
| inspect_usd_layerC | Inspect a USD layer by index. Args: node_path: LOP node path. layer_index: Layer index (0 = root layer). |
| create_lightB | Create a USD light in a LOP network. Args: parent_path: Parent LOP network path. light_type: "dome", "distant", "rect", "sphere", "disk", or "cylinder". name: Light node name. intensity: Light intensity. color: [r, g, b] color values. position: [x, y, z] world position. |
| list_lightsC | List all USD lights on a LOP stage. Args: node_path: LOP node path. |
| set_light_propertiesC | Set properties on a USD light prim via an inline Python LOP. Args: node_path: LOP node path to connect after. prim_path: USD light prim path. properties: Property name-value pairs to set. |
| create_light_rigB | Create a preset lighting rig in a LOP network. Args: parent_path: Parent LOP network path. preset: "three_point", "studio", "outdoor", or "hdri". intensity_mult: Multiplier for all light intensities. |
| list_materialsC | List all material nodes under a root path. Args: ctx: MCP context. root_path: Root path to search for materials. |
| get_material_infoA | Get detailed information about a material node. assignments lists the nodes under /obj and /stage whose material-path parameters name this material; only those parameters are read, so the call costs the same on a 4,000-node scene as on an empty one (assignment_scan reports how many nodes were visited). Args: ctx: MCP context. node_path: Absolute path to the material node. |
| create_material_networkA | Create a new material network in /mat. The keys base_color ([r, g, b]), roughness, metalness and opacity are accepted on both shader types and mapped to the shader's own parameter names (base_colorr/g/b and specular_roughness on MaterialX, basecolor, rough, metallic and opac on Principled). Any other key must be the shader's real parameter name; a list sets the whole parm tuple. The reply lists what was applied and, under "skipped", every key that matched no parameter, with the reason. Args: ctx: MCP context. name: Name for the new material node. shader_type: "principled" (principledshader::2.0), "materialx" (mtlxstandard_surface), or any material node type name. params: Parameter name-value pairs to set on the shader. |
| list_material_typesB | List available VOP/material node types. Args: ctx: MCP context. filter: Substring to filter type names and labels by. |
| create_nodeB | Create a node inside a parent network. Before using this, call list_node_types(context='', filter='') to verify a dedicated node exists for the operation. Houdini has thousands of nodes — many common operations (boolean, scatter, copy to points, fracture, ocean, hair, vellum, pyro, etc.) have dedicated nodes that are better than writing VEX or Python. Args: ctx: MCP context. parent_path: Parent network path. node_type: Node type (e.g. 'geo', 'box', 'grid'). name: Node name. position: [x, y] network editor position. |
| delete_nodeC | Delete a node. Args: ctx: MCP context. node_path: Node path. |
| rename_nodeC | Rename a node. Args: ctx: MCP context. node_path: Node path. new_name: New node name. |
| copy_nodeA | Copy a node, optionally into a different parent network. In the same network the copy lands one node width to the right of its
original instead of on top of it; in another network it keeps the
original's position. Args: ctx: MCP context. node_path: Source node path. dest_parent: Destination parent path. new_name: Name for the copy. offset: [dx, dy] from the original's position. |
| move_nodeC | Move a node to a different parent network. Args: ctx: MCP context. node_path: Node path. dest_parent: Destination parent path. |
| get_node_infoA | Get type, connections, flags, errors, cook time, and non-default parameters for a node. A parameter whose expression uses a SOP local variable ($CEX, $BBX, $PT, @N.x)
is not evaluated outside a cook: it comes with Returns only parameters that differ from their defaults (non_default_parameters)
plus a total_param_count. Use get_parameter_schema to inspect the full parameter list.
A VOP node also gets Args: ctx: MCP context. node_path: Node path. |
| list_childrenA | List children of a network node. Avoid Args: ctx: MCP context. parent_path: Parent network path. recursive: Include all descendants (use sparingly on large scenes). filter_type: Node type filter (e.g. 'box', 'merge'). include_locked_assets: With recursive, also list what locked assets contain. |
| find_nodesA | Search for nodes by name pattern, type, or context. Narrow the search: use Args: ctx: MCP context. pattern: Glob pattern for node names (e.g. 'box*'). node_type: Node type filter (e.g. 'box', 'null'). context: Category filter (e.g. 'Sop', 'Object'). inside: Root path to search within (default '/'). |
| list_node_typesA | List available node types for a context category. IMPORTANT: Any context can have hundreds of node types (SOPs alone can
exceed 800 in a production install). Always pass a Args: ctx: MCP context. context: Category name (e.g. 'Sop', 'Lop', 'Dop', 'Top', 'Cop2'). filter: Substring to filter type name or label (case-insensitive). limit: Max entries to return (default 200, max recommended 200). |
| change_node_typeA | Change a node's type in place, keeping wires, name, position, flags, parameter values and (for subnets/assets) network contents. This is how an HDA instance is moved to an installed newer version
( Args: node_path: Node to change. new_type: Type name in the node's own category. keep_name: Keep the node's name. keep_parms: Carry parameter values over by name. keep_network_contents: Keep a subnet's/asset's children (False resets an asset to its definition's contents, also on a node that is already of new_type). |
| press_buttonA | Press a button parameter — "Stash Input", "Reload Geometry", an asset's own Build button — and read the node's errors and warnings afterwards. The call holds until the callback returns, with no deadline. A callback
that opens a dialog blocks Houdini's main thread and this bridge with it;
read the button's script first if in doubt. A Python callback that
RAISES does not hang anything: the bridge runs it rather than
pressButton(), and its error comes back as this call's error.
A press usually only dirties the node, so A parm that is not a button and has no callback is refused: pressing it does nothing. The small action button beside a field ("Create spare parameters" on a VEXpression) runs with action=True; an action that opens a picker holds the bridge like a dialog does. Args: node_path: Node that owns the button. parm_name: The button parameter's name. arguments: Optional kwargs handed to the callback script; values must be int, bool, float or str. cook: Cook the node after the press so errors describe the result. action: Run the parm's action button (script_action) instead of its callback. |
| connect_nodesA | Connect two nodes together. To feed a node INSIDE a subnet from one of the subnet's own input connectors (a SubnetIndirectInput — not a node, it has no path), pass the subnet as source_path and the connector index as indirect_input. Args: ctx: MCP context. source_path: Upstream node path; with indirect_input, the subnet whose input connector is the source. dest_path: Downstream node path. output_index: Source output index. input_index: Destination input index. input_name: Destination connector name or label (e.g. "base_color" on a VOP shader); wins over input_index. indirect_input: Index of the subnet input connector at source_path to wire from (dest_path must live inside that subnet). |
| connect_nodes_batchA | Connect multiple node pairs in a single call. Args: connections: List of connections. Each dict has keys: source_path (str), dest_path (str), output_index (int, default 0), input_index (int, default 0), input_name (str, optional: connector name or label, wins over input_index), indirect_input (int, optional: source_path is then a subnet and this is the index of its input connector to wire from — for the first node of a chain built inside that subnet). |
| disconnect_nodeC | Disconnect one or all inputs of a node. Args: ctx: MCP context. node_path: Node path. input_index: Input index to disconnect. disconnect_all: Disconnect all inputs. |
| reorder_inputsC | Reorder the input connections of a node. Args: ctx: MCP context. node_path: Node path. new_order: New input ordering (e.g. [1, 0] swaps first two). |
| set_node_flagsC | Set flags on a node. Args: ctx: MCP context. node_path: Node path. display: Display flag. render: Render flag. bypass: Bypass flag. template: Template flag. lock: Lock flag. |
| layout_childrenB | Auto-layout children of a network node. Does nothing when auto-layout is disabled via FXHOUDINIMCP_AUTO_LAYOUT=0. Args: ctx: MCP context. parent_path: Parent network path. spacing: Spacing multiplier between nodes. |
| set_node_positionC | Set a node's position in the network editor. Args: ctx: MCP context. node_path: Node path. x: Horizontal position. y: Vertical position. |
| set_node_colorB | Set a node's color in the network editor. Args: ctx: MCP context. node_path: Node path. r: Red (0.0-1.0). g: Green (0.0-1.0). b: Blue (0.0-1.0). |
| create_network_boxC | Draw a titled network box around nodes, to document a graph you built. Args: ctx: MCP context. parent_path: Network the box lives in. node_paths: Sibling nodes to enclose; the box fits around them. comment: Title shown on the box. color: RGB in 0..1. |
| create_sticky_noteB | Leave a sticky note in a network. Args: ctx: MCP context. parent_path: Network the note lives in. text: Note text. position: [x, y] in network editor units. size: [width, height] in network editor units. color: RGB in 0..1. |
| set_object_transformA | Set an object's translate, rotate, scale and/or parent in one call. Only the arguments you pass change. Object-level nodes under /obj only; SOP transforms are a Transform SOP, not this. Args: ctx: MCP context. node_path: Object node, e.g. "/obj/geo1". translate: [tx, ty, tz]. rotate: [rx, ry, rz] in degrees. scale: [sx, sy, sz]. parent: Object to parent under, or "" to unparent. |
| get_parameterB | Get the value and metadata of a parameter. A ramp reads as {"type": "Ramp", "basis", "keys", "values", "is_color"}, which set_parameters and build_network take back as it is. Args: node_path: Node path. parm_name: Parameter name. |
| set_parameterA | Set a parameter value. A parameter that holds an expression does NOT take a literal: Houdini
writes the value into a slot the expression keeps overriding. The reply
then carries A parameter holding a BARE ch() reference is the opposite trap: Houdini
writes THROUGH it into the parameter it reads, so the value lands on
another node. The reply names that parameter in Inside a DOP network a write does not reset frames already simulated:
A String parameter echoes A list with {"expr": ...} components ("t": [{"expr": "$F"}, 0, 0]) and
a whole ramp ({"keys", "values", "basis"}) go through set_parameters:
this tool's A LOCKED parameter (karmarendersettings resolutiony under res_mode autoheight) takes nothing at all; the error names the menu whose callback sets the lock. Houdini runs such callbacks only from the UI: set that menu with run_callbacks=True first, then the locked parameter. Args:
node_path: Node path.
parm_name: Parameter name.
value: New value (int, float, string, bool, or list).
override_expression: Remove an expression standing in the way,
instead of reporting that the write did not take.
run_callbacks: Run the parameter's callback script after the write,
as editing it in the UI does ( |
| set_parametersA | Batch-set multiple parameters on a node, in the order given. Inside a DOP network a write does not reset frames already simulated:
Parameters that held an expression and therefore ignored the literal are
listed in Locked parameters are in Args:
node_path: Node path.
params: Mapping of parameter names to values, written in this order.
A value written {"expr": "...", "language": "hscript" | "python"}
is set as an expression, as in build_network, also as one
component of a list ("t": [{"expr": "$F"}, 0, 0]). A ramp takes the
whole ramp at once: {"keys": [0, 1], "values": [[1, 0, 0],
[0, 0, 1]], "basis": "linear"} (one basis or one per key; a
float ramp takes numbers), the shape get_parameter reads it in.
A ramp's |
| get_parameter_schemaA | Get the template schema for parameter(s) on a node. Most nodes have dozens of parameters; many have 100+. Always use
Args: node_path: Node path. parm_name: Exact parameter name for a single-parameter lookup. filter: Substring to match against parameter name or label (case-insensitive). Use instead of dumping all params. |
| get_parm_referencesA | Who references a parameter, and what it references — in one call.
Args: node_path: Node to inspect. parm_name: One parameter instead of all of them. direction: "both", "incoming" or "outgoing". limit: Cap on reported entries. include_node_level: Include node_dependents / node_references. Default: on for a whole-node query, off when parm_name names one parameter; on an asset with hundreds of children those lists run to about 100 KB and answer a question about the node, not the parameter. |
| get_parm_template_treeA | The whole parameter interface as a tree, the way Type Properties shows
it: folders (with folder_type — tabs, collapsible, multiparm), every
parameter in order with defaults, default expressions, ranges, menu
items, Hide/Disable When conditionals, callbacks, naming scheme; a
multiparm's get_hda_info shows only the top folders and get_parameter_schema flattens the structure away; read this before editing an interface. Give node_path for a node (its instance interface, spares included) or type_name + context for a type. Args: node_path: Node whose interface to read. type_name: Node type instead (with context). context: Category of type_name — "Sop", "Object", "Lop", ... folder: Narrow to one folder by label, or a list of nested labels. max_entries: Cap on entries (depth-first); the reply says when it cut. include_tags: Also return each template's tags (needed to preserve them when editing an interface; about a quarter of the size). |
| set_expressionC | Set an expression on a parameter. Args: node_path: Node path. parm_name: Parameter name. expression: Expression string. language: "hscript" (default) or "python". |
| get_expressionC | Get the expression on a parameter. Args: node_path: Node path. parm_name: Parameter name. |
| revert_parameterB | Revert a parameter to its default value. A default that is itself an expression comes back, named in
A locked parameter cannot be reverted; the error names what sets the lock. Args: node_path: Node path. parm_name: Parameter name. |
| link_parametersA | Create a channel reference from one parameter to another. The destination gets an HScript expression that reads the source as its own type: chs() for a String parameter, ch() for numbers, toggles and menus. The path is relative to the destination node (chs("../CTRL/mat")), so the link survives moving the pair, collapsing into a subnet or instancing an HDA. The reply carries the expression, the function used and the destination's evaluated value. Args: source_path: Source node path. source_parm: Source parameter name. dest_path: Destination node path. dest_parm: Destination parameter name. replace_existing: Overwrite a destination that already has keyframes or an expression. Refused otherwise, so animation is never lost by accident. A link whose source already reads the destination through ch() is refused as a cycle in every case. |
| lock_parameterC | Lock or unlock a parameter. Args: node_path: Node path. parm_name: Parameter name. locked: True to lock, False to unlock. |
| create_spare_parameterB | Add a spare parameter to a node. Args: node_path: Node path. parm_name: Internal parameter name. parm_type: "float", "int", "string", "toggle", or "menu". label: UI label. default_value: Default value. min_val: Minimum value (float/int only). max_val: Maximum value (float/int only). |
| create_spare_parametersA | Batch-create multiple spare parameters in one call, optionally in a folder tab. A name that already exists as a spare parameter is updated in place (label, default, range); its current value and keyframes are kept. A type change on an existing parameter is refused. Args: node_path: Node path. parameters: List of parameter specs. Each dict has keys: parm_name (str), parm_type (str: "float"/"int"/"string"/"toggle"/"menu"), label (str), default_value (optional), min_val (optional), max_val (optional). folder_name: If provided, wraps all parameters in a named folder tab. folder_type: Folder style: "Tabs", "Collapsible", or "Simple". |
| get_parametersA | Read many parameter values at once, matched by name or label substring. The batch counterpart of set_parameters. Several unrelated groups of settings ("flame", "wind", "buoy") come back in one call instead of one call each, and unlike get_node_card these are the live values on this node rather than the defaults for its type. Pass Args:
node_path: Node to read.
patterns: Substrings matched against parameter name and label. Omit for
everything, up to the cap. Required with |
| list_panesA | List all visible pane tabs in the Houdini UI. |
| get_viewport_infoC | Get viewport settings for a pane tab. Args: pane_name: Pane tab name. |
| set_viewport_cameraA | Set the viewport to look through a specific camera. Args: camera_path: Camera node path, or a USD camera prim path for a Solaris viewport. The result reports the camera the viewport is actually looking through, and fails if it did not take. pane_name: Pane tab name. |
| set_viewport_displayA | Set how the viewport draws: shading, environment background, grid, particle point size, colour scheme. Any of them in one call; each is read back in the reply. Args: display_mode: One of 'wireframe', 'shaded', 'smooth', 'smooth_wire', 'hidden_line', 'flat', 'flat_wire', 'matcap', 'matcap_wire'. pane_name: Pane tab name. environment_background: False hides an environment (dome) light's map behind the scene, True shows it. Set on every view of the viewer; the reply reads it back per view. reference_plane: False hides the reference plane (the grid), True shows it. point_size: Diameter in pixels of particles drawn as points, on every view of the viewer. color_scheme: 'dark', 'darkgrey', 'grey' or 'light', on every view. |
| set_viewport_rendererA | Set the viewport's Hydra rendering delegate for live preview. Use this during lookdev to preview materials and lighting directly in the viewport instead of writing full renders to disk. Args: renderer: Renderer name. The result reports the delegate that is actually active afterwards, read back from Houdini rather than inferred from a setter not raising. renderer: Renderer name — "GL", "Storm", "Karma CPU", "Karma XPU", etc. Case-insensitive partial match. pane_name: Pane tab name. |
| frame_selectionC | Frame the current selection in the viewport. Args: pane_name: Pane tab name. |
| frame_allA | Frame all geometry in the viewport, or only some nodes or a box. Args:
pane_name: Pane tab name.
node_paths: Frame just these objects or SOPs (their world bounds),
not the spread of everything in the scene. An object frames what
it draws: a null its marker, a camera or a light its icon.
bounds: Frame [xmin, ymin, zmin, xmax, ymax, zmax], world space. A
point is framed as a 1-unit cube around it ( |
| set_viewport_directionA | Set the viewport to a standard viewing direction, or place the free view. rotation/pivot/distance orbit the viewport's own (non-camera) view: rotation [rx, ry, rz] in degrees about the pivot, distance from it. The reply reads the view back. Looking through a camera, move the camera. Args: direction: "front", "back", "top", "bottom", "left", "right", or "perspective". pane_name: Pane tab name. rotation: [rx, ry, rz] degrees for the free view. pivot: [x, y, z] the free view orbits. distance: Distance of the free view from its pivot along its view axis (the dolly); a sideways pan is not counted in it. |
| capture_screenshotA | Capture a screenshot of the viewport or a specific pane tab. The image is written to disk only; open Args: output_path: Image file path. Default: a new PNG in the temp dir. pane_name: Pane tab name. settle_seconds: Wait this long before capturing, without blocking Houdini, so a Karma viewport can converge after a change. Use this instead of a shell sleep between calls. Capped at 120. |
| capture_network_editorA | Capture a screenshot of the network editor. With node_path the view is put on that node at once (no animated flight), and the reply says what the frame shows: visible_bounds, node_bounds and node_in_view, all in network space. The image is written to disk only; open Args: output_path: Image file path. Default: a new PNG in the temp dir. node_path: Node path to frame before capture. |
| set_current_networkA | Navigate the network editor to a network; the viewer follows it in. Call it on the network you build in. By default the viewer then hides every other object (the viewport's Y hotkey, no display flag touched), so the work is seen on its own and the rest of the scene does not cook. Args: network_path: Network path to navigate to. other_objects: "hide" (default), "ghost", "show", or null to leave the viewer as it is. |
| find_error_nodesC | Find all nodes with errors or warnings in the scene. Args: root_path: Root node path to search from. |
| log_statusA | Display a status message in Houdini's status bar. Call this at the START of every major step so the user can follow along in real time without having to inspect tool call logs. Examples: "Creating base geometry...", "Wiring SOP chain...", "Setting up pyro simulation...", "Assigning materials...". Args: message: Status message to display (keep it short and human-readable). severity: "message" (default), "important", "warning", or "error". |
| set_viewer_contextA | Point the Scene Viewer at a network, and optionally a node inside it. set_current_network moves the network EDITOR; this moves the VIEWER. That is what decides whether a scene graph view exists, so it is the prerequisite for previewing a USD stage or setting a Hydra delegate: call this with "/stage" before set_viewport_renderer or before binding a USD camera prim. The result reports is_scene_graph_view, which is the question you are usually really asking. Args: network_path: Network for the viewer to display, e.g. "/stage". current_node: Node inside it to make current, which selects the stage a Solaris viewport shows. pane_name: Pane tab name. |
| render_viewportB | Capture the current 3D viewport to an image file. Args: output_path: Image file path. Default: a new PNG in the temp dir. resolution: [width, height] in pixels. camera: Camera node path. settle_seconds: Wait this long before capturing, without blocking Houdini, so a Karma viewport can converge after a change. Use this instead of a shell sleep between calls. Capped at 120. |
| render_quad_viewB | Capture all four viewport panes to separate images. Args: output_path: Base image path; viewport names are appended. Default: a new PNG in the temp dir. resolution: [width, height] in pixels. |
| list_render_nodesA | List all render (ROP/Driver) nodes in the scene. |
| get_render_settingsC | Get render settings from a ROP node. Args: node_path: ROP node path. |
| set_render_settingsC | Set render parameters on a ROP node. Args: node_path: ROP node path. settings: Parameter name-value pairs. |
| create_render_nodeC | Create a new render (ROP) node in /out. Args: renderer: Renderer type ('karma', 'opengl', 'mantra', 'rop_geometry', 'rop_alembic', 'usdrender', 'fetch', 'merge', 'rop_fbx', 'rop_gltf'). name: Node name. camera: Camera node path. output_path: Output file path. |
| start_renderA | Execute any node that renders or writes files. Foreground by default: Houdini shows its own progress dialog and the user can cancel. The call holds until the render finishes, however long that is; a client that hands a long call to a background task notifies you with the verdict. Do nothing else in Houdini meanwhile and never poll the disk. Not just /out ROPs: a LOP usdrender_rop (which is how Solaris renders), a SOP ROP Geometry, or a File Cache's Save to Disk all work, because what matters is whether the node can be executed rather than its category. The result reports the output path it wrote to and whether anything is actually on disk there, so a render that succeeds and writes nowhere is visible instead of silent. Args:
node_path: Any node with a render() or an 'execute' button.
frame_range: [start, end] or [start, end, increment].
background: Render in a separate hython on the saved hip and return
at once with status "launched"; get_render_progress reports the
process, its log tail and the files. The user sees no progress
in Houdini, so use it only when asked to keep working while a
render runs.
overrides: {parm_name: value} for this render only, e.g. a draft
{"resolutionx": 640, "resolutiony": 360}; a parm tuple takes a
list. Put back afterwards, expressions and keyframes included,
even if the render fails ( |
| render_node_networkB | Capture a screenshot of a node's network editor view. Args: node_path: Node path to focus on. output_path: Image file path. Default: a new PNG in the temp dir. |
| get_render_progressA | Progress of a render or write started with start_render. Accepts every node start_render accepts (a LOP usdrender_rop or Karma
LOP, a SOP ROP, a File Cache), not only /out ROPs. Reports the node's
errors with Args: node_path: The node given to start_render. |
| render_sheetA | Render frames start..end with the OpenGL ROP and tile them into one image. One image shows motion a single frame cannot: a sim's spread, a camera move. Needs no viewport, so it works in a headless session too. A snapshot of the scene as it is now (unsaved edits included, the session untouched) renders in a separate hython, since a second OpenGL render in one hython crashes on Houdini 22; that hython takes a license seat while it runs. Frames are labelled. Objects (/obj) only, not a LOP stage. Args: start: First frame. end: Last frame. step: Frame step; at most 64 frames in all. camera: Camera object path. Default: the scene's only camera. resolution: [width, height] of each tile. Default [320, 240]. columns: Tiles per row. Default: about square. output_path: Sheet image path. Default: a new PNG in the temp dir. |
| get_houdini_connection_statusA | Check the MCP-to-Houdini bridge without raising on disconnect. Returns structured connection diagnostics, including the configured bridge
URL and Houdini health payload when reachable, and |
| get_scene_infoC | Get information about the current Houdini scene. |
| new_sceneA | Create a new empty Houdini scene. Args: save_current: Save the current scene before clearing. |
| save_sceneB | Save the current Houdini scene to disk. Args: file_path: Destination path; defaults to the current hip file. |
| load_sceneA | Open a Houdini hip file, or merge it — or named nodes from it — into the current scene. Load warnings (missing assets and the like) come back in Args: file_path: Path to the hip file to open. merge: Merge into the current scene instead of replacing it. node_paths: With merge, the absolute node paths to merge; default everything. overwrite_on_conflict: With merge, overwrite same-named nodes instead of renaming the merged copy. |
| import_fileC | Import a geometry, USD, or Alembic file into the scene. Args: file_path: Path to the file to import. parent_path: Network path for the import node. node_name: Name for the created node. |
| export_fileA | Export a node's output to a file on disk, and report whether it landed. SOPs are saved directly, LOPs export their USD stage, and a /out ROP is
pointed at file_path and executed (its own output path is restored
afterwards). Reports Args: node_path: Path to the node to export. file_path: Destination file path. For a ROP this overrides its output parameter for the duration of the export. frame_range: Frame range as [start, end] or [start, end, step]. |
| get_context_infoC | Get information about a Houdini network context. Args: context: Context path, e.g. "/obj", "/stage", "/out". |
| undoA | Undo the last change(s) made in Houdini. Every tool call is one undo step, however many nodes it touched, so one undo reverses one build_network or set_parameters call. Needs a graphical Houdini: hython keeps no undo history. Args: ctx: MCP context. steps: How many steps to undo (default 1). |
| redoA | Redo the last undone change(s) in Houdini. Args: ctx: MCP context. steps: How many steps to redo (default 1). |
| connect_houdiniB | Talk to the Houdini serving on get_houdini_connection_status lists the sessions and their ports. Args: port: Port of a Houdini serving the plugin. |
| start_houdiniA | Start a Houdini of this server's own and connect to it. Headless (hython) by default: no window, no viewport, so the capture tools refuse there. gui=True starts the full application, which serves only if the plugin's package is installed (fxhoudinimcp install). Either takes a license seat until stop_houdini. Set HYTHON to choose the build. Args: gui: Start the Houdini application instead of headless hython. hip_file: Scene to open. wait_seconds: How long to wait for it to serve. |
| stop_houdiniA | Stop a Houdini that start_houdini started, and go back to the previous session. Only sessions started by this server can be stopped: anything else may be someone's unsaved work. Args: pid: Session to stop. Default: the current one, if this server started it. |
| list_shelf_toolsA | Find shelf tools by name, label or keyword. Use this when a setup exists as a shelf tool rather than as a node: oceans, quick sims, rigging setups. A full install ships around 8,000 of them, so always filter. Args: filter: Substring matched against name, label and keywords. limit: Maximum tools to return. |
| get_shelf_tool_scriptA | Read the script a shelf tool runs, plus its help and imports. This is how you learn SideFX's own recipe instead of reinventing it. Most scripts are two or three lines calling a worker in a toolutils module, and the reported imports name exactly what to read next. Args: tool_name: Internal tool name, from list_shelf_tools. |
| run_shelf_toolA | Run a shelf tool and report the nodes it created. A tool that asks for objects takes Nodes the tool added inside networks that already existed (a FLIP tool
into the current POP network) are listed in Args:
tool_name: Internal tool name, from list_shelf_tools.
kwargs: Overrides merged into the synthetic kwargs the script reads.
parent_path: An extra network to watch for new nodes. /obj, /stage,
/out, /mat and /img are always watched, because a shelf tool is
free to build in more than one of them: largeOcean creates both
a geo in /obj and a LOP in /stage. A SOP network given here is
also where a SOP tool places its nodes ( |
| list_takesB | List all takes in the scene with their hierarchy. |
| get_current_takeB | Get the current take and its overridden parameters. |
| set_current_takeC | Set the current take by name. Args: name: Take name to make current. |
| create_takeB | Create a new take, optionally under a parent take. Args: name: Name for the new take. parent_name: Parent take name (defaults to current take). |
| get_top_network_infoB | Get an overview of a TOP network. Args: ctx: MCP context. node_path: TOPnet or TOP node path. |
| cook_top_nodeB | Cook a TOP node to execute its work items. Args: ctx: MCP context. node_path: TOP node path. block: Wait for cooking to complete. generate_only: Only generate work items, do not cook. |
| cancel_top_cookC | Cancel active cooking on a TOP network. Args: ctx: MCP context. node_path: TOP node or TOPnet path. |
| pause_top_cookC | Pause cooking on a TOP network. Args: ctx: MCP context. node_path: TOP node or TOPnet path. |
| dirty_work_itemsB | Dirty work items on a TOP node so they can be regenerated. Args: ctx: MCP context. node_path: TOP node path. remove_outputs: Also remove output files from disk. |
| get_work_item_statesC | Get work item state counts for a TOP node. Args: ctx: MCP context. node_path: TOP node path. |
| get_work_item_infoC | Get detailed information about a specific work item. Args: ctx: MCP context. node_path: TOP node path. work_item_index: Work item index within the node. |
| get_pdg_graphC | Get the PDG dependency graph structure for a TOP network. Args: ctx: MCP context. node_path: TOPnet or TOP node path. |
| generate_static_itemsB | Generate static work items on a TOP node without cooking. Args: ctx: MCP context. node_path: TOP node path. |
| get_top_scheduler_infoC | Get information about TOP scheduler nodes in a network. Args: ctx: MCP context. node_path: TOP scheduler or TOPnet path. |
| get_failed_work_itemsC | List the work items that failed on a TOP node, with the tail of each log. Args: ctx: MCP context. node_path: TOP node path. limit: Maximum items returned. |
| get_top_logsA | Cook logs for a TOP node, or the scheduler log of one work item. Args: ctx: MCP context. node_path: TOP node path. work_item_index: Work item index; omit for the node's own errors and warnings. tail: Maximum characters of log text, taken from the end. |
| create_wrangleA | Create an Attribute Wrangle node with VEX code. LAST RESORT. VEX is for attribute math that no node expresses — NEVER for modeling, scattering, copying, deforming, grouping, or randomizing, which all have dedicated nodes. Building geometry in a wrangle when a native node exists is a failure, not a shortcut. The justification parameter is mandatory: state which list_node_types searches you ran and why none of the results can do this. If you cannot write that sentence honestly, you have not checked — check first. Args: parent_path: Parent SOP network path. vex_code: VEX snippet to set. justification: Which native nodes you checked (the actual list_node_types filters used) and why none can express this logic. run_over: Element to run over ("Points", "Vertices", "Primitives", "Detail", "Numbers"). name: Node name. |
| set_wrangle_codeC | Set VEX code on an existing Attribute Wrangle node. Args: node_path: Path to the wrangle node. vex_code: VEX snippet to set. |
| get_wrangle_codeC | Read the VEX code from an Attribute Wrangle node. Args: node_path: Path to the wrangle node. |
| create_vex_expressionA | Set an HScript expression on a parameter, evaluated before it is kept. Parameters cannot run VEX: attribute @ syntax is refused with a pointer to create_wrangle. An expression that does not evaluate is not kept. Args: node_path: Path to the node. parm_name: Parameter name. vex_code: Expression code, in HScript syntax. |
| validate_vexC | Validate VEX code by cooking the node and checking for errors. Args: node_path: Path to the wrangle node. |
| setup_pyro_simA | Build a Pyro smoke/fire simulation network from source geometry. Preferred over manual DOP wiring — builds the entire pyro network in one call: Pyro Source (density, temperature, burn), Volume Rasterize Attributes, Pyro Solver and a File Cache. For custom setups beyond what this provides, use create_node with DOP nodes (pyrosolver, smokeobject, volumesource, etc.). Args: source_geo: Source SOP path. container: Container type. res_scale: Resolution scale multiplier. substeps: DOP substeps. name: Top-level geo node name. |
| setup_rbd_simA | Build an RBD rigid-body simulation network with fracture and solver. Preferred over manual DOP wiring — builds the entire RBD network in one call. For source geometry, build SOP chains with native nodes (voronoifracture, booleanfracture, rbdmaterialfracture) instead of VEX. Args: geo_path: Source geometry object path. ground: Add a ground plane. pieces_type: Fracture method ("voronoi"). name: Top-level geo node name. |
| setup_flip_simA | Build a FLIP fluid simulation network from source geometry. Preferred over manual wiring — builds SideFX's SOP FLIP chain in one call: FLIP Container sized around the source, FLIP Boundary emitting from it, FLIP Solver with a ground plane at y=0, and a File Cache on the particles. Args: source_geo: Source SOP path. domain: Domain type. particle_sep: Particle separation distance. name: Top-level geo node name. |
| setup_vellum_simA | Build a Vellum simulation network with configure node and solver. Preferred over manual DOP wiring — builds the entire Vellum network in one call: the shelf's Configure recipe for the type, the Vellum Solver, and a Vellum I/O cache that keeps constraints and collisions with the geometry. Use Vellum Drape SOP to let cloth settle before the main simulation. Args: geo_path: Source geometry object path. sim_type: Simulation type ("cloth", "hair", "grain", "softbody"). substeps: Solver substeps. name: Top-level geo node name. ground: Turn on the solver's ground plane at y=0. |
| create_materialB | Create a material in /mat with configurable surface properties. Args: name: Material node name; refused if taken. Default: material1, numbered up when that exists. mat_type: Material type ("principled", "materialx"). base_color: [R, G, B] base color, 0-1 per channel. roughness: Surface roughness, 0-1. metallic: Metallic factor, 0-1. opacity: Opacity, 0-1. |
| assign_materialC | Assign a material to a geometry node via a Material SOP. Args: geo_path: Target geometry node path. material_path: Material to assign. |
| build_sop_chainA | Build a sequential chain of SOP nodes wired together in a single call. PREFERRED over individual create_node calls for linear SOP chains — builds and wires the entire chain in one round-trip, which is significantly faster. Each step dict: {"type": str, "name": str (optional), "params": dict (optional)}. Nodes are created in order and each is automatically connected to the previous. Example: steps=[ {"type": "box"}, {"type": "polybevel", "params": {"offset": 0.05}}, {"type": "scatter", "params": {"npts": 200}}, {"type": "copy_to_points", "name": "copy1"}, ] Args: parent_path: Parent SOP network path. steps: List of step dicts defining the chain. |
| setup_renderB | Set up a render configuration with camera and ROP node. Args: renderer: Renderer type ("karma", "mantra"). camera: Camera node path; creates one if omitted. output_path: Output image path (supports Houdini variables). resolution: [width, height] resolution. samples: Render sample count. name: ROP node name in /out. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| procedural_modeling_workflow | Guide for building a procedural modeling network in SOPs. Args: description: What geometry to create (e.g. "a rocky terrain with scattered trees") output_context: Where to create the geo container |
| usd_scene_assembly | Guide for building a USD scene in Houdini's LOPs/Solaris. Args: scene_description: Description of the USD scene to build |
| simulation_setup | Guide for setting up a dynamics simulation. Dispatches to the solver-specific guide when one exists, because a single generic file had to cover pyro, FLIP, Vellum, RBD and MPM at once and so could not say more than a table row about any of them. Houdini ships a separate manual per solver, and these files mirror that split. Anything without its own guide falls back to dyno.md, the general dynamics one. Args: sim_type: Type of simulation (pyro, flip, rbd, vellum, mpm, pop) description: Additional context about the simulation |
| pdg_pipeline | Guide for building a PDG/TOPs pipeline. Args: task_description: What the pipeline should accomplish |
| hda_development | Guide for creating a Houdini Digital Asset. Args: asset_description: What the HDA should do context: Node context for the HDA (Sop, Lop, Object, etc.) |
| copernicus_workflow | Guide for image work in Copernicus (COPs). Args: description: What to build (e.g. "a tileable rust texture") |
| heightfield_terrain | Guide for building terrain with heightfields. Args: description: The terrain to build (e.g. "an eroded desert mesa") |
| houdini_workflow | Guide for any Houdini subject the shipped manual documents. One entry point rather than a function per subject, so a new corpus needs a markdown file and nothing else. `topic` is the SideFX help scope name, which is also the markdown filename: character, render, shade, crowds, copy, props, dopparticles, io, anim, ocean, grains, muscles, finiteelements, feathers, fur, ml, composite, heightfields_cop, plus every subject that has its own named prompt (pyro, fluid, vellum, destruction, mpm, solaris, tops, model, assets, copernicus, heightfields, dyno, troubleshooting). Args: topic: Help scope name for the subject, e.g. "character" or "render" description: What you are trying to build |
| debug_scene | Systematic approach to debugging a Houdini scene. Args: problem_description: What problem the user is experiencing |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| scene_info | Current Houdini scene information including hip file, version, frame range, and node counts. |
| scene_tree | Top-level node tree of the current scene. |
| scene_errors | All nodes with errors or warnings in the scene. |
| installed_hdas | List of installed Houdini Digital Assets. |
TDQS
Scored across 215 tools
Several clusters overlap in purpose: get_parameter/get_parameters/get_parameter_schema/get_node_card/get_parm_template_tree all read parameter data, while capture_screenshot/render_viewport/render_quad_view/render_node_network/capture_network_editor all capture images, and execute_hscript/execute_python/evaluate_expression/set_expression/create_vex_expression all involve expressions. The very detailed descriptions explicitly steer between many of these, but with 215 tools an agent still faces real misselection risk.
Almost all names follow a predictable snake_case verb_noun pattern (get_parameter, set_parameters, create_node, list_usd_prims, build_network), which is highly consistent across contexts. Minor deviations exist, such as playbar_control, undo/redo, and a few noun-first or verb-only names, but these are rare and readable.
At 215 tools this is far beyond the typical well-scoped range and places a heavy selection and context burden on the agent, even for a domain as broad as Houdini. The breadth justifies some expansion, but the surface is clearly over-large and would benefit from consolidation or progressive disclosure.
Coverage is unusually broad: node creation/deletion/wiring, parameter read/write/expressions, geometry inspection, DOP/TOP/CHOP/COP/LOP workflows, USD, HDAs, caches, rendering, viewport, takes, undo and session management are all present. There are minor gaps (e.g. no dedicated spare-parameter removal or parameter renaming), but agents can generally work around them with the provided escape hatches.