Files
minecraft-builder-mcp/docs/PROTOCOL.md
T

16 KiB
Raw Blame History

Протокол прототипа

Версия: 1. Точный реализованный каталог инструментов доступен через MCP tools/list, а возможности установленного Paper — через project_context.

Соединение с Paper

Сервис слушает только loopback, по умолчанию 127.0.0.1:8765. GET /health возвращает состояние и версию без приватных данных. POST /v1/rpc принимает JSON и заголовок Authorization: Bearer <token>.

Запрос: { "method": "project_context", "params": { "player_id": "UUID", "project_id": "default" }, "requestId": "correlation-id" }.

Успех: { "ok": true, "result": { ... } }. Ошибка: { "ok": false, "error": { "code": "...", "message": "..." } }. Ошибка может сопровождаться HTTP 400/403; клиент обязан читать структурированное тело. Токены в результатах не возвращаются.

Административный ключ обязателен для chat_poll, chat_reply, recovery_review и recovery_abandon. Ключ агента допускает инструменты мира в проекте связанного владельца, но не административное восстановление. player_id/project_id добавляются MCP-процессом из настроек, а не предлагаются модели. Плагин повторно проверяет владельца и его действующие права. Для изолированного тестового мира есть явно включаемый allow-local-automation и принципал console; административные операции восстановления также проходят проверку этой области полномочий.

Чтение и запись

region_inspect требует min/max как {x,y,z} и detail: "summary" | "blocks". Координаты включительные, целочисленные. Лимит прототипа — 4096 позиций. Ответ содержит палитру с количеством, а для blocks — точные состояния. Данные берутся из загруженных чанков без неявной генерации мира.

build_prepare принимает recipe: {version: 1, operations: [...]}, необязательный массив dependencies и необязательный part_id для точной маски части. Геометрия: box(min,max,block,hollow?), line(from,to,block), cylinder(center,radius,height,block,hollow?), repeat(count,offset,operations). Используется JSON-описание, не исполняемый JavaScript.

Результат подготовки: plan_id, plan_hash, changed_blocks, region, expires_at. Полный план и исходные блоки остаются в журнале. build_apply принимает этот ID, хеш и постоянный для данного вызова idempotency_key. Повтор того же вызова возвращает ту же операцию. Для другого плана нужен другой ключ.

operation_status(operation_id) возвращает состояние, счётчики и ограниченные примеры конфликтов. operation_cancel останавливает следующие порции. operation_undo_prepare создаёт обратный план; он проходит обычный build_apply и проверки. Потеря ответа на применение не даёт права создать другой ключ и повторить запись: сначала проверить project_context или повторить исходный вызов с тем же ключом.

part_define(name,operation_id) регистрирует только фактически записанные блоки завершённой операции. part_get(part_id) возвращает имя, границы, количество и защиту. Границы не равны маске: build_prepare(part_id) проверяет каждый блок по точной маске. Расширение создаётся отдельной частью.

Перед записью проверяются реальные состояния целевых блоков и объявленных зависимостей; проверка повторяется после сохранения намерения. Несовпадение не перезаписывается автоматически. Для undo также учитываются известные последующие записи наших операций, даже когда значение блока снова совпадает с прежним результатом.

Плагин наблюдает неотменённые BlockPlaceEvent и BlockBreakEvent в настроенном мире. Такое событие лишает прежнюю операцию права на undo данного блока, включая случай «изменили и вернули обратно» (ABA). Эти уведомления хранятся только в памяти текущего процесса. После перезапуска и для внешних путей без наблюдаемого события остаётся проверка текущего содержимого; полная история действий других плагинов не обещается.

Полный серверный журнал внешних изменений пока не реализован. region_changes отвечает resync_required; агент использует свежие ограниченные чтения. Это явное ограничение прототипа.

Восстановление после сбоя

Незавершённая операция после перезапуска получает recovery_required и запрещает начало новых записей. Автоматического повторения незавершённых порций нет. Административные RPC ниже не входят в MCP-инструменты агента и не являются откатом мира.

recovery_review принимает operation_id. Результат использует имена полей Java-записи: operationId, planId, positions, matchesBefore, matchesAfter, foreignStates, currentDigest, sampledAtMillis. Проверяемая маска объединяет фактически подтверждённые записи предыдущих порций и потенциальные записи незавершённой порции; пропуски без записи не включаются. Счётчики описывают совпадение текущих значений с before/after, а currentDigest — SHA-256 для этого снимка. Совпадение содержимого не доказывает авторство изменения.

recovery_abandon принимает operation_id и expected_digest, полученный из currentDigest последнего обзора. Сервер заново читает маску и отклоняет запрос, если её содержимое изменилось. При совпадении он оставляет все блоки мира на месте, переводит операцию в failed и сохраняет решение до успешного ответа. Ответ имеет обычную форму operation_status.

Отказ от неопределённой истории навсегда запрещает undo этой операции и сохраняет аннулирование прежнего права на undo для блоков затронутой маски. Новые записи разрешаются только после постоянного сохранения решения по всем незавершённым операциям. Сбой до сохранения оставляет необходимость восстановления; потеря ответа требует проверки operation_status, а не предположения, что произошёл откат. Устаревший или неверный digest возвращается как RPC-ошибка invalid_request с причиной.

Статус applied подтверждает наблюдавшийся результат записи и проверки в работающем сервере. Файлы чанков и журнал не образуют общую транзакцию; автоматической проверки сохранности всех ранее завершённых операций после аварии пока нет.

Локальные схемы

Реализованные имена RPC — asset_list, schematic_export и schematic_import_prepare. Отдельных маршрутов schematic_list и немедленного schematic_import нет. Наличие этих возможностей проверяется через project_context.

asset_list принимает необязательный query для поиска по имени без учёта регистра и возвращает { "assets": [...] }. Каждый элемент содержит assetId, name, width, height, length, blockCount, dataVersion, offset, sha256, bytes. Каталог содержит до 64 файлов; каждый файл проверяется при чтении, поэтому повреждённая схема может привести к отказу всего запроса списка.

schematic_export принимает name, включительные min/max и необязательный origin. Имя содержит 1–64 печатных символа. origin задаёт точку привязки схемы; по умолчанию она равна min. Сервер читает плотный прямоугольный участок, включая воздух, в текущей области проекта и в пределах max_plan_blocks (не более 4096). Неподдерживаемые блоки и сущности, кроме игроков, приводят к отказу; игроки в схему не записываются. Результат — один объект с теми же полями метаданных, что у asset_list. Файл остаётся в подкаталоге schematics каталога данных плагина; RPC не возвращает его содержимое или произвольный путь.

schematic_import_prepare принимает asset_id, target: {x,y,z} и необязательный rotation: 0 | 90 | 180 | 270 (по умолчанию 0). Поворот выполняется по часовой стрелке при взгляде сверху вокруг точки привязки target; сохранённый offset учитывается. Изменяются также поддерживаемые направления ступеней и оси брёвен/столбов. Результат — обычный plan_id/plan_hash/changed_blocks/region/expires_at; для записи нужен отдельный build_apply. Воздух схемы входит в план и может удалять существующие поддерживаемые блоки. Область, исходное содержимое, окружение, политика блоков и конфликты проверяются обычным путём подготовки и применения.

Поддерживается ограниченное подмножество Sponge Schematic v2: gzip и NBT с палитрой ванильных строительных состояний. Лимиты — 4096 позиций, 1 МиБ сжатого файла и 4 МиБ распакованного NBT. Сущности, block entities, биомы, неизвестные поля верхнего уровня, требуемые модификации и другие версии формата отклоняются. DataVersion новее текущего сервера не принимается; преобразования через DataFixer нет. Полная совместимость со всеми схемами WorldEdit не заявляется.

Внешний .schem можно заранее поместить локально в каталог схем под именем [A-Za-z0-9][A-Za-z0-9_-]{0,63}.schem, после чего его основание используется как asset_id. Произвольные пути, сетевые URL и символические ссылки не принимаются. Загрузки файла через RPC в прототипе нет.

Чат

chat_poll принимает стабильный на время жизни Bridge client_id. Ответ — messages с полями id, playerId, projectId, text, type, сведениями о положении и блоке под прицелом при наличии. typeprompt либо cancel. Ключ администратора обязателен.

chat_reply принимает id, playerId, text, done, необязательный error. Ответ маршрутизируется только инициатору исходного запроса. На смену Bridge-процесса незавершённые запросы не проигрываются автоматически: плагин останавливает изменения и просит проверить мир. /ai stop приостанавливает новые записи независимо от того, успел ли завершиться ACP-ход.

Камера

camera_capture принимает camera_id либо pose: {x,y,z,yaw,pitch,fov?,width?,height?}. Позиция соответствует ногам наблюдателя; Worker отдельно возвращает координаты глаз. after_operation_id проверяет завершение серверной операции, но не гарантирует получения её всех пакетов клиентом.

Paper сериализует запросы, перемещает настроенного spectator-наблюдателя и отправляет запрос локальному Camera Worker на 127.0.0.1:8766 с отдельным ключом. Pending-ответ содержит captureId; для проверки вызывается camera_capture с capture_id. Готовый результат содержит imageBase64 и mimeType, которые Bridge превращает в MCP image content, не в текстовую base64-строку.

Снимок имеет эвристическую оценку готовности чанков/кадров. serverRevisionVerified: false сохраняется до реализации строгого клиентского подтверждения. Отсутствие камеры, таймаут и невозможность получить свежий кадр не считаются визуальным успехом.

Подробности Worker: camera-mod/README.md. Потоки и журнал: world-core/README.md. ACP и изоляция: bridge/README.md.