blender-mcp
<p align="center">
<img src="docs/logos/banner_2_wireframe.svg" alt="BlenderMCP — Talk to Blender." width="700"/>
</p>
<p align="center">
<a href="https://github.com/kleer001/blender-mcp/blob/main/LICENSE"><img src="https://img.shields.io/github/license/kleer001/blender-mcp?color=blue" alt="License: MIT"/></a>
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.10%2B-blue?logo=python&logoColor=white" alt="Python 3.10+"/></a>
<a href="https://modelcontextprotocol.io/"><img src="https://img.shields.io/badge/MCP-compatible-green?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJ3aGl0ZSI+PHBhdGggZD0iTTEyIDJDNi40OCAyIDIgNi40OCAyIDEyczQuNDggMTAgMTAgMTAgMTAtNC40OCAxMC0xMFMxNy41MiAyIDEyIDJ6Ii8+PC9zdmc+" alt="MCP Compatible"/></a>
<a href="https://www.blender.org/"><img src="https://img.shields.io/badge/Blender-4.2%20LTS-E87D0D?logoColor=white" alt="Blender 4.2 LTS"/></a>
<a href="https://github.com/kleer001/blender-mcp/commits/main"><img src="https://img.shields.io/github/last-commit/kleer001/blender-mcp" alt="Last Commit"/></a>
<a href="https://github.com/kleer001/blender-mcp/issues"><img src="https://img.shields.io/github/issues/kleer001/blender-mcp" alt="Issues"/></a>
<a href="https://github.com/kleer001/blender-mcp/network/members"><img src="https://img.shields.io/github/forks/kleer001/blender-mcp?style=social" alt="Forks"/></a>
<a href="https://github.com/kleer001/blender-mcp/watchers"><img src="https://img.shields.io/github/watchers/kleer001/blender-mcp?style=social" alt="Watchers"/></a>
<a href="https://github.com/kleer001/blender-mcp/stargazers"><img src="https://img.shields.io/github/stars/kleer001/blender-mcp?style=social" alt="GitHub Stars"/></a>
</p>
<p align="center">
<strong>175 MCP tools</strong> · <strong>25 domains</strong> · <strong>Integration-tested on Blender 4.2.5 LTS</strong>
</p>
---
Control **Blender** from **Claude** (or any MCP-compatible AI) using the **Model Context Protocol**. BlenderMCP connects to your running Blender instance over a local TCP socket — your machine, your scenes, your assets.
Unlike existing Blender MCP projects that rely on `execute_blender_code` as a catch-all, this project provides **dedicated, typed tools** for every major Blender subsystem: objects, materials, shader nodes, geometry nodes, modifiers, animation, rigging, physics, compositing, and more.
## Status
**All 175 tools implemented and integration-tested against Blender 4.2.5 LTS.** Full handler coverage across all 25 domains.
## Requirements
- Python 3.10+
- [uv](https://docs.astral.sh/uv/) (recommended) or pip
- Blender 4.0+ (for the addon)
## Quick Start
```bash
# Clone and install
git clone https://github.com/kleer001/blender-mcp
cd blender-mcp
uv sync
# Run with mock Blender (no Blender needed)
uv run blender-mcp --mock
# Run against a real Blender instance
uv run blender-mcp
```
### Blender Addon Setup
1. Copy the `blender_addon/` directory to your Blender addons path, or symlink it
2. Enable **Blender MCP** in Blender → Edit → Preferences → Add-ons
3. In the 3D Viewport sidebar (N panel), find the **MCP** tab and click **Start Server**
4. Start the MCP server: `uv run blender-mcp`
### Claude Code
The `.mcp.json` in the repo root auto-configures Claude Code. Just run `claude` from the project directory.
### Claude Desktop
```json
{
"mcpServers": {
"blender-mcp": {
"command": "uv",
"args": ["run", "--directory", "/path/to/blender-mcp", "blender-mcp"]
}
}
}
```
## Architecture
```
AI Client (Claude, Cursor, ChatGPT)
│ MCP Protocol (stdio)
▼
MCP Server (src/blendermcp/)
│ TCP Socket (localhost:9334)
▼
Blender Addon (blender_addon/)
│ bpy API (main thread via timer queue)
▼
Blender
```
- **MCP Server** — FastMCP-based, runs as a separate process, communicates via stdio
- **Blender Addon** — TCP server inside Blender, dispatches commands to handlers on the main thread via `bpy.app.timers`
- **Connection** — JSON over TCP with newline framing, exponential backoff reconnection
## Available Tools (175)
| Domain | Count | Tools |
|---|---|---|
| Scene | 6 | `ping` · `get_scene_info` · `load_file` · `save_file` · `set_frame` · `set_frame_range` |
| Objects | 12 | `get_object_info` · `list_objects` · `create_object` · `delete_object` · `set_transform` · `apply_transform` · `duplicate_object` · `rename_object` · `set_parent` · `clear_parent` · `set_origin` · `select_objects` |
| Materials | 8 | `list_materials` · `get_material_info` · `create_material` · `assign_material` · `remove_material` · `set_material_property` · `duplicate_material` · `delete_material` |
| Shader Nodes | 12 | `get_node_tree` · `create_shader_node` · `delete_shader_node` · `connect_shader_nodes` · `disconnect_shader_node` · `set_node_input` · `get_node_input` · `set_node_position` · `list_shader_node_types` · `create_node_group` · `add_node_group_instance` · `layout_node_tree` |
| Geometry Nodes | 10 | `get_geonodes_tree` · `create_geonodes_modifier` · `create_geonode` · `delete_geonode` · `connect_geonodes` · `disconnect_geonode` · `set_geonode_input` · `get_geonode_input` · `list_geonode_types` · `set_geonodes_input` |
| Modifiers | 8 | `list_modifiers` · `add_modifier` · `remove_modifier` · `set_modifier_property` · `apply_modifier` · `move_modifier` · `toggle_modifier_visibility` · `copy_modifiers` |
| Animation | 10 | `get_keyframes` · `set_keyframe` · `set_keyframes` · `delete_keyframe` · `clear_animation` · `get_action_info` · `list_actions` · `set_interpolation` · `set_playback_range` · `playback_control` |
| Rigging | 10 | `create_armature` · `get_armature_info` · `add_bone` · `set_bone_property` · `get_bone_info` · `parent_mesh_to_armature` · `assign_vertex_weights` · `add_bone_constraint` · `set_pose_bone_transform` · `list_bone_constraints` |
| Constraints | 6 | `list_constraints` · `add_constraint` · `remove_constraint` · `set_constraint_property` · `set_constraint_influence` · `reorder_constraint` |
| Lighting | 7 | `list_lights` · `create_light` · `set_light_property` · `create_hdri_world` · `set_world_property` · `get_world_info` · `create_light_rig` |
| Camera | 6 | `list_cameras` · `create_camera` · `set_camera_property` · `set_active_camera` · `camera_look_at` · `setup_camera_dof` |
| Mesh Editing | 8 | `get_mesh_info` · `get_vertices` · `set_vertices` · `get_vertex_groups` · `create_vertex_group` · `set_smooth_shading` · `separate_mesh` · `join_meshes` |
| Curves | 5 | `create_curve` · `get_curve_info` · `set_curve_points` · `set_curve_property` · `convert_to_mesh` |
| Physics | 10 | `add_physics` · `remove_physics` · `set_physics_property` · `get_physics_info` · `setup_rigid_body_world` · `setup_cloth_sim` · `setup_fluid_domain` · `setup_softbody` · `bake_physics` · `free_physics_bake` |
| Particles | 6 | `add_particle_system` · `remove_particle_system` · `set_particle_property` · `get_particle_info` · `setup_hair` · `bake_particles` |
| Compositing | 8 | `get_compositor_tree` · `enable_compositor` · `create_comp_node` · `delete_comp_node` · `connect_comp_nodes` · `set_comp_node_input` · `list_comp_node_types` · `setup_basic_composite` |
| Sculpting | 4 | `enter_sculpt_mode` · `set_sculpt_brush` · `remesh` · `apply_sculpt_mask` |
| Grease Pencil | 6 | `create_grease_pencil` · `get_gp_info` · `add_gp_layer` · `set_gp_layer_property` · `create_gp_stroke` · `add_gp_modifier` |
| Textures & UV | 6 | `list_images` · `load_image` · `get_uv_maps` · `create_uv_map` · `smart_uv_project` · `pack_images` |
| Viewport | 6 | `get_viewport_info` · `capture_viewport` · `set_viewport_shading` · `set_viewport_camera` · `frame_selected` · `frame_all` |
| Rendering | 6 | `get_render_settings` · `set_render_settings` · `render_image` · `render_animation` · `render_viewport` · `list_render_engines` |
| Collections | 5 | `list_collections` · `create_collection` · `move_to_collection` · `set_collection_visibility` · `delete_collection` |
| Import/Export | 4 | `import_file` · `export_file` · `list_supported_formats` · `export_selection` |
| Code Execution | 2 | `execute_python` · `evaluate_expression` |
| Batch Operations | 4 | `find_objects` · `batch_set_property` · `batch_delete` · `find_error_objects` |
## Development
```bash
# Install with dev dependencies
uv sync
# Run tests (unit, no Blender needed)
uv run pytest tests/ --ignore=tests/integration -v
# Run integration tests (requires Blender at /opt/blender-4.2/blender)
uv run pytest tests/integration/ -v -m integration
# Run with mock (no Blender needed)
uv run blender-mcp --mock --debug
# Lint
uv run ruff check src/ tests/
```
## License
MIT
TDQS
Scored across 175 tools
The vast majority of tools target distinct domains (objects, materials, cameras, modifiers, nodes, etc.) with clear action-resource pairs. However, a few tools like execute_python vs evaluate_expression and set_frame_range vs set_playback_range could cause confusion, though descriptions clarify their intents.
Tool names overwhelmingly follow a verb_noun snake_case pattern (list_objects, create_material, set_transform, delete_object), making navigation predictable. Minor deviations include 'ping', 'remesh', 'playback_control' and the adjective-initial 'smart_uv_project', which break strict consistency but remain readable.
With 175 tools, this server is drastically over-scaled for any agent to effectively choose from, far exceeding the 50+ threshold for extreme mismatch. Even for a comprehensive application like Blender, the tool surface should be partitioned into several smaller, purpose-specific servers.
The server covers an impressively wide range of Blender functionality, including objects, materials, lighting, animation, physics, nodes, armatures, and particles. However, notable lifecycle gaps exist, such as no mode-switching tool, no rename/material/action/image operations, no action deletion, and no way to delete UV maps or vertex groups, forcing reliance on escape hatches like execute_python.