Skip to main content
Glama

game-bridge-mcp

Lassen Sie einen KI-Agenten Ihr Spiel starten, es steuern und lesen, was passiert ist – über HTTP, ein Port pro Instanz.

Ihr Spiel weiß bereits alles über sich selbst: was auf dem Bildschirm ist, wo sich jede Entität befindet, welche Befehle es akzeptiert. game-bridge-mcp ist ein MCP-Server, der das einem Agenten übergibt – als Werkzeuge, die der Agent aufrufen kann, entdeckt aus dem laufenden Spiel und nicht hier fest codiert.

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

Drei Dinge machen es mehr als ein Debug-Bridge-Skript, das Sie an einem Nachmittag schreiben würden:

  • Es startet Instanzen und wählt ihre Ports. Kein Aufrufer wählt jemals einen Port oder tippt einen Build-Befehl, sodass zwei Agenten nicht kollidieren können, und die Brücke erntet, was sie gestartet hat – keine verwaisten Spielfenster nach einer Sitzung.

  • Jedes Werkzeug nimmt einen port. Eine Brücke steuert jede Instanz, die Sie laufen haben: mehrere Agenten auf einer Maschine oder ein Agent, der zwei Builds nebeneinander vergleicht.

  • Die Werkzeugliste kommt vom Spiel. Die Brücke ruft GET /tools von jeder Instanz zur Laufzeit ab, sodass ein Debug-Befehl, den Sie heute Morgen hinzugefügt haben, heute Nachmittag aufrufbar ist – keine Veröffentlichung dieses Pakets, keine erneute Verbindung und keine Abweichung zwischen dem, was der Agent denkt, dass das Spiel akzeptiert, und dem, was es akzeptiert.

Es ist engine-agnostisch. Jede Sprache, alles, was vier kleine HTTP-Endpunkte auf localhost bedienen kann. Der Vertrag ist absichtlich kurz.


Schnellstart

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

Registrieren Sie es bei einem MCP-Client – für Claude Code, aus Ihrem Projektverzeichnis:

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

Dann, von der Seite des Agenten:

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 benötigt eine Startdeklaration. Alles andere funktioniert mit jedem Spiel, das die HTTP-Oberfläche implementiert, unabhängig davon, ob diese Brücke es gestartet hat oder nicht.


Related MCP server: minecraft-mcp

Der Vertrag

Implementieren Sie dies und Ihr Spiel ist durch diese Brücke von jedem Agenten steuerbar, ohne dass hier Code vorhanden ist, der etwas darüber weiß. Es hat drei Teile, und jeder Teil bringt etwas Bestimmtes:

Teil

Was es bringt

1. Die HTTP-Oberfläche

Lesen und Steuern einer laufenden Instanz.

2. Selbstregistrierung

Instanzen finden, ohne Ports zu erraten.

3. Die Startdeklaration

Instanzen starten, ohne dass ein Mensch einen Port wählt.

Nur Teil 1 ist erforderlich. Teil 2 macht die Erkennung zuverlässig; Teil 3 macht das Ganze angenehm.

1. Die HTTP-Oberfläche

Stellen Sie diese auf 127.0.0.1:<port> bereit, wobei der Port von einem expliziten Debug-Flag stammt. Binden Sie nur an Loopback und halten Sie die gesamte Oberfläche ausgeschaltet, es sei denn, das Spiel wurde mit diesem Flag gestartet: Dies ist eine Debug-Oberfläche, kein Netzwerkdienst.

GET /health – erforderlich

Der Lebendigkeits- und Identitätscheck. Die Erkennung ruft ihn für jeden Port in einem Bereich auf, also muss er billig sein.

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

ok: true ist das, was den Port als einen von uns markiert. Ein Port, der mit etwas anderem auf HTTP antwortet, wird dem Agenten als „etwas anderes hat diesen Port belegt“ gemeldet – ein anderes Problem mit einer anderen Lösung als „das Spiel läuft nicht“.

