Skip to main content
Glama

game-bridge-mcp

Позвольте ИИ-агенту запустить вашу игру, управлять ею и читать, что произошло — по HTTP, один порт на экземпляр.

Ваша игра уже знает о себе всё: что на экране, где находится каждая сущность, какие команды она принимает. game-bridge-mcp — это MCP сервер, который передаёт это агенту — в виде инструментов, которые агент может вызывать и которые обнаруживаются из запущенной игры, а не зашиты здесь.

agent ──MCP(stdio)──▶ game-bridge-mcp ──HTTP──▶ 127.0.0.1:7820  ← it launched this one
                                      ├───────▶ 127.0.0.1:7801  ← your IDE started this one
                                      └───────▶ 127.0.0.1:7802  ← a colleague's session

Три особенности делают его чем-то большим, чем скрипт отладочного моста, который вы написали бы за полдня:

  • Он запускает экземпляры и выбирает для них порты. Ни один вызывающий код никогда не выбирает порт и не вводит команду сборки, поэтому два агента не могут столкнуться, а мост прибирает за собой — никаких осиротевших окон игры после завершения сеанса.

  • Каждый инструмент принимает port. Один мост управляет всеми запущенными у вас экземплярами: несколько агентов на одной машине или один агент, сравнивающий две сборки бок о бок.

  • Список инструментов приходит из игры. Мост получает GET /tools от каждого экземпляра во время выполнения, поэтому отладочная команда, добавленная вами утром, доступна для вызова уже днём — без выпуска этого пакета, без переподключения и без расхождения между тем, что агент считает принимаемым игрой, и тем, что она принимает на самом деле.

Он не привязан к движку. Любой язык, что угодно, что может обслуживать четыре небольших HTTP-эндпоинта на localhost. Контракт намеренно короткий.


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

npx @wildware/game-bridge-mcp --help

Зарегистрируйте его в MCP-клиенте — например, для Claude Code, из каталога вашего проекта:

claude mcp add game-bridge -- npx -y @wildware/game-bridge-mcp

Затем со стороны агента:

launch_instance {}                                 // start a game; the bridge picks the port
list_instances  {}                                 // ...or find one already running
list_toolsets   { "port": 7820 }                   // what can this instance do?
describe_toolset { "port": 7820, "name": "play" }  // exact schemas
call_tool { "port": 7820, "name": "drop", "arguments": { "x": 1.2 } }
stop_instance { "port": 7820 }                     // clean shutdown, not a kill

Для launch_instance требуется декларация запуска. Всё остальное работает с любой игрой, реализующей HTTP-поверхность, независимо от того, запустил ли её этот мост.


Related MCP server: minecraft-mcp

Контракт

Реализуйте это — и вашей игрой сможет управлять любой агент через этот мост, при том что здесь нет ни строчки кода, который что-то о ней знает. У контракта три части, и каждая даёт что-то конкретное:

Часть

Что это даёт

1. HTTP-поверхность

Чтение состояния и управление запущенным экземпляром.

2. Саморегистрация

Поиск экземпляров без угадывания портов.

3. Декларация запуска

Запуск экземпляров без выбора порта человеком.

Обязательна только часть 1. Часть 2 делает обнаружение надёжным; часть 3 делает всё это удобным.

1. HTTP-поверхность

Обслуживайте их на 127.0.0.1:<port>, где порт берётся из явного отладочного флага. Привязывайтесь только к loopback и держите всю поверхность выключенной, если игра не была запущена с этим флагом: это отладочная поверхность, а не сетевой сервис.

GET /health — обязательно

Проверка живости и идентичности. Обнаружение вызывает его на каждом порту в диапазоне, поэтому он должен быть дешёвым.

GET /health
{ "ok": true, "frame": 91422 }

Именно ok: true помечает порт как наш. Порт, отвечающий по HTTP чем-то другим, сообщается агенту как «этот порт занят чем-то другим» — это другая проблема, с другим решением, нежели «игра не запущена».

frame — это счётчик, который увеличивается в течение всей жизни процесса. Мост следит за ним: frame, идущий назад, означает, что на этом порту отвечает новый процесс, и кэшированный манифест инструментов автоматически сбрасывается. Именно это делает пересборку и повторный запуск невидимыми для агента.

GET /state — обязательно

Полный снимок: всё, что агенту может захотеться узнать, в виде JSON. Обязательной схемы нет — это ваша игра, — но несколько общепринятых полей открывают возможности моста:

{
  "frame": 91422,
  "simFrame": 48110,
  "completedCommandId": 17,
  "paused": false,
  "ui": {
    "screen": "GameScreen",
    "elements": [ { "label": "Restart", "visible": true } ]
  },
  "events": [ { "m": "merge:cherry" }, { "m": "click:Restart" } ],
  "game": { "score": 1280, "state": "RUNNING" }
}

