Cursor + Revit

Cursor + Revit - AVRO

Cursor не открывает .rvt как текст. Он подключается к уже запущенному Revit и работает с живой моделью: читает коллекторы, меняет параметры, переименовывает виды, применяет шаблоны. Ниже — рабочая схема, собранная на Revit 2022 и проверенная на шаблоне выпуска (штампы, листы, спецификации, диспетчер). Это не обзор «всех MCP для Revit», а точная инструкция: какие пакеты, какие файлы, какие формулировки задач дают результат, а какие упираются в API.

Зачем отдельный коннектор

Типичная ошибка: установить коммерческий A.I. Connector, увидеть список инструментов в Cursor и начать править модель. У бесплатной редакции запись часто отключена: чтение есть, set_* нет. Тогда Cursor честно отвечает «я вижу штриховки, но переименовать не могу» — и предлагает Dynamo.

Рабочий бесплатный путь с чтением и записью:

СлойРоль
Autodesk RevitМодель, API
pyRevitРасширение внутри процесса Revit, Routes API
mcp-server-for-revit-pythonMCP-сервер: Cursor говорит с ним, он ходит в Routes
CursorАгент, правила, чат

Ключевой инструмент не «кнопка переименовать лист», а execute_revit_code: произвольный IronPython 2.7 в контексте открытого документа. Готовые get_* / list_* удобны для разведки; любая нестандартная правка — код.

Архитектура: два сервера, не один

Cursor (Agent)
    │  MCP stdio
    ▼
main.py  —  FastMCP «Revit MCP Server»
    │  HTTP  http://127.0.0.1:48884/revit_mcp/...
    ▼
pyRevit Routes  (живёт внутри Revit)
    │  Revit API / IronPython
    ▼
Открытый .rvt

Они не конкурируют за один порт.

  • MCP-сервер слушает Cursor по stdio (так прописано в mcp.json).
  • pyRevit Routes слушает 127.0.0.1:48884.
  • Исключение: launch_revit и list_revit_installations работают на стороне MCP (реестр Windows + subprocess), затем опрашивают /status/, пока мост не ответит.

Проверка, что Revit-сторона жива — в браузере:

http://127.0.0.1:48884/revit_mcp/status/

Ожидаемый ответ:

{
  "status": "active",
  "health": "healthy",
  "revit_available": true,
  "document_title": "имя_открытого_файла",
  "api_name": "revit_mcp"
}

Если страница не открывается — Cursor бесполезен, какой бы mcp.json ни был. Сначала Revit + pyRevit + открытая модель.

Состав стека: точные имена

Приложения

ЧтоВерсия / пакетЗачем
Autodesk Revit2022 (в этой связке)Хост модели
pyRevit6.5.5 (6.5.5.26237+2044)Routes + IronPython 2.7 внутри Revit
Cursorтекущий desktopАгент + MCP-клиент
uvuv.exe (у Cursor часто лежит в Hermes)Запуск MCP-сервера

Репозиторий коннектора:

https://github.com/mcp-servers-for-revit/mcp-server-for-revit-python

Имена внутри:

  • MCP-сервер: main.py, пакет mcp[cli] (FastMCP)
  • pyRevit-расширение: revit-mcp-python (extension.json → "name": "revit-mcp-python")
  • Routes API name: revit_mcp
  • В Cursor сервер называется Revit (в логах инструментов — namespace user-Revit)

Python-пакеты MCP-сервера

Файл requirements.txt коннектора (ориентир; uv run --with mcp[cli] может подтянуть mcp отдельно на лету):

annotated-types==0.7.0
anyio==4.9.0
certifi==2025.4.26
click==8.1.8
colorama==0.4.6
h11==0.16.0
httpcore==1.0.9
httpx==0.28.1
httpx-sse==0.4.0
idna==3.15
markdown-it-py==3.0.0
mcp==1.28.1
mdurl==0.1.2
pydantic==2.11.4
pydantic-core==2.33.2
pydantic-settings==2.9.1
pygments==2.19.1
python-dotenv==1.2.2
python-multipart==0.0.31
rich==14.0.0
shellingham==1.5.4
sniffio==1.3.1
sse-starlette==2.3.5
starlette==1.3.1
typer==0.15.4
typing-extensions==4.13.2
typing-inspection==0.4.0
uvicorn==0.34.2

На стороне Revit отдельный venv не нужен: код маршрутов исполняет IronPython 2.7 движка pyRevit (IPY2712PR). Это не CPython 3.

uv на Windows

Официально:

powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

В рабочей конфигурации Cursor запускает не «системный» uv из PATH, а:

