MCP-серверы для 3D и геймдева: всё решает дизайн инструментов
MCP-сервер с одним run_python отдаёт агенту всё и не помогает ни в чём. Чем набор инструментов, которым агент реально пользуется, отличается от бесполезного.
Любой MCP-сервер для 3D-приложения рано или поздно упирается в одну развилку. Можно отдать один инструмент — run_python(code) — и за вечер открыть агенту весь API приложения. А можно разобраться, какие двадцать операций реально нужны локации, и отдать только их; на это уйдут недели. Работы по протоколу в обоих случаях поровну; а вот того, что агент после этого сумеет, — нет.
MCP в двести слов
Model Context Protocol — это формат обмена, а не приём. Хост (то приложение с ИИ, перед которым вы сидите: агентский CLI, IDE) поднимает по одному клиенту на каждое соединение, и каждый клиент разговаривает с одним сервером — обычной программой, отвечающей по JSON-RPC либо через stdin и stdout на вашей же машине, либо по HTTP.
Сервер предлагает три вещи. Инструменты — функции, которые модель может вызвать; у каждой есть имя, описание и JSON Schema аргументов. Они и делают работу. Ресурсы — данные только на чтение, которые хост может подтянуть: файл, схема, манифест. Промпты — заготовки, которые пользователь выбирает из меню. В 3D-серверах почти весь вес несут инструменты; ресурсы попадаются изредка, промпты — почти никогда.
Anthropic опубликовала MCP в ноябре 2024 года, а через год передала его Agentic AI Foundation при Linux Foundation; в управляющем комитете — OpenAI, Google, Microsoft и AWS. Для автора инструментов это весь протокол целиком — и именно поэтому протокол здесь не самая интересная задача.
Набор инструментов и есть продукт
Чего стоит run_python
Один инструмент с выполнением кода выглядит максимальным: всё, что умеет приложение, открыто разом. На деле он не даёт агенту ничего сверх того, что у того уже было. Чтобы им пользоваться, модель должна помнить API приложения наизусть — пути модулей, порядок аргументов, договорённость о верхней оси, единицы, — а эта память заморожена на момент обучения, тогда как сборка у вас на диске — нет. Цикл получается такой: написать скрипт, прочитать трейсбек, поправить имя, прочитать следующий трейсбек. На ряд домов вдоль улицы уходит двадцать обменов, пятнадцать из которых — разгребание собственных ошибок. И у инструмента нет краёв: скрипт, добавляющий куб, теми же правами удаляет сцену.
Та же работа уровнем выше
Теперь дайте агенту инструменты по форме задачи:
get_scene_summary()
create_road_network(layout, length_m, lanes, sidewalks)
place_buildings_along(road_id, count, storeys, facade)
set_sun(azimuth_deg, elevation_deg)
Улица из двенадцати домов превращается в три вызова и одно считывание. API агенту больше не нужен, потому что список инструментов и есть план. Количество ходов падает примерно на порядок — и, что полезнее скорости, каждый неудачный ход теперь падает там, где это читается.
Это тот же довод, что и в разговоре о том, почему сцена — не объект: композиция — задача другого рода, чем геометрия, и инструменты должны быть про композицию.
Насколько крупно — уже слишком
Уйти слишком высоко — отдельный способ проиграть. Единственный build_city(prompt) — игровой автомат: один рычаг и никакой возможности поправить то, что не понравилось. Полезная высота примерно такая: инструмент должен соответствовать тому, что левел-дизайнер произнёс бы вслух. «Застрой этот квартал двухэтажными домами». Если инструмент не проговаривается предложением, высота выбрана неверно.
- Пятнадцать-сорок инструментов, а не четыреста. Каждое определение лежит в контексте ещё до того, как пользователь что-то напечатал, а длинные каталоги измеримо ухудшают выбор инструмента.
- Восемь аргументов и меньше на инструмент. Дальше модель начинает заполнять поля наугад.
- Перечисления вместо свободного текста везде, где множество замкнуто.
facade: brick | render | glassнельзя выдумать, а строку — можно. - Единицы в имени аргумента.
length_mзакрывает целый класс ошибок.
Считывание — та половина, которую пропускают
Агент, умеющий только писать, работает вслепую. У него нет глаз во вьюпорте и нет ощущения собственного положения; через четыре вызова его представление о сцене — это история, которую он сам себе рассказал. Всё хорошее в агентном 3D берётся из замыкания этой петли, а замыкается она на инструменте чтения.
Хорошая сводка по сцене — именно сводка, а не дамп: все трансформации всех объектов одновременно огромны и бесполезны. Агенту на самом деле нужны:
- количества по категориям и общий габаритный ящик в метрах;
- устойчивые идентификаторы всего, что он потом может менять;
- связи — какие здания стоят у какой дороги, в какой комнате какие предметы;
- и прежде всего проблемы: дорога с оборванным концом, два пересекающихся меша, здание, повёрнутое к улице спиной.
Последний пункт и отличает инструмент чтения от инструмента диагностики, и диагностика стоит куда дороже: агент починит то, о чём вы ему сказали, а сам заметит редко. Считайте скриншот вьюпорта таким же инструментом чтения: на вопрос «читается ли это как улица» он отвечает лучше любой таблицы координат, а на вопрос «стена сдвинута на 4 см?» — никак. Нужны оба.
Идемпотентность, или дорога, построенная трижды
Агенты повторяют вызовы. Клиенты повторяют вызовы. Вызов отваливается по таймауту, пока редактор занят, клиент шлёт заново — и вот две одинаковые дорожные сети дерутся за один и тот же z.
Лечится тем, что записи становятся адресуемыми. Инструмент, который что-то создаёт, возвращает устойчивый идентификатор, и повторный вызов с этим идентификатором обновляет, а не добавляет. place_building(building_id, ...), вызванный дважды, — это одно здание. place_building(...), вызванный дважды, — два.
У MCP для этого есть словарь. Аннотации инструментов — readOnlyHint, destructiveHint, idempotentHint, openWorldHint — появились в редакции 2025-03-26, и именно по ним хост решает, что подтверждать автоматически, а на чём останавливаться и спрашивать. Это подсказки, а не принуждение, и неаннотированный инструмент считается худшим случаем: разрушительным, неидемпотентным, ходящим в открытый интернет. Пометить читающие инструменты как read-only — десять минут работы, которые убирают подтверждение из каждого цикла.
Ошибки — это тоже промпт
У сообщения об ошибке от 3D-сервера MCP ровно один читатель, и это не человек. Это модель, которая решает, что делать дальше, без отладчика и без исходников. Написанные под этого читателя ошибки становятся самой дешёвой обучающей поверхностью, какая у вас есть.
| Что вернул инструмент | Что агент сделает дальше |
|---|---|
| «Недопустимый аргумент» | Повторит тот же вызов, потом начнёт гадать. |
| Трейсбек Python на 40 строк | Потратит 500 токенов и узнает номер строки. |
| «lane_width_m должен быть от 2.5 до 6.0, получено 45» | Вызовет заново с допустимой шириной. |
| «Дороги r_07 нет. Есть: r_01, r_02, r_03.» | Исправит идентификатор без лишнего чтения. |
Отсюда: говорите, что было неверно и что было бы верно, называйте инструмент, который снимет неопределённость, и честно сообщайте о частичном успехе. Если 34 дерева из 40 встали, а шесть оказались вне полигона, скажите, какие именно, — «успех» на частичном результате и есть тот способ, которым агент строит три этажа на плохом фундаменте.
Радиус поражения
Агента, редактирующего исходники, откатывает git. Агент, редактирующий 3D-сцену, работает с документом, который человек вручную собирал часами и часто вообще без контроля версий. Плохой сценарий здесь — не неудачный коммит, а стёртый рабочий день.
Отмена, границы и инструменты, которые не дотягиваются
- Один вызов — один шаг отмены. Если расстановка сорока деревьев оставила сорок записей в стеке отмены, отмена декоративна.
- Границы в сервере, а не в промпте. «Строй только внутри этого полигона» в промпте — пожелание; то же правило как проверка границ внутри инструмента — гарантия. Помеченные зоны запрета застройки относятся ко второй категории.
- Ограничивайте разрушительные глаголы.
delete_selection— нормально.delete_allлибо не должен существовать, либо должен жить за явным подтверждением: в MCP есть elicitation, и сервер может спросить пользователя прямо во время вызова.
Поверхность инъекции, которую никто не закладывает
Вывод инструмента — недоверенный вход. Сервер, ищущий по общественной библиотеке ассетов, возвращает названия и теги, написанные посторонними, и этот текст ложится в контекст агента рядом с вашими указаниями. Отравление инструментов — скрытые инструкции внутри того, что возвращает инструмент, — это задокументированный класс атак, и метаданные ассетов подходят для него идеально. Держите решение о следующем вызове подальше от текста, пришедшего из сети.
Cuberta берёт узкую версию этой сделки. Это бесплатный настольный редактор, который поднимает собственный MCP-сервер: нажимаете Copy connect command, вставляете строку в терминал — и ваш агент подключён. Всё, что он строит, — выделяемые объекты, которые можно двигать, удалять и отменять, внутри областей, отмеченных вами как разрешённые под застройку.
Что существует сегодня, по категориям
Всё, что рядом с 3D, раскладывается на четыре формы.
- Мосты к DCC-приложениям. Аддон внутри Blender, Maya, Houdini, Cinema 4D или текстурного пакета держит сокет, а небольшой внешний процесс перекладывает в него вызовы MCP. Самый известный — Blender MCP. Почти у всех есть инструмент выполнения кода, то есть проблема
run_pythonв естественной среде обитания; её компромиссы заслуживают отдельного разбора. - Серверы библиотек и генерации ассетов. Sketchfab, Poly Haven, Meshy, Tripo, Hyper3D Rodin. Поиск, превью, скачивание, импорт — их проще всего написать. Они преимущественно читающие и полностью «открытого мира», поэтому аннотации и гигиена против инъекций важны здесь сильнее, чем где бы то ни было.
- Мосты к движкам. Есть у Unity, Unreal, Godot и Roblox Studio. Большинство — проекты сообщества: распространённый вариант для Unity не связан с Unity Technologies. При этом в Unreal Engine 5.8 приехал экспериментальный официальный MCP-плагин от Epic с наборами инструментов для акторов, сцен и экземпляров материалов. Постоянная опасность здесь — асинхронность: инструмент, который правит скрипт и возвращает управление до того, как редактор закончил перекомпиляцию, докладывает об успехе, на который нельзя опереться.
- Редакторы, спроектированные под агента. Приложения, где агент был в замысле с самого начала, а MCP-поверхность — основной интерфейс, а не обёртка поверх API, который старше её. Cuberta сделана так. Это единственная категория, свободная выбирать себе гранулярность.
Если пишете свой
Начните с расшифровки разговора, а не с API. Выпишите десять фраз, которые пользователь действительно сказал бы вашему приложению, его словами. Эти фразы и есть ваши инструменты; API, который у вас уже есть, — деталь реализации под ними. Дальше:
- Выпустите инструмент чтения первым и пользуйтесь им сами. Если вы не понимаете собственную сводку по сцене, модель тем более не поймёт.
- Называйте инструменты по результату:
place_buildings_along, а неbatch_transform_instances. - Тестируйте на агенте, которому вы не дали ни системного промпта, ни примеров. Всё, что он не сделал с первой попытки, — проблема инструмента, а не модели.
Набор инструментов — это проектный документ. В нём сказано, из чего, по мнению вашего приложения, состоит сцена, на каком уровне о ней думает человек и какие ошибки дёшевы. Агенты просто оказались очень буквальными читателями этого документа — поэтому писать его аккуратно и есть основная работа, а протокол под ним действительно самая простая часть.