Поле

Почему это важно для моста

frame

Обнаружение перезапуска; запасное подтверждение, что команда выполнилась.

completedCommandId

Сильное подтверждение, что команда выполнилась — см. ниже.

ui.screen

Сообщается через list_instances, поэтому пять экземпляров можно с первого взгляда отличить друг от друга.

ui.elements[].label / .visible

Включаются в компактную сводку get_state.

events[].m

Недавние события, возвращаемые после каждой команды, чтобы агент видел последствия. Простые строки тоже принимаются.

game

Скалярные поля включаются в сводку. Вложенные объекты и массивы — нет; именно там живут мегабайтные списки сущностей.

Всё остальное, что вы сюда поместите, передаётся без изменений через get_state.

GET /command — обязательно

GET /command?cmd=spawn&type=cherry&x=-1.5
{ "accepted": true, "commandId": 18, "frame": 91430 }

Имя команды передаётся в ключе cmd, а не name — команды часто принимают собственный аргумент name, и дублирующийся ключ запроса молча перезаписал бы вызываемую команду. Все остальные параметры запроса — это аргументы.

Этот эндпоинт работает по принципу «выстрелил и забыл», и это самое главное, что нужно понять о контракте. Он отвечает из HTTP-потока в тот момент, когда команда поставлена в очередь; сама команда выполняется позже, в игровом потоке. Клиент, который сразу после этого читает /state, читает мир до выполнения команды. Тест выглядит нестабильным; игра в порядке.

Мост обрабатывает это, и то, как он это делает, — то, что ваша игра должна поддерживать:

  1. GET /command?... → запомните возвращённый commandId.

  2. Опрошивайте GET /state, пока completedCommandId >= commandId.

  3. Верните это состояние — уже после выполнения команды.

Если ваша игра не публикует completedCommandId, мост деградирует до ожидания увеличения frame на два и помечает результат как "confirmation": "frames-advanced", чтобы агент знал, что получил более слабую гарантию. Публикация completedCommandId — это несколько строк, и оно того стоит:

// game thread, once per frame
while (true) {
    val cmd = queue.poll() ?: break
    apply(cmd)
    completedCommandId = cmd.id   // published in the next /state snapshot
}

Команда close, завершающая игру через её штатное завершение, настоятельно рекомендуется: она позволяет агенту завершить экземпляр, не убивая процесс. Мост обрабатывает close особым образом — он никогда не ждёт завершения, которое не может наступить, он ждёт, пока порт замолчит.

GET /tools — необязательно, но это самое интересное

Манифест: что можно сказать вашей игре делать, её собственными словами.

{
  "game": { "name": "Orbital Freight", "version": "0.9.2", "protocol": 1 },
  "toolsets": [
    {
      "name": "play",
      "description": "Drive the game the way a player does.",
      "tools": [
        {
          "name": "drop",
          "description": "Release the held crate, aiming first if x is given.",
          "args": [
            { "name": "x", "type": "number", "description": "World x, -2..2", "required": true, "default": null },
            { "name": "settle", "type": "boolean", "description": "Wait for the stack to settle", "default": "true" }
          ]
        }
      ]
    }
  ],
  "passthrough": {
    "description": "Any command the debug bridge accepts, passed straight through.",
    "examples": ["set_seed { seed }", "set_gravity { x, y }"]
  }
}

Поле

Значение

game.name, game.version

Идентичность. Показывается через list_instances — так агент отличает пять запущенных экземпляров друг от друга.

game.protocol

Версионирует документ, а не набор команд. Добавление команды ничего здесь не меняет; изменение структуры манифеста — меняет. Это позволяет мосту отличать «я не могу это прочитать» от «эта игра знает другие команды, чем в прошлый раз». Текущая версия: 1.

toolsets[]

Группы, названные по тому, что вызывающий код пытается сделать, а не по тому, как устроен ваш код. Держите их немногочисленными и очевидными.

tools[].name

То, что вызывает агент.

tools[].description

Написано для агента. Опишите, что инструмент делает и когда к нему обращаться — именно по этому тексту модель рассуждает.

tools[].args[]

{ name, type, description, required, default }. type — это имя типа из JSON Schema, поэтому один конвертер обслуживает и игровые команды, и инструменты моста.

tools[].command

cmd, который нужно отправить, если он отличается от имени инструмента. По умолчанию — имя.

tools[].sync

false для команд, которых нельзя ждать. По умолчанию — true.

tools[].inputSchema

Если у вас уже есть JSON Schema, отправьте её вместо args — она будет использована дословно.

passthrough

Свободный текст с примерами, описывающий команды, которые вы не публиковали формально.

Значения по умолчанию могут быть строками ("true", "0.05") — манифест, сериализованный из типизированного языка, обычно представляет их именно так. Мост включает их в описание, а не выводит default в схеме, потому что default: "false" для свойства boolean строгий клиент может отвергнуть. null означает «нет значения по умолчанию».

Парсер намеренно толерантен, потому что манифест пишется тем сериализатором, который уже был под рукой:

  • toolsets может быть массивом объектов или картой name → toolset.

  • аргументы могут находиться в args, arguments или params — как массив объектов, массив простых имён или карта name → { type, description }.

  • Некорректный инструмент отбрасывается, это не фатально. Одна плохая запись не должна выводить из строя целый экземпляр.

Если /tools отвечает 404, ничего не ломается. Мост откатывается ко встроенному манифесту, содержащему только инструменты уровня контракта, и сообщает агенту, что игра не публикует список команд, — работайте через raw_command и читайте /state. Экземпляры сообщаются как live или live-no-manifest соответственно, а --manifest ./my-game.json поставляет манифест из файла для игры, которую вы не можете изменить.

2. Саморегистрация

Сканирование портов — это слабая форма обнаружения: ограничено диапазоном, который кто-то угадал, молчит об идентичности игры, пока та не ответит, и подвержено ложным отрицаниям во время запуска — именно в тот момент, когда агент скорее всего и смотрит.

Поэтому игра, которая успешно привязала свой отладочный порт, записывает один маленький JSON-файл, называющий себя:

~/.game-bridge/instances/<pid>.json
{
  "name": "Orbital Freight",
  "version": "0.9.2",
  "protocol": 1,
  "port": 7820,
  "pid": 12345,
  "host": "127.0.0.1",
  "started": "2026-08-20T22:27:19.774Z",
  "cwd": "/home/dev/checkouts/main"
}

cwd выбран намеренно: несколько копий одной и той же игры могут работать одновременно, и вопрос «какая это сборка?» иначе невозможно ответить извне процесса.

Правила, которым должен следовать тот, кто пишет файл:

3. Декларация запуска

Проект объявляет, как он запускается, один раз, так что вызывающему никогда не приходится вводить команду сборки или выбирать порт. Поместите gamebridge.json в корень проекта — мост поднимается вверх от своего рабочего каталога, чтобы найти его, как это делает любой другой JS-инструмент для поиска своего конфига, а --config <файл> переопределяет его.

{
  "name": "Orbital Freight",
  "launch": {
    "command": "./gradlew lwjgl3:run -PdebugPort={port} --console=plain",
    "cwd": ".",
    "portRange": "7820-7839",
    "readyTimeoutMs": 180000,
    "env": { "ORBITAL_DEV": "1" }
  }
}

Поле

Значение

command

Командная строка. Подставляется {port}. Порт должен достигать игры отсюда — это и есть весь механизм.

argv

Альтернатива command: ["./run-game", "--port", "{port}"], выполняется без оболочки.

cwd

Рабочий каталог, разрешается относительно этого файла — а не относительно того места, откуда MCP-клиент случайно запустил мост, что почти никогда не совпадает с корнем проекта.

portRange

Диапазон портов, которые может занять лаунчер. По умолчанию 7820-7839, намеренно в стороне от 7777 и 7800-7810, которые обычно занимают вручную.

readyTimeoutMs

Сколько ждать ответа от /health. Холодная сборка плюс JVM — это десятки секунд; по умолчанию 180000.

env, extraArgs

Дополнительные переменные окружения и хвостовые аргументы.

Что лаунчер затем гарантирует:

  • Порт проверяется на занятость дважды — сначала что к нему ничего не привязано, затем что на нём никто не отвечает на проверку здоровья, — потому что игра в процессе запуска уже заняла порт так, как это важно, хотя проверка привязки ещё не прошла бы. Если объявленный диапазон исчерпан, используется порт, назначенный ОС.

  • launch_instance возвращается только когда /health отвечает, так что вызывающему не нужно писать цикл повторных попыток.

  • Сбой запуска сообщается громко, с собственным выводом дочернего процесса. Когда игра не стартует, весь стек — это ответ:

    BridgeUsageError: Launch failed on port 7820: the process exited with code 1.
    Command: ./gradlew lwjgl3:run -PdebugPort=7820 --console=plain
    Working directory: /home/dev/orbital
    Full log: /tmp/game-bridge-logs/instance-7820-1787264781573.log
    
    Last output:
    'gradlew' is not recognized as an internal or external command,
    operable program or batch file.
  • stdout и stderr перехватываются в этот лог-файл на всё время жизни экземпляра, а последние 200 строк хранятся в памяти для instance_log.

  • Дочерние процессы прибираются. При stop_instance, а также при завершении сервера, по SIGINT, SIGTERM или при отключении клиента каждый запущенный экземпляр закрывается — сначала собственная команда close игры, затем завершение дерева процессов, если оно не завершилось само. Закрытая сессия не оставляет окон игры на рабочем столе.

