Blender AI MCP

Modular MCP Server + Blender Addon for AI-Driven 3D Modeling.

blender-ai-mcp

License: BUSL-1.1 Python 3.10+ Docker CI Status

πŸ’‘ Support the Project

This project is currently developed after hours as a passion project. Creating a stable bridge between AI and Blender's complex API requires significant time and effort.

If you find this tool useful or want to accelerate the development of advanced features (like Edit Mode tools, Auto-Rigging, or Macro Generators), please consider supporting the project. Your sponsorship allows me to dedicate more time to:

  • Implementing critical Mesh Editing Tools (Extrude, Bevel, Loop Cut).
  • Creating high-level Macro Tools (e.g., "Create Human Blockout", "Organify").
  • Ensuring day-one support for new Blender versions.

πŸ’– Sponsor on GitHub | β˜• Buy me a coffee

Modular MCP Server + Blender Addon for AI-Driven 3D Modeling.

Enable LLMs (Claude, ChatGPT) to control Blender reliably. Built with Clean Architecture for stability and scalability.


πŸš€ Why use this MCP Server instead of raw Python code?

Most AI solutions for Blender rely on asking the LLM to "write a Python script". This often fails because:

  1. Hallucinations: AI frequently uses outdated bpy API methods (mixing Blender 2.8 with 5.0).
  2. Context Errors: Running operators requires specific context (active window, selected object, correct mode). Raw scripts often crash Blender due to poll() failures.
  3. No Feedback Loop: If a script fails, the AI doesn't know why. Our MCP server returns precise error messages.
  4. Safety: Executing arbitrary Python code is risky. Our tools are sandboxed endpoints with validated inputs.

Blender AI MCP acts as a stable Translation Layer, handling the complexity of Blender's internal state machine so the AI can focus on creativity.


πŸ—οΈ Architecture

This project uses a split-architecture design:

  1. MCP Server (Python/FastMCP): Handles AI communication.
  2. Blender Addon (Python/bpy): Executes 3D operations.

Communication happens via JSON-RPC over TCP sockets.

See ARCHITECTURE.md for deep dive.

βœ… Support Matrix

  • Blender: tested on Blender 5.0 (E2E). The addon declares minimum Blender 4.0, but 4.x support is best-effort.
  • Python (MCP server): 3.11 is the CI baseline. 3.10+ works for core tools, but Router semantic features (LaBSE/LanceDB) require 3.11+.
  • OS: macOS / Windows / Linux (Docker recommended). On Linux, use host networking or proper host resolution for BLENDER_RPC_HOST.
  • Memory: Router semantic matching uses a local LaBSE model (~2GB RAM).

πŸ§ͺ Testing

Unit Tests (no Blender required):

PYTHONPATH=. poetry run pytest tests/unit/ -v

To see the current unit test count:

poetry run pytest tests/unit --collect-only

E2E Tests (requires Blender):

# Automated: build β†’ install addon β†’ start Blender β†’ run tests β†’ cleanup
python3 scripts/run_e2e_tests.py

To see the current E2E test count:

poetry run pytest tests/e2e --collect-only
TypeCoverage
Unit TestsAll tool handlers
E2E TestsBlender addon integration (Scene, Mesh, Material, UV, Export, Import, Baking, System, Sculpt, Router)

See _docs/_TESTS/README.md for detailed testing documentation.

============================= test session starts ==============================
platform darwin -- Python 3.13.9, pytest-9.0.1, Blender 5.0
collected 142 items

tests/e2e/tools/baking/test_baking_tools.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“
tests/e2e/tools/collection/test_collection_tools.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“
tests/e2e/tools/export/test_export_tools.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“
tests/e2e/tools/import_tool/test_import_tools.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“
tests/e2e/tools/knife_cut/test_knife_cut_tools.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“
tests/e2e/tools/material/test_material_tools.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“
tests/e2e/tools/mesh/test_mesh_cleanup.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“
tests/e2e/tools/mesh/test_mesh_edge_weights.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“
tests/e2e/tools/scene/test_*.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“
tests/e2e/tools/sculpt/test_sculpt_tools.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“
tests/e2e/tools/system/test_system_tools.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“
tests/e2e/tools/uv/test_uv_tools.py βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“

============================= 142 passed in 12.25s =============================

πŸ—ΊοΈ Roadmap & Capabilities

Legend: βœ… Done | 🚧 To Do

Our goal is to enable AI to model complex 3D assetsβ€”from organs and biological structures to hard-surface precision parts (cars, devices).


Scene Tools (scene_*)

Object Mode operations for scene management and inspection.

