Skip to main content
Glama
bpy-bridge-mcp

bpy-bridge-mcp

bpy-bridge-mcp

CI PyPI version Python 3.10+ Blender 3.6+ License: MIT

Thread-safe TCP socket and Model Context Protocol (MCP) middleware bridging Blender's internal Python (bpy) runtime with external AI coding agents (Cursor, Codex, Claude) and headless CI/CD pipelines.


Table of Contents


Related MCP server: blender-ai-mcp

Overview & Motivation

Blender is the industry-standard open-source 3D creation suite, powered by its extensive Python API (bpy). However, integrating Blender with external automated tools and Large Language Model (LLM) agents introduces two critical architectural hurdles:

  1. Thread Insecurity & C-Core Segmentation Faults: Blender's core architecture (the Dependency Graph, DNA/RNA data structures, undo stack, and OpenGL/Vulkan contexts) is fundamentally single-threaded. Calling bpy.ops or mutating geometry from a secondary OS thread causes immediate race conditions, memory corruption, and fatal segmentation faults.

  2. Security Vulnerabilities with Autonomous Agents: LLM coding agents generated dynamically can hallucinate or execute malicious system commands (os.system, subprocess.Popen, file overwrites, or network sockets). Executing untrusted code inside an artist's workstation or render farm poses significant security risks.

bpy-bridge-mcp solves both challenges by introducing a lightweight, daemonized TCP bridge guarded by an AST Static Security Sandbox and synchronized directly into Blender's main event loop using bpy.app.timers and a thread-safe FIFO queue.


System Architecture

+-----------------------------------------------------------------------------------+
|                            EXTERNAL AI / CLIENT ECOSYSTEM                         |
|                                                                                   |
|  +--------------------+     +---------------------+     +----------------------+  |
|  |   Cursor IDE       |     |   Claude Desktop    |     |   CI / CLI Script    |  |
|  |   (MCP Client)     |     |   (MCP Client)      |     |   (bpy-bridge CLI)   |  |
|  +---------+----------+     +----------+----------+     +----------+-----------+  |
+------------|---------------------------|---------------------------|--------------+
             |                           |                           |
             +---------------------------+---------------------------+
                                         |  JSON Code Payload: {"code": "..."}
                                         v  (TCP: 127.0.0.1:9876)
+-----------------------------------------------------------------------------------+
|                                 BLENDER HOST PROCESS                              |
|                                                                                   |
|  [Background Daemon Thread: BpyBridgeServerThread]                                |
|  +-----------------------------------------------------------------------------+  |
|  |  1. TCP Socket Listener (SO_REUSEADDR on 127.0.0.1:9876)                    |  |
|  |  2. Receive & Buffer Client Payload                                         |  |
|  |  3. AST Static Security Sandbox (bpy_bridge.security.validate_script_safety) |  |
|  |     - Inspect Abstract Syntax Tree                                          |  |
|  |     - Reject: os, subprocess, sys, shutil, socket, ctypes, importlib, pty   |  |
|  |     - Reject: eval(), exec(), open(), __import__(), compile()               |  |
|  +-------------------------------------+---------------------------------------+  |
|                                        |                                          |
|                     (Safe Task)        v                                          |
|  +-----------------------------------------------------------------------------+  |
|  |        Thread-Safe FIFO Task Queue (queue.Queue[(code, result_queue)])      |  |
|  +-------------------------------------+---------------------------------------+  |
|                                        |                                          |
|                                        v  Polls every 0.1s                        |
|  [Blender Main UI & Event Loop Thread]                                            |
|  +-----------------------------------------------------------------------------+  |
|  |  4. Timer Hook: bpy.app.timers (process_bpy_queue)                          |  |
|  |  5. Pull Task from Queue within Blender's Native Main Context               |  |
|  |  6. Execute Python Script safely:                                           |  |
|  |     - Inject {"bpy": bpy} execution scope                                   |  |
|  |     - Redirect and capture stdout & stderr                                  |  |
|  |     - Catch & serialize Python runtime exceptions and tracebacks            |  |
|  +-------------------------------------+---------------------------------------+  |
|                                        |                                          |
|                                        v  Put Execution Response                  |
|  +-----------------------------------------------------------------------------+  |
|  |        Result Queue (queue.Queue[dict])                                     |  |
|  +-------------------------------------+---------------------------------------+  |
|                                        |                                          |
|                                        v  Timeout wait (up to 10.0s)              |
|  [Background Daemon Thread]                                                       |
|  +-----------------------------------------------------------------------------+  |
|  |  7. Encode JSON Response: {"status": "success", "output": "...", ...}       |  |
|  |  8. Send TCP Response & Close Client Connection                             |  |
|  +-----------------------------------------------------------------------------+  |
+-----------------------------------------------------------------------------------+

Thread-Safety & Blender Concurrency

The Problem

When you run a standard socket server in Python, incoming connections are processed on a background thread. If that thread attempts to execute:

import bpy
bpy.ops.mesh.primitive_cube_add()

Blender will either crash instantly with SIGSEGV or corrupt its internal scene database. This is because:

  1. Dependency Graph (depsgraph): Not thread-safe for writes or topological node updates.

  2. Context Window (bpy.context): Thread-local to Blender's main event dispatch loop.

  3. Undo Stack: Requires serialized push/pop operations managed exclusively by the main thread.

The Solution: bpy.app.timers Pipeline

bpy-bridge-mcp decouples socket I/O from execution:

  • Socket receiving, payload parsing, and AST validation occur concurrently in a lightweight daemon thread (BpyBridgeServerThread), leaving Blender's UI completely responsive with zero frame drops.

  • Validated scripts are pushed to a thread-safe queue.Queue.

  • A timer registered via bpy.app.timers.register(process_bpy_queue, first_interval=0.1) fires on Blender's main loop every 100 milliseconds, executes queued payloads within the native main thread context, and posts results to a client-specific response queue.


Static AST Security Sandbox

Before any incoming code string is queued or evaluated, it is passed through bpy_bridge.security.validate_script_safety().

The sandbox parses the code into a Python Abstract Syntax Tree (ast.parse) and performs static verification:

Category

Blocked Entities

Reason

System & Shell Modules

os, subprocess, sys, shutil, pty

Prevents shell execution, file deletion, and arbitrary process spawning.

Low-Level & Memory

ctypes, importlib

Prevents arbitrary memory manipulation and dynamic module bypasses.

Network Sockets

socket

Prevents outbound reverse shells and socket binding conflicts.

Dangerous Built-ins

eval, exec, open, __import__, compile

Blocks dynamic string evaluation, disk writes, and runtime import stealth.

Blocked Patterns Example

All of the following attacks are intercepted before execution:

# Direct imports
import os
import subprocess as sp

# Aliased and submodule imports
from os import system as sys_exec
from subprocess import Popen

# Built-in calls
eval("1 + 1")
open("/home/user/.ssh/id_rsa", "r")
builtins.open("malicious.py", "w")
__builtins__.eval("...")

If a violation is detected, execution is aborted, and a structured security error is returned immediately:

{
  "status": "error",
  "error": "Security Violation: Import of forbidden module 'subprocess' is prohibited"
}

Quick Start

1. Installation

Install bpy-bridge-mcp via pip:

pip install bpy-bridge-mcp

Or install from source in editable mode:

git clone https://github.com/CodeByDeepak-dev/bpy-bridge-mcp.git
cd bpy-bridge-mcp
pip install -e .[dev]

2. Enabling in Blender

Method A: Direct Addon Installation

  1. Download or zip the bpy_bridge directory.

  2. In Blender, navigate to Edit → Preferences → Add-ons → Install...

  3. Select the file and enable BPY Bridge MCP.

Method B: Blender Python Console

Open the Interactive Python Console inside Blender and run:

import bpy_bridge
bpy_bridge.register()

Output:

[bpy-bridge] Server listening on 127.0.0.1:9876
[bpy-bridge] Registered bpy.app.timers callback (interval: 0.1s).

3. Headless Blender Startup

For CI/CD pipelines, render farms, or Docker containers:

blender -b --python-expr "import bpy_bridge; bpy_bridge.register()"

CLI Usage

The package bundles the bpy-bridge command-line executable:

1. Inline Python Code

bpy-bridge "import bpy; bpy.ops.mesh.primitive_cube_add(size=2.0); print('Cube successfully added!')"

Output:

Cube successfully added!

2. Executing Script Files

Create a script (e.g. generate_terrain.py):

import bpy
import math

bpy.ops.mesh.primitive_grid_add(x_subdivisions=64, y_subdivisions=64, size=10.0)
grid = bpy.context.active_object
grid.name = "ProceduralTerrain"
print(f"Created terrain with {len(grid.data.vertices)} vertices.")

Execute via CLI:

bpy-bridge --file generate_terrain.py

3. Structured JSON Output

Pass --json to receive raw structured execution output:

bpy-bridge "print('Testing JSON output')" --json

Output:

{
  "status": "success",
  "output": "Testing JSON output",
  "error": null
}

4. Custom Host and Port

bpy-bridge --file script.py --host 127.0.0.1 --port 9876

Model Context Protocol (MCP) Integration

bpy-bridge-mcp acts as a zero-latency backend for MCP servers, allowing agents like Claude Desktop, Cursor, and Codex to manipulate Blender scenes in real time.

Configuration for Claude Desktop / Cursor

Add the following tool definition to your MCP server configuration:

{
  "mcpServers": {
    "blender": {
      "command": "bpy-bridge",
      "args": []
    }
  }
}

MCP Tool Schema Example

{
  "name": "execute_blender_code",
  "description": "Execute sandboxed Python code inside a live Blender session via bpy-bridge-mcp.",
  "parameters": {
    "type": "object",
    "properties": {
      "code": {
        "type": "string",
        "description": "Python code using bpy to construct 3D scenes, shaders, or animations."
      }
    },
    "required": ["code"]
  }
}

TCP Socket Protocol Specification

The bridge server communicates via raw TCP sockets on 127.0.0.1:9876.

Request Format

Clients send a JSON-encoded payload over TCP:

{
  "code": "import bpy\nbpy.ops.mesh.primitive_uv_sphere_add(radius=1.5)\nprint('Sphere generated')"
}

Response Format

The server responds with a JSON-encoded object:

Success Response:

{
  "status": "success",
  "output": "Sphere generated\n",
  "error": null
}

Security Violation Response:

{
  "status": "error",
  "error": "Security Violation: Import of forbidden module 'subprocess' is prohibited"
}

Runtime Exception Response:

{
  "status": "error",
  "output": "",
  "error": "AttributeError: 'NoneType' object has no attribute 'location'",
  "traceback": "Traceback (most recent call last):\n  File ... line 4, in <module>\nAttributeError: ..."
}

Development & Testing

Running Tests

The repository contains comprehensive unit tests verifying the AST security sandbox, CLI argument parser, and bridge lifecycle:

pytest -v

Test Coverage Highlights

  • Safe bpy, bmesh, and mathutils operations

  • Comprehensive AST interception of os, subprocess, sys, shutil, socket, ctypes, importlib, pty

  • Forbidden builtin interception (open, eval, exec, __import__, compile)

  • Malformed syntax handling

  • CLI parser validation and offline socket error reporting


Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository and create a feature branch (git checkout -b feature/amazing-feature).

  2. Ensure all tests pass (pytest -v).

  3. Commit your changes (git commit -m "Add amazing feature").

  4. Push to your branch (git push origin feature/amazing-feature).

  5. Open a Pull Request.


License

Distributed under the MIT License. See LICENSE for details.

Developed with care by Deepak Behera (@CodeByDeepak-dev).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Connects MCP-compatible clients to a live Blender scene for AI-assisted 3D workflows, enabling inspection and controlled operations on objects, materials, cameras, lights, render settings, animation, UVs, Geometry Nodes, imports, exports, and Python execution.
      1
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      An MCP server that enables AI assistants like Codex or ChatGPT to inspect and control a local Blender scene, including creating objects, editing materials, setting cameras and lights, rendering previews, and saving safe copies of .blend files.
      1
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables LLM clients like Claude to control Blender remotely, including scene inspection, object creation/modification, and Python code execution, via a socket-based MCP server.
      279 npm
      MIT