Metadata-Version: 2.4
Name: blender-studio-pro-mcp
Version: 1.0.0
Summary: Comprehensive Blender MCP server with search+execute architecture — 220+ tools, asset management, real-time collaboration, visual programming, synthetic dataset generation, and more
License: MIT
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: mcp[cli]>=1.5.0
Requires-Dist: pillow>=10.0.0
Requires-Dist: pyyaml>=6.0.0
Provides-Extra: dev
Requires-Dist: pyright>=1.1.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest-timeout>=2.3.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Description-Content-Type: text/markdown

# Blender Studio MCP

A comprehensive [Model Context Protocol](https://modelcontextprotocol.io/) server for Blender, giving AI assistants full control over a running Blender session. Built with a **search + execute** architecture that exposes 215 tools through just three MCP endpoints — keeping your AI's context window lean while retaining the full capability set.

Compatible with Claude, Cursor, VS Code, and any MCP-capable client.

---

## Features

- **220 Blender tools** across 50 categories — objects, materials, UV, shape keys, constraints, rigging, animation, NLA, rendering, physics, mesh cleanup, compositor, curves, drivers, library linking, custom properties, vertex attributes, world/environment, timeline markers, node groups, batch execution, asset management, real-time collaboration, visual programming, synthetic data generation, and more
- **Search + execute architecture** — LLMs call `search_tools` to discover capabilities, then `execute_tool` or `execute_tools` to act, without loading all tool schemas into context
- **Natural language search** — `search_tools("shiny metal")` finds `create_material`; examples and use-cases are embedded in every tool so AI agents discover the right tools faster
- **Context-aware suggestions** — `blender://suggestions` resource returns the most relevant next tools based on scene state and command history
- **Intelligent asset management** — index thousands of `.blend` files into a local SQLite + FTS5 database; full-text search, dependency tracking, Git-aware loading, and context-aware recommendations
- **Real-time collaboration** — multi-client sessions with per-object locking, pub/sub event feed, heartbeat monitoring, and shared checkpoints; supports editor and observer roles
- **Safe batch execution** — `execute_tools_safe` dry-runs all steps first, creates a checkpoint, and auto-rolls back if anything fails
- **Sandbox mode** — set `BLENDER_MCP_SANDBOX=1` to block destructive operations (delete, clear, Python execution) during safe exploration
- **Auto-checkpoint** — set `BLENDER_MCP_AUTO_CHECKPOINT=1` to automatically snapshot state before any destructive operation
- **Fuzzy error correction** — "Did you mean 'Unity Camera'?" when an object name is mistyped
- **Tool reference generator** — `generate_tool_docs` produces a complete Markdown reference of all tools with parameters and examples
- **Batch execution** — `execute_tools` runs multiple tools in one call, eliminating round-trips for multi-step workflows
- **Full Blender 5.x support** — tested against Blender 5.2 including the Grease Pencil v3 API
- **AI model generation** — text-to-3D via Hyper3D Rodin, TripoAI, and Tencent Hunyuan3D
- **Asset library integration** — search and import from [Poly Haven](https://polyhaven.com), [Ambient CG](https://ambientcg.com) (both free, no key), and [Sketchfab](https://sketchfab.com)
- **Headless mode** — spawn `blender --background` for batch operations without a GUI session
- **Arbitrary Python execution** — run any `bpy` code in the live Blender session and capture output
- **Command history** — rolling log of the last 50 executed commands, available as an MCP resource

---

## Architecture

```
AI Client (Claude, Cursor, etc.)
       │
       │  MCP (stdio)
       ▼
blender-studio-mcp  ←── search_tools / execute_tool / execute_tools
       │
       │  TCP socket (port 9877, newline-delimited JSON)
       ▼
Blender addon (blender_studio_addon.py)
       │
       │  bpy.app.timers (main thread)
       ▼
Blender Python API
```

All `bpy` calls execute on Blender's main thread via a queue + timer, satisfying Blender's strict thread-safety requirements. Every executed command is recorded in a rolling history log.

---

## Installation

### 1. Install the Blender addon

1. Open Blender → **Edit → Preferences → Add-ons → Install from Disk**
2. Select `addon/blender_studio_addon.py` from this repository
3. Enable **Blender Studio MCP** in the add-ons list
4. In the **3D Viewport → Sidebar (N) → MCP** tab, click **Start MCP Server**

The server binds to `localhost:9877` by default. Port and host are configurable in the panel.

### 2. Install the MCP server

**Via `uvx` (recommended — no install required):**

```bash
uvx blender-studio-mcp
```

**Via `uv` (persistent install):**

```bash
uv tool install blender-studio-mcp
blender-studio-mcp
```

**Via `pip`:**

```bash
pip install blender-studio-mcp
blender-studio-mcp
```

---

## MCP Client Configuration

### Claude Desktop / Claude Code

Add to your `claude_desktop_config.json` or `.mcp.json`:

```json
{
  "mcpServers": {
    "blender-studio": {
      "type": "stdio",
      "command": "uvx",
      "args": ["blender-studio-mcp"],
      "env": {
        "BLENDER_PORT": "9877"
      }
    }
  }
}
```

### Cursor

Add to `.cursor/mcp.json` in your project root:

```json
{
  "mcpServers": {
    "blender-studio": {
      "command": "uvx",
      "args": ["blender-studio-mcp"]
    }
  }
}
```

---

## Environment Variables

| Variable | Required | Description |
|---|---|---|
| `BLENDER_HOST` | No | Blender addon host (default: `localhost`) |
| `BLENDER_PORT` | No | Blender addon port (default: `9877`) |
| `BLENDER_TIMEOUT` | No | Socket timeout in seconds (default: `60`) |
| `BLENDER_EXECUTABLE` | No | Path to Blender binary (default: `blender` on `$PATH`) |
| `BLENDER_MCP_VERBOSE` | No | Enable DEBUG logging (`1` = enabled) |
| `BLENDER_MCP_LOG_LEVEL` | No | Explicit log level override (`DEBUG`, `INFO`, `WARNING`) |
| `BLENDER_MCP_AUDIT_LOG` | No | Enable persistent audit logging to `~/.blender_studio_mcp/audit.jsonl` (`1` = enabled) |
| `BLENDER_MCP_SANDBOX` | No | Block destructive operations — delete, clear, Python execution (`1` = enabled) |
| `BLENDER_MCP_AUTO_CHECKPOINT` | No | Auto-snapshot state before destructive operations (`1` = enabled) |
| `RODIN_API_KEY` | For Rodin | [Hyper3D Rodin](https://hyper3d.ai) API key |
| `TRIPO_API_KEY` | For Tripo | [TripoAI](https://www.tripo3d.ai) API key |
| `HUNYUAN_API_KEY` | For Hunyuan | Tencent Hunyuan3D API key |
| `SKETCHFAB_API_KEY` | For Sketchfab | [Sketchfab](https://sketchfab.com/settings/password) API key |
| `MESHY_API_KEY` | For Meshy | [Meshy AI](https://www.meshy.ai) API key |
| `LUMA_API_KEY` | For Luma | [Luma AI](https://lumalabs.ai) API key |
| `BLENDERKIT_API_KEY` | For paid BlenderKit assets | [BlenderKit](https://www.blenderkit.com) API key (free assets need no key) |

Poly Haven and Ambient CG require no API key.

---

## Usage

The server exposes three MCP tools. An AI assistant uses `search_tools` to discover what's available, then `execute_tool` for single operations or `execute_tools` for multi-step workflows.

### search_tools

```
search_tools(query="material", limit=10)
```

Returns matching tool names, descriptions, and full parameter schemas. Use an empty query to list all 77 tools.

### execute_tool

```
execute_tool(tool_name="create_material", params={
  "name": "Chrome",
  "color": [0.8, 0.8, 0.8],
  "metallic": 1.0,
  "roughness": 0.05
})
```

Routes to Blender or a custom handler (for AI generation, asset downloads, headless execution).

### execute_tools

Run multiple tools in one call — each step reports success or failure independently:

```
execute_tools(tools=[
  {"tool_name": "create_object",   "params": {"object_type": "SPHERE", "name": "Ball"}},
  {"tool_name": "create_material", "params": {"name": "Red", "color": [1, 0, 0]}},
  {"tool_name": "assign_material", "params": {"object_name": "Ball", "material_name": "Red"}},
  {"tool_name": "unwrap_uv",       "params": {"object_name": "Ball"}}
])
```

Set `stop_on_error: false` to continue the sequence even if an individual step fails.

---

## Advanced Workflow Features (Phase 3)

### Checkpoints & Transactions

Save and restore Blender state for safe experimentation:

```python
# Create a checkpoint before risky operations
create_checkpoint(name="before_boolean", description="Pre-boolean op state")

# Start a transaction with automatic checkpoint
begin_transaction(name="complex_workflow")

# ... perform multiple operations ...

# Commit if successful, or rollback to discard changes
commit()  # or rollback()

# List and restore checkpoints
list_checkpoints(limit=10)
restore_checkpoint(name="before_boolean")
```

Checkpoints are saved to `~/.blender_studio_mcp/checkpoints/` with metadata (timestamp, scene info, file size).

### Macro Recording & Playback

Capture and replay command sequences with variable substitution:

```python
# Record a workflow
start_recording(name="my_workflow")
create_object(object_type="CUBE", name="Box")
create_material(name="Red", color=[1, 0, 0])
assign_material(object_name="Box", material_name="Red")
stop_recording()  # Returns captured commands

# Save for reuse
save_macro(name="create_red_cube", commands=[...], description="...")

# Execute with variable substitution
execute_macro(
    name="create_red_cube",
    variables={"object_name": "MyBox", "material_name": "MyRed"}
)

# List available macros
list_macros()
```

Macros support `${variable}` syntax for dynamic values. Bundled macros include:
- **setup_pbr_sphere**: UV-unwrapped sphere with PBR material
- **setup_product_lighting**: Three-point lighting setup
- **game_ready_export_prep**: Apply transforms, triangulate, recalc normals

---

## AI-Specific Features (Phase 5)

### Context-Aware Suggestions

Read the `blender://suggestions` resource to get the most relevant next tools based on your current scene:

```
blender://suggestions
→ {"suggestions": [
    {"tool": "assign_material", "reason": "Apply material to object", "confidence": 0.95},
    {"tool": "set_material_property", "reason": "Adjust material properties", "confidence": 0.7}
  ], "context": {"recent_commands": ["create_material"], ...}}
```

### Natural Language Search

`search_tools` now understands natural language queries:

```
search_tools("shiny metal")              → create_material
search_tools("prepare mesh for texturing") → unwrap_uv
search_tools("set up studio lighting")   → set_hdri_environment
```

Results include an `examples[]` field so AI agents can immediately see how each tool is used.

### Fuzzy "Did you mean?" Errors

Typos in object or material names produce helpful corrections:

```
execute_tool("set_location", {"name": "Spheer", ...})
→ RuntimeError: Object not found: 'Spheer'
  Suggestions:
    • Did you mean 'Sphere'? (found 4 objects/materials in scene)
```

---

## Visual Programming & Node Workflows (Phase 10)

### `visualize_macro` — Flowchart Diagrams

Convert any saved macro into a Mermaid or Graphviz diagram for documentation or debugging:

```
visualize_macro("studio_setup", format="mermaid")
→ {
    "name": "studio_setup",
    "format": "mermaid",
    "diagram": "flowchart TD\n  Start([Start])\n  Step0[\"create_object<br/>type=PLANE\"]\n  ...",
    "complexity": {"total_steps": 8, "unique_tools": 6, "complexity_score": 58, ...}
  }
```

Paste the `diagram` value into any Mermaid renderer (GitHub, Notion, VS Code extension) to see your workflow as a visual flowchart.

### `create_macro_from_diagram` — Visual Macro Builder

Create macros by writing a Mermaid flowchart instead of JSON:

```
create_macro_from_diagram(
  diagram_text="""
    flowchart TD
      Start([Start])
      Step0["create_object<br/>type=SPHERE, name=Hero"]
      Step1["create_material<br/>name=HeroMat"]
      Step2["assign_material<br/>object_name=Hero, material_name=HeroMat"]
      End([End])
      Start --> Step0 --> Step1 --> Step2 --> End
  """,
  name="hero_setup",
  description="Create and material a hero sphere"
)
→ {"saved": true, "commands_count": 3, "valid": true, "errors": [], "warnings": []}
```

### `analyze_node_graph` — Node Tree Analysis

Detect unused nodes and complexity issues in a material's shader graph:

```
analyze_node_graph("HeroMat")
→ {
    "material": "HeroMat",
    "total_nodes": 12,
    "unused_nodes": ["Mix Shader.001", "Texture Coordinate.002"],
    "link_count": 18,
    "suggestions": [
      {"priority": "high", "type": "remove_unused_nodes", "description": "Remove 2 unused nodes", ...}
    ]
  }
```

### `auto_wire_nodes` — Smart Socket Connection

Automatically connect compatible sockets between two nodes based on type matching and name similarity:

```
auto_wire_nodes("HeroMat", from_node="Image Texture", to_node="Principled BSDF", confidence_threshold=0.7)
→ {
    "connections_made": 2,
    "details": [
      {"from": "Image Texture.Color", "to": "Principled BSDF.Base Color", "score": 1.0},
      {"from": "Image Texture.Alpha", "to": "Principled BSDF.Alpha", "score": 0.9}
    ]
  }
```

---

## Synthetic Training Data Generation (Phase 12)

### `generate_synthetic_scene` — Procedural Scene Builder

Populate a Blender scene from a named template with a reproducible seed:

```
generate_synthetic_scene(template="product_photography", seed=42, render_output="/tmp/rgb.png", render_width=512, render_height=512)
→ {"template": "product_photography", "seed": 42, "objects_created": 2, "lights_created": 2, "rendered": true}
```

Built-in templates: `product_photography`, `interior_scene`, `object_detection`.  Same seed always produces the same scene.

### `export_training_sample` — Ground Truth Exporter

Render RGB + segmentation mask + 2D bounding boxes for the current scene:

```
export_training_sample(output_dir="/data/train", sample_id=0, width=512, height=512, include_segmentation=True, include_bbox=True)
→ {"sample_id": 0, "rgb": "sample_000000_rgb.png", "annotations": "sample_000000_annotations.json", ...}
```

### `generate_dataset` — Batch Pipeline

Generate thousands of labeled samples in one call:

```
generate_dataset(template="object_detection", num_samples=1000, output_dir="/data/my_dataset", start_seed=0)
→ {"status": "complete", "num_samples": 1000, "manifest": "/data/my_dataset/dataset.json", "elapsed_seconds": 342.1}
```

### `export_coco_annotations` / `export_yolo_annotations` — ML Format Export

Convert a generated dataset to COCO JSON or YOLO .txt format:

```
export_coco_annotations(annotations_dir="/data/my_dataset", output_path="/data/coco.json", class_names=["box", "ball"])
export_yolo_annotations(annotations_dir="/data/my_dataset", output_dir="/data/yolo_labels", class_names=["box", "ball"])
```

---

## Performance Profiling & Optimization (Phase 11)

### `get_performance_stats` — Live Timing Analytics

Track execution time for every tool call this session. Sorted slowest-first, with full percentile breakdown:

```
get_performance_stats(limit=5)
→ {
    "total_calls": 47,
    "statistics": [
      {"command": "render_image",  "executions": 3,  "mean_ms": 8234.0, "p95_ms": 9100.0, "success_rate": 1.0},
      {"command": "bake_texture",  "executions": 1,  "mean_ms": 4210.0, ...},
      ...
    ]
  }
```

Also available as the `blender://perf-stats` MCP resource for zero-cost polling.

### `estimate_render_time` — Predict Before You Render

Get a ±30% time estimate before committing to a long render:

```
estimate_render_time(samples=512, width=3840, height=2160, engine="CYCLES")
→ {
    "estimated_seconds": 342.1,
    "estimated_minutes": 5.7,
    "lower_bound_seconds": 239.5,
    "upper_bound_seconds": 444.7,
    "confidence": 0.7,
    "engine": "CYCLES",
    "factors": {"triangle_count": 85000, "light_count": 3, ...}
  }
```

Omit any parameter to use the current scene's render settings.

### `get_optimization_suggestions` — Auto-Analyse Your Scene

Get ranked, actionable suggestions before rendering or exporting:

```
get_optimization_suggestions()
→ {
    "total_suggestions": 3,
    "suggestions": [
      {"type": "no_camera",         "priority": "critical", "impact": "render_image will fail without an active camera", ...},
      {"type": "high_poly",         "priority": "high",     "impact": "40–60% faster rendering, lower VRAM usage",      "affected_objects": ["DenseMesh"]},
      {"type": "unapplied_modifiers","priority": "medium",  "impact": "~20% faster rendering",                          "action": "apply_all_modifiers"}
    ]
  }
```

Checks: no camera, no lights, high-poly meshes (>100K verts), high-subdivision surfaces, unapplied modifiers, missing UV maps, duplicate materials.

### `get_memory_usage` — Monitor Server Memory

Track Python heap and OS RSS for the MCP server process:

```
get_memory_usage(detect_leaks=True)
→ {
    "current": {"python_current_kb": 18432.0, "python_peak_kb": 21000.0, "rss_mb": 94.3},
    "suspected_leaks": [],
    "leak_count": 0,
    "recent_samples": [...]
  }
```

---

## Safe Execution & Safety Features (Quick Wins)

### `execute_tools_safe` — Validate-then-Execute

Unlike `execute_tools`, this tool validates all steps before touching Blender, creates a checkpoint, and auto-rolls back if any step fails:

```
execute_tools_safe(tools=[
  {"tool_name": "boolean_operation", "params": {"target": "Cube", "cutter": "Sphere", "operation": "DIFFERENCE"}},
  {"tool_name": "recalculate_normals", "params": {"object_name": "Cube"}},
  {"tool_name": "merge_by_distance",   "params": {"object_name": "Cube", "threshold": 0.001}}
])
→ {"status": "success", "checkpoint": "safe_exec_1753440000", "rolled_back": false, "results": [...]}
```

If step 2 fails, the scene is restored to its pre-execution state automatically.

### Sandbox Mode

Set `BLENDER_MCP_SANDBOX=1` to block destructive operations during safe exploration or demos:

```bash
BLENDER_MCP_SANDBOX=1 blender-studio-mcp
```

Blocked tools: `delete_object`, `clear_scene`, `clean_scene`, `save_blend`, `unpack_textures`, `execute_python`, `execute_python_headless`.

### Auto-Checkpoint

Set `BLENDER_MCP_AUTO_CHECKPOINT=1` to automatically snapshot state before any destructive operation:

```bash
BLENDER_MCP_AUTO_CHECKPOINT=1 blender-studio-mcp
```

A checkpoint named `auto_<tool>_<timestamp>` is created before: `delete_object`, `clear_scene`, `clean_scene`, `apply_modifier`, `apply_all_modifiers`, `boolean_operation`, `join_objects`, `recalculate_normals`.

### `generate_tool_docs` — Auto-Generated Reference

Generate a complete Markdown reference of all tools:

```
generate_tool_docs(output_path="docs/tools/reference.md")
→ {"status": "written", "tool_count": 210, "category_count": 50}
```

Omit `output_path` to receive the Markdown inline as a string.

---

## MCP Resources

In addition to the tools, MCP resources provide live read-only access to Blender state:

| Resource | Description |
|---|---|
| `blender://scene-info` | Live snapshot of the current scene (objects, engine, frame range) |
| `blender://history` | Rolling log of the last 50 commands with timing and success/error status |
| `blender://health` | Server health check: uptime, last Blender ping, connection status |
| `blender://queue-stats` | Command queue statistics: depth, average processing time |
| `blender://perf-stats` | **NEW** Live performance stats: slowest tools, call counts, memory usage |
| `blender://system-prompt` | Bundled LLM instructions for working with this server |

---

## Tool Reference

Full parameter documentation is in the [`docs/tools/`](docs/README.md) directory.



### Scene & Inspection
| Tool | Description |
|---|---|
| `get_scene_info` | Scene name, frame range, render engine, all objects |
| `get_object_info` | Location, rotation, scale, materials, modifiers, vertex count |
| `get_blend_file_summary` | Data-block counts (meshes, materials, images, etc.) |
| `get_scene_stats` | **NEW** Triangle count, texture memory usage, estimated render time |
| `take_screenshot` | Capture viewport as base64 PNG (with optional object highlighting) |
| `get_history` | Return rolling command log with timing and error info |
| `ping` | **NEW** Health check: returns Blender + addon versions |

### Objects
| Tool | Description |
|---|---|
| `create_object` | Create mesh, light, camera, armature, Grease Pencil, and more (15 types) |
| `delete_object` | Remove an object from the scene |
| `duplicate_object` | Duplicate with optional linked mesh data |
| `select_object` | Select and make active |
| `set_object_visibility` | Show/hide in viewport or render |

### Transforms
| Tool | Description |
|---|---|
| `set_location` | World-space position (meters) |
| `set_rotation` | Euler XYZ rotation (degrees) |
| `set_scale` | Scale multiplier per axis |
| `apply_transforms` | Apply location/rotation/scale to reset to identity |
| `set_parent` | Parent one object to another |

### Materials
| Tool | Description |
|---|---|
| `create_material` | Principled BSDF with color, metallic, roughness, emission |
| `assign_material` | Assign to an object's material slot |
| `set_material_property` | Adjust any BSDF input on an existing material |
| `add_image_texture` | Connect an image file to BASE_COLOR, ROUGHNESS, NORMAL, etc. |

### UV Unwrapping
| Tool | Description |
|---|---|
| `unwrap_uv` | Unwrap UVs using ANGLE_BASED, CONFORMAL, or Smart UV Project |
| `mark_seam` | Mark or clear seams on all selected edges |
| `pack_uvs` | Pack UV islands into 0–1 space with configurable margin |

### Shape Keys
| Tool | Description |
|---|---|
| `add_shape_key` | Add a shape key (morph target) — first key becomes the Basis |
| `set_shape_key_value` | Set a shape key's influence (0–1) |
| `remove_shape_key` | Delete a shape key by name |
| `list_shape_keys` | Return all shape keys with current values and ranges |

### Object Constraints
| Tool | Description |
|---|---|
| `add_constraint` | Add COPY_LOCATION, TRACK_TO, LIMIT_ROTATION, CHILD_OF, and more |
| `remove_constraint` | Remove a named constraint from an object |

### Modeling
| Tool | Description |
|---|---|
| `add_modifier` | Add SUBSURF, ARRAY, MIRROR, BEVEL, BOOLEAN, DECIMATE, and more |
| `apply_modifier` | Bake a modifier to real geometry |
| `boolean_operation` | DIFFERENCE, UNION, or INTERSECT between two meshes |
| `set_smooth_shading` | Toggle smooth vs flat shading |
| `join_objects` | Merge multiple objects into one |

### Animation
| Tool | Description |
|---|---|
| `insert_keyframe` | Set location/rotation/scale and add a keyframe |
| `delete_keyframe` | Remove a keyframe from an object |
| `set_frame` | Jump to a specific frame |
| `set_frame_range` | Set start/end frame and FPS |

### Camera & Lighting
| Tool | Description |
|---|---|
| `set_camera_properties` | Focal length, sensor size, depth of field, clipping |
| `set_active_camera` | Choose which camera the scene renders from |
| `set_light_properties` | Energy, color, radius, spot angle |
| `set_hdri_environment` | Set HDRI world lighting from a `.hdr` or `.exr` file |

### Rendering
| Tool | Description |
|---|---|
| `set_render_settings` | Engine (Cycles/EEVEE), resolution, samples, output path |
| `render_image` | Render and return base64 PNG |
| `render_animation` | Render a frame sequence to disk |

### Texture Baking
| Tool | Description |
|---|---|
| `bake_texture` | Bake AO, DIFFUSE, NORMAL, ROUGHNESS, or SHADOW to a PNG (requires Cycles) |

### Physics
| Tool | Description |
|---|---|
| `add_rigid_body` | ACTIVE or PASSIVE rigid body with mass and friction |
| `add_cloth_simulation` | Cloth physics with Cotton/Denim/Leather/Silk presets |
| `add_particle_system` | EMITTER or HAIR particle system |

### Geometry Nodes
| Tool | Description |
|---|---|
| `add_geometry_nodes` | Add a Geometry Nodes modifier (creates a new node group) |

### File I/O
| Tool | Description |
|---|---|
| `import_file` | Import OBJ, FBX, GLTF/GLB, USD, PLY, STL |
| `import_files` | **NEW** Batch import multiple files with per-file status reporting |
| `export_file` | Export selected or full scene to any supported format |
| `save_blend` | Save the current `.blend` file |

### Preset Library
| Tool | Description |
|---|---|
| `save_preset` | **NEW** Save material/lighting/camera preset to `~/.blender_studio_mcp/presets/` |
| `load_preset` | **NEW** Load a preset from the library and return its data |
| `list_presets` | **NEW** List all available presets by category |

### Collections
| Tool | Description |
|---|---|
| `create_collection` | Create a new collection in the outliner |
| `move_to_collection` | Move an object into a collection |

### Grease Pencil
| Tool | Description |
|---|---|
| `create_grease_pencil` | Create an empty Grease Pencil object |
| `add_gp_stroke` | Add a stroke to a layer and frame (supports GP v2 and v3 API) |

### Video Sequence Editor
| Tool | Description |
|---|---|
| `add_video_strip` | Add a video file as a VSE strip |
| `render_vse` | Render the VSE timeline to MP4 |

### Python Execution & Undo
| Tool | Description |
|---|---|
| `execute_python` | Run arbitrary `bpy` code in the live session. Assign `__result__` to return data. |
| `execute_python_headless` | Spawn `blender --background` subprocess for batch operations |
| `undo` | Undo the last N operations in Blender |
| `execute_tools_safe` | **NEW** Validate all steps with dry-run, checkpoint, execute, and auto-rollback on failure |
| `generate_tool_docs` | **NEW** Generate complete Markdown tool reference with params and examples |
| `bake_fluid_simulation` | **NEW** Bake Mantaflow fluid domain with frame range control |
| `bake_smoke_simulation` | **NEW** Bake Mantaflow smoke/fire domain |
| `bake_cloth_simulation` | **NEW** Bake cloth physics cache — required before game-engine export |
| `create_ik_leg` | **NEW** One-call IK leg rig: creates target + pole bones and wires IK constraint |
| `create_fk_spine` | **NEW** Build a FK spine bone chain on an existing armature |
| `edit_node_group` | **NEW** Add nodes and links to any existing node group (shader, geometry, compositor) |
| `get_performance_stats` | **NEW** Execution-time statistics (min/max/mean/p95/p99) for all tools this session |
| `get_memory_usage` | **NEW** MCP server process memory (Python heap + RSS) with optional leak detection |
| `estimate_render_time` | **NEW** Heuristic render-time prediction before committing to a long render |
| `get_optimization_suggestions` | **NEW** Ranked scene analysis — missing camera/lights, high-poly, unapplied modifiers, etc. |

### Asset Libraries
| Tool | Description |
|---|---|
| `search_poly_haven_assets` | Search Poly Haven (HDRIs, textures, models) — free, no key required |
| `download_poly_haven_asset` | Download and auto-import into the scene |
| `search_ambientcg_assets` | Search Ambient CG PBR materials and HDRIs — free, no key required |
| `download_ambientcg_asset` | Download a PBR material and auto-wire Color, Roughness, Normal, Metalness maps |
| `search_sketchfab_models` | Search Sketchfab for downloadable models (requires `SKETCHFAB_API_KEY`) |
| `search_blenderkit` | **NEW** Search BlenderKit asset library — free assets need no key |
| `download_blenderkit_asset` | **NEW** Download and import a BlenderKit asset by ID |

### AI Model Generation
| Tool | Description |
|---|---|
| `generate_model_rodin` | Text-to-3D via Hyper3D Rodin, imported as GLB (requires `RODIN_API_KEY`) |
| `generate_model_tripo` | Text-to-3D via TripoAI (requires `TRIPO_API_KEY`) |
| `generate_model_hunyuan` | Text-to-3D via Tencent Hunyuan3D (requires `HUNYUAN_API_KEY`) |
| `generate_model_meshy` | **NEW** Text-to-3D via Meshy AI with art style control (requires `MESHY_API_KEY`) |
| `generate_model_luma` | **NEW** Text-to-3D via Luma AI Genie (requires `LUMA_API_KEY`) |

### Scene Utilities
| Tool | Description |
|---|---|
| `set_origin` | Set origin to geometry center, cursor, center of mass, or center of volume |
| `get_material_info` | Inspect a material's full node graph — all nodes, input values, and links |
| `rename_object` | Rename an object and its data block |
| `apply_all_modifiers` | Apply every modifier in stack order (common pre-export step) |
| `set_world_color` | Set a flat solid background color with optional transparency |

### Shader Nodes
| Tool | Description |
|---|---|
| `add_shader_node` | Add any node type to a material's node tree (ShaderNodeMath, ShaderNodeTexNoise, etc.) |
| `connect_nodes` | Link an output socket of one node to an input socket of another |
| `set_node_value` | Set an input socket's default value (float, vector, or color) |

### Rigging
| Tool | Description |
|---|---|
| `add_bone` | Add a bone to an armature at given head/tail positions |
| `set_bone_parent` | Parent one bone to another (offset or connected) |
| `set_vertex_group` | Assign vertex indices to a named vertex group with a given weight |
| `add_armature_modifier` | Link a mesh to an armature for skeletal deformation |

### Mesh Cleanup
| Tool | Description |
|---|---|
| `recalculate_normals` | Fix inside-out normals — recalculate to point outward (or inward) |
| `merge_by_distance` | Weld overlapping vertices within a threshold (remove doubles) |
| `flip_normals` | Invert all face normals on a mesh object |

### Scene Utilities
| Tool | Description |
|---|---|
| `set_3d_cursor` | Place the 3D cursor at a world position or snap to an object's origin |
| `clean_scene` | Remove all orphan data blocks (meshes, materials, images, etc.) with zero users |
| `clear_scene` | Delete all objects, optionally preserving camera and/or lights |
| `pack_textures` | Embed all external images into the .blend file |
| `unpack_textures` | Extract packed images back to disk |

### Materials (Extended)
| Tool | Description |
|---|---|
| `set_blend_mode` | Set alpha blend mode — OPAQUE, BLEND, CLIP, or HASHED (required for transparency in EEVEE) |
| `duplicate_material` | Clone an existing material into an independent copy |
| `list_materials` | List all materials in the scene with user counts |

### Animation (Extended)
| Tool | Description |
|---|---|
| `set_keyframe_interpolation` | Set interpolation mode (LINEAR, BEZIER, CONSTANT) on an object's keyframes |
| `clear_animation` | Remove all keyframes and drivers from an object |
| `bake_action` | Bake constraints and driven values to direct keyframes — required before game-engine export |

### Text Objects
| Tool | Description |
|---|---|
| `set_text_content` | Set the body text of a Text (FONT) object |
| `set_text_font` | Load a .ttf/.otf font file and assign it to a Text object |

### Queries (Extended)
| Tool | Description |
|---|---|
| `list_objects_by_type` | Return all objects matching a given type (MESH, LIGHT, CAMERA, ARMATURE, etc.) |
| `get_modifier_info` | Read back a modifier's current settings |
| `find_orphan_data` | List unused data blocks by category before running clean_scene |

### Compositor
| Tool | Description |
|---|---|
| `enable_compositing` | Toggle the compositor and its node graph on the current scene |
| `add_compositor_node` | Add a node to the compositor tree (Glare, Blur, ColorBalance, BrightContrast, etc.) |

### Custom Properties
| Tool | Description |
|---|---|
| `set_custom_property` | Set a custom property on an object (string, int, float, bool) |
| `get_custom_property` | Read a named custom property from an object |
| `list_custom_properties` | List all custom properties with their values |
| `remove_custom_property` | Delete a named custom property |

### Curves
| Tool | Description |
|---|---|
| `set_curve_properties` | Set bevel depth, resolution, fill mode, extrude, and cyclic on a curve object |
| `convert_to_mesh` | Convert a curve, text, or surface object to a mesh |

### NLA Editor
| Tool | Description |
|---|---|
| `push_action_to_nla` | Push the active action down to an NLA strip |
| `create_nla_track` | Add a named NLA track to an object |

### Image Management
| Tool | Description |
|---|---|
| `create_image` | Create a blank image data block (required as a bake target) |
| `save_image` | Save an image data block to disk |
| `reload_image` | Reload an image from disk after external edits |

### Viewport
| Tool | Description |
|---|---|
| `set_viewport_shading` | Switch 3D viewport between SOLID, MATERIAL, RENDERED, WIREFRAME |

### Library / Asset Pipeline
| Tool | Description |
|---|---|
| `append_from_blend` | Append objects, materials, or collections from another .blend file |
| `link_from_blend` | Link (read-only) assets from another .blend file |

### Drivers
| Tool | Description |
|---|---|
| `add_driver` | Attach a scripted driver expression to any animatable property |
| `remove_driver` | Remove a driver from a property |

### Render Passes
| Tool | Description |
|---|---|
| `enable_render_pass` | Enable/disable a render pass (Z, AO, Normal, Diffuse, Glossy, Shadow, UV, etc.) |

### Vertex Attributes
| Tool | Description |
|---|---|
| `add_attribute` | Add a named vertex attribute layer (FLOAT_COLOR, FLOAT, FLOAT_VECTOR, etc.) |
| `set_vertex_colors` | Fill a color attribute with a solid color across all vertices |

### Asset Management
| Tool | Description |
|---|---|
| `index_asset_library` | **NEW** Crawl a directory tree and index all `.blend` files into a local SQLite + FTS5 database |
| `search_asset_library` | **NEW** Full-text search the indexed library with mesh/material/camera/tag filters |
| `get_asset_dependencies` | **NEW** Report missing textures and linked libraries for any indexed `.blend` file |
| `load_asset_from_git` | **NEW** Append or link a `.blend` at any historical Git commit without touching the working tree |
| `get_asset_recommendations` | **NEW** Context-aware asset suggestions based on the current scene (missing lights, materials, etc.) |
| `list_asset_commits` | **NEW** List Git commits that modified a `.blend` file |
| `get_asset_library_stats` | **NEW** Summary statistics for the local asset index (total assets, missing dependencies) |

### Collaboration
| Tool | Description |
|---|---|
| `create_collaboration_session` | **NEW** Start a multi-client editing session; returns a session ID to share |
| `join_collaboration_session` | **NEW** Join an existing session as editor or read-only observer |
| `leave_collaboration_session` | **NEW** Leave a session and release all held object locks |
| `get_session_state` | **NEW** Inspect active clients, locks, and shared checkpoints for a session |
| `list_collaboration_sessions` | **NEW** List all active sessions |
| `acquire_object_lock` | **NEW** Acquire an exclusive edit lock on a Blender object |
| `release_object_lock` | **NEW** Release your lock on an object |
| `check_object_lock` | **NEW** Check whether an object is locked and by whom |
| `send_session_heartbeat` | **NEW** Keep-alive ping (required every < 30 s to stay in the session) |
| `get_session_messages` | **NEW** Poll for recent collaboration events (object changes, lock events, client joins) |
| `record_shared_checkpoint` | **NEW** Create an attributed Blender checkpoint visible to all session participants |
| `cleanup_session_dead_clients` | **NEW** Prune timed-out clients and release their locks |

---

## Requirements

- **Blender 3.0+** (tested on Blender 5.2)
- **Python 3.10+**
- **uv** or **pip** for server installation

---

## Development

### Setup

```bash
git clone git@github.com:skyionblue/blender-studio-mcp.git
cd blender-studio-mcp

# Install dependencies
uv sync --dev
# or: make dev

# Run the server locally
uv run blender-studio-mcp
```

### Testing

**Prerequisites:**
- Running Blender instance with addon enabled
- MCP socket server active (port 9877)

**Run tests:**
```bash
# All tests
pytest
# or: make test

# Phase 3 tests only
pytest tests/test_phase3.py -v
# or: make test-phase3

# With coverage
pytest --cov=blender_studio_mcp --cov-report=term-missing
# or: make coverage

# HTML coverage report
pytest --cov=blender_studio_mcp --cov-report=html
# or: make coverage-html
# then: open htmlcov/index.html
```

**Test Statistics:**
- **842 tests passing** across all phases (0 failures)
- Phase 3: checkpoints, transactions, macros, preview, material diff
- Phase 8: SQLite database, FTS5 search, asset indexer, Git utils, recommendations, MCP tools
- Phase 9: session management, message broker, change detection, conflict resolution, MCP tools
- **Target coverage:** 85%+ overall

See [`docs/testing.md`](docs/testing.md) for detailed testing guide.

### Code Quality

```bash
# Lint
ruff check .
# or: make lint

# Auto-fix
ruff check --fix .
# or: make lint-fix

# Type check
pyright
# or: make type-check

# Run all checks
make check-all
```

### Makefile Commands

```bash
make help          # Show all available commands
make dev           # Set up development environment
make test          # Run all tests
make test-phase3   # Run Phase 3 tests only
make coverage      # Run tests with coverage
make coverage-html # Generate HTML coverage report
make lint          # Lint code
make format        # Format code
make type-check    # Type check
make clean         # Clean generated files
```

---

## License

MIT