ToolDescriptionStatus
scene_list_objectsList all objects in sceneβœ…
scene_delete_objectDelete object by nameβœ…
scene_clean_sceneRemove all objectsβœ…
scene_duplicate_objectDuplicate objectβœ…
scene_set_active_objectSet active objectβœ…
scene_get_viewportCapture viewport image (AI vision)βœ…
scene_get_modeReport current Blender modeβœ…
scene_list_selectionList selected objects/componentsβœ…
scene_inspect_objectDetailed object infoβœ…
scene_snapshot_stateCapture scene snapshotβœ…
scene_compare_snapshotCompare two snapshotsβœ…
scene_inspect_material_slotsMaterial slot assignmentsβœ…
scene_inspect_mesh_topologyTopology statsβœ…
scene_inspect_modifiersModifier stack infoβœ…
scene_rename_objectRename object by nameβœ…
scene_hide_objectHide/show object in viewportβœ…
scene_show_all_objectsShow all hidden objectsβœ…
scene_isolate_objectIsolate object (hide all others)βœ…
scene_camera_orbitOrbit viewport around targetβœ…
scene_camera_focusFocus viewport on objectβœ…
scene_get_custom_propertiesGet object metadata/custom propertiesβœ…
scene_set_custom_propertySet/delete custom property on objectβœ…
scene_get_hierarchyGet parent-child hierarchyβœ…
scene_get_bounding_boxGet precise bounding box cornersβœ…
scene_get_origin_infoGet origin/pivot point infoβœ…

Modeling Tools (modeling_*)

Object Mode operations for creating and transforming objects.

ToolDescriptionStatus
modeling_create_primitiveCreate cube, sphere, cylinder, etc.βœ…
modeling_transform_objectMove, rotate, scale objectsβœ…
modeling_add_modifierAdd modifier to objectβœ…
modeling_apply_modifierApply (bake) modifierβœ…
modeling_list_modifiersList modifiers on objectβœ…
modeling_convert_to_meshConvert curve/text to meshβœ…
modeling_join_objectsJoin multiple objectsβœ…
modeling_separate_objectSeparate by loose parts/materialβœ…
modeling_set_originSet object origin pointβœ…

Lattice Deformation

ToolDescriptionStatus
lattice_createCreate lattice fitted to objectβœ…
lattice_bindBind object to lattice deformerβœ…
lattice_edit_pointMove lattice control pointsβœ…

Text Objects

ToolDescriptionStatus
text_createCreate 3D text objectβœ…
text_editModify text content and propertiesβœ…
text_to_meshConvert text to mesh for exportβœ…

Skin Modifier (Tubular Structures)

ToolDescriptionStatus
skin_create_skeletonCreate skeleton for skin modifierβœ…
skin_set_radiusSet skin radius at verticesβœ…

Mesh Tools (mesh_*)

Edit Mode operations for geometry manipulation.

Selection

ToolDescriptionStatus
mesh_select_allSelect/deselect all geometryβœ…
mesh_select_by_indexSelect by vertex/edge/face indexβœ…
mesh_select_linkedSelect connected geometryβœ…
mesh_select_moreGrow selectionβœ…
mesh_select_lessShrink selectionβœ…
mesh_select_boundarySelect boundary edgesβœ…
mesh_select_loopSelect edge loopβœ…
mesh_select_ringSelect edge ringβœ…
mesh_select_by_locationSelect by 3D positionβœ…
mesh_get_vertex_dataGet vertex positionsβœ…

Core Operations

ToolDescriptionStatus
mesh_extrude_regionExtrude selected facesβœ…
mesh_delete_selectedDelete selected geometryβœ…
mesh_fill_holesFill holes with facesβœ…
mesh_bevelBevel edges/verticesβœ…
mesh_loop_cutAdd loop cutsβœ…
mesh_insetInset facesβœ…
mesh_booleanBoolean operationsβœ…
mesh_merge_by_distanceMerge nearby verticesβœ…
mesh_subdivideSubdivide geometryβœ…

Transform & Geometry

ToolDescriptionStatus
mesh_transform_selectedMove/rotate/scale selected geometryβœ…
mesh_bridge_edge_loopsBridge two edge loopsβœ…
mesh_duplicate_selectedDuplicate selected geometryβœ…

Deformation

ToolDescriptionStatus
mesh_smoothSmooth verticesβœ…
mesh_flattenFlatten to planeβœ…
mesh_randomizeRandomize vertex positionsβœ…
mesh_shrink_fattenMove along normalsβœ…

Precision Tools

ToolDescriptionStatus
mesh_bisectCut mesh with planeβœ…
mesh_edge_slideSlide edges along topologyβœ…
mesh_vert_slideSlide vertices along edgesβœ…
mesh_triangulateConvert to trianglesβœ…
mesh_remesh_voxelVoxel remeshβœ…

Procedural

ToolDescriptionStatus
mesh_spinSpin/lathe geometry around axisβœ…
mesh_screwCreate spiral/helix geometryβœ…
mesh_add_vertexAdd single vertexβœ…
mesh_add_edge_faceCreate edge/face from selectionβœ…

Vertex Groups

ToolDescriptionStatus
mesh_list_groupsList vertex groupsβœ…
mesh_create_vertex_groupCreate new vertex groupβœ…
mesh_assign_to_groupAssign vertices to groupβœ…
mesh_remove_from_groupRemove vertices from groupβœ…

Edge Weights & Creases

ToolDescriptionStatus
mesh_edge_creaseSet crease weight for subdivisionβœ…
mesh_bevel_weightSet bevel weight for bevel modifierβœ…
mesh_mark_sharpMark/clear sharp edgesβœ…

Cleanup & Optimization

ToolDescriptionStatus
mesh_dissolveDissolve vertices/edges/faces (limited dissolve)βœ…
mesh_tris_to_quadsConvert triangles to quadsβœ…
mesh_normals_make_consistentRecalculate normalsβœ…
mesh_decimateReduce polycount on selectionβœ…

Knife & Cut

ToolDescriptionStatus
mesh_knife_projectProject cut from selected geometryβœ…
mesh_ripRip/tear geometry at selectionβœ…
mesh_splitSplit selection from meshβœ…
mesh_edge_splitSplit mesh at selected edgesβœ…

Symmetry & Fill

ToolDescriptionStatus
mesh_symmetrizeMake mesh symmetricβœ…
mesh_grid_fillFill boundary with quad gridβœ…
mesh_poke_facesPoke faces (add center vertex)βœ…
mesh_beautify_fillRearrange triangles uniformlyβœ…
mesh_mirrorMirror selected geometryβœ…
mesh_set_proportional_editEnable soft selection falloffβœ…

Curve Tools (curve_*)

Curve creation and conversion.

ToolDescriptionStatus
curve_createCreate Bezier/NURBS/Path/Circle curveβœ…
curve_to_meshConvert curve to meshβœ…

Collection Tools (collection_*)

Collection management and hierarchy.

ToolDescriptionStatus
collection_listList all collectionsβœ…
collection_list_objectsList objects in collectionβœ…
collection_manageCreate/delete/move collectionsβœ…

Material Tools (material_*)

Material creation and assignment.

ToolDescriptionStatus
material_listList all materialsβœ…
material_list_by_objectList materials on objectβœ…
material_createSetup PBR materialsβœ…
material_assignAssign to objects/facesβœ…
material_set_paramsAdjust roughness, metallic, etc.βœ…
material_set_textureBind image texturesβœ…
material_inspect_nodesInspect shader node graphβœ…

UV Tools (uv_*)

UV mapping operations.

ToolDescriptionStatus
uv_list_mapsList UV maps on objectβœ…
uv_unwrapSmart UV Project / Cube Projectionβœ…
uv_pack_islandsPack UV islandsβœ…
uv_create_seamMark/clear UV seamsβœ…

System Tools (system_*)

Global project-level operations.

ToolDescriptionStatus
system_set_modeHigh-level mode switchingβœ…
system_undoSafe undo for AIβœ…
system_redoSafe redo for AIβœ…
system_save_fileSave .blend fileβœ…
system_new_fileCreate new fileβœ…
system_snapshotQuick save/restore checkpointsβœ…

Export Tools (export_*)

File export operations.

ToolDescriptionStatus
export_glbExport to GLB formatβœ…
export_fbxExport to FBX formatβœ…
export_objExport to OBJ formatβœ…

Import Tools (import_*)

File import operations.

ToolDescriptionStatus
import_objImport OBJ fileβœ…
import_fbxImport FBX fileβœ…
import_glbImport GLB/GLTF fileβœ…
import_image_as_planeImport image as textured plane (reference)βœ…

Baking Tools (bake_*)

Texture baking for game dev workflows.

ToolDescriptionStatus
bake_normal_mapBake normal map (high-to-low or self)βœ…
bake_aoBake ambient occlusion mapβœ…
bake_combinedBake full render to textureβœ…
bake_diffuseBake diffuse/albedo colorβœ…

Extraction Tools (extraction_*)

Analysis tools for the Automatic Workflow Extraction System. Enables deep topology analysis, component detection, symmetry detection, and multi-angle rendering for LLM Vision integration.

ToolDescriptionStatus
extraction_deep_topologyDeep topology analysis with feature detectionβœ…
extraction_component_separateSeparate mesh into loose partsβœ…
extraction_detect_symmetryDetect X/Y/Z symmetry planesβœ…
extraction_edge_loop_analysisAnalyze edge loops and patternsβœ…
extraction_face_group_analysisAnalyze face groups by normal/heightβœ…
extraction_render_anglesMulti-angle renders for LLM Visionβœ…

Metaball Tools (metaball_*)

Organic blob primitives for medical/biological modeling.

ToolDescriptionStatus
metaball_createCreate metaball objectβœ…
metaball_add_elementAdd element (ball, capsule, ellipsoid)βœ…
metaball_to_meshConvert metaball to meshβœ…

Macro Tools (macro_*)

High-level abstractions where one command executes hundreds of Blender operations.

ToolDescriptionStatus
macro_organifyConvert blockouts to organic shapes🚧
macro_create_phone_baseGenerate smartphone chassis🚧
macro_human_blockoutGenerate proportional human mesh🚧
macro_retopologizeAutomate low-poly conversion🚧
macro_panel_cutHard-surface panel cutting🚧
macro_lowpoly_convertReduce polycount preserving silhouette🚧
macro_cleanup_allScene-wide mesh cleanup🚧

Sculpting Tools (sculpt_*)

Organic shaping and sculpt workflows.

Core Brushes

ToolDescriptionStatus
sculpt_autoHigh-level sculpt operation (mesh filters)βœ…
sculpt_brush_smoothSmooth brushβœ…
sculpt_brush_grabGrab brushβœ…
sculpt_brush_creaseCrease brushβœ…

Organic Brushes

ToolDescriptionStatus
sculpt_brush_clayAdd clay-like materialβœ…
sculpt_brush_inflateInflate/deflate areasβœ…
sculpt_brush_blobCreate organic bulgesβœ…
sculpt_brush_snake_hookPull long tendrils (vessels, nerves)βœ…
sculpt_brush_drawBasic sculpt drawβœ…
sculpt_brush_pinchPinch geometry togetherβœ…

Dynamic Topology

ToolDescriptionStatus
sculpt_enable_dyntopoEnable dynamic topologyβœ…
sculpt_disable_dyntopoDisable dynamic topologyβœ…
sculpt_dyntopo_flood_fillApply detail level to entire meshβœ…

Armature Tools (armature_*)

Skeletal rigging and animation.

ToolDescriptionStatus
armature_createCreate armature with initial boneβœ…
armature_add_boneAdd bone to armatureβœ…
armature_bindBind mesh to armature (auto weights)βœ…
armature_pose_bonePose armature boneβœ…
armature_weight_paint_assignAssign weights to vertex groupβœ…

πŸ€– Router Supervisor βœ…

Intelligent Router acting as supervisor over LLM tool calls - not just an "intent matcher". Intercepts, corrects, expands, and overrides tool calls before execution.

Status: βœ… Complete | All 6 Phases Done | Test counts vary β€” see πŸ§ͺ Testing for up-to-date numbers

Documentation: See _docs/_ROUTER/ for full documentation including Quick Start, Configuration, Patterns, and API Reference.

All Phases Complete βœ…

PhaseComponentsStatus
Phase 1: FoundationDirectory structure, Domain entities, Interfaces, Metadata loader (119 JSON files), Configβœ…
Phase 2: AnalysisTool interceptor, Scene context analyzer, Geometry pattern detector, Proportion calculatorβœ…
Phase 3: EnginesTool correction, Tool override, Workflow expansion, Error firewall, Intent classifier (LaBSE)βœ…
Phase 4: IntegrationSupervisorRouter orchestrator, MCP integration, Logging & telemetryβœ…
Phase 5: WorkflowsPhone workflow, Tower workflow, Screen cutout workflow, Custom YAML workflowsβœ…
Phase 6: Testing & DocsE2E test suite (see πŸ§ͺ Testing), Complete documentation (6 guides)βœ…

Key Features

FeatureDescription
LLM SupervisorIntercepts and corrects LLM tool calls before execution
Scene-AwareAnalyzes Blender state via RPC for informed decisions
Pattern DetectionRecognizes 9 patterns: tower, phone, table, pillar, wheel, box, sphere, cylinder
Auto-CorrectionFixes mode violations, missing selection, invalid parameters
Workflow ExpansionSingle tool β†’ complete multi-step workflow
Error FirewallBlocks/fixes invalid operations before they crash
100% OfflineNo external API calls - LaBSE runs locally (~1.8GB RAM)
MultilingualLaBSE supports 109 languages for intent classification
Semantic MatchingMatch workflows by meaning, not just keywords (LaBSE embeddings)
GeneralizationUse similar workflow when exact match missing
Feedback LearningImprove matching from user corrections
LanceDB Vector StoreO(log N) HNSW search with metadata filtering (TASK-047)
Confidence AdaptationHIGH/MEDIUM/LOW confidence β†’ full/filtered/core workflow (TASK-051)
Parametric Variables$variable syntax with defaults and modifiers for dynamic params (TASK-052)

Workflow-First Quick Start (recommended)

Use this when you want the LLM to prefer existing YAML workflows and only fall back to manual tool-calling when no workflow matches.

1) Optional: preview likely workflow matches (read-only)
   workflow_catalog(action="search", query="<your prompt>", top_k=5, threshold=0.0)

2) Set the goal (mandatory)
   router_set_goal(goal="<your prompt including modifiers>")

3) Handle Router response
   - status == "needs_input": call router_set_goal(goal, resolved_params={...})
   - status == "ready": proceed (workflow executes / expands into tool calls)
   - status == "no_match": switch to manual tool-calling
   - status == "error": router malfunction (fail-fast). Check logs and open a GitHub issue.

Example: LLM sends mesh tool in wrong mode

LLM: mesh_extrude(depth=0.5)  # In OBJECT mode, no selection

Router detects:
  - Mode: OBJECT (mesh tool needs EDIT)
  - Selection: None (extrude needs faces)
  - Pattern: phone_like

Router outputs:
  1. system_set_mode(mode="EDIT")
  2. mesh_select(action="all", mode="FACE")
  3. mesh_inset(thickness=0.03)
  4. mesh_extrude(depth=-0.02)
  5. system_set_mode(mode="OBJECT")

Result: Screen cutout created instead of crash!

Semantic Workflow Matching

User: "zrΓ³b krzesΕ‚o" (make a chair)

Router behavior:
  β†’ LaBSE semantic similarity search
  β†’ Found: table_workflow (0.72), tower_workflow (0.45)
  β†’ Uses table_workflow with inherited proportions
  β†’ Chair has proper leg ratios from table, vertical proportions from tower

Parametric Variables (TASK-052)

# In workflow YAML:
defaults:
  leg_angle: 0.32        # A-frame legs (default)

modifiers:
  "straight legs":
    leg_angle: 0         # Override for vertical legs
  "proste nogi":         # Polish support
    leg_angle: 0

steps:
  - tool: modeling_transform_object
    params:
      rotation: [0, "$leg_angle", 0]  # Uses variable
User: "table with straight legs"
β†’ Modifier "straight legs" matches
β†’ leg_angle = 0 (vertical legs instead of A-frame)

User: "stΓ³Ε‚ z proste nogi"
β†’ Polish modifier matches
β†’ Same result: vertical legs

Configuration Presets

from server.router.infrastructure.config import RouterConfig

# Default (recommended)
config = RouterConfig()

# Strict mode (no auto-fixes)
config = RouterConfig(auto_mode_switch=False, auto_selection=False)

# Performance mode (longer cache)
config = RouterConfig(cache_ttl_seconds=2.0, log_decisions=False)

🧠 LLM Context Optimization

Unified "mega tools" that consolidate multiple related operations to reduce LLM context usage.

Scene Mega Tools

Mega ToolActionsSavingsStatus
scene_contextmode, selection-1βœ…
scene_createlight, camera, empty-2βœ…
scene_inspectobject, topology, modifiers, materials-3βœ…

Mesh Mega Tools

Mega ToolActionsSavingsStatus
mesh_selectall, none, linked, more, less, boundary-4βœ…
mesh_select_targetedby_index, loop, ring, by_location-3βœ…

Total: 18 tools β†’ 5 mega tools (-13 definitions for LLM context)


πŸš€ Quick Start

1. Install the Blender Addon

  1. Download blender_ai_mcp.zip from the Releases Page.
  2. Open Blender -> Edit -> Preferences -> Add-ons.
  3. Click Install... and select the zip file.
  4. Enable the addon. It will start a local server on port 8765.

2. Configure your MCP Client (Cline / Claude Code / Codex CLI)

We recommend using Docker to run the MCP Server.

{
  "mcpServers": {
    "blender-ai-mcp": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e", "BLENDER_RPC_HOST=host.docker.internal",
        "ghcr.io/patrykiti/blender-ai-mcp:latest"
      ],
      "disabled": false,
      "autoApprove": [
        "scene_list_objects",
        "scene_delete_object",
        "scene_clean_scene",
        "scene_duplicate_object",
        "scene_set_active_object",
        "scene_get_viewport",
        "scene_set_mode",
        "scene_context",
        "scene_create",
        "scene_inspect",
        "scene_snapshot_state",
        "scene_compare_snapshot",
        "scene_rename_object",
        "scene_hide_object",
        "scene_show_all_objects",
        "scene_isolate_object",
        "scene_camera_orbit",
        "scene_camera_focus",
        "scene_get_custom_properties",
        "scene_set_custom_property",
        "scene_get_hierarchy",
        "scene_get_bounding_box",
        "scene_get_origin_info",
        "collection_list",
        "collection_list_objects",
        "collection_manage",
        "material_list",
        "material_list_by_object",
        "material_create",
        "material_assign",
        "material_set_params",
        "material_set_texture",
        "material_inspect_nodes",
        "uv_list_maps",
        "uv_unwrap",
        "uv_pack_islands",
        "uv_create_seam",
        "modeling_create_primitive",
        "modeling_transform_object",
        "modeling_add_modifier",
        "modeling_apply_modifier",
        "modeling_convert_to_mesh",
        "modeling_join_objects",
        "modeling_separate_object",
        "modeling_set_origin",
        "modeling_list_modifiers",
        "mesh_select",
        "mesh_select_targeted",
        "mesh_delete_selected",
        "mesh_extrude_region",
        "mesh_fill_holes",
        "mesh_bevel",
        "mesh_loop_cut",
        "mesh_inset",
        "mesh_boolean",
        "mesh_merge_by_distance",
        "mesh_subdivide",
        "mesh_smooth",
        "mesh_flatten",
        "mesh_list_groups",
        "mesh_get_vertex_data",
        "mesh_randomize",
        "mesh_shrink_fatten",
        "mesh_create_vertex_group",
        "mesh_assign_to_group",
        "mesh_remove_from_group",
        "mesh_bisect",
        "mesh_edge_slide",
        "mesh_vert_slide",
        "mesh_triangulate",
        "mesh_remesh_voxel",
        "mesh_transform_selected",
        "mesh_bridge_edge_loops",
        "mesh_duplicate_selected",
        "mesh_spin",
        "mesh_screw",
        "mesh_add_vertex",
        "mesh_add_edge_face",
        "mesh_edge_crease",
        "mesh_bevel_weight",
        "mesh_mark_sharp",
        "mesh_dissolve",
        "mesh_tris_to_quads",
        "mesh_normals_make_consistent",
        "mesh_decimate",
        "mesh_knife_project",
        "mesh_rip",
        "mesh_split",
        "mesh_edge_split",
        "mesh_symmetrize",
        "mesh_grid_fill",
        "mesh_poke_faces",
        "mesh_beautify_fill",
        "mesh_mirror",
        "curve_create",
        "curve_to_mesh",
        "text_create",
        "text_edit",
        "text_to_mesh",
        "export_glb",
        "export_fbx",
        "export_obj",
        "sculpt_auto",
        "sculpt_brush_smooth",
        "sculpt_brush_grab",
        "sculpt_brush_crease",
        "sculpt_brush_clay",
        "sculpt_brush_inflate",
        "sculpt_brush_blob",
        "sculpt_brush_snake_hook",
        "sculpt_brush_draw",
        "sculpt_brush_pinch",
        "sculpt_enable_dyntopo",
        "sculpt_disable_dyntopo",
        "sculpt_dyntopo_flood_fill",
        "metaball_create",
        "metaball_add_element",
        "metaball_to_mesh",
        "skin_create_skeleton",
        "skin_set_radius",
        "lattice_create",
        "lattice_bind",
        "lattice_edit_point",
        "mesh_set_proportional_edit",
        "system_set_mode",
        "system_undo",
        "system_redo",
        "system_save_file",
        "system_new_file",
        "system_snapshot",
        "bake_normal_map",
        "bake_ao",
        "bake_combined",
        "bake_diffuse",
        "import_obj",
        "import_fbx",
        "import_glb",
        "import_image_as_plane",
        "extraction_deep_topology",
        "extraction_component_separate",
        "extraction_detect_symmetry",
        "extraction_edge_loop_analysis",
        "extraction_face_group_analysis",
        "extraction_render_angles",
        "armature_create",
        "armature_add_bone",
        "armature_bind",
        "armature_pose_bone",
        "armature_weight_paint_assign",
        "workflow_catalog",
        "router_set_goal",
        "router_get_status",
        "router_clear_goal"
      ]
    }
  }
}
{
  "mcpServers": {
    "blender-ai-mcp": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "--network", "host",
        "-e", "BLENDER_RPC_HOST=127.0.0.1",
        "ghcr.io/patrykiti/blender-ai-mcp:latest"
      ],
      "disabled": false,
      "autoApprove": [
        "scene_list_objects",
        "scene_delete_object",
        "scene_clean_scene",
        "scene_duplicate_object",
        "scene_set_active_object",
        "scene_get_viewport",
        "scene_set_mode",
        "scene_context",
        "scene_create",
        "scene_inspect",
        "scene_snapshot_state",
        "scene_compare_snapshot",
        "scene_rename_object",
        "scene_hide_object",
        "scene_show_all_objects",
        "scene_isolate_object",
        "scene_camera_orbit",
        "scene_camera_focus",
        "scene_get_custom_properties",
        "scene_set_custom_property",
        "scene_get_hierarchy",
        "scene_get_bounding_box",
        "scene_get_origin_info",
        "collection_list",
        "collection_list_objects",
        "collection_manage",
        "material_list",
        "material_list_by_object",
        "material_create",
        "material_assign",
        "material_set_params",
        "material_set_texture",
        "material_inspect_nodes",
        "uv_list_maps",
        "uv_unwrap",
        "uv_pack_islands",
        "uv_create_seam",
        "modeling_create_primitive",
        "modeling_transform_object",
        "modeling_add_modifier",
        "modeling_apply_modifier",
        "modeling_convert_to_mesh",
        "modeling_join_objects",
        "modeling_separate_object",
        "modeling_set_origin",
        "modeling_list_modifiers",
        "mesh_select",
        "mesh_select_targeted",
        "mesh_delete_selected",
        "mesh_extrude_region",
        "mesh_fill_holes",
        "mesh_bevel",
        "mesh_loop_cut",
        "mesh_inset",
        "mesh_boolean",
        "mesh_merge_by_distance",
        "mesh_subdivide",
        "mesh_smooth",
        "mesh_flatten",
        "mesh_list_groups",
        "mesh_get_vertex_data",
        "mesh_randomize",
        "mesh_shrink_fatten",
        "mesh_create_vertex_group",
        "mesh_assign_to_group",
        "mesh_remove_from_group",
        "mesh_bisect",
        "mesh_edge_slide",
        "mesh_vert_slide",
        "mesh_triangulate",
        "mesh_remesh_voxel",
        "mesh_transform_selected",
        "mesh_bridge_edge_loops",
        "mesh_duplicate_selected",
        "mesh_spin",
        "mesh_screw",
        "mesh_add_vertex",
        "mesh_add_edge_face",
        "mesh_edge_crease",
        "mesh_bevel_weight",
        "mesh_mark_sharp",
        "mesh_dissolve",
        "mesh_tris_to_quads",
        "mesh_normals_make_consistent",
        "mesh_decimate",
        "mesh_knife_project",
        "mesh_rip",
        "mesh_split",
        "mesh_edge_split",
        "mesh_symmetrize",
        "mesh_grid_fill",
        "mesh_poke_faces",
        "mesh_beautify_fill",
        "mesh_mirror",
        "curve_create",
        "curve_to_mesh",
        "text_create",
        "text_edit",
        "text_to_mesh",
        "export_glb",
        "export_fbx",
        "export_obj",
        "sculpt_auto",
        "sculpt_brush_smooth",
        "sculpt_brush_grab",
        "sculpt_brush_crease",
        "sculpt_brush_clay",
        "sculpt_brush_inflate",
        "sculpt_brush_blob",
        "sculpt_brush_snake_hook",
        "sculpt_brush_draw",
        "sculpt_brush_pinch",
        "sculpt_enable_dyntopo",
        "sculpt_disable_dyntopo",
        "sculpt_dyntopo_flood_fill",
        "metaball_create",
        "metaball_add_element",
        "metaball_to_mesh",
        "skin_create_skeleton",
        "skin_set_radius",
        "lattice_create",
        "lattice_bind",
        "lattice_edit_point",
        "mesh_set_proportional_edit",
        "system_set_mode",
        "system_undo",
        "system_redo",
        "system_save_file",
        "system_new_file",
        "system_snapshot",
        "bake_normal_map",
        "bake_ao",
        "bake_combined",
        "bake_diffuse",
        "import_obj",
        "import_fbx",
        "import_glb",
        "import_image_as_plane",
        "extraction_deep_topology",
        "extraction_component_separate",
        "extraction_detect_symmetry",
        "extraction_edge_loop_analysis",
        "extraction_face_group_analysis",
        "extraction_render_angles",
        "armature_create",
        "armature_add_bone",
        "armature_bind",
        "armature_pose_bone",
        "armature_weight_paint_assign",
        "workflow_catalog",
        "router_set_goal",
        "router_get_status",
        "router_clear_goal"
      ]
    }
  }
}

Copilot uses a slightly different config structure. Ensure you map the temp directory properly if you want file outputs.

{
  "mcpServers": {
    "blender-ai-mcp": {
      "type": "local",
      "command": "docker",
      "tools": [
        "*"
      ],
      "args": [
        "run",
        "-i",
        "--rm",
        "-v",
        "/tmp:/tmp",
        "ghcr.io/patrykiti/blender-ai-mcp:latest"
      ],
      "env": {
        "BLENDER_AI_TMP_INTERNAL_DIR": "/tmp",
        "BLENDER_AI_TMP_EXTERNAL_DIR": "/tmp",
        "BLENDER_RPC_HOST": "host.docker.internal"
      }
    }
  }
}

Create/update ~/.codex/config.toml:

[mcp_servers.blender-ai-mcp]
command = "docker"
# Optional
args = [
  "run",
  "-i",
  "-v",
  "/tmp:/tmp",
  "-e",
  "BLENDER_AI_TMP_INTERNAL_DIR=/tmp",
  "-e",
  "BLENDER_AI_TMP_EXTERNAL_DIR=/tmp",
  "-e",
  "ROUTER_ENABLED=true",
  "-e",
  "LOG_LEVEL=DEBUG",
  "-e",
  "BLENDER_RPC_HOST=host.docker.internal",
  "blender-ai-mcp:latest"
]

# Optional: propagate additional env vars to the MCP server.
# A default whitelist of env vars will be propagated to the MCP server.
# https://github.com/openai/codex/blob/main/codex-rs/rmcp-client/src/utils.rs#L82
env = {}

enabled_tools = [
  "scene_list_objects",
  "scene_delete_object",
  "scene_clean_scene",
  "scene_duplicate_object",
  "scene_set_active_object",
  "scene_get_viewport",
  "scene_set_mode",
  "scene_context",
  "scene_create",
  "scene_inspect",
  "scene_snapshot_state",
  "scene_compare_snapshot",
  "scene_rename_object",
  "scene_hide_object",
  "scene_show_all_objects",
  "scene_isolate_object",
  "scene_camera_orbit",
  "scene_camera_focus",
  "scene_get_custom_properties",
  "scene_set_custom_property",
  "scene_get_hierarchy",
  "scene_get_bounding_box",
  "scene_get_origin_info",
  "collection_list",
  "collection_list_objects",
  "collection_manage",
  "material_list",
  "material_list_by_object",
  "material_create",
  "material_assign",
  "material_set_params",
  "material_set_texture",
  "material_inspect_nodes",
  "uv_list_maps",
  "uv_unwrap",
  "uv_pack_islands",
  "uv_create_seam",
  "modeling_create_primitive",
  "modeling_transform_object",
  "modeling_add_modifier",
  "modeling_apply_modifier",
  "modeling_convert_to_mesh",
  "modeling_join_objects",
  "modeling_separate_object",
  "modeling_set_origin",
  "modeling_list_modifiers",
  "mesh_select",
  "mesh_select_targeted",
  "mesh_delete_selected",
  "mesh_extrude_region",
  "mesh_fill_holes",
  "mesh_bevel",
  "mesh_loop_cut",
  "mesh_inset",
  "mesh_boolean",
  "mesh_merge_by_distance",
  "mesh_subdivide",
  "mesh_smooth",
  "mesh_flatten",
  "mesh_list_groups",
  "mesh_get_vertex_data",
  "mesh_randomize",
  "mesh_shrink_fatten",
  "mesh_create_vertex_group",
  "mesh_assign_to_group",
  "mesh_remove_from_group",
  "mesh_bisect",
  "mesh_edge_slide",
  "mesh_vert_slide",
  "mesh_triangulate",
  "mesh_remesh_voxel",
  "mesh_transform_selected",
  "mesh_bridge_edge_loops",
  "mesh_duplicate_selected",
  "mesh_spin",
  "mesh_screw",
  "mesh_add_vertex",
  "mesh_add_edge_face",
  "mesh_edge_crease",
  "mesh_bevel_weight",
  "mesh_mark_sharp",
  "mesh_dissolve",
  "mesh_tris_to_quads",
  "mesh_normals_make_consistent",
  "mesh_decimate",
  "mesh_knife_project",
  "mesh_rip",
  "mesh_split",
  "mesh_edge_split",
  "mesh_symmetrize",
  "mesh_grid_fill",
  "mesh_poke_faces",
  "mesh_beautify_fill",
  "mesh_mirror",
  "curve_create",
  "curve_to_mesh",
  "text_create",
  "text_edit",
  "text_to_mesh",
  "export_glb",
  "export_fbx",
  "export_obj",
  "sculpt_auto",
  "sculpt_brush_smooth",
  "sculpt_brush_grab",
  "sculpt_brush_crease",
  "sculpt_brush_clay",
  "sculpt_brush_inflate",
  "sculpt_brush_blob",
  "sculpt_brush_snake_hook",
  "sculpt_brush_draw",
  "sculpt_brush_pinch",
  "sculpt_enable_dyntopo",
  "sculpt_disable_dyntopo",
  "sculpt_dyntopo_flood_fill",
  "metaball_create",
  "metaball_add_element",
  "metaball_to_mesh",
  "skin_create_skeleton",
  "skin_set_radius",
  "lattice_create",
  "lattice_bind",
  "lattice_edit_point",
  "mesh_set_proportional_edit",
  "system_set_mode",
  "system_undo",
  "system_redo",
  "system_save_file",
  "system_new_file",
  "system_snapshot",
  "bake_normal_map",
  "bake_ao",
  "bake_combined",
  "bake_diffuse",
  "import_obj",
  "import_fbx",
  "import_glb",
  "import_image_as_plane",
  "extraction_deep_topology",
  "extraction_component_separate",
  "extraction_detect_symmetry",
  "extraction_edge_loop_analysis",
  "extraction_face_group_analysis",
  "extraction_render_angles",
  "armature_create",
  "armature_add_bone",
  "armature_bind",
  "armature_pose_bone",
  "armature_weight_paint_assign",
  "workflow_catalog",
  "router_set_goal",
  "router_get_status",
  "router_clear_goal"
]

⚠️ Important Network Configuration:

  • macOS/Windows: Use host.docker.internal (as shown in the first config). The --network host option does NOT work on Docker Desktop for Mac/Windows.
  • Linux: Use --network host with 127.0.0.1 (as shown in the second config).
  • Troubleshooting: If the MCP server starts but cannot connect to Blender (timeout errors), ensure Blender is running with the addon enabled and that port 8765 is not blocked.

Viewport Output Modes & Temp Directory Mapping

The scene_get_viewport tool supports multiple output modes via the output_mode argument:

  • IMAGE (default): returns a FastMCP Image resource (best for Cline / clients with native image support).
  • BASE64: returns the raw base64-encoded JPEG string for direct Vision-module consumption.
  • FILE: writes the image to a temp directory and returns a message with host-visible file paths.
  • MARKDOWN: writes the image and returns rich markdown with an inline data: URL plus host-visible paths.

When running in Docker, map the internal temp directory to a host folder and configure env vars:

# Example volume & env mapping
docker run -i --rm \
  -v /host/tmp/blender-ai-mcp:/tmp/blender-ai-mcp \
  -e BLENDER_RPC_HOST=host.docker.internal \
  -e BLENDER_AI_TMP_INTERNAL_DIR=/tmp/blender-ai-mcp \
  -e BLENDER_AI_TMP_EXTERNAL_DIR=/host/tmp/blender-ai-mcp \
  ghcr.io/patrykiti/blender-ai-mcp:latest

πŸ“ˆ Star History

Star History Chart


🀝 Contributing

We welcome contributions! Please read CONTRIBUTING.md to understand our Clean Architecture standards before submitting a Pull Request.

🧩 Community & Support

πŸ‘¨β€πŸ’» Author

Patryk CiechaΕ„ski

License

This project is licensed under the Business Source License 1.1 (BSL 1.1)
with a custom Additional Use Grant authored by Patryk CiechaΕ„ski (PatrykIti).

The license automatically converts to Apache 2.0 on 2029-12-01.

For the full license text, see: LICENSE

Change License text (Apache 2.0): LICENSE-APACHE-2.0.txt

Related Servers