Skip to main content
Glama
README.md
# mcpmine

[![CI](https://github.com/Z1ppzy/mcpmine/actions/workflows/ci.yml/badge.svg)](https://github.com/Z1ppzy/mcpmine/actions/workflows/ci.yml)

Два MCP App для Minecraft-разработки. Оба рисуются прямо в чате Claude (claude.ai, Claude Desktop,
мобильное приложение): сервер отдаёт инструменты и HTML-панель, человек правит мышкой, Claude теми
же инструментами, состояние одно на двоих.

| Приложение | Что делает |
| --- | --- |
| **Пиксельный холст** (`pixel/`) | Холст 16×16 с палитрой ресурспака: иконки предметов рисуются вручную и инструментами Claude, импортируются из PNG и экспортируются обратно с удвоением пикселя, как ждёт пак. |
| **Тест-игрок** (`tester/`) | Бот на [mineflayer](https://github.com/PrismarineJS/mineflayer) заходит на тестовый сервер, выполняет команды, читает GUI-инвентари и диалоги (1.21.6+), нажимает кнопки и слоты, показывает мир радаром. Claude получает всё это текстом и картинками. |

## Как это устроено

MCP Apps — расширение протокола MCP: инструмент указывает в `_meta.ui.resourceUri` ресурс `ui://…`
с HTML, хост рисует его в песочном iframe под сообщением и прокидывает мост. Страница вызывает
инструменты того же сервера (`callServerTool`), получает результаты (`ontoolresult`) и сообщает
модели о действиях пользователя (`updateModelContext`). Поэтому клик по холсту и команда «отзеркаль»
идут одной дорогой: оба становятся вызовом инструмента, сервер держит состояние, страница
перерисовывается по ответу. Правки Claude страница подтягивает опросом.

Все инструменты снабжены аннотациями (`readOnlyHint`, `destructiveHint`, `idempotentHint`,
`openWorldHint`), ошибки валидации и ошибки бота возвращаются текстом результата, а не падением
сервера. В HTTP-режиме есть `GET /health`.

## Требования

- Node.js 22+ (проверено на 22 и 24). Тестовый хост запускается как `node serve.ts`, без сборки TypeScript.
- Хост с поддержкой MCP Apps: claude.ai, Claude Desktop, Claude на телефоне. В Claude Code окна нет,
  инструменты работают, картинки приходят как изображения.
- Для тест-игрока: **тестовый** Paper/Spigot-сервер в `online-mode=false` на версии, которую знает
  mineflayer. Версия подбирается автоматически по ping сервера; список известных:
  `node -p "require('minecraft-protocol').supportedVersions"`.

## Быстрый старт

```bash
npm install
npm run build          # собирает обе панели в dist/
```

**Claude Desktop** (локальный stdio-сервер). В `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "pixel":     { "command": "node", "args": ["C:\\path\\to\\mcpmine\\pixel\\server.mjs"] },
    "mc-tester": { "command": "node", "args": ["C:\\path\\to\\mcpmine\\tester\\server.mjs"] }
  }
}
```

Потом Developer → Reload MCP Configuration (Developer Mode включается в Help → Troubleshooting) и в
новом чате: «открой пиксельный холст» или «открой тест-игрока».

**Claude Code.** В репозитории лежит `.mcp.json` с HTTP-адресами. Подними серверы и они появятся в
проекте:

```bash
npm run pixel:http     # http://localhost:3311/mcp
npm run tester:http    # http://localhost:3312/mcp
```

**claude.ai** (веб). Нужен публичный адрес: `npx cloudflared tunnel --url http://localhost:3311`,
затем Settings → Connectors → Add custom connector.

## Пиксельный холст

Панель: холст 16×16 с сеткой, палитра пака, превью в слоте инвентаря 1:1, 2:1 и 3:1, действия
(отмена, зеркало, очистка, экспорт) и подсказки на каждом элементе.

- ЛКМ рисует выбранным цветом, ПКМ стирает, протяжка красит. Ctrl+Z отменяет последнюю правку,
  свою или Claude, история до 50 шагов.
- Палитра ограничена цветами пака: имена цветов те же, что принимают инструменты.
- Каждая ручная правка уходит в контекст модели картой символов, пересказывать ничего не нужно.

| Инструмент | Что делает |
| --- | --- |
| `open_canvas` | Показать панель и вернуть состояние |
| `get_canvas` | Состояние без панели, для опроса |
| `set_pixels` | Пиксели по координатам, (0,0) слева сверху; цвет именем, символом карты или индексом |
| `fill` | Прямоугольник или весь холст одним цветом |
| `mirror` | `x`: левую половину направо, `y`: верхнюю вниз |
| `clear`, `undo` | Очистить; откатить последнюю правку |
| `set_map` | Загрузить карту: 16 строк по 16 символов, `.` прозрачно, `legend` сопоставляет символ имени цвета |
| `import_png` | Загрузить `<name>.png` из каталога вывода: квадрат со стороной, кратной 16, цвета вне палитры заменяются ближайшими |
| `export_png` | Записать `<name>.png` в каталог вывода с масштабом (2 даёт 32×32) и вернуть картинку |

Окружение: `PIXEL_OUT_DIR` — каталог PNG (по умолчанию `out/`), `PIXEL_PALETTE_FILE` — своя палитра
в JSON, массив `{ "name", "char", "hex" }`, первый элемент прозрачный (`"hex": null`, `"char": "."`).

## Тест-игрок

Панель: форма входа, чипы статуса (позиция, здоровье, режим, кто рядом), открытое окно сеткой слотов
с тултипами (имя, лор, модель предмета), диалог с кнопками, радар, чат с полем команд.

**Безопасность.** Бот входит без аккаунта (`auth: offline`), поэтому сервер должен быть тестовым и в
`online-mode=false`. Не направляй его на боевой сервер.

**Подготовка сервера.** В `server.properties`: `online-mode=false`, `enforce-secure-profile=false`,
для спокойных прогонов `difficulty=peaceful`. Выдай боту права через консоль: `op QaBot`. Для
быстрых проверок GUI хватает плоского мира (`level-type=minecraft:flat`).

| Инструмент | Что делает |
| --- | --- |
| `open_tester` | Показать панель и вернуть состояние |
| `bot_state` | Статус, окно, диалог, инвентарь и сообщения после `since` |
| `bot_join`, `bot_leave` | Подключиться (версия по ping или явная, ждёт spawn и чанки) и отключиться |
| `bot_command` | Отправить текст или команду, подождать `waitMs` и вернуть ответы, окно и диалог |
| `bot_window`, `bot_click`, `bot_close_window` | Слоты открытого окна; клик левой/правой, обычный или shift; закрыть |
| `bot_open_block` | Правый клик по контейнеру рядом с ботом (сундук, ящик кейса) |
| `bot_dialog`, `bot_dialog_click`, `bot_dialog_close` | Диалоги `show_dialog`: заголовок, тело, поля, кнопки; нажать по индексу; закрыть |
| `bot_inventory` | Предметы бота с именами и лором |
| `bot_radar` | Вид сверху вокруг бота: PNG в ответе и в панели |

**Окна.** Для каждого слота: `name`, `count`, `displayName`, `lore`, `model` (компонент `item_model`),
`customModelData`, список типов компонентов. Этого достаточно, чтобы проверить состояние иконки
кастомного предмета без клиента.

**Диалоги.** mineflayer не знает пакет `show_dialog`, разбор написан здесь: типы `notice`,
`confirmation`, `multi_action`, `dialog_list`, поля ввода, `exit_action`. Кнопки `run_command`
выполняются как команды (подстановка `$(key)` из `inputs` для динамических). Кнопки `custom`
пока недоступны: в minecraft-data нет пакета `custom_click_action`.

**Радар.** Верхний непустой блок каждого столбца в радиусе (по умолчанию 24), высота светлотой,
цвет по имени блока, белый маркер бота со штрихом направления, пурпурные маркеры игроков. Замена
3D-viewer: prismarine-viewer знает версии только до 1.21.4.

**Ограничения.**

- Версия сервера должна быть в списке mineflayer. Если по ping ничего не подошло, `bot_join`
  объясняет, какие версии известны.
- Текст длиннее 256 символов сервер отбрасывает с киком, бот отказывает заранее: длинные `setblock`
  и `give` выполняй через консоль.
- Эмодзи и глифы ресурспака в текстах заменяются на `▯`: Java пишет их в NBT как modified UTF-8,
  а библиотека читает как UTF-8. У игрока они видны нормально.
- Если сервер пришлёт `clear_dialog`, которого нет в minecraft-data, бот отвалится с ошибкой в чате.
- Ключи переводов вида `item.minecraft.coal` подставляются английскими названиями из minecraft-data,
  остальные ключи остаются как есть.

## Тестовый хост без Claude

Для отладки панелей есть basic-host из репозитория ext-apps. Он не хранится здесь (смешанные
лицензии), а скачивается:

```bash
npm run host:setup     # sparse-клон examples/basic-host в host/basic-host и npm install
npm run host:build
npm run pixel:http     # в отдельных окнах
npm run tester:http
npm run host           # http://localhost:8080
```

Прямые ссылки: `http://localhost:8080/?server=pixel&tool=open_canvas&call=true` и
`http://localhost:8080/?server=mc-tester&tool=open_tester&call=true`. На странице видно то, что
видит хост: панель в iframe, Model Context (что панель сообщила модели) и Tool Result.

## Разработка

```bash
npm test                # node:test: юнит-тесты и интеграция обоих серверов по stdio
npm run lint            # eslint
npm run smoke:pixel                                              # stdio: инструменты, ресурс, правки, undo, экспорт
npm run smoke:tester -- --port 25565 --command /help             # живой сервер: вход, сундук, команда, радар
npm run smoke:tester -- --port 25565 --command /menu --button OK # плюс нажать кнопку диалога по подстроке
npm run probe -- --port 25565 --command /menu                    # сырые пакеты сервера в ответ на команду
npm run e2e:pixel                                                # панель холста в тестовом хосте через Playwright и системный Edge/Chrome
npm run e2e:tester -- --port 25565 --command /menu --dialog Меню --button OK
```

Сценарии e2e ждут запущенные `pixel:http`, `tester:http` и `host`; браузер берётся системный
(`--browser msedge` или `chrome`), скриншоты складываются в `out/`.

CI на GitHub Actions гоняет lint, сборку и тесты на Node 22 и 24. Интеграционные тесты поднимают
настоящие серверы по stdio; тесту-игроку Minecraft-сервер для этого не нужен: проверяются
объявления инструментов, ошибки без бота и отказ на закрытый порт.

## Структура

```
pixel/        сервер холста: canvas.mjs (состояние, история, PNG), palette.mjs, tools.mjs, server.mjs, ui/
tester/       сервер бота: bot.mjs (сессия), version.mjs, chat-log.mjs, items.mjs, dialog.mjs, radar.mjs, text.mjs, translate.mjs, tools.mjs, server.mjs, ui/
shared/       тема (светлая и тёмная от хоста) и общие стили панелей
host/         установка, сборка и запуск тестового хоста
scripts/      smoke-прогоны и отладка пакетов
tests/        node:test
```

## Дальше

- Конструктор окна 9×6 с подложкой пака и записью YAML для меню.
- Запись иконок прямо в ресурспак и проверка правил пака (рамка, минимум видимых пикселей).
- Декодирование modified UTF-8 в NBT, чтобы эмодзи доходили целыми.
- Кнопки `custom` в диалогах, когда пакет появится в minecraft-data.
- 3D-вид, когда prismarine-viewer догонит текущие версии.

Собрано на [ext-apps](https://github.com/modelcontextprotocol/ext-apps),
[mineflayer](https://github.com/PrismarineJS/mineflayer) и остальном PrismarineJS.

Maintenance

ActivityMaintained
ResponsivenessNo issues