frame ist ein Zähler, der für die Lebensdauer des Prozesses ansteigt. Die Brücke beobachtet ihn: Ein frame, das rückwärts geht, bedeutet, dass ein neuer Prozess auf diesem Port antwortet, und das zwischengespeicherte Tool-Manifest wird automatisch verworfen. Das macht Wiederaufbau und Neustart für den Agenten unsichtbar.

GET /state – erforderlich

Der vollständige Schnappschuss: alles, was ein Agent wissen möchte, als JSON. Es gibt kein erforderliches Schema – es ist Ihr Spiel – aber ein paar konventionelle Felder schalten Brückenfunktionen frei:

{
  "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" }
}

Feld

Warum die Brücke sich darum kümmert

frame

Neustarterkennung; die Fallback-Bestätigung, dass ein Befehl ausgeführt wurde.

completedCommandId

Die starke Bestätigung, dass ein Befehl ausgeführt wurde – siehe unten.

ui.screen

Wird von list_instances gemeldet, sodass fünf Instanzen auf einen Blick unterscheidbar sind.

ui.elements[].label / .visible

Im kompakten get_state-Digest enthalten.

events[].m

Aktuelle Ereignisse, die nach jedem Befehl zurückgegeben werden, damit der Agent die Konsequenz sieht. Auch einfache Zeichenketten werden akzeptiert.

game

Skalare Felder sind im Digest enthalten. Verschachtelte Objekte und Arrays nicht – dort leben die megabytegroßen Entitätslisten.

Alles andere, was Sie hier einfügen, wird von get_state unverändert durchgereicht.

GET /command – erforderlich

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

Der Befehlsname ist als cmd verschlüsselt, nicht als name – Befehle nehmen routinemäßig ein eigenes name-Argument an, und ein doppelter Abfrageschlüssel würde den aufgerufenen Befehl stillschweigend überschreiben. Jeder andere Abfrageparameter ist ein Argument.

Dieser Endpunkt ist Fire-and-Forget, und das ist das Wichtigste, was man über den Vertrag verstehen muss. Er antwortet vom HTTP-Thread in dem Moment, in dem der Befehl in die Warteschlange gestellt wird; der Befehl selbst läuft später im Spiel-Thread. Ein Client, der sofort danach /state liest, liest die Welt von vor dem Befehl. Der Test sieht instabil aus; das Spiel ist in Ordnung.

Die Brücke handhabt das, und die Art und Weise, wie sie es tut, sollte Ihr Spiel unterstützen:

  1. GET /command?... → notieren Sie die zurückgegebene commandId.

  2. Pollen Sie GET /state, bis completedCommandId >= commandId.

  3. Geben Sie diesen Zustand zurück – wirklich nachdem der Befehl ausgeführt wurde.

Wenn Ihr Spiel completedCommandId nicht veröffentlicht, degradiert die Brücke dazu, zu warten, bis frame um zwei vorrückt, und kennzeichnet das Ergebnis als "confirmation": "frames-advanced", damit der Agent weiß, dass er die schwächere Garantie erhalten hat. completedCommandId zu veröffentlichen ist eine Handvoll Zeilen und lohnt sich:

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

Ein close-Befehl, der das Spiel über sein normales Herunterfahren beendet, wird dringend empfohlen: Er ermöglicht es einem Agenten, eine Instanz zu beenden, ohne einen Prozess zu töten. Die Brücke behandelt close besonders – sie wartet nie auf eine Vervollständigung, die nicht eintreffen kann, sondern wartet darauf, dass der Port ruhig wird.

GET /tools – optional, aber das ist der gute Teil

Das Manifest: was Ihrem Spiel gesagt werden kann, in seinen eigenen Worten.

{
  "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 }"]
  }
}

Feld

Bedeutung

game.name, game.version

Identität. Wird von list_instances angezeigt, so kann ein Agent fünf laufende Instanzen unterscheiden.

game.protocol

Versioniert das Dokument, nicht den Befehlssatz. Einen Befehl hinzuzufügen ändert hier nichts; das Manifest umzustrukturieren schon. Es ermöglicht einer Brücke, „Ich kann das nicht lesen“ von „Dieses Spiel kennt andere Befehle als beim letzten Mal“ zu unterscheiden. Aktuelle Version: 1.

