pyxel-mcp — MCP-сервер, который даёт ИИ-агенту запускать ретроградные игры и смотреть на них

· 2 мин чтения
mcp game-development ai-agents python testing
📂 Исходный код на GitHub

MCP-сервер для Pyxel: гоняет игру в headless-режиме по заданному расписанию нажатий, останавливает её на нужном событии и отдаёт агенту кадры, состояние, тайлмапы, звук и сравнение кадров как доказательства

pyxel-mcp — MCP-сервер, который даёт ИИ-агенту запускать ретроградные игры и смотреть на них

Pyxel — это ретроградный игровой движок на Python, а pyxel-mcp — MCP-сервер, который позволяет ИИ-агенту им пользоваться. Сервер запускает игровой скрипт без окна, подаёт нажатия по расписанию кадров, останавливает игру в тот момент, когда выполнилось нужное условие, и отдаёт агенту факты: скриншоты, пиксельные сетки, состояние игры, ресурсы, звук и разницы между кадрами. Оценку «хорошая ли игра» сервер не выносит — это остаётся за агентом и тем, кто его спрашивал.

Зачем нужен отдельный сервер

Агент пишет игру на Pyxel за секунды, но не умеет открывать окно, нажимать стрелки и смотреть на экран. Обычное решение — MCP-сервер внутри редактора, к которому подключается уже запущенный процесс. У Pyxel нет отдельного процесса редактора, поэтому pyxel-mcp управляет самой игрой.

На этом построены пять принципов:

  • Запуск без окна. Каждый вызов запускает скрипт в новом подпроцессе с драйверами-заглушками SDL и лимитом на число кадров. Параметр random_seed задаёт зерно для модуля random из Python и для генератора случайных чисел Pyxel. Другие источники случайности, тайминги и внешнее состояние по-прежнему влияют на кадры.
  • Ввод как данные. Кнопки, оси и позиция мыши расписаны по кадрам. Тестовый прогон — это JSON-документ, который агент может повторить и дополнить.
  • Остановка по событию, а не по таймеру. Условие until="score >= 1" завершает прогон на первом кадре, где нужный атрибут игры принял нужное значение. Снимок с "frame": "end" захватывает именно этот момент.
  • Факты, а не оценки. Инструменты сообщают пиксели, значения и измерения.
  • Кадр сразу в ответе. Флаг inline: true возвращает PNG как изображение MCP, и модель видит экран без отдельного чтения файла.

Установка

Сервер работает через stdio и запускается утилитой uvx. Для Claude Code:

claude mcp add --scope user pyxel -- uvx pyxel-mcp

Для Codex CLI:

codex mcp add pyxel -- uvx pyxel-mcp

Для Gemini CLI:

gemini mcp add pyxel uvx pyxel-mcp

Для Cursor, проектного файла .mcp.json в Claude Code и любого другого клиента с общим JSON-форматом подходит такая запись:

{
  "mcpServers": {
    "pyxel": {
      "command": "uvx",
      "args": ["pyxel-mcp"]
    }
  }
}

У VS Code свой файл .vscode/mcp.json с ключом servers верхнего уровня и полем "type": "stdio". Codex CLI можно настроить и в файле ~/.codex/config.toml секцией [mcp_servers.pyxel]. Команда uvx pyxel-mcp install печатает все варианты разом.

После правки конфигурации клиент нужно перезапустить. Сервер пишет в stderr такую строку:

[pyxel-mcp] starting - 8 tools

Нужен Python 3.11 или новее, движок Pyxel версии 2.9.6 и выше ставится как зависимость.

Скилл pyxel-skill

Отдельно существует проект https://ai4coding.ru/skills/kitao-pyxel-skill — это Agent Skill, который объясняет агенту, когда и зачем звать каждый инструмент и каких доказательств достаточно. Сам pyxel-mcp поставляет только наблюдения. Для Claude Code скилл ставится плагином вместе с сервером:

claude plugin marketplace add kitao/pyxel-skill && claude plugin install pyxel@pyxel-skill

Инструменты

