| """Blender startup script for headless HF Spaces (NOT blender -b). |
| |
| Run under a virtual display so Blender's GUI event loop runs and the |
| MCP addon's bpy.app.timers dispatcher fires (upstream explicitly refuses |
| -b background mode for this reason): |
| |
| xvfb-run -a blender --python /app/bootstrap.py |
| |
| What it does: |
| 1. Enables the bundled blender_mcp addon (expects addon.py copied to |
| the Blender scripts/addons dir as blender_mcp.py by the Dockerfile). |
| 2. Sets the socket port (env BLENDER_PORT, default 9876). |
| 3. Calls the addon's own start operator (blendermcp.start_server) — |
| no clicks needed. |
| Blender stays alive afterwards (GUI loop under xvfb), serving MCP clients |
| until the container stops. |
| """ |
|
|
| import os |
| import sys |
|
|
| import bpy |
|
|
|
|
| def main() -> None: |
| port = int(os.environ.get("BLENDER_PORT", "9876")) |
|
|
| bpy.ops.preferences.addon_enable(module="blender_mcp") |
|
|
| scene = bpy.context.scene |
| if hasattr(scene, "blendermcp_port"): |
| scene.blendermcp_port = port |
|
|
| bpy.ops.blendermcp.start_server() |
|
|
| running = getattr(getattr(bpy.types, "blendermcp_server", None), "running", False) |
| print(f"BOOTSTRAP: blendermcp_server running={running} port={port}", flush=True) |
| if not running: |
| print("BOOTSTRAP FATAL: server did not start", flush=True) |
| sys.exit(1) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|