Skip to main content
Glama

game-bridge-mcp

Let an AI agent start your game, drive it, and read what happened — over HTTP, one port per instance.

Your game already knows everything about itself: what is on screen, where every entity is, what commands it accepts. game-bridge-mcp is an MCP server that hands that to an agent — as tools the agent can call, discovered from the running game rather than hardcoded here.

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

Three things make it more than a debug-bridge script you would write in an afternoon:

  • It launches instances and picks their ports. No caller ever chooses a port or types a build command, so two agents cannot collide, and the bridge reaps what it started — no orphaned game windows after a session ends.

  • Every tool takes a port. One bridge drives every instance you have running: several agents on one machine, or one agent comparing two builds side by side.

  • The tool list comes from the game. The bridge fetches GET /tools from each instance at runtime, so a debug command you added this morning is callable this afternoon — no release of this package, no reconnect, and no drift between what the agent thinks the game accepts and what it accepts.

It is engine-agnostic. Any language, anything that can serve four small HTTP endpoints on localhost. The contract is short on purpose.


Quick start

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

Register it with an MCP client — for Claude Code, from your project directory:

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

Then, from the agent's side:

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 needs a launch declaration. Everything else works against any game implementing the HTTP surface, whether this bridge started it or not.


Related MCP server: minecraft-mcp

The contract

Implement this and your game is drivable by any agent, through this bridge, with no code here that knows anything about it. It has three parts, and each one buys something specific:

Part

What it buys

1. The HTTP surface

Reading and driving a running instance.

2. Self-registration

Finding instances without guessing at ports.

3. The launch declaration

Starting instances without a human choosing a port.

Only part 1 is required. Part 2 makes discovery reliable; part 3 makes the whole thing pleasant.

1. The HTTP surface

Serve these on 127.0.0.1:<port>, where the port comes from an explicit debug flag. Bind to loopback only, and keep the whole surface off unless the game was launched with that flag: this is a debug surface, not a network service.

GET /health — required

The liveness and identity check. Discovery calls it against every port in a range, so it must be cheap.

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

ok: true is what marks the port as one of ours. A port answering HTTP with anything else is reported to the agent as "something else has taken this port" — a different problem, with a different fix, from "the game isn't running".

frame is a counter that increases for the life of the process. The bridge watches it: a frame that goes backwards means a new process is answering on this port, and the cached tool manifest is dropped automatically. That is what makes rebuild-and-rerun invisible to the agent.

GET /state — required

The full snapshot: everything an agent might want to know, as JSON. There is no required schema — it is your game — but a few conventional fields unlock bridge features:

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

Field

Why the bridge cares

frame

Restart detection; the fallback confirmation that a command ran.

completedCommandId

The strong confirmation that a command ran — see below.

ui.screen

Reported by list_instances, so five instances are tellable apart at a glance.

ui.elements[].label / .visible

Included in the compact get_state digest.

events[].m

Recent events, returned after every command so the agent sees the consequence. Plain strings are accepted too.

game

Scalar fields are included in the digest. Nested objects and arrays are not — that is where the megabyte-sized entity lists live.

Everything else you put here is passed through untouched by get_state.

GET /command — required

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

The command name is keyed cmd, not name — commands routinely take a name argument of their own, and a duplicate query key would silently overwrite the command being invoked. Every other query parameter is an argument.

This endpoint is fire-and-forget, and it is the single most important thing to understand about the contract. It answers from the HTTP thread the moment the command is queued; the command itself runs later, on the game thread. A client that reads /state immediately afterwards reads the world from before the command happened. The test looks flaky; the game is fine.

The bridge handles this, and the way it does is what your game should support:

  1. GET /command?... → note the returned commandId.

  2. Poll GET /state until completedCommandId >= commandId.

  3. Return that state — genuinely after the command ran.

If your game does not publish completedCommandId, the bridge degrades to waiting for frame to advance by two and labels the result "confirmation": "frames-advanced", so the agent knows it got the weaker guarantee. Publishing completedCommandId is a handful of lines and worth it:

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

A close command that shuts the game down through its normal teardown is strongly recommended: it lets an agent end an instance without killing a process. The bridge treats close specially — it never waits for a completion that cannot arrive, it waits for the port to go quiet.

GET /tools — optional, but this is the good part

The manifest: what your game can be told to do, in its own words.

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

Field

Meaning

game.name, game.version

Identity. Shown by list_instances, which is how an agent tells five running instances apart.

game.protocol

Versions the document, not the command set. Adding a command changes nothing here; restructuring the manifest does. It lets a bridge distinguish "I cannot read this" from "this game knows different commands than last time". Current version: 1.

toolsets[]

Groups named for what a caller is trying to do, not for how your code is arranged. Keep them few and obvious.

tools[].name

What the agent calls.

tools[].description

Written for the agent. Say what it does and when to reach for it — this is the text the model reasons over.

tools[].args[]

{ name, type, description, required, default }. type is a JSON Schema type name, so one converter serves both game commands and bridge tools.

tools[].command

The cmd to send, if it differs from the tool name. Defaults to the name.

tools[].sync

false for commands that must not be waited on. Defaults to true.

tools[].inputSchema

If you already have JSON Schema, send it instead of args and it is used verbatim.

passthrough

Free text plus examples, describing commands you have not formally published.

Defaults may be strings ("true", "0.05") — a manifest serialised from a typed language usually renders them that way. The bridge folds them into the description rather than emitting default in the schema, because default: "false" on a boolean property is something a strict client may reject. null means "no default".

The parser is deliberately tolerant, because a manifest gets written in whatever serialiser was already to hand:

  • toolsets may be an array of objects or a map of name → toolset.

  • arguments may live under args, arguments or params, as an array of objects, an array of bare names, or a map of name → { type, description }.

  • A malformed tool is dropped, not fatal. One bad entry must not take a whole instance offline.

If /tools 404s, nothing breaks. The bridge falls back to a built-in manifest containing only the contract-level tools and tells the agent that the game publishes no command list, so work through raw_command and read /state. Instances are reported as live or live-no-manifest accordingly, and --manifest ./my-game.json supplies one from a file for a game you cannot change.

2. Self-registration

Port scanning is the weak form of discovery: bounded by a range someone guessed at, silent about a game's identity until it answers, and prone to false negatives during startup — the exact moment an agent is most likely to look.

So a game that has successfully bound its debug port writes one small JSON file naming itself:

~/.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 is deliberate: several checkouts of the same game run at once, and "which build is this?" is otherwise unanswerable from outside the process.

The rules a writer must follow:

  • Write the entry after the port is bound, never before. An entry for a port that was never claimed is worse than no entry.

  • Delete it on clean shutdown.

  • Never let registry failure break the game. An unwritable directory, a read-only home, a sandbox — the game must still start and still serve its endpoints. This is advertising, not infrastructure.

  • Honour GAME_BRIDGE_INSTANCES (the entries directory) or GAME_BRIDGE_HOME (its parent) if either is set.

The rules a reader must follow — and these matter more:

  • Entries are advisory, never authoritative. A crash or a force-kill leaves the file behind. This happens constantly in practice.

  • Verify every entry with GET /health before believing it. An entry whose port does not answer is a stale file, not a running game, and must be reported as such rather than as an instance.

  • Never trust an entry over the live game. The bridge takes name and version from /tools when the game answers, and uses the entry only for what the wire cannot say: pid, working directory, start time.

  • Do not delete other processes' files by default. A game still binding its port is indistinguishable from a crashed one for a second or two. The bridge prunes only on an explicit prune: true, and only after verifying the port is dead.

  • Keep scanning too. Games predating the registry exist; the bridge merges registry entries and a port scan and de-duplicates by port, reporting each instance's discovery as registry, scan or both.

3. The launch declaration

A project declares once how it is started, so no caller ever types a build command or picks a port. Put gamebridge.json in the project root — the bridge walks up from its working directory to find it, the way every other JS tool finds its config, and --config <file> overrides that.

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

Field

Meaning

command

Shell command line. {port} is substituted. The port must reach the game from here — that is the whole mechanism.

argv

Alternative to command: ["./run-game", "--port", "{port}"], executed without a shell.

cwd

Working directory, resolved relative to this file — not to wherever the MCP client happened to start the bridge, which is almost never the project.

portRange

Ports the launcher may claim. Default 7820-7839, deliberately clear of 7777 and 7800-7810, which are the ports people hand out by hand.

readyTimeoutMs

How long to wait for /health. A cold build plus a JVM is tens of seconds; the default is 180000.

env, extraArgs

Extra environment and trailing arguments.

What the launcher then guarantees:

  • The port is verified free twice — nothing bound to it, and nothing answering a health check on it — because a game mid-startup has claimed the port in the way that matters while still failing a bind test milliseconds earlier. If the declared range is full, it falls back to an OS-assigned port.

  • launch_instance returns only when /health answers, so a caller never writes a retry loop.

  • A boot failure fails loudly, with the child's own output. When a game fails to start, the stack trace is the whole answer:

    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 and stderr are captured to that log file for the life of the instance, and the last 200 lines are held in memory for instance_log.

  • Children are reaped. On stop_instance, and on server shutdown, SIGINT, SIGTERM or the client disconnecting, every launched instance is closed — the game's own close command first, then termination of the process tree if it will not go. A closed session never leaves game windows on the desktop.

Escalation past a clean close applies only to processes this bridge spawned and is still tracking. stop_instance on any other port refuses and tells you to ask the game to close itself instead.


Tools

Tool

Arguments

What it does

launch_instance

port?, timeoutMs?

Starts a game, picks a free port, waits for /health, returns the handle.

list_instances