Эскалация за пределы штатного закрытия применяется только к процессам, которые породил этот мост и за которыми он продолжает следить. stop_instance на любом другом порту отказывается и предлагает вам самим попросить игру закрыться.


Инструменты

Инструмент

Аргументы

Что делает

launch_instance

port?, timeoutMs?

Запускает игру, выбирает свободный порт, ждёт ответа от /health, возвращает дескриптор.

list_instances

range?, registry?, scan?, prune?

Реестр плюс сканирование портов. Имена, версии, PID, рабочие каталоги, экраны. Только чтение.

stop_instance

port?, graceMs?

Штатное закрытие, затем эскалация — только для экземпляров, запущенных этим мостом.

instance_log

port?, lines?

Перехваченные stdout/stderr запущенного экземпляра.

list_toolsets

port?

Инструменты этого экземпляра, как он сам их описывает.

describe_toolset

port?, name

Полные JSON-схемы. bridge — для собственных инструментов моста, passthrough — для неопубликованных команд.

call_tool

port?, name, arguments?

Выполняет инструмент, ждёт подтверждения от игры, возвращает итоговый дайджест.

Рекламируются только эти семь. Собственные инструменты игры доступны через call_tool, потому что MCP-клиенту список инструментов выдаётся один раз, при подключении, и он больше не переспрашивает — фиксированный список устарел бы для игры, которая ещё дописывается, и был бы просто неверен, когда одна сессия управляет двумя разными сборками. (--eager выгружает всё заранее для клиентов, которые не умеют обходить дерево открытия.)

Собственный набор инструментов моста

Предоставляется для любой соответствующей игры, какой бы она ни была:

Инструмент

Что делает

get_state

Полный снимок /state или компактный дайджест при summary: true.

get_health

Живость и счётчик кадров.

raw_command

Любая команда по имени, опубликованная или нет.

wait_for

Опрашивает /state, пока поле не достигнет значения, поле не изменится или не появится событие. Так вы дожидаетесь того, о чём запустившая команда не может сообщить сама — например, скриншот, дошедший до диска, или симуляция, дошедшая до кадра N.

close

Штатное завершение; подтверждение — порт замолчал.

Как call_tool разрешает имя

  1. Сначала составные инструменты моста, включая те, что зарегистрировало хост-приложение. Составной инструмент затеняет игровую команду с тем же именем — и это всегда улучшение, а не сюрприз: составной инструмент носит это имя именно потому, что сырая команда возвращается раньше, чем произошло то, о чём её просили.

  2. Затем манифест игры — с одной повторной загрузкой при промахе, чтобы пересобранная игра с новыми командами подхватывалась посреди сессии.

  3. Затем сквозная передача — всё остальное отправляется как сырая команда. Команда, которая есть в игре, но отсутствует в манифесте, по-прежнему работает. Если игра отвечает «неизвестно», вы получаете список того, что она принимает.

Как разрешается port

Каждый инструмент принимает необязательный port (на верхнем уровне или внутри arguments). Он разрешается в таком порядке:

  1. явный port в вызове,

  2. --port в командной строке,

  3. GAME_BRIDGE_PORT в окружении,

  4. 7777.

Так что одиночный экземпляр вообще не думает о портах, а многоэкземплярной сессии не нужен второй сервер.


Управление двумя экземплярами одновременно

Сценарий, ради которого это создавалось: две сборки одной игры рядом, один агент, одна сессия.

// 1. What is already running?
list_instances {}
{
  "registryDir": "/home/dev/.game-bridge/instances",
  "live": [
    { "port": 7801, "discovery": "scan", "status": "live-no-manifest",
      "frame": 2453, "manifest": "fallback", "screen": "GameScreen" },
    { "port": 7820, "discovery": "both", "status": "live", "game": "Orbital Freight",
      "version": "0.9.2", "protocol": 1, "manifest": "game", "pid": 87488,
      "cwd": "/home/dev/checkouts/main", "screen": "MenuScreen",
      "toolsets": ["play", "build", "flow", "bridge"], "launchedByThisBridge": true }
  ],
  "stale": [],
  "notAGame": [],
  "free": [7777, 7802, 7803]
}

Порт 7801 — более старая сборка без /tools: полностью управляемая, просто не самоописывающаяся. Порт 7820 — запущенный этим мостом.

// 2. Start a second one. You do not choose the port.
launch_instance {}
{ "port": 7821, "pid": 90114, "name": "Orbital Freight", "version": "0.9.3-rc1",
  "cwd": "/home/dev/checkouts/rc", "readyInMs": 4080,
  "logFile": "/tmp/game-bridge-logs/instance-7821-1787264835950.log" }
