fusion360
by GeBondar
README.md
<div align="center">
# Fusion 360 MCP Agent Kit
**Подключение AI-агентов к Autodesk Fusion 360 — с последовательной отправкой команд и адресной работой с открытыми документами.**
[](LICENSE)



[Быстрый старт](#quick-start) · [Подключение агента](#connect) · [Неактивные документы](#inactive) · [Инструкция агенту](AGENTS.md) · [Устранение проблем](#troubleshooting)
</div>
> **English:** A Windows integration kit for any local MCP-capable agent: serialized Fusion commands, a 2.1-second spacing policy, no automatic command replay, and explicit targeting of open inactive documents. Built on the MIT-licensed [Fusion360 MCP Server by Faust Machines](https://github.com/faust-machines/fusion360-mcp-server). The detailed guide below is in Russian; the [agent contract](AGENTS.md) is in English.
## Что здесь есть
Это готовая обвязка и практическая документация для подключения к upstream MCP-серверу. Python-сервер и add-in устанавливаются из зафиксированной версии исходного проекта.
| Возможность | Как реализована |
|---|---|
| Любой локальный агент | Стандартный MCP через STDIO; для агента с терминалом — `run_query.py` |
| Открытые неактивные модели | Выбор через `app.documents` по `dataFile.id`, получение собственного Design-продукта |
| Операции с активным контекстом | Временная активация и возврат прежней вкладки в одном вызове |
| Несколько клиентов | Общая межпроцессная блокировка Windows по одному пути |
| Интервал команд | 1,05 с до + 1,05 с после отправки; между соседними вызовами ≥ 2,1 с |
| Защита от повторной операции | `retries=0`; неопределённый результат оставляет блокирующий маркер |
| Проверка без Fusion | Тесты блокировки, аварийного завершения, адресации и MCP в mock-режиме |
**Пределы поддержки:** готовые скрипты рассчитаны на Windows и Python 3.11+. Примеры могут работать с разными MCP-клиентами, но конкретный UI каждого клиента здесь не тестировался. Универсальное невидимое редактирование любой геометрии Fusion API не гарантирует: некоторые операции переключают вкладку. CAD-проверки на живой модели не входят в автоматические тесты этого репозитория.
## Как проходит команда
```mermaid
flowchart LR
A[Агент / MCP-клиент] -->|MCP STDIO| B[server_serialized.py]
Q[Агент с терминалом] --> R[run_query.py]
R -->|MCP STDIO| B
B --> G[Общий lock + паузы + pending marker]
G --> S[Upstream Python-сервер]
S -->|TCP 127.0.0.1:9876| F[Fusion360MCP add-in]
F -->|CustomEvent| M[Главный поток Fusion]
M --> D[Выбранный открытый документ]
```
MCP-интерфейс предоставляет upstream-сервер; gate оборачивает его TCP-отправку. `9876` — порт внутреннего протокола add-in, **не HTTP/SSE MCP URL**. Указывать `http://127.0.0.1:9876` в поле URL клиента нельзя. Один Fusion обслуживает несколько открытых документов; отдельный сервер для каждого документа не нужен.
<a id="quick-start"></a>
## 1. Быстрый старт на Windows
### Требования
- Установленный Autodesk Fusion с доступом к нужным документам.
- Python 3.11+ и Git в PATH; команды ниже используют Python Launcher `py`.
- MCP-клиент с поддержкой STDIO или агент, умеющий запускать локальный Python.
- Все команды ниже выполняются в PowerShell. В примерах используется `C:\CAD` — при другом размещении обновить пути в конфигурациях.
### 1.1. Установить комплект и зависимости
```powershell
New-Item -ItemType Directory -Path C:\CAD -Force | Out-Null
git clone https://github.com/GeBondar/fusion360-mcp-agent-kit.git C:\CAD\fusion360-mcp-agent-kit
Set-Location C:\CAD\fusion360-mcp-agent-kit
py -3.12 -m venv .venv
& .\.venv\Scripts\python.exe -m pip install -r requirements.txt
```
Если установлена другая поддерживаемая версия Python, заменить `-3.12`. Активация venv не нужна: далее используется полный путь к его Python. При ненулевом exit code остановиться и исправить ошибку установки.
Зафиксированы upstream commit `8bb5cb0400c551ac9fe74a02e6be09782064f5a8` и MCP SDK `1.26.0`. Остальные транзитивные зависимости разрешает pip; это фиксация интеграции, а не полный lockfile окружения.
### 1.2. Установить add-in той же версии
```powershell
New-Item -ItemType Directory -Path .\vendor -Force | Out-Null
git clone https://github.com/faust-machines/fusion360-mcp-server.git .\vendor\fusion360-mcp-server
git -C .\vendor\fusion360-mcp-server checkout --detach 8bb5cb0400c551ac9fe74a02e6be09782064f5a8
```
После успешного checkout выполнить блок для **новой установки**:
```powershell
$fusionAddonPath = Join-Path $env:APPDATA 'Autodesk\Autodesk Fusion 360\API\AddIns\Fusion360MCP'
if (Test-Path -LiteralPath $fusionAddonPath) {
throw 'Add-in уже существует. Проверьте версию и сохраните его копию перед обновлением.'
}
New-Item -ItemType Directory -Path $fusionAddonPath -Force | Out-Null
Copy-Item -Path '.\vendor\fusion360-mcp-server\addon\*' -Destination $fusionAddonPath -Recurse
```
В папке `Fusion360MCP` непосредственно должны находиться `Fusion360MCP.py`, `Fusion360MCP.manifest` и каталог `server`. Если add-in уже установлен, остановить его в Fusion, сравнить версию/исходники и отдельно выполнить осознанное обновление. Скрипты комплекта не перезаписывают установленную надстройку.
### 1.3. Запустить в Fusion
1. Открыть Fusion и хотя бы один документ CAD-модели.
2. Открыть **Scripts and Add-Ins** / «Скрипты и надстройки» (`Shift+S`).
3. Во вкладке Add-Ins выбрать **Fusion360MCP → Run**; при необходимости включить Run on Startup.
4. Завершить активную команду и закрыть модальные диалоги. Для первого `execute_code` оставить активным продукт **Design**.
Проверить слушающий порт без CAD-команд:
```powershell
Get-NetTCPConnection -LocalPort 9876 -State Listen -ErrorAction SilentlyContinue
Get-Content -LiteralPath (Join-Path $env:USERPROFILE 'fusion360mcp.log') -Tail 40
```
Порт может принадлежать другой программе; сопоставить PID процесса и сообщения журнала add-in. Сам по себе открытый порт не подтверждает готовность Fusion API.
<a id="connect"></a>
## 2. Подключить любого агента
### MCP-клиент с JSON-конфигурацией
Добавить запись из [configs/mcp.json](configs/mcp.json) в конфигурацию клиента, сохранив остальные серверы:
```json
{
"mcpServers": {
"fusion360": {
"command": "C:/CAD/fusion360-mcp-agent-kit/.venv/Scripts/python.exe",
"args": [
"C:/CAD/fusion360-mcp-agent-kit/server_serialized.py",
"--mode", "socket", "--host", "127.0.0.1", "--port", "9876"
],
"env": {
"PYTHONIOENCODING": "utf-8",
"FUSION_MCP_LOCK": "C:/CAD/fusion-control/fusion.lock"
}
}
}
}
```
Это шаблон для клиентов со схемой `mcpServers`. Если клиент использует UI или другую схему, перенести значения `command`, `args`, `env` в соответствующие поля. Имя и интеллект модели не меняют протокол подключения. MCP-клиент сам запускает и обслуживает процесс сервера; вручную открытый `server_serialized.py` может просто ждать входящий JSON-RPC.
### Codex
Фрагмент [configs/codex.toml](configs/codex.toml) предназначен для `~/.codex/config.toml` либо доверенной проектной `.codex/config.toml`:
```toml
[mcp_servers.fusion360]
command = "C:/CAD/fusion360-mcp-agent-kit/.venv/Scripts/python.exe"
args = ["C:/CAD/fusion360-mcp-agent-kit/server_serialized.py", "--mode", "socket", "--host", "127.0.0.1", "--port", "9876"]
startup_timeout_sec = 20
tool_timeout_sec = 60
[mcp_servers.fusion360.env]
PYTHONIOENCODING = "utf-8"
FUSION_MCP_LOCK = "C:/CAD/fusion-control/fusion.lock"
```
Сохранить остальные секции, перезапустить соединение MCP и проверить `codex mcp list`, если CLI установлен. Формат настроек: [официальная документация Codex MCP](https://developers.openai.com/codex/mcp/). Клиентский тайм-аут 60 с не увеличивает внутреннее ожидание add-in примерно в 30 с.
### Агент только с терминалом
```powershell
Set-Location C:\CAD\fusion360-mcp-agent-kit
$env:FUSION_MCP_LOCK = 'C:\CAD\fusion-control\fusion.lock'
$env:PYTHONIOENCODING = 'utf-8'
& .\.venv\Scripts\python.exe .\run_query.py .\examples\list_documents.py
```
`run_query.py` читает UTF-8 Python-файл, проверяет синтаксис, запускает сериализованный STDIO-сервер и вызывает один `execute_code`. Код исполняется внутри Fusion. В stdout возвращается MCP-результат JSON, диагностика идёт в stderr; код возврата 1 означает ошибку инструмента или локального запуска. `--output local.result.json` дополнительно сохранит ответ. Скрипт не ограничивает Python режимом чтения: передавать ему только проверенный код в согласованном объёме задачи.
**Общий lock обязателен.** Его путь в терминале должен совпасть с путём в MCP-конфигурациях. Если переменная не задана, default — `%LOCALAPPDATA%\Fusion360MCP\fusion.lock`, одинаковый для копий комплекта одного Windows-пользователя. Не смешивать этот default с явно заданным другим путём.
### Облачный или удалённый агент
Агенту нужен локальный исполнитель на компьютере Fusion либо отдельно защищённый мост. `localhost` облачного контейнера не является вашим ПК. Не публиковать порт add-in в интернет: TCP-протокол не имеет аутентификации и позволяет исполнять Python. Этот комплект документирует подключение по loopback, не развёртывает удалённый шлюз.
<a id="inactive"></a>
## 3. Работа с открытыми неактивными документами
**Да, можно выбрать открытую соседнюю модель.** Для чтения используется собственный `Design` нужного `Document`; для операции, требующей активности, — временное переключение с возвратом вкладки.
| Состояние | Порядок работы |
|---|---|
| Активный документ | Всё равно проверить его ID и версию перед изменением |
| Открытый, неактивный | Найти через `app.documents`, получить `doc.products` |
| Операция требует активной вкладки | Выбрать → activate → операция → finally вернуть вкладку в одном вызове |
| Файл ещё не открыт | Найти DataFile, проверить отсутствие уже открытой копии, открыть отдельно |
| Внешний компонент сборки | Определить исходный документ; не считать его автоматически открытой редактируемой моделью |
Начать с [examples/list_documents.py](examples/list_documents.py), скопировать нужный `id` из результата и вызвать:
```powershell
& .\.venv\Scripts\python.exe .\run_query.py .\examples\inspect_inactive.py --document-id 'ID_ИЗ_СПИСКА'
```
Ключевая часть [примера](examples/inspect_inactive.py):
```python
target_id = "__TARGET_DOCUMENT_ID__"
matches = tuple(d for d in app.documents if d.isSaved and d.dataFile.id == target_id)
assert len(matches) == 1, "Expected exactly one open saved target document"
doc = matches[0]
target_design = adsk.fusion.Design.cast(doc.products.itemByProductType("DesignProductType"))
assert target_design is not None, "Target has no Design product"
target_root = target_design.rootComponent
```
При вызове через MCP напрямую заменить placeholder реальным ID. Через runner это делает `--document-id`. Получение продукта по типу описано в [Autodesk Products.itemByProductType](https://help.autodesk.com/cloudhelp/ENU/Fusion-360-API/files/core_Products_itemByProductType.htm).
Для проверки временной активации без изменения геометрии:
```powershell
& .\.venv\Scripts\python.exe .\run_query.py .\examples\activate_inspect_restore.py --document-id 'ID_ИЗ_СПИСКА'
```
**Не использовать `app.activeProduct` как неявную цель.** Встроенные upstream-инструменты обычно адресуют активную модель; общего аргумента `document_id` у них нет. В `execute_code` готовые переменные `design` и `component` также относятся к исходной активной модели. Подробности, шаблон редактирования и сохранение: [docs/INACTIVE_DOCUMENTS.md](docs/INACTIVE_DOCUMENTS.md).
## 4. Параллельные агенты, последовательный Fusion
Распределять между агентами можно анализ размеров, расчёты, подбор решений и подготовку скриптов. Отправка в один процесс Fusion принадлежит одному исполнителю.
```text
Агент A: анализ геометрии ─┐
Агент B: расчёты ├─→ единый исполнитель → gate → Fusion
Агент C: подготовка кода ─┘
```
Gate блокирует **каждый отдельный вызов**, включая чтение и ping. Второй клиент получает `FUSION_BUSY_NOT_SENT`; это отказ до отправки, не очередь для накопления заданий. Исполнитель может позже отправить именно отклонённую попытку после освобождения lock. Операцию с неопределённым результатом повторять нельзя.
После обычного завершения удержание lock и паузы обеспечивают минимум 2,1 с между завершением предыдущей отправки и следующей. Отдельный `sleep(2)` в агенте не нужен. Lock не защищает от ручных действий пользователя, прямого TCP, обычного upstream launcher, другого lock-пути или другого компьютера. Он также не делает цепочку из нескольких MCP-вызовов одной транзакцией.
Короткий [AGENTS.md](AGENTS.md) можно передать любому исполнителю. Подробное устройство блокировки: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
<a id="recovery"></a>
## 5. Что делать после тайм-аута
Тайм-аут означает, что подтверждение не получено. Fusion может продолжать операцию или исполнить её позже. Автоматический повтор выреза, отверстия или экспорта может продублировать действие.
Перед отправкой gate создаёт `fusion.lock.pending.json`. При успешном транспортном ответе маркер снимается. При исключении, сбое процесса или потерянном ответе он остаётся и блокирует последующие вызовы, даже после перезапуска launcher. Отказ соединения до фактической отправки тоже может оставить маркер: блокировка намеренно консервативна.
1. Прекратить отправку. Не перезапускать ту же команду.
2. Проверить интерфейс Fusion и `fusion360mcp.log`, дождаться фактического завершения работы/очереди. Определить, успела ли операция изменить модель.
3. Убедиться, что Fusion свободен и прежняя операция больше не может выполниться позже. Если это не установлено, маркер не снимать.
4. Закрыть/переподключить старые MCP-сеансы, чтобы не использовать сокет с запоздалым ответом. Затем снять маркер локальной командой с тем же lock-путём.
5. Начать с чтения состояния конкретной цели; решение о следующем изменении принимать по фактической геометрии.
```powershell
$env:FUSION_MCP_LOCK = 'C:\CAD\fusion-control\fusion.lock'
& .\.venv\Scripts\python.exe .\fusion_gate.py status
# Только после проверки завершения операции и свободного Fusion:
& .\.venv\Scripts\python.exe .\fusion_gate.py clear --confirm-fusion-idle
```
`clear` меняет только локальный маркер; он не отменяет команду, не очищает очередь add-in и не проверяет Fusion автоматически. Пока другой процесс удерживает lock, снять маркер нельзя. Сам файл `fusion.lock` может существовать постоянно — не удалять его для «разблокировки».
Возвращённая ошибка API с `ok=False` обычно означает завершённый вызов: маркер снимается, MCP сообщает `isError=True`. Это не откат изменений. После такой ошибки нужно проверить модель перед продолжением.
## 6. Проверка установки
### Без запущенного Fusion
```powershell
& .\.venv\Scripts\python.exe -m unittest discover -s tests -v
& .\.venv\Scripts\python.exe .\run_query.py .\examples\list_documents.py --mode mock
```
Mock проверяет запуск и обмен MCP, но не исполняет Fusion API. Его данные и deltas синтетические. Тесты поведения документов используют подставные объекты, не CAD-приложение. Методика и фактически проверенное окружение: [docs/VALIDATION.md](docs/VALIDATION.md).
### С запущенным Fusion
1. В MCP-клиенте получить список инструментов и вызвать `ping`.
2. Выполнить `examples/list_documents.py` в режиме `socket`.
3. Выбрать открытый соседний документ по ID и прочитать его через `inspect_inactive.py`.
4. Убедиться, что вернулись ID/имя нужного документа и активная вкладка не изменилась.
5. При необходимости отдельно проверить `activate_inspect_restore.py`.
Успешный ping доказывает только доступность TCP/add-in: он обходит главный поток Fusion. Готовность CAD подтверждает короткий запрос к модели.
<a id="troubleshooting"></a>
## 7. Устранение проблем
| Симптом | Причина и следующий шаг |
|---|---|
| Клиент не запускает MCP | Проверить абсолютные пути, venv и stderr. stdout сервера должен содержать только MCP |
| `ModuleNotFoundError` | Запускается другой Python или не установлены requirements |
| Connection refused | Fusion/add-in не запущен, другой порт или неверный процесс слушает порт |
| `FUSION_BUSY_NOT_SENT` | Другой исполнитель удерживает lock либо ОС отказала в блокировке; эта попытка не отправлена |
| `FUSION_UNCERTAIN_NOT_SENT` | Остался pending marker; выполнить процедуру восстановления выше |
| Ping отвечает, CAD зависает | Главный поток занят командой, диалогом или вычислением |
| Ошибка `designType` / `rootComponent` до скрипта | Начальный activeProduct не является CAD Design; активировать модель в UI |
| Документ не найден | Заново получить inventory; внешний компонент не обязательно открыт отдельным Document |
| Несколько совпадений ID | Разрешить неоднозначность по версии и состоянию; не выбирать первый автоматически |
| Изменена соседняя модель | Использован активный контекст без явного выбора целевого документа |
| Результат OK, нужной геометрии нет | Проверить тело и feature целевого документа, а не только глобальные deltas |
| `save` принят, облачная версия старая | Дождаться завершения загрузки отдельными короткими проверками; не отправлять save повторно |
| Команды всё ещё пересекаются | Найти клиент с другим lock-путём/без wrapper; сериализация действует только для участников |
## Структура
```text
fusion360-mcp-agent-kit/
├── README.md # Установка, подключение, восстановление
├── AGENTS.md # Контракт для AI-агентов и субагентов
├── server_serialized.py # STDIO launcher поверх pinned upstream
├── fusion_gate.py # Windows lock, паузы, pending marker
├── run_query.py # Один Python-файл → один execute_code
├── requirements.txt # Версия bridge и MCP SDK
├── configs/ # JSON и Codex TOML
├── examples/ # Три запроса без изменений геометрии
├── docs/ # Адресация, устройство, проверка
└── tests/ # Локальные проверки без Fusion
```
## Источники и развитие
- [Upstream server / Faust Machines](https://github.com/faust-machines/fusion360-mcp-server) — MCP-инструменты, add-in и основная реализация.
- [Зафиксированный connection.py](https://github.com/faust-machines/fusion360-mcp-server/blob/8bb5cb0400c551ac9fe74a02e6be09782064f5a8/src/fusion360_mcp/connection.py) — повторы и ожидание TCP.
- [Зафиксированный command_handler.py](https://github.com/faust-machines/fusion360-mcp-server/blob/8bb5cb0400c551ac9fe74a02e6be09782064f5a8/addon/server/command_handler.py) — контекст execute_code и snapshots.
- [Зафиксированный event_bridge.py](https://github.com/faust-machines/fusion360-mcp-server/blob/8bb5cb0400c551ac9fe74a02e6be09782064f5a8/addon/server/event_bridge.py) — CustomEvent, очередь и тайм-ауты.
- [Autodesk Fusion API](https://help.autodesk.com/cloudhelp/ENU/Fusion-360-API/) — API документов и геометрии.
Перед обновлением upstream проверять совместимость wrapper и add-in; менять их версию вместе. Для отчёта об ошибке указать ОС, версии Python/Fusion/upstream, тип клиента, шаги и обезличенный stderr. Не публиковать реальные document ID, CAD-файлы и журналы проекта без отдельного решения владельца.
Лицензия комплекта — [MIT](LICENSE). Автор комплекта: [GeBondar](https://github.com/GeBondar). Upstream и зависимости сохраняют свои лицензии: [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues