3D-ассеты через агента Как устроена связка агент — MCP — Blender
0%

Как устроена связка агент — MCP — Blender

Как устроена связка агент — MCP — Blender

Прежде чем ставить, полезно понять, из чего состоит конструкция. Здесь три процесса и два протокола, и почти все проблемы новичка живут на стыках.

Агент  ──stdio/MCP──▶  blender-mcp server  ──TCP 127.0.0.1:9876──▶  аддон внутри Blender

Агент (Digit, Claude Code, любой MCP-клиент) знает только про инструменты: get_scene_info, execute_blender_code, get_viewport_screenshot и ещё полтора десятка.

blender-mcp server — отдельный Python-процесс, который агент запускает через uvx. Он объявляет инструменты и переводит их вызовы в JSON-команды.

Аддон внутри Blender — самое интересное. Это обычный Blender-аддон, который поднимает TCP-сервер в самом процессе Blender. Он принимает JSON и исполняет его через bpy — тот же API, которым пользуются все скрипты Blender.

Ключевое следствие: Blender должен быть уже запущен. MCP-сервер его не поднимает. Если Blender не работает, инструменты просто уходят в таймаут. Это причина примерно половины сообщений «у меня ничего не отвечает».

Почему нельзя просто blender -b

Первое, что делает любой инженер на сервере без монитора, — пробует фоновый режим. У Blender он есть и отлично работает для рендера ферм: blender -b scene.blend -f 1.

С этим аддоном не работает. В коде стоит явная защита:

if bpy.app.background:
    print("BlenderMCP: cannot start server in background mode ...")
    return

Соблазн — убрать три строки и пересобрать. Не поможет, и вот почему.

Сокет-сервер аддона живёт в отдельном потоке. Но bpy не потокобезопасен: трогать данные Blender из чужого потока — верный путь к падению. Поэтому аддон не исполняет команду сразу, а кладёт её в очередь и регистрирует bpy.app.timers — механизм, которым Blender выполняет отложенный код в главном потоке.

А таймеры тикают только тогда, когда у Blender крутится цикл обработки событий. В фоновом режиме цикла нет: Blender выполняет свою задачу и выходит. Команда ляжет в очередь и останется там навсегда.

Симптом при снятой защите был бы хуже, чем с ней: не ошибка, а вечное молчание. Защита честно превращает «зависнет» в «откажется стартовать» — и это правильное инженерное решение, хоть и неудобное.

Обобщение, которое стоит унести: если библиотека запрещает режим, сначала ищите причину запрета. Она обычно не в трёх строках проверки, а в модели исполнения, которую этими строками охраняют. Снятие проверки меняет явный отказ на тихий сбой.

Виртуальный дисплей

Раз нужен цикл событий — значит, нужен настоящий GUI. Раз GUI, нужен дисплей. На сервере дисплея нет, поэтому его создают: Xvfb — X-сервер, который рисует в память и никому ничего не показывает.

xvfb-run -a -s "-screen 0 1920x1080x24" blender --factory-startup --python startup.py

Blender считает, что открыт на мониторе 1920×1080. Крутится цикл событий, тикают таймеры, аддон работает. Никакого монитора при этом нет.

Второй слой — OpenGL. Blender’у нужен реальный GL-контекст даже для запуска интерфейса, а на виртуальной машине обычно нет пригодного 3D-ускорения. Спасает llvmpipe — программный растеризатор Mesa: рисует на процессоре, медленно, но полноценно.

export LIBGL_ALWAYS_SOFTWARE=1
export GALLIUM_DRIVER=llvmpipe

У этого есть неожиданное последствие для рендера, разобранное в https://courses.digitable.life/post/3d-pipeline/05-materials/: без GPU Cycles оказывается быстрее EEVEE, хотя на десктопе всё наоборот.

Изоляция запуска

Две детали запускалки, которые стоит перенять для любого инструмента.

--factory-startup — Blender стартует с заводскими настройками, не трогая ~/.config/blender. В паре с проектным BLENDER_USER_SCRIPTS (аддон лежит в папке репозитория, а не в системной) вся конструкция становится самодостаточной: она не портит рабочий Blender того же пользователя и её можно снести одним rm -rf.

setsid — Blender уходит в собственную группу процессов. Это не украшательство: xvfb-run порождает детей, и обычный kill по одному PID оставит сироту, которая продолжит держать порт. Запускалка убивает группу целиком.

Готовность проверяется портом, а не sleep:

port_open() { (exec 3<>"/dev/tcp/127.0.0.1/$PORT") 2>/dev/null; }

Bash умеет открывать TCP-соединения через /dev/tcp — внешние утилиты не нужны. Цикл ждёт открытия порта и параллельно проверяет, что процесс ещё жив: если Blender умер, лучше сказать об этом сразу, чем ждать таймаут.

Проверка себя

Прежде чем идти дальше, убедитесь, что понимаете:

  • почему нельзя blender -b (дело не в проверке, а в таймерах);
  • почему Blender должен быть запущен до обращения агента;
  • зачем нужен llvmpipe и во что это обойдётся по скорости;
  • почему готовность — это открытый порт, а не выжданные пять секунд.

Дальше — https://courses.digitable.life/post/3d-pipeline/02-setup/: ставим, регистрируем и разбираемся с телеметрией, которая включена по умолчанию.

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

Статья описывает общий случай. Если у вас частный — можно разобрать его отдельно, платно. А если не хватает целого материала, предложите тему: её оплачивают вскладчину, и она выходит открытой для всех.

Доска запросов
Дальше