C:\Users\<user>\AppData\Local\hermes\bin\uv.exe

Если uv в терминале «не находится», в mcp.json лучше указать полный путь к этому uv.exe.

Установка по шагам

1. pyRevit

  1. Поставить pyRevit (тот же major, что в таблице выше).
  2. Привязать к нужной версии Revit (здесь — 2022).
  3. Открыть Revit → вкладка pyRevit должна появиться на ленте.

Конфиг pyRevit: %APPDATA%\pyRevit\pyRevit_config.ini

Рабочий фрагмент:

[environment]
clones = {"master":"C:\\Users\\<user>\\AppData\\Roaming\\pyRevit-Master"}

[core]
userextensions = ["C:\\Users\\<user>\\AppData\\Roaming\\pyRevit\\Extensions"]

[routes]
enabled = true
host = "127.0.0.1"
port = 48884

[revit-mcp-python.extension]
disabled = false

В UI то же самое:

  1. pyRevit → Settings → Routes — включить Routes Server.
  2. Host 127.0.0.1, port 48884.

2. Расширение MCP внутри Revit

Клонировать репозиторий, например:

C:\Users\<user>\Documents\__projects\non\mcp-server-for-revit-python

В pyRevit расширение должно лежать как папка с суффиксом .extension. На практике это копия:

%APPDATA%\pyRevit\Extensions\revit-mcp-python.extension\

Внутри обязательны startup.py, extension.json, каталог revit_mcp\.

Два способа установки из README проекта:

  • pyRevit → Extensions → MCP Server for Revit Python → Install (путь по умолчанию как раз %APPDATA%\pyRevit\Extensions).
  • Вручную: клон → имя папки с .extension → Settings → Custom Extensions → путь → Save → Reload pyRevit (иногда полный рестарт Revit).

После загрузки startup.py регистрирует маршруты: status, model_info, views, placement, colors, code_execution, document.

Две копии — ловушка. Cursor гоняет main.py из папки проекта. Revit грузит маршруты из %APPDATA%\pyRevit\Extensions\.... Правка revit_mcp\code_execution.py только в проекте не попадёт в Revit, пока не синхронизируете extension и не перезагрузите pyRevit.

3. Cursor MCP

Файл: %USERPROFILE%\.cursor\mcp.json

Рабочая конфигурация:

{
  "mcpServers": {
    "Revit": {
      "command": "C:\\Users\\<user>\\AppData\\Local\\hermes\\bin\\uv.exe",
      "args": [
        "run",
        "--directory",
        "C:\\Users\\<user>\\Documents\\__projects\\non\\mcp-server-for-revit-python",
        "--with",
        "mcp[cli]",
        "mcp",
        "run",
        "main.py"
      ],
      "timeout": 60000
    }
  }
}

Что важно:

  • --directory — корень клона, чтобы main.py и пакет tools находились.
  • --with mcp[cli] — uv подтягивает MCP SDK, даже если локальный venv неполный.
  • timeout: 60000 — 60 секунд на вызов. Совпадает с таймаутом execute_revit_code на HTTP (timeout=60.0). Массовые коллекторы по большому шаблону иногда упираются сюда: дробите задачу или поднимайте оба таймаута согласованно.
  • После правки mcp.json полностью перезапустите Cursor, не только окно чата.

В Cursor: Settings → MCP — сервер Revit должен быть зелёным, когда Revit открыт и /status/ отвечает.

4. Правило агента (обязательно)

Готовые MCP-кнопки не покрывают BIM-шаблон. Без правила агент будет звать несуществующие set_* или Nonica. Файл проекта:

.cursor/rules/revit-mcp.mdc

---
description: Use pyRevit MCP Python as the primary Revit connection
alwaysApply: true
---

Revit is connected through **pyRevit MCP Python**, not NonicaTab write tools.

- Prefer `execute_revit_code` for any model change (rename fill patterns, set parameters, collectors).
- Ready-made tools (`get_revit_model_info`, `get_current_view_elements`, `list_levels`, …) are fine for reads.
- Code is IronPython 2.7: no f-strings, no type hints, wrap edits in a Transaction (the tool may already wrap one — do not double-start if it errors).
- Do not call Nonica `set_*` tools. Nonica Free cannot write.
- Before destructive edits, ask the user to save a copy of the `.rvt`.
- Routes API: `http://127.0.0.1:48884/revit_mcp/` — Revit must be open with pyRevit loaded.

alwaysApply: true — правило висит на каждом чате в этом workspace.

5. Порядок запуска в рабочий день

  1. Открыть Revit 2022.
  2. Открыть модель или шаблон (не пустой splash без документа).
  3. Убедиться, что на ленте есть pyRevit.
  4. Проверить http://127.0.0.1:48884/revit_mcp/status/.
  5. Открыть Cursor в папке проекта (там же правило и клон MCP).
  6. В чате: «проверь доступ к Revit» — агент должен вызвать get_revit_status и увидеть имя файла.

Workshared-файл: агент ходит в локальную копию, которая сейчас открыта. sync_with_central есть, но это уже осознанный шаг, не фон.

Каталог инструментов

Готовые инструменты (то, что Cursor реально видит у сервера Revit):

Статус и модель

ИнструментНазначение
get_revit_statusЖив ли Routes, имя документа
get_revit_model_infoСводка по открытой модели
list_levelsУровни и отметки

Виды и картинка

ИнструментНазначение
list_revit_viewsЭкспортируемые виды по типам
get_revit_viewPNG вида по имени (агент видит чертёж)
get_current_view_infoАктивный вид: масштаб, шаблон, дисциплина
get_current_view_elementsЭлементы текущего вида (limit по умолчанию 5000)

get_revit_view — недооценённый инструмент: можно попросить «открой лист 01.0.1 и покажи, что на штампе», не гадая по именам параметров.

Семейства

ИнструментНазначение
list_family_categoriesКатегории семейств
list_familiesТипы, фильтр contains, limit (по умолчанию 50)
place_familyПостановка экземпляра в точку

Для аудита штампов list_families с contains: "sx__Лист" быстрее, чем писать коллектор. Для «какие типы реально вставлены на листы» — всё равно execute_revit_code: готовый список типов не говорит, где instance.

Цвет

ИнструментНазначение
color_splashРаскрасить категорию по параметру
clear_colorsСнять override
list_category_parametersКакие параметры есть у категории

Удобно для проверки: «покажи стены по sx__Марка». Это визуальный QA, не замена фильтров вида.

Документ

ИнструментНазначение
list_revit_installationsГод и путь установки
launch_revitСтарт Revit, опционально файл, язык (ENU, …), timeout 120 с
open_documentОткрыть .rvt / .rfa / .rte; detach, audit
close_documentЗакрыть; save по умолчанию false
save_documentSave / Save As
sync_with_centralСинхронизация workshared; comment, compact, relinquish_all

open_document с detach: true — правильный способ «посмотреть центральную, не привязываясь». Не просите агента Save As поверх центральной без явной команды.

Главный инструмент

execute_revit_code(code, description)

В коде уже есть:

  • doc — активный документ
  • uidoc — UI-документ
  • DB — Autodesk.Revit.DB
  • revit — модуль pyRevit
  • print — уходит в ответ инструмента

Транзакция не открывается сама. Для записи:

t = DB.Transaction(doc, "Rename sheets")
t.Start()
# ...
t.Commit()

Смена активного вида — вне транзакции:

uidoc.ActiveView = target_view

HTTP-таймаут вызова — 60 секунд. Тяжёлые проходы (все спецификации шаблона, все семейства штампов) дробите: сначала dump в JSON через print, потом правка пачками.

Как формулировать задачи, чтобы агент не «плыл»

Связка сильна на массовых, однозначных, проверяемых операциях. Слаба на том, чего нет в API, и на размытом «наведи красоту».

Шаблон хорошего запроса

  1. Где — файл уже открыт / имя документа / папка диспетчера.
  2. Что — конкретный параметр, категория, префикс.
  3. Критерий — «все спецификации с sx__Группа вида1 = 02_РД».
  4. Исключения — «лист 1 Условные не трогать».
  5. Проверка — «выведи счётчик до/после».

Плохо: «почисти штампы».
Хорошо: «собери все Title Blocks: семейство, типы, на скольких листах instance, только витрина или рабочие альбомы. Потом предложи, что удалить».

Плохо: «переименуй листы как надо».
Хорошо: «у листов с sx__Группа вида1 = 01_ЭП системный номер 10.x → 01.x. Печатный sx__НомерЛиста не менять».

Скриншоты

Агент видит картинку диалога. Это отлично для спецификации желаемого (таблица Model Line Weights, переименованный фильтр стадий). Это не гарантия, что API позволит то же самое записать. Если после разведки агент говорит «в API этого нет» — не давите на UI-кликер: модальные окна Revit почти не автоматизируются из IronPython.

Сначала разведка, потом запись

Рабочий ритм из реальных сессий:

  1. get_revit_status — тот ли файл.
  2. Коллектор / list_* — сколько объектов, какие имена.
  3. Короткий план в чат (группы, исключения).
  4. Транзакция.
  5. Повторный коллектор — сверка счётчиков.

Не просите «сразу удаляй» на первом сообщении, если сами не видели инвентаризацию. И наоборот: после явного «удаляй лишние» агент должен удалять, а не согласовывать третий круг.

Примеры, которые хорошо ложатся на эту связку

Ниже — типы задач, которые на шаблоне выпуска отрабатываются часами вручную и минутами из Cursor. Формулировки можно копировать.

1. Инвентаризация семейств штампа

Запрос: «Посмотри семейства штампа. Я вижу sx__Лист_….rfa. Что ещё загружено, что стоит на листах, что только в проекте.»

Как делать: FilteredElementCollector по Family / FamilySymbol категории Title Blocks + collector экземпляров на ViewSheet. Свести таблицу: семейство, типы, «на листах / только витрина / нигде».

Почему MCP: руками это клик по каждому листу. Код за один проход отличает «лежит в проекте» от «вставлено».

2. Массовая нумерация листов

Запрос: «Все листы в 01_ЭП — номер с 10. на 01.. Печатный номер не трогать.»

Как делать: параметр sx__Группа вида1 на ViewSheet + Sheet Number (SHEET_NUMBER). Не путать с sx__НомерЛиста.

Типичная ловушка: после 10. → 1. понадобится второй проход 1. → 01., иначе сортировка диспетчера поедет. Просите сразу целевой формат: 01.x.

3. Шаблоны видов на все спецификации стадии

Запрос: «Для всех спецификаций 01_ЭП шаблон Спец_Manrope, для 02_РД — Спец_Arial.»

Как делать: сначала спросить агента, что включает шаблон (у этих двух в шаблоне было включено только Appearance — шрифт сетки, не поля/фильтры). Потом View.ViewTemplateId.

Зачем спрашивать состав шаблона: если в шаблоне включены Fields, вы затрёте структуру спецификации. Разведка через API дешевле, чем откат 140 спек.

4. Тематические папки диспетчера

Запрос: «Спецификации 01_ЭП и 02_РД: разобрать sx__Группа вида2 по темам 00_Название (полы, потолки, мебель…). Сводные со словом СВОДНАЯ — в отдельную группу.»

Как делать: dump имён → классификатор по подстрокам (Двери_, Потолок, СВОДНАЯ) → запись параметра. Префикс в имени сильнее случайного слова: Двери_плинтус всё равно проёмы, не полы.

Это лучший класс задач для агента: много однотипных элементов, правило можно сформулировать, результат проверяется списком.

5. Переименование по всему проекту

Запрос: «Везде ДП → РД: виды, шаблоны видов, легенды, листы, семейство штампа, сокращение стадии. ДП-РД и ДП/РД сначала в РД, потом голый ДП. Полное “ДИЗАЙН-ПРОЕКТ” не трогать.»

Как делать: явный порядок замен (иначе ДП-РД станет РД-РД). Отдельные сущности: View.Name, ViewFamilyType, project parameter sx__СтадияПроектаСокращенно, Family.Name. После прохода — поиск остатков ДП и отчёт «0 leftover».

6. Параметры: где Марка и куда назначить

Запрос: «Найди спецификации, где поле Марка. Список категорий. Добавь эти категории в параметр sx__Марка.»

Связка «спека использует поле → категория должна иметь параметр» — ручная дыра в шаблонах. Коллектор спецификаций + GetSchedulableFields / поля + CategorySet у параметра.

7. Документация шаблона

Запрос: «Глубоко разбери открытый шаблон и напиши инструкцию в .md в том же стиле, что существующий регламент по листам.»

Агент здесь — исследователь: Project Information, параметры шаблона, организация браузера, альбомы. Пишет не код в модель, а регламент для людей. Имеет смысл держать такие файлы в том же workspace, чтобы следующие чаты опирались на них, а не заново инвентаризировали 200 спецификаций.

8. Визуальная сверка

Запрос: «Переименуй фильтр стадий Show All → Показать все» + скриншот.

Имя фильтра — API. Скриншот нужен, чтобы агент не перепутал Phase Filter с Phase и с Phase Filter на виде.

IronPython 2.7: что ломает правки

Код в execute_revit_code — не тот Python, на котором вы пишете скрипты в Cursor.

НельзяВместо этого
f-строки"%s" % x или "{}".format(x)
type hints в исполняемом фрагментебез аннотаций
print(f"{name}")print(name)
Кириллица в литерале исходника MCP\u0414\u041f или сравнение со строкой, уже прочитанной из Revit
next(x for x in xs if …) иногда капризничаетобычный for
Двойной t.Start(), если снаружи уже транзакцияпо ошибке отката — убрать свою обёртку

Кириллица — главная боль русскоязычного шаблона. Литерал "02_ДП" в коде, который едет JSON-ом через HTTP, часто не совпадает с именем параметра в документе. Надёжный приём:

  1. Прочитать значения из Revit (p.AsString()).
  2. Сравнивать с ними.
  3. Для новых имён собирать строку через unichr / \uXXXX.

Имя элемента:

name = getattr(el, "Name", None)
if not name:
    p = el.get_Parameter(DB.BuiltInParameter.VIEW_NAME)
    name = p.AsString() if p else "?"

Проверка перед записью:

if element:
    # ...

Чего ждать не стоит

Revit API — не полный UI. Если агент упёрся, это часто не «плохой промпт».

Нет публичного API на таблицу Model Line Weights (мм пера по масштабам). Category.SetLineWeight ставит номер пера 1–16, не толщину в мм. Внутренние PenWidthTable / PenInfoForScale — пустые managed-обёртки. Перенос — Transfer Project Standards вручную, с Overwrite, не New Only. Клики по сетке GXWND из скрипта ненадёжны.

PostCommand (открыть диалог Line Weights, Transfer…) ставится в очередь и плохо стыкуется с MCP: модальное окно блокирует Revit, UIA Revit-кнопок без InvokePattern, кастомный грид не отдаёт ячейки.

Не всё «переименовать уровень при копировании» чинится: внутренний seed имени уровня API не сбрасывает. Можно переименовать уже созданный уровень, нельзя заставить следующий Copy называться 2 этаж.

UI-only настройки (некоторые Extra Settings, часть Transfer Project Standards) остаются ручными. Честный ответ агента здесь ценнее, чем час SendInput.

Безопасность и worksharing

  • Перед удалением семейств, purge, массовой заменой имён — Save As / локальная копия. Правило агента должно это спрашивать; человек подтверждает.
  • Workshared: правки идут в открытую локальную. sync_with_central — отдельная команда (comment, relinquish_all).
  • execute_revit_code — полный доступ к API. Опечатка в фильтре коллектора может переименовать не те виды. Просите счётчики и список имён до Commit, если объём большой.
  • Routes без авторизации, только localhost. Для продакшена на общей машине это осознанный риск README проекта.
  • Не путать активный документ: если открыты шаблон и чужой .rte, коллекторы идут в active. Имеет смысл начинать с print(doc.Title) / get_revit_status.

Мини-шпаргалка промптов

Проверка моста:

Проверь get_revit_status: какой файл открыт, Routes healthy?

Разведка без записи:

Выведи все Title Block: семейство, типы, число экземпляров на листах. Ничего не удаляй.

Массовая запись с границей:

У видов и спецификаций с sx__Группа вида1 = 02_ДП замени группу на 02_РД. Остальные группы не трогай. В конце — сколько изменено.

Шаблон вида:

Сначала покажи, какие вкладки включены у шаблонов Спец_Arial и Спец_Manrope. Если только Appearance — примени Manrope ко всем спекам 01_ЭП, Arial — ко всем 02_РД.

Документ для команды:

По открытому шаблону напиши инструкцию: сведения о проекте, диспетчер, альбомы. В том же стиле, что уже принятый регламент по листам.

Чеклист, если «Cursor не видит Revit»

  1. Revit запущен, документ открыт, не только стартовый экран без файла.
  2. Вкладка pyRevit на ленте.
  3. pyRevit_config.ini: [routes] enabled = true, порт 48884.
  4. Браузер: http://127.0.0.1:48884/revit_mcp/status/.
  5. Extension revit-mcp-python не disabled.
  6. Cursor перезапущен после правки mcp.json.
  7. В MCP Settings сервер Revit не красный.
  8. --directory указывает на папку с main.py.
  9. uv.exe по пути из command существует.
  10. Нет второго коннектора (старый Nonica в mcp.json), который перехватывает имя Revit.

Коротко: как работать эффективно

Держите в одном workspace клон MCP, правило .mdc, регламенты шаблона. Агент тогда не заново открывает Америку каждый чат.

Используйте готовые MCP-методы для «что открыто / какие уровни / покажи вид». Всё остальное — execute_revit_code с транзакцией, без f-строк, с \uXXXX для кириллицы.

Просите задачи, которые считаются: N листов, M спецификаций, 0 leftover ДП. Не просите закрыть дыры API кликами по диалогам.

Сначала инвентаризация и правило замены, потом Commit. На workshared-шаблоне это разница между «полезный проход по диспетчеру» и «сюрприз на синхронизации».