Skip to main content
Glama
README.md
# Blender Asset MCP

**An MCP server for building game assets in Blender, where the agent renders
its work, looks at the result, and fixes what it sees.**

Most Blender MCP servers give an AI agent a remote control. This one also gives
it a way to check its work. The agent models, textures and lights an asset,
calls `render_preview`, looks at the image, and fixes what is wrong. It then
checks the asset against your engine budgets and exports GLB/FBX. It works in
**your running Blender session**, so you can watch every step and take over at
any point.

- **126 typed MCP tools** covering scene, objects, transforms, meshes,
  modifiers, materials, textures, UVs, cameras, lighting, rendering,
  checkpoints, export, validation, collision and LODs, plus a Python escape
  hatch for everything else.
- **Checks its own work.** `render_preview` and `render_turntable` do real
  renders and return images the agent can open. The built-in agent
  instructions tell it never to call an asset finished until it has viewed a
  render.
- **Game-ready output.** `analyze_game_asset` and `validate_game_asset` check
  triangle, vertex and material budgets, size, UVs, applied transforms, n-gons
  and manifold geometry. `create_lod` generates LOD chains and the collision
  tools create `UCX_` colliders. It exports to GLB, glTF, FBX and OBJ.
- **Safe to leave running.** Named operations take a checkpoint before they
  start, so a failed attempt can be rolled back. Checkpoints never overwrite
  your `.blend`, all writes stay inside one workspace folder, and the bridge
  listens on localhost only, with an optional access token.
- Works with any MCP client: Claude Code, Claude Desktop, Cursor, and others.

## Requirements

