Blender MCP Server
by ssoj13
README.md
# Blender MCP Server
Control Blender from an AI agent (Claude Code, or any MCP client). **241 tools** ā
233 that act on the scene, 5 that manage the Blender process itself, and 3 that search
the built-in Blender knowledge base ā all written in Rust, the scene ones executed
against `bpy` inside Blender. Includes a unified node layer that covers
every one of Blender's 570 node types.
š **Full documentation:** [`docs/`](docs/) (mdbook ā Introduction, Whitepaper, User &
Developer guides). This README is the short version.
## Architecture
```
MCP client <--stdio--> blender-mcp-rs.exe <--named pipe--> Blender
(Claude) (MCP server) (addon + blender_mcp.pyd)
```
A tool is **declared once**, in `src/tools/`, with its name, description, typed
params and handler:
```rust
crate::tool!(
"obj_list",
"List objects. Filter by type or collection",
ObjList,
|py: Python<'_>, p: ObjList| { /* bpy */ }
);
```
The JSON Schema the model sees is generated from the params struct by `schemars`;
the doc comment on each field becomes that property's description. Registration is
automatic (`inventory`) ā there is no central list to update.
### One registry, two processes
The tool catalog is needed in the **server** process, which has no `bpy`. Execution
happens **inside Blender**. Both are Rust, and both are built from the same crate
(`crate-type = ["cdylib", "rlib"]`), so a single registry serves both:
```
tools::all()
/ \
server binary blender_mcp.pyd
name + description name -> handler
+ schema -> tools/list -> bpy via PyO3
```
The server needs no per-tool code: one route forwards `params -> pipe -> Blender ->
result` for every tool.
### Why Python is still in the addon
`bpy` is reachable only from Blender's Python process ā that is a Blender constraint,
not a design choice. But the addon is *thin*: it starts the pipe client and, from a
`bpy.app.timers` callback, hands each command to `blender_mcp.execute_tool`. All 233
scene tools are Rust. (`bpy` is not thread-safe, hence the timer: the reader thread only
queues commands, and they execute on Blender's main thread.)
### Transport
One duplex local socket ā a named pipe on Windows, a Unix socket elsewhere, via
`interprocess`. Pure Rust: no C library to build, no TCP port, no firewall prompt.
Framing is newline-delimited JSON.
The **server listens**; **Blender connects** and retries forever. So the two may start
in either order, and Blender survives a server restart. `--tag` names the pipe
(`blender-mcp-<tag>.sock`), so several Blender instances can be driven independently.
## Quick Start
```bash
python bootstrap.py b # build: the server binary AND the Python extension
python bootstrap.py d # deploy the addon + extension into Blender
python bootstrap.py i # register the server with the AI agents you have
```
Then connect Blender to the agent, either way:
- **Let the agent launch it** ā ask it to start Blender and it calls `blender_launch`
(`blender_status`, `blender_quit`, `blender_kill`, `blender_restart` manage it too). No
need to open Blender yourself. Blender is found via `--blender`, then
`$BLENDER_PATH` / `$BLENDER`, then standard locations; `install` bakes the discovered
path into the agent config as `BLENDER_PATH`.
- **Or start it by hand** ā in Blender: `Edit > Preferences > Add-ons > MCP Server`,
enable it, and click `MCP > Start` in the topbar.
Either way the agent then discovers the tools.
`bootstrap.py` also has `t` (test, including against a real Blender), `c` (fmt +
clippy) and `cl` (clean). Run it with no arguments for the full list.
### Registering by hand
`blender-mcp-rs install` knows 18 agents and writes each one's dialect for you
(`status` shows where it is registered, `uninstall` removes only what it added). If
you would rather do it yourself:
```json
{
"mcpServers": {
"blender": { "command": "C:\\path\\to\\blender-mcp-rs.exe" }
}
}
```
## Project Structure
```
src/
tools/ # THE tool registry ā one file per domain, see tools/AGENTS.md
mod.rs # ToolDef, the `tool!` macro, execute_tool
bpy.rs # shared bpy helpers
nodes/ # the unified node layer ā see nodes/AGENTS.md
object.rs ⦠# the tools themselves
ipc.rs # named-pipe transport, shared by both processes
protocol.rs # Command / Response
main.rs # MCP server: rmcp on stdio, pipe listener
rmcp_bridge.rs # rmcp ServerHandler; builds tools/list from the registry
control.rs # the 5 process-control tools (run in the server, not Blender)
mcp_catalog.rs # resources and prompts only (tools are NOT here)
crates/
blender-control/ # internal crate: find/launch/monitor/kill, no bpy/MCP
addon/mcp_server/
__init__.py # thin addon: pipe client + timer + UI
addon/autostart.py # auto-connect script used by blender_launch
```
## Tools (241)
The authoritative list is `tools/list` ā it is generated from the registry, so it
cannot go stale. 233 scene tools by domain, plus 5 process-control tools
(`blender_status` / `launch` / `quit` / `kill` / `restart`) and 3 knowledge tools
(`kdb_search` / `kdb_read` / `kdb_guide`), all of which run in the server process
rather than inside Blender:
| Domain | Count | What |
|---|---|---|
| `nodes` | 12 | **Every node tree Blender has** ā shader, geometry, compositor, world, texture. See below |
| `misc` | 19 | render, screenshot, file I/O, modifiers, collections, undo/redo, `util_execute_python` |
| `mesh` | 18 | mesh data, UVs unwrap, curves, text, shape keys, instancing |
| `rig` | 18 | armatures, bones, IK, weights, drivers, and constraints **on pose bones** |
| `util` | 17 | align/distribute/snap, booleans, assets, video sequencer |
| `scene_extra` | 17 | scene analysis and auto-fix, stats, purge, templates, cameras, lights, presets |
| `anim_extra` | 17 | F-curve modifiers, motion paths, NLA, Grease Pencil |
| `phys` | 15 | rigid body, cloth, particles, force fields, simulation zones, render queue |
| `object` | 14 | create, transform, parent, **shade smooth, apply transform, join, separate, origin** |
| `attribute` | 14 | **vertex groups, colour attributes, named mesh attributes** |
| `material` | 13 | create/assign/query, **material slots, per-face assignment, blend settings** |
| `animation` | 6 | keyframes, frame, animation data |
| `volume` | 6 | volume objects, hair curves |
| `scene` | 5 | scene info, **frame range/fps, render settings, colour management, render passes** |
| `mesh_edit` | 5 | **build topology from raw data, select by predicate, extrude/bevel/inset/ā¦, seams** |
| `uv` | 4 | UV maps: add, remove, choose the active and the render layer |
| `image` | 4 | load, create, list, save image datablocks |
| `world` | 3 | background, HDRI |
| `custom_prop` | 3 | custom properties on any datablock **or pose bone** ā this is what a rig control is |
| `bake` | 1 | texture baking (normal / AO / diffuse / emit / ā¦) |
### Building node graphs
One family covers all 570 of Blender's node types ā nothing is hand-listed, the types
and their sockets are read from Blender itself:
```
node_types(kind, search) search the 500 creatable node types
node_schema(type, props) a type's REAL sockets, properties and enums
node_graph_build(tree, ...) build a whole graph in ONE call, auto-laid-out
node_graph_get / _edit read it back, patch it
node_group_make / _add reusable subgraphs
mat_preview(material) render it and look at it
```
**Use `node_schema` instead of guessing socket names.** Blender 5 renamed most of
them: Principled's `Specular` is now `Specular IOR Level`, `Emission` split into
`Emission Color` and `Emission Strength`, and Noise's `Fac` output is `Factor`. A
wrong socket name is an error that hands back the node's actual sockets.
Trees are addressed by one string: `material:Rust`, `world`, `compositor`,
`group:MyGroup`, `object:Cube/GeoNodes`.
`scene_screenshot` returns the viewport as an image; `mat_preview` renders a single
material on a preview sphere in a throwaway scene. `util_execute_python` is the escape
hatch for anything not covered.
## Resources (14) and Prompts (18)
Guides, examples and references the model can read via `resources/read`
(`blender://guide/*`, `blender://examples/*`, `blender://ref/*`), plus 18 prompt
templates. Both live in `src/mcp_catalog.rs`.
## Requirements
- Blender 5.2 LTS (the tools target the Blender 5.2 API; see `src/tools/AGENTS.md` for the
4.x APIs that were removed and how they are handled)
- Rust 1.85+ (edition 2024)
- Python 3 for `bootstrap.py` (standard library only)
The `.pyd` comes straight out of `cargo build` (the crate is a `cdylib`); `bootstrap.py`
drives it. maturin is only needed if you build the extension via `pip`/PEP 517.
## License
Dual-licensed: **BSD 3-Clause** (open source) **OR** a **commercial** license ā use
whichever fits. See [`LICENSE`](LICENSE), [`LICENSE-BSD3`](LICENSE-BSD3), and
[`LICENSE-COMMERCIAL`](LICENSE-COMMERCIAL).
`SPDX-License-Identifier: BSD-3-Clause OR LicenseRef-Commercial`
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues