pyrevit-mcp
# pyrevit-mcp
An MCP server that exposes an open Autodesk Revit model to any MCP client, so the model can
be inspected and edited in plain language instead of through the Revit UI.
Ask *"find all doors narrower than 1.2m and highlight them in red"*, *"how many square metres
of wall are in this building"* or *"place a container next to the site entrance"*, and the
server translates that into Revit API calls through pyRevit Routes.
A small web chat UI is included for demos: split-screen with Revit, CSV import and export,
undo, and screenshots of the model right in the chat.
Built for live demos, prototyping and everyday experimenting.
> **This is not an official Autodesk product and comes with no support commitment.**
> I work at Autodesk as a Technical Specialist for Emerging Tech in Construction, and this
> project is not part of that role. See [Disclaimer and support](#disclaimer-and-support).
## How it works
```
MCP client (Claude Code, Claude Desktop, ...)
│ stdio
▼
server.py (Python 3 / FastMCP) ──HTTP :48884──> pyRevit Routes (IronPython, inside Revit)
▲ │
│ shared revit_get/revit_post ▼
app.py (FastAPI :8100) ◄── web chat UI Revit API, Transactions
│
▼ Claude API
```
Two entry points share one bridge:
- **`server.py`** is the MCP server. Any MCP client can connect over stdio and gets 29 tools.
- **`app.py`** is a FastAPI backend with a chat UI (`web/index.html`) driven by the Claude API.
It exposes the same tools plus CSV export, and renders images, downloads, and undo in the chat.
Inside Revit, a pyRevit extension (`pyrevit-mcp.extension/`) registers REST routes. pyRevit
injects the active document into the handlers, which run in the Revit API context, one
transaction per write.
## What it covers
29 MCP tools:
| Area | Tools |
| --- | --- |
| Orientation | `get_status`, `get_model_info`, `get_levels`, `get_views`, `get_categories`, `list_parameters` |
| Query | `get_elements`, `find_elements` (level + parameter filters, returns requested parameters in one call), `get_element_properties` |
| Write | `set_parameter`, `set_parameters` (bulk, one transaction, one undo entry) |
| Visual | `override_graphics`, `isolate_elements`, `color_by_parameter` (legend included), `reset_view`, `export_image` |
| Selection | `get_selection`, `set_selection` |
| Views | `set_active_view` |
| Model health | `get_warnings` (grouped, with failing element ids) |
| Geometry | `get_element_geometry` (position, size, area, volume), `get_quantities` (take-off by category and type) |
| Families | `list_families`, `load_family`, `place_family` |
| Editing | `transform_elements` (move, copy, rotate), `delete_elements` (two-step, confirmed) |
| Creation | `create_element` (wall, floor, level, grid, including a grid derived from existing walls) |
| Persistence | `save_document` (save or synchronize with central) |
Parameter access covers instance **and** type parameters: reads fall back to the element type
automatically, and a type write reports how many instances it affects before you trust it.
Values are returned as display values in project units. Doors report their room assignment
(FromRoom/ToRoom).
Anything geometric works in **metres** and takes **anchors** rather than coordinates. An
anchor is `{"room": "Lager"}`, `{"element_id": 123456}`, `{"grid": "B/3"}` or, as a last
resort, `{"point_m": {...}}`, and it can carry a `level` and an `offset_m`. This is not
decoration: a language model asked for absolute coordinates will produce plausible numbers
that put the wall outside the building, whereas an anchor is resolved against the model.
Deleting is deliberately two-step. The first call changes nothing and returns a preview plus
a token derived from the affected ids; only a second call carrying that token deletes. The
token cannot be replayed against a different set of elements.
## Documentation
The full guide with a validated per-tool reference is hosted at
[mk92at.github.io/pyrevit-mcp/pyrevit-mcp.html](https://mk92at.github.io/pyrevit-mcp/pyrevit-mcp.html).
It supports English and German (`?lang=en|de`), light and dark themes, and per-tool anchors
(`#find_elements`). The web chat UI links into it from the tool reference sidebar.
## Requirements
- Autodesk Revit 2024 or newer (developed against Revit 2027) with [pyRevit](https://pyrevitlabs.io/) installed
- Python 3.11 or newer and [uv](https://docs.astral.sh/uv/)
- For the web chat UI: an Anthropic API key
## Setup
**1. Install the Revit extension.** Copy or clone this repository, then add
`pyrevit-mcp.extension` to pyRevit's extension search paths (pyRevit Settings → Custom
Extension Directories, pointing at this repository's root). Enable the Routes server in
pyRevit's settings. Restart Revit.
**2. Verify the bridge.** With a model open:
```bash
curl http://localhost:48884/pyrevit_mcp/status/
```
The trailing slash is mandatory on every route.
**3. Install the Python side:**
```bash
uv sync
```
**4a. Register with an MCP client**, e.g. Claude Code:
```bash
claude mcp add revit -s user -- uv --directory "<path-to>/pyrevit-mcp" run python server.py
```
**4b. Or run the web chat UI.** Create a `.env` with your `ANTHROPIC_API_KEY` (see
`.env.example`), then:
```bash
uv run uvicorn app:app --port 8100
```
Open `http://localhost:8100`. The sidebar has a tool reference generated from the server at
runtime, with a clickable example per tool.
**After any change to the extension code, restart Revit cold.** The Routes server (Beta)
crashes Revit on a pyRevit reload. `scripts/restart_revit.ps1` automates the cold restart and
`test_routes.py` smoke-tests every route afterwards.
## Layout
```
server.py MCP server, 29 tools, shared HTTP bridge
app.py FastAPI chat backend (CSV, undo, images, downloads)
web/index.html chat UI, single file
test_routes.py end-to-end smoke test for every route
test_mcp.py smoke test for the MCP stdio transport itself
explore_model.py quick model inventory via the running server
scripts/restart_revit.ps1 automated cold restart
pyrevit-mcp.extension/
startup.py route registration
lib/pyrevit_mcp/
status.py, elements.py, parameters.py, views.py, selection.py, model.py
geometry.py measurements, quantities, anchor resolution
editing.py families, transforms, confirmed deletion
creation.py walls, floors, levels, grids
utils.py ElementId helpers, safe JSON encoding, parameter access
```
## Known limits
- No clash detection. Revit and ACC Model Coordination already do interference checking
properly, across linked models and with a result workflow attached. This does not try to
replace them.
- Geometry creation covers walls, floors, levels and grids. Not roofs, stairs, curtain
systems, MEP runs, or anything that needs a sketch more complex than a closed outline.
- The derived grid is a heuristic read off wall positions. It recovers the orthogonal order
of a building, not a designer's grid, and it wants a human to check it.
- No editing of geometry after creation beyond move, copy, rotate and delete. Walls cannot
be re-hosted, joined, or trimmed through this server.
- Type parameters are written with a warning, but there is no dry-run mode.
- Rooms queries slow down on very large models.
- The Routes server is a pyRevit beta feature; treat the whole bridge as a prototype.
## Disclaimer and support
I work at Autodesk as a Technical Specialist for Emerging Tech in Construction. This project
grew out of my own exploration of MCP and the Revit API and runs alongside that work, not as
part of it. It is not an official Autodesk product or project. Nothing here is built,
reviewed, endorsed or maintained by Autodesk, and nothing in this repository is a statement
on behalf of Autodesk. Reaching me through my job is not a way to get help with it.
On support I want to be straight with you, because the honest answer has two halves.
I would like to offer as much help as I can, and I am genuinely interested in developing this
further together with anyone who finds it useful. Questions and ideas are best raised in
[Discussions](https://github.com/mk92at/pyrevit-mcp/discussions); bugs go to Issues, and pull
requests are welcome. I will read all of it. Tell me what you built with it — Show and tell
exists for exactly that.
What I cannot do is promise any of that. There is no guaranteed response, no timeline, no fix
for your blocker, and no commitment that this keeps working against future Revit or pyRevit
changes. If you are building something that has to work, fork it and own your copy.
This project stands on [pyRevit](https://github.com/pyrevitlabs/pyRevit) by Ehsan
Iran-Nejad and the pyRevit Labs community, licensed GPL-3.0. pyRevit is a prerequisite
you install yourself, not something this repository ships: its Routes module is the
bridge that makes any of this possible, and no pyRevit code is included here.
The ElementId helpers in the extension were adapted from
[revit-mcp-server](https://github.com/Demolinator/revit-mcp-server), licensed MIT,
Copyright (c) 2025 Juan Rodriguez, whose handling of the Revit 2024+ ElementId change and of
Revit's modal failure dialogs during headless transactions I reused. Everything else was
written for this project and is licensed MIT as well, see `LICENSE`.
TDQS
Scored across 21 tools
Most tools have clearly distinct purposes (selection, views, levels, parameters, graphics), but get_elements and find_elements overlap since both retrieve elements by category; find_elements adds filtering but the simpler get_elements could be confusingly similar. override_graphics and color_by_parameter both apply colors, though one is manual and the other parameter-driven.
The naming convention is mixed: many query tools use get_ (get_elements, get_views, get_model_info), setters use set_ (set_selection, set_parameter), but there are also list_parameters, find_elements, override_graphics, isolate_elements, reset_view, and export_image which deviate from a strict verb_object pattern. It's readable but not fully consistent.
With 21 tools, the server is slightly above the typically ideal 3-15 range, but the breadth is justified by Revit's complexity, covering model info, element queries, parameter editing, view management, graphics overrides, and save/export. No tool feels redundant enough to be cut.
The tool surface covers a wide range of operations (query, selection, view control, parameter editing, graphics, warnings, save), but it notably lacks element creation or deletion, which are core lifecycle operations in Revit. Some gaps like geometry access are absent, but agents can work around them using the existing parameters and element queries.