| | |
|---|---|
| Blender | **5.2 or newer** (Blender extension format) |
| Python | 3.10+ for the MCP server (separate from Blender's own Python) |
| MCP SDK | `mcp>=2.2` (installed automatically) |
| OS | Windows, macOS, Linux |

---

## Installation

### 1. Install the Blender add-on

Download `ai_bridge.zip` from the
[latest release](https://github.com/yi00it/blender-asset-mcp/releases/latest),
then in Blender: **Edit → Preferences → Add-ons → ⌄ → Install from Disk…** and
choose the zip. Make sure **AI Bridge** is enabled.

From a clone you can instead copy the add-on straight into Blender's extensions
folder:

```bash
python scripts/install_extension.py          # add --blender-version 5.3 etc. if needed
python scripts/install_extension.py --zip-only   # just build ai_bridge.zip
```

### 2. Start the bridge

In the 3D viewport press **N**, open the **AI Bridge** tab and click **Start
Bridge**. To have it start with Blender, tick **Start bridge when Blender
loads** in the add-on preferences.

### 3. Connect your MCP client

The quickest way to run the server is [uv](https://docs.astral.sh/uv/). There
is nothing to clone:

```bash
uvx --from git+https://github.com/yi00it/blender-asset-mcp blender-asset-mcp
```

**Claude Code**

```bash
claude mcp add blender -- uvx --from git+https://github.com/yi00it/blender-asset-mcp blender-asset-mcp
```

**Claude Desktop** (`claude_desktop_config.json`) / **Cursor** (`.cursor/mcp.json`)

```json
{
  "mcpServers": {
    "blender": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/yi00it/blender-asset-mcp", "blender-asset-mcp"]
    }
  }
}
```

<details>
<summary>Running from a clone instead of uvx</summary>

```bash
git clone https://github.com/yi00it/blender-asset-mcp
cd blender-asset-mcp
python -m venv .venv
# Windows: .venv\Scripts\python -m pip install -e .
# macOS/Linux:
.venv/bin/python -m pip install -e .
```

Then point your client at the venv's `blender-asset-mcp` executable
(`.venv/Scripts/blender-asset-mcp.exe` on Windows, `.venv/bin/blender-asset-mcp`
elsewhere), or at `python server/server.py`.
</details>

### 4. Try it

Ask your agent something like:

> Build a low-poly wooden crate for a mobile game, under 500 triangles, with a
> worn wood material. Render it from a few angles, fix anything that looks off,
> validate it and export it as GLB.

To check the bridge without an agent, run
`python scripts/smoke_test.py`. It creates a temporary `SMOKETEST_Cube`,
renders it, deletes it and confirms the scene is back to how it was.

### Configuration

| Environment variable (MCP server) | Default | Purpose |
|---|---|---|
| `BLENDER_MCP_WORKSPACE` | `~/blender-asset-mcp/workspace` | Where previews, checkpoints and exports go |
| `BLENDER_MCP_TOKEN` | *(unset)* | Must match the add-on's **Access token**, if you set one |
| `BLENDER_MCP_PORT` | `9876` | Bridge port |

Set environment variables in your client's config, e.g. `"env": {"BLENDER_MCP_TOKEN": "..."}`
in the JSON above, or `claude mcp add -e BLENDER_MCP_TOKEN=... blender -- ...`.

---

## Tool categories

| Category | Tools | Examples |
|---|---|---|
| Health | 5 | `ping_blender`, `get_bridge_status`, `list_bridge_actions` |
| Scene inspection | 11 | `get_scene_info`, `get_object`, `list_objects`, `list_materials` |
| Objects | 15 | `create_primitive`, `duplicate_object`, `move_to_collection`, `set_parent` |
| Transforms | 6 | `set_transform`, `rotate_object`, `apply_transforms`, `set_origin` |
| Meshes | 8 | `create_mesh`, `join_objects`, `shade_smooth`, `mesh_cleanup` |
| Modifiers | 15 | `add_modifier`, `add_bevel`, `add_boolean`, `apply_modifier` |
| Materials | 11 | `create_material`, `assign_material`, `connect_nodes` |
| Textures | 5 | `load_image`, `create_image_texture_node` |
| UVs | 7 | `smart_uv_project`, `unwrap_selected`, `mark_seams_by_angle` |
| Cameras | 6 | `frame_objects_with_camera`, `look_at`, `set_camera_transform` |
| Lighting | 6 | `create_light`, `create_preview_lighting`, `set_world_background` |
| **Rendering** | 6 | **`render_preview`**, `render_turntable`, `read_preview_image` |
| Save / checkpoint | 8 | `create_checkpoint`, `restore_checkpoint`, `undo`, `save_blend` |
| Export | 5 | `export_glb`, `export_fbx`, `export_gltf`, `export_obj` |
| Validation | 6 | `analyze_game_asset`, `validate_game_asset`, `create_lod` |
| Advanced | 6 | `execute_blender_python`, `begin_operation`, `cancel_operation` |

Conventions across every tool:

- **Rotations are DEGREES.** Blender stores radians; the bridge converts.
- **Colors are `[r, g, b]` or `[r, g, b, a]` floats in 0..1, linear.** Not
  0–255, not sRGB hex.
- Objects are addressed by name.
- Lengths are Blender units (1 unit = 1 metre by default).

See [docs/AGENT_GUIDE.md](docs/AGENT_GUIDE.md) for how an agent should drive
the toolkit.

---

## Architecture

```
MCP client (Claude Code, Claude Desktop, Cursor, ...)
     │  stdio, JSON-RPC
     ▼
blender_asset_mcp  (server/)       ← never imports bpy
  app.py      MCP server + agent instructions
  client.py   TCP protocol client
  paths.py    workspace rules
  tools/      126 typed tools
     │  TCP, newline-delimited JSON
     ▼  127.0.0.1:9876
blender_extension/  (Blender add-on "AI Bridge")
  bridge.py     listener + per-connection threads  ← never touch bpy
     │  queue.Queue
     ▼
  bpy.app.timers pump  ← Blender's MAIN THREAD
  dispatch.py → handlers/   ← the only code that calls bpy
```

Two rules hold this together, and the file layout enforces them:

1. **The socket threads never call bpy.** They parse JSON and put work on a
   queue.
2. **Every bpy call happens on Blender's main thread**, run by a
   `bpy.app.timers` callback that drains that queue. The timer is registered
   with `persistent=True`, so it keeps running after a `.blend` file is loaded.

The MCP server and the Blender add-on are separate programs in separate
processes. They share nothing but the wire protocol.

### Wire protocol

One JSON object per line, in each direction.

```jsonc
// request
{"action": "create_primitive", "primitive": "cube", "name": "Crate", "_timeout": 30.0}

// success
{"ok": true, "created": "Crate", "object": { ... }, "_duration_ms": 4.2}

// failure: always structured, never silent
{"ok": false, "error": "No object named 'Crat'.", "error_type": "object_not_found",
 "action": "get_object", "suggestions": ["Crate"]}
```

`_timeout` tells Blender how long it may spend before the client gives up.
`_token` carries the access token when one is configured.

---

## Workspace

```
~/blender-asset-mcp/workspace/
  previews/      render_preview output (PNG)
  checkpoints/   timestamped .blend copies
  exports/       .glb / .gltf / .fbx / .obj
  logs/          bridge-YYYYMMDD.log (JSONL, one line per command)
  temp/          scratch saves
```

Both sides default to this folder. Change it with the **Workspace** add-on
preference in Blender and `BLENDER_MCP_WORKSPACE` for the server.
`get_bridge_status` reports both and warns if they differ. **Blender's path
takes precedence**, since Blender is the one writing the files.

Logs record the timestamp, action, duration, success and error. They store only
the size and a SHA-1 prefix of mesh arrays and Python source, never the content.

---

## Security model

| Rule | How it is enforced |
|---|---|
| Listener is localhost only | Binds to `127.0.0.1`, plus a peer-address check that drops any non-loopback connection |
| Web pages cannot drive it | Requests that start with an HTTP request line are dropped, so a browser tab POSTing to `127.0.0.1:9876` gets nothing |
| Optional access token | Set **Access token** in the add-on preferences (the ↻ button generates one and copies it to the clipboard) and `BLENDER_MCP_TOKEN` for the server. Other local programs are then refused. Compared in constant time and never logged |
| No OS commands from the bridge | The structured actions expose no shell, spawn no subprocess and open no outbound socket |
| Writes stay in the workspace | Output paths must be relative. Drive letters, `..` and reserved characters are rejected, and the resolved path is checked to be inside the workspace. Both the server and Blender check this |
| Reads are constrained | `load_image` only reads from the workspace or the open `.blend`'s folder, unless you tick **Allow reads outside workspace** |
| Checkpoints never clobber your file | `save_as_mainfile(copy=True)`, so `bpy.data.filepath` still points at your document |
| Request size is bounded | 16 MB per request |

### `execute_blender_python` is trusted local execution

This tool runs arbitrary Python in your live Blender session, with the same
power as Blender's scripting console. That includes file access and anything
else Python can do. **It is not a sandbox.** It exists so the agent can use
`bpy`/`bmesh`/`mathutils` when the structured tools don't cover a task. When
code imports modules such as `subprocess` or `socket`, the response lists them
in `notable_imports`, so their use is always visible.

Your MCP client asks for approval before tool calls, so review these calls the
way you would review any code an agent wants to run. To turn off every tool,
stop the bridge.

---

## Troubleshooting

**`bridge_unreachable` / "Cannot connect to Blender"**
Blender must be open, the AI Bridge add-on enabled, and **Start Bridge**
clicked. The sidebar panel shows Running/Stopped, the port and the last error.

**`unauthorized`**
The add-on has an access token set, and `BLENDER_MCP_TOKEN` in your MCP client
config is missing or different. After changing the token in Blender, restart
the bridge.

**"Address already in use" when starting the bridge**
Another Blender instance (or another Blender MCP add-on) still holds port
9876. Close it, or stop its bridge first.

**Tools behave the old way after updating the add-on**
Reload the add-on: untick and re-tick **AI Bridge** in Preferences, or restart
Blender.

**`timeout` on a render**
Increase samples or resolution in smaller steps. A heavy render blocks
Blender's main thread, and the bridge queue with it. Blender is still working
on the command; only the client stopped waiting.

**Preview looks washed out**
`render_preview` uses the `Standard` view transform by default, because
Blender's `AgX` desaturates colours heavily. If you passed
`view_transform="AgX"`, that is why.

**Undo does nothing**
Blender's undo stack needs a window, so in a windowless session the bridge
refuses rather than risk a crash. Use checkpoints instead; they work either
way.

**Workspace mismatch warning**
Set the add-on's **Workspace** preference and `BLENDER_MCP_WORKSPACE` to the
same folder, or clear both to use the defaults.

---

## Development

```bash
python -m pip install -e ".[dev]"
python -m pytest                       # protocol, paths, tools; no Blender needed
python scripts/smoke_test.py           # end to end against a running bridge
python scripts/install_extension.py    # copy the add-on into Blender
```

`tests/` covers the protocol client (framing, timeouts, error mapping, split
packets, tokens), the bridge's request screening, the workspace path rules and
the tool layer (request shape, validation, timeouts, description quality).

Issues and pull requests are welcome.

## License

[MIT](LICENSE) © 2026 Yiğit Özdamar

TDQS

C2.9/5.0

Scored across 126 tools

Disambiguation3/5

Most tools target a specific resource and action, and the descriptions are unusually clear, but several pairs overlap purposefully: add_modifier duplicates the specialized add_bevel/add_subdivision/... wrappers, create_primitive duplicates create_cube, and analyze_game_asset/validate_game_asset plus execute_blender_python/evaluate_blender_expression sit close together. An agent can usually disambiguate by reading descriptions, but the boundaries are not always crisp.

Naming Consistency4/5

Names overwhelmingly follow a snake_case verb_noun pattern (list_objects, create_material, apply_modifier), which makes the set predictable. The pattern breaks in spots: bare verbs (undo, redo, ping), noun-first or adjective-first names (mesh_cleanup, smart_uv_project), and inconsistent singular/plural pairs (delete_object vs delete_objects, connect_nodes vs disconnect_node_input) keep it from being perfect.

Tool Count1/5

At 126 tools this is far beyond the 3-15 well-scoped range and above any reasonable surface for an agent to consider; many are convenience wrappers that could be consolidated (8+ add_<modifier> tools, 7 export/read/render variants). Even if Blender is a wide domain, this tool count is an extreme mismatch and will hurt selection reliability.

Completeness4/5

The surface covers the full game-asset pipeline: scene/object CRUD, mesh editing, modifiers, materials/nodes, UVs, cameras/lights, rendering/previews, exports, checkpoints, validation, collisions, and LODs. Gaps like structured armature/rigging and animation tools, collection/image deletion, and a singular collection getter remain, though execute_blender_python acts as an escape hatch.

Maintenance

ActivityMaintained
ResponsivenessNo issues