// 3. Same seed, same move, both runs.
call_tool { "port": 7820, "name": "set_seed", "arguments": { "seed": 12345 } }
call_tool { "port": 7821, "name": "set_seed", "arguments": { "seed": 12345 } }

call_tool { "port": 7820, "name": "drop", "arguments": { "x": 1.2 } }
call_tool { "port": 7821, "name": "drop", "arguments": { "x": 1.2 } }

Каждый возвращает состояние после применения команды, так что их можно напрямую сравнивать:

{
  "port": 7821, "tool": "drop", "via": "manifest", "command": "drop",
  "applied": true, "commandId": 18, "confirmation": "completedCommandId",
  "frame": 948, "screen": "GameScreen",
  "game": { "score": 1280, "state": "RUNNING" },
  "events": ["merge:cherry", "score:+40"]
}
// 4. Wait for something the command could not report.
call_tool { "port": 7821, "name": "wait_for",
            "arguments": { "path": "game.pendingMerges", "equals": 0, "timeoutMs": 5000 } }

// 5. Clean up what you started. 7801 is not yours - leave it alone.
stop_instance { "port": 7821 }
{ "port": 7821, "stopped": true, "how": "closed cleanly" }

Когда что-то не так

Мост различает сбои, которые снаружи выглядят одинаково:

GameOffline: No game is answering on http://127.0.0.1:7809.
Start one with:
  ./gradlew lwjgl3:run -PdebugPort=7809

NotAGameSurface: Something is listening on http://127.0.0.1:7802, but it is not a
debuggable game: GET /health returned HTTP 404.
A drivable game must answer GET /health with {"ok":true,"frame":N}. Check whether
another process has taken this port.

CommandTimeout: Command 'restart' was queued on port 7801 but was not applied
within 5000ms. The game accepted it, so it is probably blocked, frozen, or on a
screen that ignores this command.

Задайте команду, указанную в первом сообщении, с помощью --launch-hint "make run PORT={port}" (или позвольте launch_instance выполнить запуск).


CLI

npx @wildware/game-bridge-mcp [options]

  -p, --port <n>           Default port for tools that do not name one (default 7777)
      --scan-range <spec>  Ports list_instances sweeps (default 7777,7800-7810)
      --no-scan            Discover only via the instance registry
      --no-registry        Discover only by scanning ports
      --registry-dir <dir> Where instance entries live (default ~/.game-bridge/instances)
      --config <file>      Project launch declaration (default: nearest gamebridge.json)
      --launch-hint <cmd>  Command shown when a port is dead; {port} is substituted
      --manifest <file>    Tool manifest for games that do not serve GET /tools
      --eager              Advertise every tool flatly, for clients that cannot discover
      --timeout <ms>       HTTP and command timeout (default 5000)
  -h, --help
  -v, --version

Окружение: GAME_BRIDGE_PORT, GAME_BRIDGE_SCAN_RANGE (или GAME_BRIDGE_SCAN), GAME_BRIDGE_LAUNCH_HINT (или GAME_BRIDGE_LAUNCH), GAME_BRIDGE_MANIFEST, GAME_BRIDGE_CONFIG, GAME_BRIDGE_INSTANCES, GAME_BRIDGE_HOME.

Всё, что мост пишет в журнал, уходит в stderr; stdout — это транспорт MCP, и случайная строка в нём портит поток протокола.


Использование в собственном проекте

Составные части экспортируются так же, как поставляются в виде CLI. Если вашей игре нужны инструменты, которые выстраивают цепочку из нескольких команд — «сбросить, затем дождаться, пока доска устаканится, затем сообщить дельту счёта» — регистрируйте их как составные и наследуйте протокол, лаунчер, обнаружение и сообщения об ошибках, вместо того чтобы поддерживать вторую их копию.

#!/usr/bin/env node
import { parseCli, applyProjectConfig, startStdioServer } from "@wildware/game-bridge-mcp";

const { config } = parseCli(process.argv.slice(2), process.env);
await applyProjectConfig(config);

await startStdioServer(config, {
  composites: [
    {
      name: "drop_and_settle",
      description: "Drop at world x and wait until nothing is moving. The main way to play.",
      only: "Orbital Freight",            // never offered to a game that has no crates
      args: [{ name: "x", type: "number", required: true, description: "World x" }],
      async run(ctx) {
        const before = await ctx.state();
        await ctx.commandAndSync("drop", { x: ctx.args.x });
        const settled = await ctx.call("wait_for", { path: "game.moving", equals: 0, timeoutMs: 10000 });
        const after = await ctx.state();
        return { settled: settled.matched, scoreDelta: after.game.score - before.game.score };
      },
    },
  ],
});

Составной инструмент получает контекст, ограниченный одним экземпляром — state, health, command, commandAndSync, call (любой другой инструмент), manifest, summarise, sleep — так что ему никогда не приходится думать о портах. only перечисляет игры, которым он подходит, сверяясь с game.name из манифеста; мост, претендующий на универсальность, не должен предлагать drop_and_settle авиасимулятору.

Правило для того, что попадает в составной инструмент: он либо выстраивает цепочку из нескольких команд, либо ждёт того, о чём /command сообщить не может. Всё, что является одной командой с одним набором аргументов, принадлежит собственному манифесту игры, где остаётся в шаге с кодом, который её реализует.

Низкоуровневые части — Bridge, GameClient, Launcher, readRegistry, normaliseManifest — тоже экспортируются. Bridge и GameClient принимают необязательный fetchImpl — именно так тестовый набор прогоняет всё целиком без игры и без сокета.


Разработка

npm install
npm run build     # TypeScript -> dist/
npm test          # builds, then runs node --test

Публикация

Пока не опубликовано в npm. Когда будет:

npm version minor          # keep SERVER_VERSION in src/server.ts in step
npm test                   # prepublishOnly runs build + test again
npm pack --dry-run         # confirm dist/, README.md and LICENSE are the payload
npm publish                # publishConfig.access is already "public"

files в package.json ограничивает архив dist/, README.md и LICENSE; prepare собирает при установке из git, поэтому зависимость, установленная через git, работает без включённого в репозиторий dist/.

Лицензия

MIT — см. LICENSE.

Available Tools

7 tools
call_toolA

Run a tool on one instance and return the result. Accepts any tool from any of that instance's toolsets, and any raw debug command it understands even if unpublished. Commands are waited on until the game reports them applied, so the state returned is the state after the command ran.

NameRequiredDescriptionDefault
nameYesTool or command name
portNoDebug port of the game instance to talk to. Defaults to the bridge's --port, then GAME_BRIDGE_PORT, then 7777. launch_instance returns one; list_instances finds the rest.
argumentsNoArguments for the tool

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It discloses that it accepts unpublished raw debug commands, runs on one instance, waits until the game reports the command applied, and returns the state after execution. This gives an agent crucial insight into side effects and synchronization behavior beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two focused sentences with no filler. The primary purpose is front-loaded, and the important behavioral qualifiers about command applicability and waiting semantics are delivered compactly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is largely complete for a generic dynamic executor, especially given the schema documents parameters. It covers purpose, target scope, command breadth, and post-command state. It does not enumerate return-value shapes or possible errors, but that is difficult for arbitrary tools and is not a major gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaningful semantics to the 'name' parameter by explaining it can be any tool from the instance's toolsets or any raw debug command, even unpublished. It also implicitly ties 'port' to 'one instance' and clarifies that arguments are forwarded to the selected tool or command.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Run a tool on one instance and return the result.' It clearly distinguishes call_tool from the lifecycle/discovery siblings (launch_instance, list_instances, stop_instance, instance_log) by framing it as the generic executor for any tool or command.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage context instead of stating it explicitly: use this tool when you need to run any tool or raw debug command against a single instance. However, it never mentions alternatives or calls out when not to use it, such as preferring instance_log for log retrieval or launch_instance for starting a game.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

describe_toolsetA

Full schemas for the tools in one toolset on one instance. 'bridge' is the toolset this bridge adds itself; 'passthrough' explains how to send commands the game has not published.

NameRequiredDescriptionDefault
nameYesToolset name, 'bridge', or 'passthrough'
portNoDebug port of the game instance to talk to. Defaults to the bridge's --port, then GAME_BRIDGE_PORT, then 7777. launch_instance returns one; list_instances finds the rest.

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry behavioral disclosure. It implies a read-only introspection operation by saying it provides 'full schemas' and 'explains' commands, which is reasonably transparent. It does not mention error behavior, whether a running instance is required, or that it makes no modifications, but the read-only nature is strongly implied.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact, with the core purpose front-loaded in the first sentence and essential special-case terminology in the second. Every sentence contributes useful information and there is no filler or repetition of schema content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple introspection tool with two parameters and full schema coverage, the description covers the essential semantics including special name values and instance scoping. It does not describe the exact return structure, but 'full schemas' sufficiently conveys the expected output for this tool type. Missing explicit usage guidance vs siblings is the main gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The tool description adds genuine value beyond the schema by explaining what 'bridge' and 'passthrough' mean for the name parameter, which the schema only lists as allowed values. Port semantics are already fully covered in the parameter description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool returns full schemas for all tools in a toolset on a single instance, which is a specific, recognizable purpose. It also distinguishes itself from siblings like list_toolsets by emphasizing schema detail and instance scoping. The special values 'bridge' and 'passthrough' add useful differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The intended use is implied: if an agent needs full tool schemas, this is the tool. However, it does not explicitly contrast with list_toolsets, call_tool, or other siblings, nor state when not to use it. The explanation of 'bridge' and 'passthrough' gives usage context but not alternative-based selection guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

instance_logA

The captured stdout/stderr of an instance this bridge launched. When a game fails to boot, or dies mid-session, the stack trace is here and nowhere else.

NameRequiredDescriptionDefault
portNoDebug port of the game instance to talk to. Defaults to the bridge's --port, then GAME_BRIDGE_PORT, then 7777. launch_instance returns one; list_instances finds the rest.
linesNoHow many trailing lines (default 50)

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral burden. It clearly states this is a read-only view of captured stdout/stderr from bridge-launched instances and that the interesting failure information is 'here and nowhere else', giving a strong execution-time mental model. It doesn't mention output formatting or truncation, but the captured-log framing covers the main behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences: the first defines what the tool returns, the second says when to use it. No filler, no repetition of schema details, and the key use case is front-loaded early.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only log tool with two optional parameters and schema-covered parameter semantics, this description plus the schema is nearly complete. It tells the agent what the tool does, which scenarios call for it, and how parameters work. A minor gap is the exact return format, but with no output schema this is not critical.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the parameters port and lines already have clear meaning, defaults, and port resolution order. The description adds no extra parameter-level detail, but the baseline is 3 when schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description identifies the tool's resource: captured stdout/stderr for an instance launched by this bridge, and ties it to boot failures and mid-session crashes. It lacks an explicit verb like 'get' or 'read', but the meaning is unmistakable and it is clearly distinct from the launch/list/stop siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives direct usage context: when a game fails to boot or dies mid-session, the stack trace is here. It doesn't name alternative tools, but among lifecycle/toolset siblings this one is obviously the log-reader, so the guidance is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

launch_instanceA

Start a game instance and wait until it answers. The bridge picks a free port itself, so you never choose one and never collide with someone else's instance, and it owns the process: it is reaped when this server shuts down. Uses the project's launch declaration (gamebridge.json). Returns the port to pass to every other tool. Prefer this over starting the game yourself.

NameRequiredDescriptionDefault
portNoForce a specific port instead of letting the bridge choose. Rarely needed.
timeoutMsNoHow long to wait for the game to answer. A cold build plus a JVM can take minutes.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full behavioral burden, and it largely succeeds. It discloses that launch is synchronous ('wait until it answers'), that ports are auto-selected to avoid collisions, that the bridge owns the process and reaps it on shutdown, that it reads the project's gamebridge.json, and that the tool returns a port. These are exactly the behavioral details an agent needs beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Every sentence earns its place. The description is front-loaded with the core action and wait behavior, then explains port auto-selection, process ownership, config source, return value, and provides a usage recommendation. It is compact, well-organized, and free of filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with two optional parameters and no output schema, the description explains the key runtime contract: the launched process lifecycle, how the port is chosen, what the return value is for, and why the tool should be preferred over manual startup. An agent has enough context to select and call the tool correctly, including what to do with the returned port.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents both parameters (port and timeoutMs), so baseline is 3. The description adds meaningful context beyond the schema: the bridge automatically picks a free port, so forcing one is rarely needed, and the returned port must be passed to all other tools. This helps an agent understand when and why to use or omit the optional port parameter. Timeout semantics are left mostly to the schema, but the description's 'wait until it answers' supports the intent.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description starts with a clear, specific verb and resource: 'Start a game instance and wait until it answers.' It also distinguishes itself from starting the game manually and, by mentioning the returned port that every other tool needs, it implicitly differentiates from listing/stopping/logging tools. This is unambiguous and not a tautology.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context: it is the preferred way to launch the game, the bridge handles port allocation, and the tool waits until the game responds. It explicitly says 'Prefer this over starting the game yourself,' which is strong guidance. It does not enumerate exact when-not-to-use conditions for each sibling, but the context is sufficient for an agent to choose it appropriately.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_instancesA

What is running: instances that self-registered, plus a sweep of the configured port range for games that predate the registry. Reports name, version, pid, working directory, current screen and whether each was found via the registry or the scan. Read-only, so it is safe to point at instances someone else owns. Use it to attach to a game you did not launch.

NameRequiredDescriptionDefault
scanNoSweep the port range (default true)
pruneNoDelete registry entries whose port has been verified dead. Off by default: a game still binding its port looks identical to a crashed one.
rangeNoPorts to sweep, e.g. '7777,7800-7810'. Defaults to --scan-range.
registryNoRead the instance registry (default true)

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It explicitly discloses the read-only safety property ('Read-only, so it is safe to point at instances someone else owns'), which is the key behavioral trait an agent needs. It does not contradict any annotations since none exist.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the core purpose ('What is running'), followed by reported fields, then safety and use case. Zero wasted words; every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully enumerates the returned fields and that coverage is complete for a read-only enumeration tool. The only mild gap is that the output format/ordering is unspecified, which is a minor omission for a listing tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline 3 applies even without param detail in the description. The description adds conceptual framing (the port sweep relation to 'games that predate the registry') but the schema already documents scan, prune, range, and registry thoroughly, including the dangerous prune default behavior.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Leads with a specific verb and object — 'What is running: instances that self-registered, plus a sweep of the configured port range'. It names the exact fields reported (name, version, pid, working directory, current screen) and the two discovery sources (registry vs scan), and the read-only framing plus the 'attach to a game you did not launch' use case clearly separates it from the launch/stop/log siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit purpose statement — 'Use it to attach to a game you did not launch' — and explains the two data sources, which signals when a scan is needed (old instances) vs the registry alone. It does not explicitly name when NOT to use it or point to an alternative (e.g. instance_log for logs), but the context is clear enough for an agent to select it for enumeration.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_toolsetsA

List the toolsets one instance publishes, as that instance describes itself. Different ports can legitimately return different lists. Start here, then describe_toolset, then call_tool.

NameRequiredDescriptionDefault
portNoDebug port of the game instance to talk to. Defaults to the bridge's --port, then GAME_BRIDGE_PORT, then 7777. launch_instance returns one; list_instances finds the rest.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden of behavioral disclosure. It reveals that the response reflects the instance's self-description and can vary by port, which is meaningful behavioral context. It also implies a read-only listing operation, though it doesn't go deeper into failure cases or return format.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences deliver the purpose, a critical caveat, and the recommended workflow. Every sentence earns its place, and the key distinction is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the essential workflow, port variability, and the self-describing nature of the response. It doesn't describe the exact return structure, but for a simple list operation without an output schema this is a minor gap given the clear intent and provided next steps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single 'port' parameter is fully documented in the schema, including defaults and how to obtain a port from sibling tools. The description adds only the note that different ports may return different lists, which supplements but does not significantly expand on the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb ('List') and resource ('toolsets one instance publishes') and adds the important qualifier 'as that instance describes itself.' It is immediately distinguishable from sibling tools like launch_instance, list_instances, describe_toolset, and call_tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly instructs the agent to start here and then proceed to describe_toolset and call_tool, giving a clear workflow. It also warns that different ports can return different lists, which is essential context for choosing which instance/port to query.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

stop_instanceA

Shut down an instance this bridge launched: the game's own close command first, then termination of the process tree if it will not go. Only ever applies to a process this bridge started. To ask a game you did not launch to exit, use call_tool { name: 'close' }.

NameRequiredDescriptionDefault
portNoDebug port of the game instance to talk to. Defaults to the bridge's --port, then GAME_BRIDGE_PORT, then 7777. launch_instance returns one; list_instances finds the rest.
graceMsNoHow long to wait for a clean exit

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it delivers: it discloses the two-stage shutdown behavior, the escalation to process-tree termination, and the boundary that only bridge-launched processes are affected. This is exactly the kind of hidden destructive behavior an agent needs to know before invoking.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact sentences, with the core action and escalation front-loaded and no filler. Every sentence earns its place; nothing restates the tool name or repeats schema content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a shutdown tool with two optional parameters, clear destructive behavior, explicit scope boundaries, and a named sibling alternative, everything needed to select and invoke it correctly is present. The absence of an output schema is not a practical gap since the agent does not need return-value details to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Both parameters are already fully described in the input schema, including port resolution order and graceMs purpose. The description adds no additional parameter-level detail, but with 100% schema coverage the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Shut down') and resource ('an instance this bridge launched'), and explicitly contrasts it with call_tool's 'close' command. An agent can immediately tell this tool is for shutdown of bridge-launched instances only.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly scopes the tool to processes this bridge started and gives the exact alternative for games not launched by the bridge: use call_tool { name: 'close' }. This gives the agent both a clear when-to-use and when-not-to-use rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 7 tool updatesv0.1.0
    • First observedcall_tool
    • First observeddescribe_toolset
    • First observedinstance_log
    • First observedlaunch_instance
    • First observedlist_instances
    • First observedlist_toolsets
    • First observedstop_instance

TDQS

A4.4/5.0

Scored across 7 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: launch, list, stop, get log, list toolsets, describe toolset, and call tool. No overlapping functionality.

Naming Consistency4/5

Most tools follow the verb_noun pattern (launch_instance, list_instances, stop_instance, list_toolsets, describe_toolset, call_tool), but 'instance_log' is a noun phrase rather than a verb action, which is a minor inconsistency.

Tool Count5/5

Seven tools is well-scoped for a game bridge server, covering management and introspection without being excessive or insufficient.

Completeness5/5

The tool set covers the full lifecycle of game instances (launch, list, stop, log) and toolset interaction (list, describe, call), leaving no obvious gaps for the stated purpose.

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers