bonsai-mcp

bonsai-mcp

MCP server for reading, viewing, and editing IFC models using IfcOpenShell and Bonsai. Enables querying model data, viewing via Blender's viewport, and making IFC-semantic edits without raw mesh operations.

Category
访问服务器

README

bonsai-mcp

tests python ifcopenshell bonsai mcp license

MCP server to read, view and edit IFC models with IfcOpenShell and Bonsai (Blender).

Query a model, look at it through Blender's viewport, and edit it with IFC semantics — profiles, placements, property sets — never raw mesh operations. The read tools run with Blender closed.

Status: Stage 3 — read tools, Blender/Bonsai viewport, and IFC-semantic editing.


Table of contents


1. Requirements

Python >= 3.11 (3.13 recommended)
uv >= 0.5
OS Windows 11 (primary), macOS, Linux
Blender >= 4.2, only needed for the bl_* tools
Bonsai the build matching Blender's Python (Blender 5.x → bonsai_py313)

The ifc_* tools run with Blender closed. The bl_* tools need Blender + Bonsai + the add-on.


2. Install

git clone https://github.com/nhantruong96/bonsai-mcp.git
cd bonsai-mcp
uv sync

To pin Python 3.13:

uv sync --python 3.13

Sample model. --selfcheck and pytest use KIT's FZK-Haus model. It is not committed — it is not this project's file — and is downloaded automatically on first run. Nothing to do.

Fetch it manually if the machine is offline at run time:

curl -L -o tests/fixtures/AC20-FZK-Haus.ifc https://www.ifcwiki.org/images/e/e3/AC20-FZK-Haus.ifc

Or point the selfcheck at any IFC file:

uv run python -m bonsai_mcp --selfcheck --file "D:\path\to\your.ifc"

3. Install the Blender add-on

Only needed for the bl_* tools. Skip this if you only use the read tools.

3.1. Install Bonsai (if it is not installed yet)

Blender 5.x runs Python 3.13 → take the bonsai_py313 build. Blender 4.2 runs Python 3.11 → bonsai_py311.

Blender → Edit > Preferences > Get Extensions → the ˅ button top right → Install from Disk... → pick the Bonsai zip.

3.2. Build the add-on zip

Compress-Archive -Path C:\Tools\bonsai-mcp\addon\bonsai_mcp_addon -DestinationPath C:\Tools\bonsai-mcp\bonsai_mcp_addon.zip -Force

3.3. Install the add-on

Blender → Edit > Preferences > Get Extensions → the ˅ button top right → Install from Disk... → pick bonsai_mcp_addon.zip.

3.4. Point the add-on at src

Edit > Preferences > Add-onsBonsai MCP Bridge → expand → fill in bonsai-mcp src:

C:\Tools\bonsai-mcp\src

This is what lets the ifc_* tools read the model Blender has open. Without it the bl_* tools still work but ifc_* cannot read through Blender.

Alternatively set the BONSAI_MCP_SRC environment variable, which takes precedence.

3.5. Run

  1. Open an IFC file: Bonsai > Project > Load Project.
  2. In the 3D viewport press NBonsai MCP tab → Start Server.
  3. The panel shows Running, the address 127.0.0.1:9876, request/error counts and the last 20 log lines.

Change the port under Edit > Preferences > Add-ons > Bonsai MCP Bridge > Port, then set BONSAI_MCP_BLENDER_PORT to the same value on the MCP side.


4. Selfcheck

uv run python -m bonsai_mcp --selfcheck
uv run python -m bonsai_mcp --list-tools
uv run python -m pytest

Selfcheck exits 0 on success. All logging goes to stderr.

The Blender integration tests skip themselves when no bridge is running. To run them, Start Server in Blender then:

uv run python -m pytest tests/test_blender_integration.py -v
uv run python -m pytest tests/test_blender_edit_integration.py -v

5. Claude Desktop config

File: %APPDATA%\Claude\claude_desktop_config.json (Windows) · ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)

{
  "mcpServers": {
    "bonsai-mcp": {
      "command": "uv",
      "args": [
        "--directory",
        "C:\\Tools\\bonsai-mcp",
        "run",
        "python",
        "-m",
        "bonsai_mcp"
      ],
      "env": {
        "BONSAI_MCP_BLENDER_HOST": "127.0.0.1",
        "BONSAI_MCP_BLENDER_PORT": "9876",
        "BONSAI_MCP_LOG_LEVEL": "INFO"
      }
    }
  }
}