toolsets[]

Gruppen, benannt nach dem, was ein Aufrufer zu tun versucht, nicht nach der Anordnung Ihres Codes. Halten Sie sie wenige und offensichtlich.

tools[].name

Was der Agent aufruft.

tools[].description

Für den Agenten geschrieben. Sagen Sie, was es tut und wann man es verwenden sollte – das ist der Text, über den das Modell nachdenkt.

tools[].args[]

{ name, type, description, required, default }. type ist ein JSON-Schema-Typname, sodass ein Konverter sowohl Spielbefehle als auch Brückenwerkzeuge bedient.

tools[].command

Der zu sendende cmd, falls er sich vom Werkzeugnamen unterscheidet. Standardmäßig der Name.

tools[].sync

false für Befehle, auf die nicht gewartet werden darf. Standardmäßig true.

tools[].inputSchema

Wenn Sie bereits JSON-Schema haben, senden Sie es anstelle von args und es wird wörtlich verwendet.

passthrough

Freitext plus Beispiele, die Befehle beschreiben, die Sie nicht formal veröffentlicht haben.

Standardwerte können Zeichenketten sein ("true", "0.05") – ein Manifest, das aus einer typisierten Sprache serialisiert wurde, rendert sie normalerweise so. Die Brücke fügt sie in die Beschreibung ein, anstatt default im Schema auszugeben, weil default: "false" bei einer boolean-Eigenschaft von einem strengen Client abgelehnt werden könnte. null bedeutet „kein Standardwert“.

Der Parser ist bewusst tolerant, weil ein Manifest in dem Serialisierer geschrieben wird, der gerade zur Hand war:

  • toolsets kann ein Array von Objekten oder eine Map von name → toolset sein.

  • Argumente können unter args, arguments oder params liegen, als Array von Objekten, als Array von bloßen Namen oder als Map von name → { type, description }.

  • Ein fehlerhaftes Werkzeug wird verworfen, nicht fatal. Ein schlechter Eintrag darf nicht eine ganze Instanz offline nehmen.

Wenn /tools 404 liefert, bricht nichts. Die Brücke fällt auf ein eingebautes Manifest zurück, das nur die Vertragswerkzeuge enthält, und teilt dem Agenten mit, dass das Spiel keine Befehlsliste veröffentlicht, also arbeiten Sie über raw_command und lesen Sie /state. Instanzen werden entsprechend als live oder live-no-manifest gemeldet, und --manifest ./my-game.json liefert eines aus einer Datei für ein Spiel, das Sie nicht ändern können.

2. Selbstregistrierung

Port-Scanning ist die schwache Form der Erkennung: begrenzt durch einen Bereich, den jemand erraten hat, still über die Identität eines Spiels, bis es antwortet, und anfällig für falsch negative Ergebnisse während des Starts – genau der Moment, in dem ein Agent am wahrscheinlichsten sucht.

Ein Spiel, das seinen Debug-Port erfolgreich gebunden hat, schreibt also eine kleine JSON-Datei, die sich selbst benennt:

~/.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 ist beabsichtigt: Mehrere Checkouts desselben Spiels laufen gleichzeitig, und „Welcher Build ist das?“ ist sonst von außerhalb des Prozesses nicht zu beantworten.

Die Regeln, die ein Schreiber befolgen muss:

  • Schreibe den Eintrag nach dem Binden des Ports, niemals davor. Ein Eintrag für einen Port, der nie beansprucht wurde, ist schlimmer als gar kein Eintrag.

  • Lösche ihn beim sauberen Herunterfahren.

  • Lass niemals zu, dass ein Registry-Fehler das Spiel zerstört. Ein nicht beschreibbares Verzeichnis, ein schreibgeschütztes Home-Verzeichnis, eine Sandbox – das Spiel muss trotzdem starten und seine Endpunkte bedienen. Das ist Werbung, keine Infrastruktur.

  • Beachte GAME_BRIDGE_INSTANCES (das Einträge-Verzeichnis) oder GAME_BRIDGE_HOME (dessen Elternverzeichnis), falls eines gesetzt ist.

