Blender MCP
PHATT's headless blender-mcp-veles server: 10.0.0.100:9876, raw TCP JSON-RPC; not stock ahujasid/blender-mcp. No local Blender, GUI addon, or uvx required. Python 3 plus network access is enough.
Connect
Replace SKILL_DIR with this skill's absolute directory. Use native tools if exposed; otherwise use the bundled client:
python3 SKILL_DIR/scripts/blender.py init
python3 SKILL_DIR/scripts/blender.py call get_scene_info '{}'
python3 SKILL_DIR/scripts/blender.py tools
Expect server identity, scene data, and live tool schemas. Override host/port with BLENDER_HOST / BLENDER_PORT. The client initializes each connection, buffers responses, saves inline images, and exits nonzero on errors.
Preserve and find work
Shared scene: coordinate ownership, make calls serially, and save an unused checkpoint before changes. Never automatically clear the scene or overwrite someone else's assets.
Choose the project-loading route; do not stop at the historical crash warning. To bring assets into the shared scene, append selected objects. To open/render a complete .blend, use a separate Blender process with the file loaded at startup. Recipes: existing .blend files. load_blend passed three isolated tests using the deployed server on 2026-09-07 (Brother Green Paw, chair, tree). This demonstrates that the handler worked in those tests, not that replacing an active shared scene is harmless. Do not call load_blend, bpy.ops.wm.open_mainfile, or read_homefile in the shared production MCP interpreter. Isolated tests of that handler require explicit authorization; ordinary project work should use the established routes without asking again.
Tool paths are inside the server: /projects/ = host /mnt/user/shared-projects/blender = Paperclip /paperclip/blender-projects when mounted. OpenClaw has no assumed mount. Copy local files into the shared project tree before importing.
python3 SKILL_DIR/scripts/blender.py call list_files '{"path":"/projects/","pattern":".blend"}'
python3 SKILL_DIR/scripts/blender.py call execute_python '{"code":"from pathlib import Path; Path(\"/projects/my-job\").mkdir(parents=True, exist_ok=True)"}'
python3 SKILL_DIR/scripts/blender.py call save_blend '{"filepath":"/projects/my-job/checkpoint-001.blend"}'
Replace my-job and filenames with actual project paths.
Assets: search before modeling
For ordinary props (a chair, tree, crate), search existing assets before building custom geometry. Call asset_creation_strategy first. Free assets licensed for commercial use are authorized; do not ask permission again for each prop. Prefer Poly Haven CC0, then Sketchfab CC0. For other free commercial-use licenses, verify the actual terms and retain required attribution; exclude noncommercial/editorial-only assets. Record asset URL, creator when relevant, license and attribution with the project. No purchases, paid APIs, trials, or new subscriptions without approval. A free asset license does not automatically authorize paid API access.
Poly Haven and Sketchfab were already enabled at the 2026-09-07 audit. Check live status when needed; do not reinstall integrations merely because a task needs an asset. If credentials or access are unavailable, report the specific blocker and use another authorized source where possible. Do not change credentials or containers.
python3 SKILL_DIR/scripts/blender.py call search_polyhaven_assets '{"asset_type":"models"}'
python3 SKILL_DIR/scripts/blender.py call search_polyhaven_assets '{"asset_type":"textures","categories":"brick"}'
python3 SKILL_DIR/scripts/blender.py call get_sketchfab_status '{}'
python3 SKILL_DIR/scripts/blender.py call search_sketchfab '{"query":"wooden chair","license":"cc0","count":5}'
Consult live schemas for supported filters. Poly Haven: download_polyhaven_asset with returned asset_id, asset_type, and resolution:"1k"; apply textures using set_texture with object_name and texture_id. Sketchfab: use returned uid with download_sketchfab_model.
Asset download tools can import into the active scene. Treat them as scene mutations, not download-only helpers. Use them only in the scene you own; isolated asset tests must not use production MCP to import their fixtures. For download-only work, fetch the complete asset and dependencies from its documented source into the project directory.
Complete the asset, not just the mesh: retrieve referenced textures, resolve missing paths, preserve material connections and foliage alpha, and pack supported image dependencies into the final .blend. Check dependencies before saving and inspect a render afterward. Magenta materials, missing foliage, or broken transparency mean the import is unfinished.
Import, edit, save
For GLB/GLTF, FBX, OBJ, STL:
python3 SKILL_DIR/scripts/blender.py call import_model '{"filepath":"/projects/my-job/model.glb"}'
python3 SKILL_DIR/scripts/blender.py call get_scene_info '{}'
python3 SKILL_DIR/scripts/blender.py call modify_object '{"object_name":"Cube","location":[0,0,1],"rotation":[0,0,25]}'
python3 SKILL_DIR/scripts/blender.py call set_material '{"object_name":"Cube","material_name":"Blue","color":[0.05,0.2,0.8,1],"roughness":0.4}'
python3 SKILL_DIR/scripts/blender.py call save_blend '{"filepath":"/projects/my-job/result.blend"}'
Use actual object names from inspection. Create geometry with create_object, e.g. {"type":"SPHERE","name":"Ball","location":[0,0,0],"size":0.5}. For .blend assets, append selected objects or open the full file in a separate process per the reference above.
For arbitrary edits, write a local Python script importing bpy, then send its contents:
python3 SKILL_DIR/scripts/blender.py python /absolute/local/edit_scene.py
Batch related edits; print brief summaries. Structured object rotations are degrees; Python rotation_euler uses radians. Cycles cannot use Shader to RGB: avoid cel_shade/diffuse_steps, use emission_flat or compatible materials.
Preview, render, deliver
GPU: Blender 4.2/Cycles CUDA on the Quadro K2200; no OptiX or silent CPU fallback. Serialize renders and coordinate GPU use, including separate Blender processes.
python3 SKILL_DIR/scripts/blender.py --timeout 600 --image-out /tmp/preview.png call get_preview_render '{"max_size":512,"samples":8,"engine":"CYCLES"}'
Open the downloaded preview with an image tool. The preview restores temporary settings and supplies a temporary camera if needed. Frame the whole subject with margins; make surfaces readable through lighting and contrast. Check missing textures, foliage transparency, clipping and exposure. Fix visible defects before a full render; a successful render command alone is not visual verification.
Only if the working scene lacks a camera/light:
python3 SKILL_DIR/scripts/blender.py call setup_camera '{"preset":"isometric","ortho_scale":5}'
python3 SKILL_DIR/scripts/blender.py call create_object '{"type":"LIGHT","name":"KeyLight","light_type":"POINT","location":[2,-3,5],"light_energy":1000}'
Configure and render:
python3 SKILL_DIR/scripts/blender.py call execute_python '{"code":"import bpy; p=bpy.context.preferences.addons[\"cycles\"].preferences; p.compute_device_type=\"CUDA\"; p.get_devices(); gpu=[d for d in p.devices if d.type==\"CUDA\" and \"K2200\" in d.name]; assert gpu, \"K2200 CUDA unavailable\"; [setattr(d,\"use\",d in gpu) for d in p.devices]; print([(d.name,d.use) for d in p.devices])"}'
python3 SKILL_DIR/scripts/blender.py call set_render_settings '{"engine":"CYCLES","device":"GPU","resolution_x":1024,"resolution_y":1024,"samples":32,"transparent":false,"output_format":"PNG"}'
python3 SKILL_DIR/scripts/blender.py --timeout 7200 call render_image '{"output_path":"/projects/my-job/final.png"}'
python3 SKILL_DIR/scripts/blender.py call save_blend '{"filepath":"/projects/my-job/result.blend"}'
python3 SKILL_DIR/scripts/blender.py call list_files '{"path":"/projects/my-job/"}'
For animation, replace the render call with:
python3 SKILL_DIR/scripts/blender.py --timeout 7200 call render_animation '{"output_path":"/projects/my-job/frame_","frame_start":1,"frame_end":24,"frame_step":1}'
Allow the shell at least the client's deadline, or use background execution with completion checks. A timeout does not cancel Blender: inspect logs/process/output evidence before another mutation; never retry blindly or restart services.
The client downloads inline previews only. Final renders remain on the server; retrieve through an existing shared mount or approved file transfer. Paperclip's mounted final path is /paperclip/blender-projects/my-job/final.png. Verify files exist, inspect the actual images, then attach them in the visible reply along with the saved .blend path. When screenshots are requested, deliver images—not merely a statement that they rendered. Clearly label interim previews and remaining defects.
Connection errors: report endpoint/reachability, no install/restart. Invalid arguments: consult tools. Missing files: inspect server paths, not local ones. Upstream uses different names/protocols—see compatibility.