Claude
Skills
Sign in
Back

blender-mcp

Included with Lifetime
$97 forever

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.

AI Agents

What this skill does


# 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:

```bash
# 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](#known-errors--workarounds).

### Step 2: Inspect Scene

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

```python
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:

```python
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:

```bash
# 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`:

```bash
# 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](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](https://sandbox.babylonjs.com). Verify: mesh renders correctly, textures appear, animations play, no black/pink materials.
- [ ] **No Three.js console errors** — load in a minimal T
Files: 4
Size: 47.9 KB
Complexity: 51/100
Category: AI Agents

Related in AI Agents