Die Regeln, die ein Leser befolgen muss – und diese sind wichtiger:

  • Einträge sind beratend, niemals maßgeblich. Ein Absturz oder ein erzwungenes Beenden hinterlässt die Datei. Das passiert in der Praxis ständig.

  • Überprüfe jeden Eintrag mit GET /health, bevor du ihm glaubst. Ein Eintrag, dessen Port nicht antwortet, ist eine veraltete Datei, kein laufendes Spiel, und muss als solche gemeldet werden, nicht als Instanz.

  • Vertraue niemals einem Eintrag über dem Live-Spiel. Die Bridge übernimmt Name und Version von /tools, wenn das Spiel antwortet, und verwendet den Eintrag nur für das, was die Leitung nicht sagen kann: PID, Arbeitsverzeichnis, Startzeit.

  • Lösche standardmäßig keine Dateien anderer Prozesse. Ein Spiel, das seinen Port noch bindet, ist für ein oder zwei Sekunden nicht von einem abgestürzten zu unterscheiden. Die Bridge bereinigt nur bei explizitem prune: true und nur, nachdem sie verifiziert hat, dass der Port tot ist.

  • Scanne weiterhin. Es gibt Spiele, die älter als die Registry sind; die Bridge führt Registry-Einträge und einen Port-Scan zusammen und dedupliziert nach Port, wobei sie die discovery jeder Instanz als registry, scan oder both meldet.

3. Die Startdeklaration

Ein Projekt deklariert einmal, wie es gestartet wird, damit kein Aufrufer jemals einen Build-Befehl eingibt oder einen Port wählt. Lege gamebridge.json im Projektstamm ab – die Bridge geht von ihrem Arbeitsverzeichnis nach oben, um es zu finden, so wie jedes andere JS-Tool seine Konfiguration findet, und --config <file> überschreibt das.

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

Feld

Bedeutung

command

Shell-Befehlszeile. {port} wird ersetzt. Der Port muss von hier aus das Spiel erreichen – das ist der gesamte Mechanismus.

argv

Alternative zu command: ["./run-game", "--port", "{port}"], ohne Shell ausgeführt.

cwd

Arbeitsverzeichnis, relativ zu dieser Datei aufgelöst – nicht zu dem Ort, an dem der MCP-Client die Bridge zufällig gestartet hat, was fast nie das Projekt ist.

portRange

Ports, die der Launcher beanspruchen darf. Standard 7820-7839, bewusst frei von 7777 und 7800-7810, die Ports, die Leute von Hand vergeben.

readyTimeoutMs

Wie lange auf /health gewartet wird. Ein kalter Build plus eine JVM dauert zig Sekunden; der Standard ist 180000.

env, extraArgs

Zusätzliche Umgebung und nachgestellte Argumente.

Was der Launcher dann garantiert:

  • Der Port wird zweimal als frei verifiziert – nichts ist daran gebunden und nichts beantwortet einen Health-Check darauf –, weil ein Spiel, das gerade startet, den Port auf die Weise beansprucht hat, die zählt, während es Millisekunden zuvor einen Bind-Test noch fehlschlug. Wenn der deklarierte Bereich voll ist, fällt es auf einen vom Betriebssystem zugewiesenen Port zurück.

  • launch_instance gibt erst zurück, wenn /health antwortet, sodass ein Aufrufer nie eine Wiederholungsschleife schreiben muss.

  • Ein Startfehler schlägt laut fehl, mit der eigenen Ausgabe des Kindprozesses. Wenn ein Spiel nicht startet, ist der Stack-Trace die ganze Antwort:

    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 und stderr werden für die Lebensdauer der Instanz in diese Logdatei erfasst, und die letzten 200 Zeilen werden für instance_log im Speicher gehalten.

  • Kinder werden eingesammelt. Bei stop_instance und beim Herunterfahren des Servers, SIGINT, SIGTERM oder wenn der Client die Verbindung trennt, wird jede gestartete Instanz geschlossen – zuerst der eigene close-Befehl des Spiels, dann die Beendigung des Prozessbaums, falls es nicht gehen will. Eine geschlossene Sitzung hinterlässt niemals Spielfenster auf dem Desktop.

Die Eskalation über ein sauberes Schließen hinaus gilt nur für Prozesse, die diese Bridge gestartet hat und noch verfolgt. stop_instance auf einem anderen Port verweigert und sagt dir, das Spiel zu bitten, sich selbst zu schließen.


Werkzeuge

Werkzeug

Argumente

Was es tut

launch_instance

port?, timeoutMs?

Startet ein Spiel, wählt einen freien Port, wartet auf /health, gibt das Handle zurück.

list_instances

range?, registry?, scan?, prune?

Registry plus Port-Scan. Namen, Versionen, PIDs, Arbeitsverzeichnisse, Bildschirme. Schreibgeschützt.

stop_instance

port?, graceMs?

Sauberes Schließen, dann Eskalation – nur für Instanzen, die diese Bridge gestartet hat.

instance_log

port?, lines?

Erfasste stdout/stderr einer gestarteten Instanz.

list_toolsets

port?

Die Toolsets dieser Instanz, wie sie sich selbst beschreibt.

describe_toolset

port?, name

Vollständige JSON-Schemas. bridge für die eigenen Werkzeuge der Bridge, passthrough für unveröffentlichte Befehle.

call_tool

port?, name, arguments?

Führt ein Werkzeug aus, wartet auf die Bestätigung des Spiels, gibt den resultierenden Digest zurück.

Nur diese sieben werden beworben. Die eigenen Werkzeuge des Spiels werden über call_tool erreicht, weil ein MCP-Client die Werkzeugliste nur einmal erhält, wenn er sich verbindet, und nie wieder fragt – eine feste Liste wäre für ein Spiel, das noch geschrieben wird, veraltet und schlicht falsch, wenn eine Sitzung zwei verschiedene Builds steuert. (--eager flacht alles im Voraus ab für Clients, die keinen Discovery-Pfad gehen können.)

Das eigene Toolset der Bridge

Für jedes konforme Spiel bereitgestellt, was auch immer es ist:

Werkzeug

Was es tut

get_state

Die vollständige /state-Momentaufnahme, oder summary: true für einen kompakten Digest.

get_health

Lebendigkeit und Frame-Zähler.

raw_command

Jeder Befehl nach Namen, veröffentlicht oder nicht.

wait_for

Pollt /state, bis ein Feld einen Wert erreicht, ein Feld sich ändert oder ein Ereignis erscheint. So wartest du auf das, was der Befehl, der es gestartet hat, nicht melden kann – einen in der Warteschlange befindlichen Screenshot, der die Festplatte erreicht, eine Simulation, die Frame N erreicht.

close

Sauberes Herunterfahren; der Port, der still wird, ist die Bestätigung.

Wie call_tool einen Namen auflöst

  1. Die Composites der Bridge, einschließlich aller, die eine Host-Anwendung registriert hat. Ein Composite überschattet einen Spielbefehl mit demselben Namen, was immer eine Verbesserung und keine Überraschung ist: Ein Composite trägt genau deshalb diesen Namen, weil der rohe Befehl zurückkehrt, bevor das, worum er gebeten wurde, geschehen ist.

  2. Das Manifest des Spiels – mit einem erneuten Abruf bei einem Fehlschlag, sodass ein neu gebautes Spiel mit neuen Befehlen mitten in der Sitzung erkannt wird.

  3. Passthrough – alles andere wird als roher Befehl gesendet. Ein Befehl, der im Spiel existiert, aber nicht in seinem Manifest, funktioniert heute noch. Wenn das Spiel ihn als unbekannt ablehnt, erhältst du die Liste dessen, was es akzeptiert.

Wie port aufgelöst wird

Jedes Werkzeug akzeptiert einen optionalen port (auf oberster Ebene oder innerhalb von arguments). Er wird in dieser Reihenfolge aufgelöst:

  1. der explizite port im Aufruf,

  2. --port auf der Befehlszeile,

  3. GAME_BRIDGE_PORT in der Umgebung,

  4. 7777.

Ein Einzelinstanz-Setup muss sich also nie um Ports kümmern, und eine Mehrinstanz-Sitzung braucht nie einen zweiten Server.


Zwei Instanzen gleichzeitig steuern

Das Szenario, für das dies gebaut wurde: zwei Builds desselben Spiels nebeneinander, ein Agent, eine Sitzung.

// 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]
}

Port 7801 ist ein älterer Build ohne /tools: vollständig steuerbar, nur nicht selbstbeschreibend. Port 7820 ist einer, den diese Bridge gestartet hat.

// 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 } }

Jeder gibt den Zustand nach der Anwendung des Befehls zurück, sodass die beiden direkt vergleichbar sind:

{
  "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" }

Wenn etwas falsch ist

Die Bridge unterscheidet die Fehler, die von außen identisch aussehen:

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.

Setze den Befehl, der in der ersten Nachricht genannt wird, mit --launch-hint "make run PORT={port}" (oder lass launch_instance das Starten übernehmen).


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

Umgebung: GAME_BRIDGE_PORT, GAME_BRIDGE_SCAN_RANGE (oder GAME_BRIDGE_SCAN), GAME_BRIDGE_LAUNCH_HINT (oder GAME_BRIDGE_LAUNCH), GAME_BRIDGE_MANIFEST, GAME_BRIDGE_CONFIG, GAME_BRIDGE_INSTANCES, GAME_BRIDGE_HOME.

Alles, was die Bridge protokolliert, geht an stderr; stdout ist der MCP-Transport, und eine verirrte Zeile darauf beschädigt den Protokollstrom.


Verwendung in deinem eigenen Projekt

Die Teile werden sowohl als CLI ausgeliefert als auch exportiert. Wenn dein Spiel Werkzeuge benötigt, die mehrere Befehle verketten – „ablegen, dann warten, bis sich das Brett beruhigt, dann das Punktedelta melden“ – registriere sie als Composites und erbe das Protokoll, den Launcher, die Discovery und die Fehlermeldungen, anstatt eine zweite Kopie davon zu pflegen.

#!/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 };
      },
    },
  ],
});

Ein Composite erhält einen Kontext, der auf eine Instanz beschränkt ist – state, health, command, commandAndSync, call (jedes andere Werkzeug), manifest, summarise, sleep –, sodass es sich nie um Ports kümmern muss. only benennt die Spiele, für die es geeignet ist, abgeglichen mit dem game.name des Manifests; eine Bridge, die vorgibt, generisch zu sein, darf einem Flugsimulator kein drop_and_settle anbieten.

Die Regel für das, was in ein Composite gehört: Es verkettet entweder mehrere Befehle oder wartet auf etwas, das /command nicht melden kann. Alles, was ein Befehl mit einem Satz Argumente ist, gehört in das eigene Manifest des Spiels, wo es mit dem Code, der es implementiert, Schritt hält.

Niedrigere Ebenen – Bridge, GameClient, Launcher, readRegistry, normaliseManifest – werden ebenfalls exportiert. Bridge und GameClient akzeptieren ein optionales fetchImpl, was die Testsuite nutzt, um das Ganze ohne Spiel oder Socket zu steuern.


Entwicklung

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

81 Tests, von denen keiner ein laufendes Spiel benötigt: Portauflösungsreihenfolge, Manifest-Caching und seine drei Invalidierungspfade, der /tools-404-Fallback, der command/poll/confirm-Zyklus und seine frames-advanced-Degradierung, Registry-Lesen mit veralteten und fehlerhaften Einträgen, Launcher-Portauswahl, Boot-Fehler und Child-Reaping sowie die MCP-Oberfläche selbst, die über einen In-Memory-Transport betrieben wird.

Veröffentlichung

Noch nicht auf npm veröffentlicht. Wenn es so weit ist:

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 in package.json begrenzt das Tarball auf dist/, README.md und LICENSE; prepare baut bei der Installation aus git, sodass eine per git installierte Abhängigkeit ohne ein eingechecktes dist/ funktioniert.

Lizenz

MIT — siehe 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