MCP Idle Game
by Ku6epXBOCTuK
README.md
# MCP Idle Game
Идл-игра, в которой играет LLM-агент. Агент подключается по MCP как клиент,
ставит активное действие, добывает ресурсы, крафтит, продаёт, качает скиллы,
бьёт монстров, выполняет квесты и делает престиж. Наблюдатель смотрит на ту же
игру через дебаг-страницу.
Стек: Node.js 24, TypeScript (ESM, strict), чистая архитектура, `node:sqlite`,
`@modelcontextprotocol/server`, `zod`, `neverthrow`, Vite (HMR дебаг-страницы),
Vitest, ESLint, pnpm.
## Быстрый старт
```sh
pnpm install
pnpm build
pnpm start
```
Сервер поднимается на `http://127.0.0.1:3000` и создаёт дефолтного игрока. В
режиме разработки авторизация выключена (`MCPG_AUTH=off`), ключ не нужен.
Дальше:
- `http://127.0.0.1:3000/mcp` — точка входа MCP (Streamable HTTP);
- `http://127.0.0.1:3000/` — дебаг-страница с состоянием игры.
Для разработки: `pnpm dev` — два процесса рядом: API-сервер на `3000`
(`node --watch`, TS напрямую через strip-types) и Vite на `5173` с HMR.
Дебаг-страница открывается на `http://127.0.0.1:5173/`, запросы `/api` и `/mcp`
Vite проксирует на API-сервер. По отдельности: `pnpm dev:api` и `pnpm dev:web`.
## Подключение MCP-клиента
Локально (авторизация выключена) ключ не нужен:
```json
{
"mcpServers": {
"idle-game": {
"type": "http",
"url": "http://127.0.0.1:3000/mcp"
}
}
}
```
С ключом (`MCPG_AUTH=keys`) он передаётся заголовком
`Authorization: Bearer <key>`. Фолбэк — заголовок `X-API-Key`. Параметр `?key=`
работает только в dev-режиме.
```json
{
"mcpServers": {
"idle-game": {
"type": "http",
"url": "http://127.0.0.1:3000/mcp",
"headers": {
"Authorization": "Bearer mcp_live_..."
}
}
}
}
```
Клиент видит инструменты: `game_state`, `game_action`, `game_craft`,
`game_upgrades`, `game_trade`, `game_use`, `game_bank`, `game_combat`,
`game_quests`, `game_market`, `game_skills`, `game_prestige`, `game_log`,
`game_tick`, плюс ресурсы `game://state`, `game://skills`, `game://market`,
`game://quests` и промпт `game_strategy`.
При `MCPG_AUTH=keys` запрос без ключа отклоняется с 401, с неверным или
отозванным ключом — с 403. При `MCPG_AUTH=off` ключ не нужен: сервер работает с
дефолтным игроком, а переданный валидный ключ всё равно выбирает своего игрока.
## Ключи
```sh
pnpm run keys -- create --label "ноутбук" # печатает ключ один раз
pnpm run keys -- list # игроки и их ключи
pnpm run keys -- revoke --id <key id> # отзыв ключа
```
Ключи нужны только при `MCPG_AUTH=keys`. В базе лежит только SHA-256 хэш ключа и
его префикс `mcp_live_xxxx`. Ключ с scope `read` может только читать состояние,
с `play` — ещё и менять игру.
## Дебаг-страница
`/` отдаёт статику дебаг-страницы: кошелёк, активное действие с прогрессом,
скиллы, инвентарь, апгрейды с ценами и кнопкой «Купить», рынок, квесты, лента
событий. Данные приходят из `GET /api/state`, действия — из `POST /api/action`.
Страница обновляется раз в две секунды и показывает, чей это игрок. Ключ с
правами `read` получает страницу без кнопок мутаций. При `MCPG_AUTH=off` поле
ключа скрыто, а рядом горит метка «auth off».
## Баланс и симулятор
Числа игры лежат в `content/`, а не в коде. Симулятор прогоняет прогрессию через
чистый тик и считает метрики: время до престижа, доход по этапам, долю простоя,
окупаемость апгрейдов, узкие места.
```sh
pnpm run sim -- 24 # прогон на 24 часа, печатает метрики
pnpm run autotune # подбор кривых, пишет content/balance.json
```
Критерии баланса: апгрейд окупается за 3–15 минут, престиж доступен через 2–6
часов, простой не занимает больше 60% времени.
## Структура
```sh
src/
domain/ чистое ядро: состояние, тик, действия по видам
(start-gather/craft/fight, switch-zone), зоны, бои,
торговля, банк, квесты, престиж
application/ сценарии и порты; use-cases разрезаны по фичам вокруг
ядра (core.run, actions, state, combat, trade, bank,
quests, upgrades, items, prestige, players)
infrastructure/ node:sqlite, контент и zod-схемы, MCP (tools/ по фичам,
views, texts), HTTP, симулятор и автотюн (sim/)
bootstrap/ composition root, CLI ключей, симулятор, автотюн
content/ данные игры: скиллы, предметы, рецепты, апгрейды, зоны, квесты
web/ дебаг-страница: index.html, debug.js, style.css (корень Vite)
tests/ vitest: домен, use cases, инфраструктура, интеграция, e2e
```
Домен и application не знают про MCP, HTTP, SQLite и таймеры. `tick(state, now)`
— чистая функция: вся мутабельность возвращается новым состоянием. Время и
случайность идут через порты, тик детерминирован по seed из состояния.
Направление зависимостей и раскладку слоёв проверяет
`tests/architecture.test.ts`: домен ничего не импортирует извне себя,
application не знает про infrastructure, инструменты баланса живут в
`infrastructure/sim`, а не в домене.
## Переменные окружения
| Переменная | По умолчанию | Назначение |
| ------------------ | ------------- | ------------------------------------- |
| `MCPG_PORT` | `3000` | порт HTTP-сервера |
| `MCPG_HOST` | `127.0.0.1` | адрес привязки |
| `MCPG_DATA_DIR` | `./data` | каталог файла базы |
| `MCPG_CONTENT_DIR` | `./content` | каталог данных игры |
| `MCPG_PUBLIC_DIR` | `dist/web` | каталог статики: сборка или `web/` |
| `MCPG_ENV` | `development` | `production` отключает `?key=` |
| `MCPG_AUTH` | по окружению | `off` — без ключей, `keys` — по ключу |
## Проверки
```sh
pnpm test # vitest, без сети и без внешней БД
pnpm run lint # eslint
pnpm run typecheck
pnpm run build
```
## Лицензия и атрибуция
Код распространяется по лицензии MIT (файл `LICENSE`).
Структура слоёв прогрессии — референс Antimatter Dimensions (MIT); код и тексты
не копируются. Числовые ориентиры кривых — «по мотивам Melvor Idle» (порядок
величин, не копия таблиц).
Как устроено — `docs/DESIGN.md`, план оставшихся работ — `docs/PLAN.md`.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues