MCP-серверы для 3D и геймдева: всё решает дизайн инструментов

MCP-сервер с одним run_python отдаёт агенту всё и не помогает ни в чём. Чем набор инструментов, которым агент реально пользуется, отличается от бесполезного.

Вид с высоты на целый квартал с домами и дорогами, построенный агентом в Cuberta

Любой 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.
  • Тестируйте на агенте, которому вы не дали ни системного промпта, ни примеров. Всё, что он не сделал с первой попытки, — проблема инструмента, а не модели.

Набор инструментов — это проектный документ. В нём сказано, из чего, по мнению вашего приложения, состоит сцена, на каком уровне о ней думает человек и какие ошибки дёшевы. Агенты просто оказались очень буквальными читателями этого документа — поэтому писать его аккуратно и есть основная работа, а протокол под ним действительно самая простая часть.