vladmdgolam/agent-skills4 files

Blender MCP

Blender MCP expert for scene inspection, Python scripting, GLTF export, and material/animation extraction. Activate when: (1) using Blender MCP tools (get_scene_info, execute_python, screenshot, etc.), (2) writing Blender Python scripts for extraction or manipulation, (3) exporting scenes to GLTF/GLB for web (Three.js, R3F), (4) debugging material or texture export losses, (5) optimizing GLB files with gltf-transform, (6) using asset integrations (PolyHaven, Sketchfab, Hyper3D Rodin, Hunyuan3D). Covers critical export gotchas, material mapping survival, texture optimization pipeline, headless CLI patterns, and known failure modes.

Specification
Skill ID
vladmdgolam/agent-skills/blender-mcp
Publisher
vladmdgolam
Repository
agent-skills
Installs
0
Files
4
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

vladmdgolam/agent-skills/blender-mcpInstalls these files
  • SKILL.md
  • references/asset-integrations.md
  • references/errors.md
  • references/texture-optimization.md

What this skill tells the agent

Blender MCP

Tool Selection

Use structured MCP tools (get_scene_info, screenshot) for quick inspection.

Use `execute_python` for anything non-trivial: hierarchy traversal, material extraction, animation baking, bulk operations. It gives full bpy API access and avoids tool schema limitations.

Use headless CLI for GLTF exports — the MCP server times out on export operations.

Health Check (Always First)

  1. get_scene_info — verify connection (default port 9876)
  2. execute_python with print("ok") — verify Python works
  3. screenshot — verify viewport capture works

If MCP is unresponsive, check that the Blender MCP addon is enabled and the socket server is running.

Complete Export Workflow

This is the end-to-end linear narrative. Follow these steps in order. Do not skip steps.

Step 1: Health Check

Confirm MCP is alive before touching anything else:

# In MCP tool call:
get_scene_info
execute_python: print("ok")
screenshot

If any step fails, stop and fix MCP connectivity first. See Known Errors.

Step 2: Inspect Scene

Run the full hierarchy extraction to understand what you're working with:

import bpy, json

def extract_hierarchy(obj, depth=0):
    data = {
        "name": obj.name,
        "type": obj.type,
        "location": list(obj.location),
        "rotation": list(obj.rotation_euler),
        "scale": list(obj.scale),
        "visible": not obj.hide_viewport,
        "children": [],
    }
    if obj.type == 'MESH' and obj.data:
        data["vertices"] = len(obj.data.vertices)
        data["faces"] = len(obj.data.polygons)
        data["materials"] = [slot.material.name for slot in obj.material_slots if slot.material]
    if obj.type == 'LIGHT':
        data["light_type"] = obj.data.type
        data["energy"] = obj.data.energy
        data["color"] = list(obj.data.color)
    for mod in obj.modifiers:
        if mod.type == 'ARRAY':
            data.setdefault("modifiers", []).append({
                "type": "ARRAY",
                "count": mod.count,
                "offset_object": mod.offset_object.name if mod.offset_object else None,
            })
    for child in obj.children:
        data["children"].append(extract_hierarchy(child, depth + 1))
    return data

scene_data = {
    "name": bpy.context.scene.name,
    "fps": bpy.context.scene.render.fps,
    "frame_start": bpy.context.scene.frame_start,
    "frame_end": bpy.context.scene.frame_end,
    "objects": [],
}
for obj in bpy.context.scene.objects:
    if obj.parent is None:
        scene_data["objects"].append(extract_hierarchy(obj))

print(json.dumps(scene_data, indent=2))

Look for:

  • Array modifiers (will balloon file size if baked — must replicate at runtime)
  • Objects with many vertices (risk of slow export or large GLB)
  • Hidden objects you may or may not want to export
  • Missing materials (empty material_slots)

Step 3: Verify Materials

Run the material extraction to catch export-lossy setups before committing to an export:

import bpy, json

def extract_materials():
    materials = []
    for mat in bpy.data.materials:
        if not mat.use_nodes:
            continue
        info = {"name": mat.name, "nodes": [], "warnings": []}
        has_principled = False
        for node in mat.node_tree.nodes:
            node_data = {"type": node.type, "name": node.name}
            if node.type == 'BSDF_PRINCIPLED':
                has_principled = True
                for inp in node.inputs:
                    if inp.is_linked:
                        node_data[inp.name] = "linked"
                    elif hasattr(inp, 'default_value'):
                        val = inp.default_value
                        try:
                            node_data[inp.name] = list(val)
                        except TypeError:
                            node_data[inp.name] = float(val)
            if node.type == 'TEX_IMAGE' and node.image:
                node_data["image"] = node.image.filepath
                node_data["size"] = [node.image.size[0], node.image.size[1]]
                if node.image.size[0] > 2048:
                    info["warnings"].append(f"Large texture: {node.image.filepath} ({node.image.size[0]}x{node.image.size[1]})")
            if node.type in ('TEX_NOISE', 'TEX_VORONOI', 'TEX_WAVE', 'TEX_MUSGRAVE'):
                info["warnings"].append(f"Procedural texture node '{node.name}' ({node.type}) will be LOST on GLTF export")
            if node.type == 'VALTORGB':  # Color Ramp
                info["warnings"].append(f"Color Ramp '{node.name}' remapping will be LOST on GLTF export")
        if not has_principled:
            info["warnings"].append("No Principled BSDF found — export result unpredictable")
        info["nodes"].append(node_data)
        materials.append(info)
    return materials

result = extract_materials()
for mat in result:
    if mat["warnings"]:
        print(f"WARN [{mat['name']}]: {'; '.join(mat['warnings'])}")
print(json.dumps(result, indent=2))

Review all warnings before proceeding. Decide: bake procedural textures now, or patch materials at runtime after export.

Step 4: Export via Headless CLI

The MCP server cannot handle GLTF exports (timeout). Always use headless CLI:

# Use 'blender' if it's on PATH, otherwise use the platform-specific path:
#   macOS:   /Applications/Blender.app/Contents/MacOS/Blender
#   Windows: "C:\Program Files\Blender Foundation\Blender 4.x\blender.exe"
#   Linux:   /usr/bin/blender
blender \
  --background "/path/to/scene.blend" \
  --python-expr "
import bpy, os
export_path = '/path/to/output.glb'
os.makedirs(os.path.dirname(os.path.abspath(export_path)), exist_ok=True)
bpy.ops.export_scene.gltf(
    filepath=export_path,
    export_format='GLB',
    export_apply=False,
    export_animations=True,
    export_nla_strips=True,
    export_cameras=True,
    export_lights=False,
    export_draco_mesh_compression_enable=False,
)
size_mb = os.path.getsize(export_path) / 1024 / 1024
print(f'Export complete: {export_path} ({size_mb:.1f} MB)')
"

Critical flags:

  • export_apply=False — do not bake modifiers (Array modifier turns 1 MB into 56 MB)
  • export_draco_mesh_compression_enable=False — apply Draco later via gltf-transform
  • Quote all paths that may contain spaces

Step 5: Optimize with gltf-transform

Run after a successful export. Always use individual steps, never optimize:

# 1. Inspect raw export first
npx @gltf-transform/cli inspect output.glb

# 2. Resize textures (max 1K for web/mobile)
npx @gltf-transform/cli resize output.glb resized.glb --width 1024 --height 1024

# 3. WebP compression (quality 90 preserves detail)
npx @gltf-transform/cli webp resized.glb webp.glb --quality 90

# 4. Draco mesh compression (LAST — irreversible)
npx @gltf-transform/cli draco webp.glb final.glb

# 5. Inspect final result
npx @gltf-transform/cli inspect final.glb

Expected size reduction: ~22 MB raw → ~3.7 MB (WebP) → ~1 MB (Draco). See references/texture-optimization.md for detailed metrics.

Step 6: Validate

Run the full Post-Export Validation checklist below before shipping.

Post-Export Validation Checklist

After every export, verify the following before handing off the GLB for integration:

  • [ ] File size is reasonable — raw GLB under 30 MB, optimized GLB under 5 MB for typical web scenes. Flag anything above these thresholds.
  • [ ] Inspect with gltf-transform CLI — run npx @gltf-transform/cli inspect final.glb and check: mesh count, texture count, texture sizes, animation count, accessor sizes. No unexpected duplication.
  • [ ] Visual test in Babylon.js Sandbox — drag-and-drop the GLB at sandbox.babylonjs.com. Verify: mesh renders correctly, textures appear, animations play, no black/pink materials.

Use this skill in a project

Open any RiverX project, search the Skills panel for vladmdgolam/agent-skills/blender-mcp, and install it in one click.

Use this skill