Аргумент script — это путь к файлу, а не исходный код на Python. Относительные пути к ресурсам внутри скрипта считаются от каталога самого скрипта, как при запуске python game.py из этого каталога.

Инструмент Что возвращает
validate Ошибки синтаксиса и узнаваемые паттерны кода Pyxel, без запуска
run Кадры без окна, расписание ввода, журнал и снимки state, screen_image, screen_grid или video
pyxel_info Установленные версии, пути, встроенные примеры и адреса ресурсов
read_palette Цвета палитры и индексы банка изображений, которые используются
read_image Пиксели банка изображений и, по желанию, PNG-рендер
read_tilemap Координаты тайлов, исходный банк, счётчики использования, границы и, по желанию, рендер
read_audio Отрисованный WAV звука или музыки плюс измеримые данные
diff_frames Различия между пикселями двух PNG-файлов

У всех инструментов описаны схемы входа и выхода. В каждом результате есть поля ok и errors.

Скриптовые инструменты наблюдают первый вызов pyxel.run(), пока внешние ресурсы остаются активными. Прогон управляет колбэками именно там, а читатели ресурсов смотрят на состояние до входа в цикл. pyxel.quit() завершает прогон штатно и сохраняет уже готовые кадры. Код после pyxel.run() не выполняется. Остановка внутри делается через внутренние сигналы на базе BaseException; скрипты и менеджеры контекста, которые эти сигналы подавляют, не поддерживаются и могут выполнить код после прогона.

Как выглядит прогон

Держим вправо, прыгаем на 25-м кадре, останавливаемся сразу после изменения счёта и смотрим на этот кадр:

{
  "script": "/absolute/path/game.py",
  "frames": 600,
  "random_seed": 7,
  "inputs": [
    {"frame": 0, "buttons": ["KEY_RIGHT"]},
    {"frame": 25, "buttons": ["KEY_RIGHT", "KEY_SPACE"]},
    {"frame": 26, "buttons": ["KEY_RIGHT"]}
  ],
  "until": "score >= 1",
  "snapshots": [
    {"kind": "state", "frame": "end", "attrs": ["score", "player.x"]},
    {"kind": "screen_image", "frame": "end", "scale": 3, "inline": true}
  ]
}

В ответе будут признак выполнения условия, реально отработанное число кадров, запрошенные значения состояния, путь к PNG и сам PNG как содержимое изображения. Пути к артефактам, которые вы выбираете сами, должны быть абсолютными.

Чтобы PNG ехал прямо в ответе, достаточно поставить inline: true у снимка screen_image или inline=true у read_image и read_tilemap. Не более 12 изображений встраивается за один вызов. Если у единственного встроенного кадра не задан путь сохранения, файл всё равно записывается во временный каталог системы, а путь сообщается в ответе — иначе diff_frames и последующие сравнения перестали бы работать.

Ресурсы

  • pyxel://run-snapshots-schema — полная грамматика run.snapshots, включая "end", диапазоны и inline.
  • pyxel://validation-patterns — список категорий, которые сообщает validate.
  • pyxel://palette/default — таблица палитры по умолчанию.
  • pyxel://examples/{name} — исходник примера из установленного пакета Pyxel; имена находятся через pyxel_info.

Обновление и диагностика

uvx кэширует пакеты, поэтому принудительное обновление выглядит так:

uvx --refresh-package pyxel-mcp pyxel-mcp install

Если инструменты не появились, ищите строку starting - 8 tools и перезапустите клиент. Если упал run, смотрите поля errors, exit_status и log. Если скрипт не находит ресурс, проверяйте путь относительно файла скрипта, а не рабочего каталога клиента.

Ограничения

Скриптовые инструменты выполняют локальный Python в подпроцессах ради изоляции состояния Pyxel, но не изолируют недоверенный код. Об этом прямо написано в файле SECURITY.md. Сам движок Pyxel лежит в репозитории https://github.com/kitao/pyxel, пакет доступен на PyPI и зарегистрирован в реестре MCP под именем io.github.kitao/pyxel-mcp. Лицензия MIT, изменения по версиям собраны в CHANGELOG.md.

Источник: https://github.com/kitao/pyxel-mcp