range?, registry?, scan?, prune?

Registry plus port scan. Names, versions, pids, working directories, screens. Read-only.

stop_instance

port?, graceMs?

Clean close, then escalation — only for instances this bridge launched.

instance_log

port?, lines?

Captured stdout/stderr of a launched instance.

list_toolsets

port?

That instance's toolsets, as it describes itself.

describe_toolset

port?, name

Full JSON Schemas. bridge for the bridge's own tools, passthrough for unpublished commands.

call_tool

port?, name, arguments?

Runs a tool, waits for the game to confirm it, returns the resulting digest.

Only these seven are advertised. The game's own tools are reached through call_tool, because an MCP client is handed the tool list once, when it connects, and never asks again — a fixed list would be stale for a game still being written and simply wrong when one session is driving two different builds. (--eager flattens everything up front for clients that cannot walk a discovery path.)

The bridge's own toolset

Provided for every conforming game, whatever it is:

Tool

What it does

get_state

The full /state snapshot, or summary: true for a compact digest.

get_health

Liveness and frame counter.

raw_command

Any command by name, published or not.

wait_for

Poll /state until a field reaches a value, a field changes, or an event appears. This is how you wait for what the command that started it cannot report — a queued screenshot reaching disk, a simulation reaching frame N.

close

Clean shutdown; the port going quiet is the confirmation.

How call_tool resolves a name

  1. The bridge's composites, including any a host application registered. A composite shadows a game command of the same name, which is always an improvement rather than a surprise: a composite carries that name precisely because the raw command returns before the thing it asked for has happened.

  2. The game's manifest — with one re-fetch on a miss, so a rebuilt game with new commands is picked up mid-session.

  3. Passthrough — anything else is sent as a raw command. A command that exists in the game but not in its manifest still works today. If the game rejects it as unknown, you get the list of what it does accept.

How port resolves

Every tool takes an optional port (at the top level or inside arguments). It resolves in this order:

  1. the explicit port on the call,

  2. --port on the command line,

  3. GAME_BRIDGE_PORT in the environment,

  4. 7777.

So a single-instance setup never thinks about ports, and a multi-instance session never needs a second server.


Driving two instances at once

The scenario this was built for: two builds of the same game, side by side, one agent, one session.

// 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 is an older build with no /tools: still fully drivable, just not self-describing. Port 7820 is one this bridge started.

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

Each returns the state after the command was applied, so the two are directly comparable:

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

When something is wrong

The bridge distinguishes the failures that look identical from the outside:

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.

Set the command named in the first message with --launch-hint "make run PORT={port}" (or let launch_instance do the starting).


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

Environment: GAME_BRIDGE_PORT, GAME_BRIDGE_SCAN_RANGE (or GAME_BRIDGE_SCAN), GAME_BRIDGE_LAUNCH_HINT (or GAME_BRIDGE_LAUNCH), GAME_BRIDGE_MANIFEST, GAME_BRIDGE_CONFIG, GAME_BRIDGE_INSTANCES, GAME_BRIDGE_HOME.

Everything the bridge logs goes to stderr; stdout is the MCP transport, and a stray line on it corrupts the protocol stream.


Using it from your own project

The pieces are exported as well as shipped as a CLI. If your game needs tools that chain several commands — "drop, then wait for the board to settle, then report the score delta" — register them as composites and inherit the protocol, the launcher, discovery and the error messages rather than maintaining a second copy of them.

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

A composite is handed a context scoped to one instance — state, health, command, commandAndSync, call (any other tool), manifest, summarise, sleep — so it never has to think about ports. only names the games it suits, matched against the manifest's game.name; a bridge that claims to be generic must not offer drop_and_settle to a flight simulator.

The rule for what belongs in a composite: it either chains several commands or waits for something /command cannot report. Anything that is one command with one set of arguments belongs in the game's own manifest, where it stays in step with the code that implements it.

Lower-level pieces — Bridge, GameClient, Launcher, readRegistry, normaliseManifest — are exported too. Bridge and GameClient take an optional fetchImpl, which is how the test suite drives the whole thing without a game or a socket.


Development

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

81 tests, none of which need a running game: port resolution order, manifest caching and its three invalidation paths, the /tools 404 fallback, the command/poll/confirm cycle and its frames-advanced degradation, registry reading with stale and malformed entries, launcher port selection, boot failure and child reaping, and the MCP surface itself driven over an in-memory transport.

Publishing

Not published to npm yet. When it is:

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 limits the tarball to dist/, README.md and LICENSE; prepare builds on install from git, so a git-installed dependency works without a checked-in dist/.

Licence

MIT — see 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.

ParametersJSON Schema
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.

ParametersJSON Schema
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.

ParametersJSON Schema
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.

ParametersJSON Schema
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.

ParametersJSON Schema
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.

ParametersJSON Schema
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' }.

ParametersJSON Schema
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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers