Bimwright — the predictable Revit MCP server.
Pure C#. Apache-2.0. 28 tools across Revit 2022–2027, transaction-safe and auditable. Extensible via ToolBaker when you need more.
Built for AI agents and BIM workflows that want reversible, reviewable edits — every change shows up in the undo stack.
Key traits:
- Full R22–R27 span. One codebase, six plugin shells, .NET 4.8 → .NET 10. Most peers skip at least one year.
- Pure C# + Apache-2.0. No Node.js runtime beside Revit. Enterprise-safe license + audit-ready dependency graph.
- Transaction-safe batching.
batch_executewraps a command list in one RevitTransactionGroup— one undo, atomic rollback on failure. - Progressive disclosure.
--toolsets+--read-onlygate what the model sees. Weak models stay sharp. - ToolBaker self-extension. The model writes, compiles, and registers new Revit tools at runtime (Debug).
MCP client (Claude Code, etc.) ⇄ stdio ⇄ Bimwright.Rvt.Server (.NET 8) ⇄ TCP/Pipe ⇄ Bimwright.Rvt.Plugin.R<nn> (inside Revit.exe) ⇄ Revit API
Two processes. The server is a .NET global tool; the plugin is a per-Revit-year add-in DLL. See ARCHITECTURE.md for the full picture.
dotnet tool install -g Bimwright.Rvt.Server
bimwright-rvt --helpRequires .NET 8 SDK on the machine that runs the MCP client.
Download the latest release from GitHub Releases. Extract it and run:
pwsh install.ps1 # detects every installed Revit year
pwsh install.ps1 -WhatIf # preview without changes
pwsh install.ps1 -Uninstall # clean removalThe script detects installed Revit versions via HKLM:\SOFTWARE\Autodesk\Revit\ and copies the matching plugin into %APPDATA%\Autodesk\Revit\Addins\<year>\Bimwright\.
Add one entry per Revit year to your client's MCP config (e.g. .mcp.json):
{
"mcpServers": {
"bimwright-rvt-r23": {
"command": "bimwright-rvt",
"args": ["--target", "R23"]
}
}
}Drop the --target flag and Bimwright auto-detects the running Revit instance via discovery files in %LOCALAPPDATA%\Bimwright\.
| Client | Status | Notes |
|---|---|---|
| Claude Code CLI | ✅ verified | primary test target |
| Claude Desktop | ✅ verified | .mcp.json entry |
| Cursor | ⏳ pending verification | stdio; expected to work |
| Cline (VS Code) | ⏳ pending verification | stdio; expected to work |
| Other MCP clients | ⏳ pending | open an issue if you try one |
Broader client-compat matrix is on the v0.2 roadmap.
dotnet tool install -g Bimwright.Rvt.Server+pwsh install.ps1.- Open Revit, click the Bimwright → Start MCP ribbon button.
- In your MCP client, run
tools/list— you should see the default toolsets (query,create,view,meta). - Call
get_current_view_info— you'll get back a DTO like:{ "viewName": "Level 1", "viewType": "FloorPlan", "levelName": "Level 1", "scale": 100 } - Try something real:
One undo step, both ops committed atomically.
batch_execute({ "commands": "[ {\"command\":\"create_grid\",\"params\":{\"name\":\"A\",\"start\":[0,0],\"end\":[20000,0]}}, {\"command\":\"create_level\",\"params\":{\"name\":\"L2\",\"elevation\":3000}} ]" })
28 tools across 10 groups. Four groups are on by default (query, create, view, meta); the rest opt in via --toolsets or config.
| Toolset | Tools | Default |
|---|---|---|
query |
get current view, selected elements, available family types, material quantities, model stats, AI element filter | on |
create |
grid, level, room, line-based, point-based, surface-based element | on |
view |
create view, get current view info, place view on sheet | on |
meta |
show_message, batch_execute |
on |
modify |
operate_element, color_elements |
off |
delete |
delete_element |
off |
annotation |
tag_all_rooms, tag_all_walls |
off |
export |
export_room_data |
off |
mep |
detect_system_elements |
off |
toolbaker |
bake_tool, list_baked_tools, run_baked_tool, send_code_to_revit (Debug only) |
off |
Enable with --toolsets query,create,modify,meta or --toolsets all. Add --read-only to strip create/modify/delete regardless of what you requested.
| Revit | Target Framework | Transport | Notes |
|---|---|---|---|
| 2022 | .NET 4.8 | TCP | |
| 2023 | .NET 4.8 | TCP | |
| 2024 | .NET 4.8 | TCP | |
| 2025 | .NET 8 (net8.0-windows7.0) |
Named Pipe | First .NET 8 shell |
| 2026 | .NET 8 (net8.0-windows7.0) |
Named Pipe | ElementId.IntegerValue removed — uses RevitCompat.GetId() |
| 2027 | .NET 10 (net10.0-windows7.0) |
Named Pipe | Experimental — .NET 10 still preview |
Compile gate is 6/6; runtime verified 4/4 on R23–R26 (see A1 in the commit history). R22 and R27 ship on compile-evidence because the stack is identical to R23 and R26 respectively.
- Default loopback bind. TCP transport listens on
127.0.0.1only. Opt in to0.0.0.0withBIMWRIGHT_ALLOW_LAN_BIND=1. - Token-gated handshake. Every connection must present a per-session token written only to
%LOCALAPPDATA%\Bimwright\portR<nn>.txt. - Strict schema validation. Malformed tool calls are rejected with an error-as-teacher envelope (
error,suggestion,hint) before any handler runs. - Path-leak mask. Handler exceptions are sanitized before they reach the MCP response or logs — no absolute paths, UNC shares, or user-home dirs leak out.
See the security appendix for the full threat model.
Three layers, later wins: JSON file → env vars → CLI args.
| Setting | CLI | Env | JSON key |
|---|---|---|---|
| Target Revit year | --target R23 |
BIMWRIGHT_TARGET |
target |
| Toolsets | --toolsets query,create |
BIMWRIGHT_TOOLSETS |
toolsets |
| Read-only | --read-only |
BIMWRIGHT_READ_ONLY=1 |
readOnly |
| Allow LAN bind | — | BIMWRIGHT_ALLOW_LAN_BIND=1 |
allowLanBind |
| Enable ToolBaker | --enable-toolbaker / --disable-toolbaker |
BIMWRIGHT_ENABLE_TOOLBAKER |
enableToolbaker |
JSON file path: %LOCALAPPDATA%\Bimwright\bimwright.config.json.
Generic MCP tools force one-size-fits-all workflows. Real BIM tasks aren't — when the model stitches 10+ primitive tools together to do your actual job, you pay in time and tokens every single session. That was the itch. ToolBaker is the scratch.
You describe the workflow once. The model writes C# against the Revit API, bake_tool compiles it through Roslyn into an isolated AssemblyLoadContext, and registers it as a first-class MCP tool. Next session, your workflow is a single call — no re-planning, no re-invented glue code, no token burn.
How it works:
- Describe your real dataflow in plain language (e.g. "schedule every door by fire rating, tag failures, export to CSV").
- The model generates a handler matching the
IRevitCommandcontract. bake_toolcompiles via Roslyn, links against the live Revit API, loads into a sandboxed assembly context.- SQLite persists the bake. Auto-registered on every future Bimwright session.
- Call it like any built-in — same schema validation, same transaction safety.
Gated behind --enable-toolbaker (off by default). send_code_to_revit — the unsandboxed escape hatch — is Debug-build only.
- ARCHITECTURE.md — process model, transport, multi-version strategy, ToolBaker pipeline.
- CONTRIBUTING.md — dev setup, build matrix, coding style.
- docs/roadmap.md — v0.2 (MCP Resources, ToolBaker hardening), v0.3 (async job polling, aggregator listings), v1.0 (governance).
Apache-2.0. See LICENSE.
