Blender session
A Blender session (pipeline/blender.js, class BlenderSession) is the only
way the pipeline touches Blender: a Blender MCP server spoken to over stdio
JSON-RPC — never hand-rolled sockets, never a hand-managed Blender subprocess.
Shape
- Spawn:
uvx blender-mcpby default.blender.mcp.command+blender.mcp.argsoverride the executable;blender.mcp.uvx: falsefalls back to a bareblender-mcpbinary;blender.mcp.uvxBinrenames the uvx executable. - Tool surface used: exactly
get_scene_infoandexecute_blender_code. Everything else — import, export, decimate, rig — is Blender Python (bpy) sent throughexecute_blender_code. - Environment: the MCP child gets a scrubbed environment (PATH/HOME only), so no credential can leak through env inheritance.
Lifecycle
BlenderSession.start(options)spawns the server and performs the MCP handshake. A failed start throws:blender MCP server failed to start (<command> <args>): <reason>. Run 'node pipeline/setup.js' to provision Blender + blender-mcp.execute(code)wraps the code intry/exceptbefore sending. The addon's execute path has a nasty failure mode: an exception escaping the executed block kills the addon's server thread (every subsequent call gets "connection refused"). Wrapping turns bugs into capturedGAC-EXEC-ERROR: <traceback>output instead — the error still reaches the caller, but the session survives.importModel(path)resets the scene through the data API only (objects, actions, meshes, armatures, materials) and imports the GLB.bpy.ops.wm.read_factory_settingsis never used — it would wipe the addon's scene properties and kill the MCP server thread. Stale actions are removed too: leaving an oldflapaction made previews pick a stale clip after repeated imports.exportGlb(path)exports the whole scene and stats the file; an absent or empty file throwsexport produced no file at <path>: <reason>.close()ends the MCP process.
Health
isHealthy() is three checks, because the MCP server starts fine even when
the Blender side of the bridge is dead — tool listing alone lies:
- the server answers
tools/list, execute_blender_codeis among the tools,- a trivial
print("health-probe")actually round-trips into Blender.
glina blender-health prints { healthy, tools } and exits 0/1 on it.
The bridge itself
The MCP server bridges into Blender's own addon listening on
127.0.0.1:9876. The addon requires a GUI Blender session.
scripts/ensure-blender.sh guards invocations: if port 9876 is not
answering it launches Blender ($BLENDER_BIN, default
/opt/homebrew/bin/blender), waits up to 60 s for the bridge, then execs the
real command — or fails with ensure-blender: bridge did not come up.
Invariants
- One session per job; sessions are always closed in a
finally, even on failure. - Consumers that see three consecutive execute failures stop probing — see the sculpt job bridge-down rule.