The env block is optional; leaving it out uses exactly those defaults.

Restart Claude Desktop after editing the file.


6. Claude Code config

claude mcp add bonsai-mcp -- uv --directory C:\Tools\bonsai-mcp run python -m bonsai_mcp

Verify:

claude mcp list

7. Usage procedure

7.1. Without Blender

  1. ifc_open — open the file; check schema, units and element counts.
  2. ifc_list_property_namesalways run this before writing any property query.
  3. ifc_model_info or ifc_spatial_tree — get the storey structure and per-class counts.
  4. ifc_list_entities / ifc_select — filter to the elements you need; page with limit + offset.
  5. ifc_get_element — full detail for one element.
  6. ifc_geometry_info — geometry, profile and absolute placement of that element.
  7. ifc_representation_stats / ifc_validate — whole-file QC.

7.2. With Blender

  1. Load Project in Bonsai, then Start Server in the Bonsai MCP panel.
  2. bl_status — confirm the file, the versions, and that the session switched to blender mode.
  3. From here every ifc_* tool reads the model Blender holds. Do not call ifc_open — it is refused by design.
  4. bl_set_view for an overview, bl_focus_element(guid) for one element.
  5. For anything internal pass isolate=true, or use bl_isolate, then bl_isolate(restore=true).

8. Tool reference

8.1. IFC read tools

Tool Parameters Returns
ifc_open path schema, exporter, creation dates, units, entity/element totals, ifcopenshell.version
ifc_model_info class_limit=60, storey_limit=200 the above plus a per-class histogram and the storey list
ifc_list_entities ifc_class, limit=50, offset=0 real total plus one page: guid, name, class, storey
ifc_get_element guid | step_id attributes, psets, quantities, material, type, container
ifc_select query, limit=50, offset=0 ifcopenshell.util.selector results
ifc_spatial_tree max_depth=4, class_limit=10 Project → Site → Building → Storey with element counts per node
ifc_list_property_names limit=200, properties_per_set=60 every pset/property name that actually exists, with occurrence counts
ifc_geometry_info guid | step_id, include_metrics=true representations, items, profiles, absolute 4×4 matrix, bbox, volume, area; plus flat profiles[] and extrusions[]
ifc_representation_stats limit=60, shared_map_limit=20, map_scan_limit=2000 breakdown by RepresentationIdentifier/Type and item class, parametric/tessellated share, most-shared maps
ifc_validate limit=50, express_rules=false condensed ifcopenshell.validate report

Query syntax for ifc_select:

IfcWall
IfcWall, IfcSlab
IfcBeam, Name=/B-.*/
IfcSpace, Pset_SpaceCommon.IsExternal=TRUE

8.2. Blender tools

Tool Parameters Returns
bl_status timeout=30 whether Blender is reachable, Bonsai version, the IFC file it has open, ifcopenshell comparison of both sides, session state
bl_screenshot width=1280, timeout=30 viewport PNG plus its real dimensions
bl_focus_element guid, isolate=false, width=1280, timeout=30 selects and zooms to the element, returns the image and what was focused
bl_isolate guids[], restore=false, width=1280, timeout=30 hides everything else, returns the image and hidden/kept counts
bl_set_view direction, frame_all=true, width=1280, timeout=30 sets the viewpoint, returns the image
bl_reload guids[] (empty = all), timeout=60 resyncs the viewport from the in-memory IFC data

direction: front, back, left, right, top, bottom, axo.

width bounds the image's longest side, not literally its width. The viewport aspect ratio is preserved. Clamped to 320–2048.

bl_reload does not reload from disk; it rebuilds the viewport from the in-memory IFC data.

8.3. Edit tools, group A: attributes

No geometry is touched. Each takes guid for one element or query for many.

Tool Parameters
ifc_set_attribute attribute, value, guid | query, max_elements=100
ifc_set_pset_value pset, property, value, guid | query, max_elements=100
ifc_add_pset pset, properties{}, guid | query, max_elements=100
ifc_remove_pset pset, guid | query, max_elements=100

8.4. Edit tools, group B: placement

Tool Parameters
ifc_move_element dx, dy, dz (metres), guid | query, max_elements=100
ifc_rotate_element axis (x/y/z), degrees, guid | query, max_elements=100
ifc_set_placement guid, matrix 4×4 (translation in metres)

ifc_rotate_element spins the element about its own origin, not the project origin.

8.5. Edit tools, group C: parametric geometry

Tool Parameters
ifc_edit_profile guid, params{}, apply_to_all=false
ifc_set_extrusion_depth guid, depth (metres), apply_to_all=false
ifc_patch recipe, args{}, allow_file_replacement=false

Recipes: ResetAbsoluteCoordinates, OffsetObjectPlacements, SetWorldCoordinateSystem, ConvertLengthUnit, Optimise.

args uses the recipe's own parameter names; a wrong name is answered with the accepted list and their defaults.

8.6. Saving

Tool Parameters
ifc_save path, overwrite=false, validate=true
ifc_revert

9. Safe editing procedure

  1. Run ifc_geometry_info before any geometry edit — check the real parameter names and whether the element shares a representation map.
  2. Edit. The session's first edit automatically writes <name>.backup-<timestamp>.ifc beside the original.
  3. Read the before/after values in the result. Every edit tool returns both.
  4. In blender mode, use bl_focus_element or bl_screenshot to look at the result. The viewport is already resynced.
  5. ifc_save to a new path. Overwriting requires an explicit overwrite=true.
  6. If it went wrong, ifc_revert returns to the state before the first edit.

Guardrails

Guardrail Behaviour
Automatic backup Once per session, taken just before the first edit
Never overwrite the original ifc_save requires a new path; overwriting needs overwrite=true
Shared geometry Group C refuses when a map or profile is shared, reporting how many elements would be affected; pass apply_to_all=true to change all of them
No tessellation Editing tessellated geometry is refused, and no tool creates a Tessellation
Bulk ceiling A query matching more than max_elements (default 100) is refused without changing anything
Before and after Every edit tool returns before, after, changed — never {"status": "ok"}
Viewport sync In blender mode, Bonsai rebuilds exactly the affected elements after each edit

Note: Blender's own undo (Ctrl+Z) does not cover MCP edits. Use ifc_revert.


10. Unit conventions

Quantity Unit returned Note
Coordinates, dimensions metres (*_m, origin_m, bounding_box_m) already multiplied by length_unit_scale_to_metre
Profile parameters both parameters_file_units and parameters_metres
Extrusion depth extrusion_depth_file_units and extrusion_depth_m
Volume / area volume_m3, surface_area_m2 from the IfcOpenShell kernel (SI)
Storey elevation elevation_m
Angles degrees
4×4 matrix matrix_4x4_metres (translation column converted to metres) and matrix_4x4_file_units row-major, absolute
Values passed into edit tools metres and degrees dx/dy/dz, depth, matrix, degrees
params of ifc_edit_profile the file's own units use the numbers shown in parameters_file_units

The placement matrix is absolute: the whole nested IfcLocalPlacement chain is multiplied through.


11. Environment variables

Variable Set where Default Effect
BONSAI_MCP_LOG_LEVEL MCP side INFO DEBUG, INFO, WARNING, ERROR
BONSAI_MCP_BLENDER_HOST MCP side 127.0.0.1 add-on address
BONSAI_MCP_BLENDER_PORT MCP side 9876 add-on port; must match the preference set in Blender
BONSAI_MCP_SRC Blender side path to src; takes precedence over the add-on preference

12. Troubleshooting

Symptom Fix
No IFC model is open. Call ifc_open(path) first. Call ifc_open first
IFC file not found: ... Use an absolute path; escape \\ in JSON on Windows
ifc_select returns total: 0 when the data is definitely there Run ifc_list_property_names; real pset names often differ from the standard (BaseQuantitiesQto_WallBaseQuantities)
'IfcXxx' is not usable with by_type Wrong class name; see the suggestions in the error, or ifc_model_info
Result looks truncated Read total, has_more, next_offset and call again with offset
Coordinates are in the wrong place Use origin_m / matrix_4x4_metres, not the raw IfcLocalPlacement
metrics.available: false The element has no geometry the kernel could build; read metrics.error
No profile found under representations Clipping booleans nest; use the flat profiles[] and extrusions[]
profile.parametric: false It is an IfcArbitraryClosedProfileDef — an explicit curve with no parameters to edit
representation_maps.scan_note is not null The map scan was capped; raise map_scan_limit
ModuleNotFoundError: mcp.server.fastmcp mcp moved to 2.x — re-run uv sync (pyproject.toml pins <2)
Could not download the sample model Offline. Fetch it manually with the curl command in section 2, or pass --file
returned N bytes that do not start with 'ISO-10303-21' A captive portal or error page answered instead of the file; nothing was written
sample model sha256 is ..., expected ... The upstream file changed; tests asserting exact counts may now fail
pytest reports many s (skipped) Blender integration tests, or a missing sample model; see the reasons with -rs
Server does not appear in Claude Wrong --directory path, or Claude was not restarted
No log output anywhere Logging goes to stderr, not stdout

Blender

Symptom Fix
Blender is not running, or the Bonsai MCP add-on has not been started In Blender: 3D viewport → N → Bonsai MCP tab → Start Server
The Bonsai MCP panel is not there The add-on is not enabled: Edit > Preferences > Add-ons → tick Bonsai MCP Bridge
Could not bind 127.0.0.1:9876 The port is taken; change Port in the preferences and set BONSAI_MCP_BLENDER_PORT to match
VERSION MISMATCH in bl_status Pin them together: set ifcopenshell==<Bonsai's build> in pyproject.toml and re-run uv sync
query_modules_loaded: false The add-on has no path to src; see section 3.4
No IFC project is loaded in Blender Load one first with Bonsai > Project > Load Project
ifc_open refused with ModelLockedError By design — Blender holds the model; load the other file in Blender instead
bl_focus_element returns an image without the element in it It is behind other geometry; call again with isolate=true
The image is very tall or very narrow The image follows the viewport aspect ratio; make the Blender window landscape
No 3D viewport is available Blender is headless, or the workspace has no VIEW_3D area
main thread is busy Blender has a dialog open or a modal operator running; close it, or raise timeout
Screenshots show the old geometry after an edit Call bl_reload

Editing

Symptom Fix
EditRefused: ... apply to N element(s), not one Shared geometry. Check with ifc_geometry_info; if that is what you want, pass apply_to_all=true
EditRefused: ... will not tessellate The element has no parameters left; re-export it upstream as a swept solid
matches N elements, over the max_elements ceiling Narrow the query, or raise max_elements after checking the count with ifc_select
matched nothing, so there was nothing to edit Run ifc_list_property_names; real pset names often differ from the standard
has no property set named '...' Create it first with ifc_add_pset
has no parameter(s) [...] The error already lists the profile's real parameter names
FileExistsError: Refusing to overwrite Save to a different path, or pass overwrite=true
NoBackupError Nothing has been edited yet, so no backup exists
rebuilds the model into a new file object ConvertLengthUnit / Optimise: standalone needs allow_file_replacement=true; blender mode needs the project closed in Blender first
BackupError: Could not write the safety copy The folder holding the original is not writable; nothing was changed
Ctrl+Z in Blender does not undo an edit Blender's undo does not cover MCP edits; use ifc_revert

13. Development

uv sync
uv run python -m pytest -v
uv run python -m bonsai_mcp --selfcheck

Conventions:

  • uv.lock is committed; .venv/ never is.
  • No print(). stdout is the JSON-RPC channel; log through config.py to stderr.
  • Nothing in src/ may import bpy — the server must run with Blender closed. A test enforces it.
  • addon/bonsai_mcp_addon/protocol.py runs on the socket thread and must never touch bpy; all bpy calls live in handlers.py and run only from the main-thread timer. bpy is not thread safe — a call from the wrong thread crashes Blender dozens of commands later, somewhere unrelated. An AST test enforces it.
  • Failing tools return the full traceback in the traceback field; Blender-side failures carry Blender's own traceback too.
  • Every write goes through ifcopenshell.api, and through Session.write; no tool touches the model directly.
  • There are no raw-mesh tools. Editing a mesh freely and writing it back turns a SweptSolid into a Tessellation — parameters gone, file inflated, recipient unable to edit. A test enforces it.
  • The guardrail fixture is generated by tests/steel_fixture.py: 4 beams sharing one IfcRepresentationMap, 1 column with its own profile, 1 tessellated slab.

License: MIT — see LICENSE.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选