Skip to main content
Glama

game-bridge-mcp

AI 에이전트가 게임을 실행하고, 조종하고, 결과를 읽을 수 있게 해주는 도구 — HTTP를 통해, 인스턴스당 포트 하나.

게임은 이미 자신에 대해 모든 것을 알고 있습니다: 화면에 무엇이 있는지, 모든 엔티티가 어디에 있는지, 어떤 명령을 받아들이는지. game-bridge-mcp는 이를 에이전트에게 전달하는 MCP 서버입니다 — 에이전트가 호출할 수 있는 도구 형태로, 여기에 하드코딩되지 않고 실행 중인 게임에서 발견됩니다.

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

단순히 오후에 작성할 디버그 브리지 스크립트 이상이 되게 만드는 세 가지가 있습니다:

  • 인스턴스를 실행하고 포트를 선택합니다. 호출자가 포트를 선택하거나 빌드 명령을 입력할 일이 없으므로, 두 에이전트가 충돌할 수 없고, 브리지는 자신이 시작한 것을 정리합니다 — 세션이 끝난 후 고아가 된 게임 창이 남지 않습니다.

  • 모든 도구는 port를 받습니다. 하나의 브리지가 실행 중인 모든 인스턴스를 구동합니다: 한 머신에서 여러 에이전트, 또는 한 에이전트가 두 빌드를 나란히 비교하는 경우.

  • 도구 목록은 게임에서 옵니다. 브리지는 각 인스턴스에서 런타임에 GET /tools를 가져오므로, 오늘 아침에 추가한 디버그 명령이 오늘 오후에 호출 가능합니다 — 이 패키지의 릴리스도, 재연결도, 에이전트가 게임이 받아들인다고 생각하는 것과 실제로 받아들이는 것 사이의 불일치도 없습니다.

엔진에 구애받지 않습니다. 어떤 언어든, localhost에서 네 개의 작은 HTTP 엔드포인트를 제공할 수 있는 무엇이든 됩니다. 계약은 의도적으로 짧습니다.


빠른 시작

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

MCP 클라이언트에 등록하세요 — Claude Code의 경우, 프로젝트 디렉토리에서:

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

그런 다음 에이전트 쪽에서:

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

launch_instance실행 선언이 필요합니다. 그 외 모든 것은 HTTP 표면을 구현하는 모든 게임에 대해 작동합니다 — 이 브리지가 시작했는지 여부와 무관하게.


Related MCP server: minecraft-mcp

계약

이것을 구현하면 게임은 이 브리지를 통해 어떤 에이전트든 구동할 수 있게 되며, 여기에는 게임에 대해 아는 코드가 전혀 필요 없습니다. 세 부분으로 구성되며, 각 부분은 특정한 것을 제공합니다:

부분

제공하는 것

1. HTTP 표면

실행 중인 인스턴스를 읽고 구동하기.

2. 자체 등록

포트를 추측하지 않고 인스턴스 찾기.

3. 실행 선언

사람이 포트를 선택하지 않고 인스턴스 시작하기.

1번만 필수입니다. 2번은 발견을 안정적으로 만들고, 3번은 전체를 쾌적하게 만듭니다.

1. HTTP 표면

127.0.0.1:<port>에서 제공하세요. 포트는 명시적인 디버그 플래그에서 옵니다. 루프백에만 바인딩하고, 게임이 해당 플래그로 실행된 경우에만 전체 표면을 켜두세요: 이것은 디버그 표면이지 네트워크 서비스가 아닙니다.

GET /health — 필수

활성 및 정체성 확인입니다. 발견은 범위 내의 모든 포트에 대해 이를 호출하므로, 저렴해야 합니다.

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

ok: true가 포트를 우리 것으로 표시합니다. 다른 것으로 HTTP에 응답하는 포트는 에이전트에게 "다른 무언가가 이 포트를 차지했습니다"로 보고됩니다 — "게임이 실행 중이 아님"과는 다른 문제, 다른 해결책입니다.

frame은 프로세스 수명 동안 증가하는 카운터입니다. 브리지는 이를 감시합니다: 뒤로 가는 frame은 새 프로세스가 이 포트에 응답하고 있음을 의미하며, 캐시된 도구 매니페스트는 자동으로 삭제됩니다. 이것이 재빌드-재실행을 에이전트에게 보이지 않게 만드는 것입니다.

GET /state — 필수

전체 스냅샷: 에이전트가 알고 싶어할 모든 것을 JSON으로. 필수 스키마는 없습니다 — 그것은 당신의 게임이니까요 — 하지만 몇 가지 관례적 필드는 브리지 기능을 잠금 해제합니다:

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

필드

브리지가 신경 쓰는 이유

frame

재시작 감지; 명령이 실행되었는지에 대한 차선의 확인.

completedCommandId

명령이 실행되었는지에 대한 강력한 확인 — 아래 참조.

ui.screen

list_instances가 보고하므로, 다섯 인스턴스를 한눈에 구분할 수 있습니다.

ui.elements[].label / .visible

간결한 get_state 다이제스트에 포함됩니다.

events[].m

최근 이벤트, 모든 명령 후에 반환되어 에이전트가 결과를 볼 수 있습니다. 일반 문자열도 허용됩니다.

game

스칼라 필드는 다이제스트에 포함됩니다. 중첩 객체와 배열은 포함되지 않습니다 — 메가바이트 크기의 엔티티 목록이 있는 곳입니다.

여기에 넣은 다른 모든 것은 get_state에 의해 변경 없이 전달됩니다.

GET /command — 필수

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

명령 이름은 cmd 키로 지정됩니다. name이 아닙니다 — 명령은 종종 자체 name 인수를 가지며, 중복 쿼리 키는 호출되는 명령을 조용히 덮어쓸 수 있습니다. 다른 모든 쿼리 매개변수는 인수입니다.

이 엔드포인트는 fire-and-forget이며, 계약에서 가장 중요한 이해 사항입니다. 명령이 대기열에 들어가는 순간 HTTP 스레드에서 응답합니다; 명령 자체는 나중에 게임 스레드에서 실행됩니다. 직후에 /state를 읽는 클라이언트는 명령이 발생하기 전의 세계를 읽습니다. 테스트가 불안정해 보여도 게임은 정상입니다.

브리지는 이를 처리하며, 게임이 지원해야 할 방식은 다음과 같습니다:

  1. GET /command?... → 반환된 commandId를 기록합니다.

  2. completedCommandId >= commandId가 될 때까지 GET /state를 폴링합니다.

  3. 해당 상태를 반환합니다 — 명령이 실제로 실행된 후의 상태입니다.

게임이 completedCommandId를 게시하지 않으면, 브리지는 frame이 2만큼 진행될 때까지 기다리는 것으로 대체하고 결과에 "confirmation": "frames-advanced"라고 표시하여, 에이전트가 더 약한 보장을 받았음을 알게 합니다. completedCommandId를 게시하는 것은 몇 줄에 불과하며 그만한 가치가 있습니다:

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

정상적인 종료 절차를 통해 게임을 종료하는 close 명령은 강력히 권장됩니다: 에이전트가 프로세스를 죽이지 않고 인스턴스를 종료할 수 있게 해줍니다. 브리지는 close를 특별히 처리합니다 — 도착할 수 없는 완료를 기다리지 않고, 포트가 조용해질 때까지 기다립니다.

GET /tools — 선택 사항이지만, 이것이 핵심입니다

매니페스트: 게임이 지시받을 수 있는 것, 게임 자신의 언어로.

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

필드

의미

game.name, game.version

정체성. list_instances가 표시하며, 에이전트가 실행 중인 다섯 인스턴스를 구분하는 방법입니다.

game.protocol

문서의 버전입니다. 명령 세트가 아닙니다. 명령을 추가해도 여기서는 아무것도 바뀌지 않습니다; 매니페스트를 재구성하면 바뀝니다. 브리지가 "이것을 읽을 수 없음"과 "이 게임은 지난번과 다른 명령을 알고 있음"을 구분할 수 있게 합니다. 현재 버전: 1.

toolsets[]

호출자가 하려는 것에 따라 이름이 붙은 그룹입니다. 코드가 어떻게 구성되어 있는지에 따른 것이 아닙니다. 적고 명확하게 유지하세요.

tools[].name

에이전트가 호출하는 이름입니다.

tools[].description

에이전트를 위해 작성됩니다. 무엇을 하는지 그리고 언제 사용해야 하는지를 말하세요 — 모델이 추론하는 텍스트입니다.

tools[].args[]

{ name, type, description, required, default }. type은 JSON Schema 타입 이름이므로, 하나의 변환기가 게임 명령과 브리지 도구 모두에 사용됩니다.

tools[].command

도구 이름과 다를 경우 보낼 cmd. 기본값은 이름입니다.

tools[].sync

대기해서는 안 되는 명령의 경우 false. 기본값은 true입니다.

tools[].inputSchema

이미 JSON Schema가 있다면 args 대신 보내면 그대로 사용됩니다.

passthrough

공식적으로 게시하지 않은 명령을 설명하는 자유 텍스트와 예제.

기본값은 문자열일 수 있습니다 ("true", "0.05") — 타입 언어에서 직렬화된 매니페스트는 보통 그렇게 렌더링합니다. 브리지는 스키마에서 default를 내보내는 대신 설명에 접어 넣습니다. boolean 속성의 default: "false"는 엄격한 클라이언트가 거부할 수 있기 때문입니다. null은 "기본값 없음"을 의미합니다.

파서는 의도적으로 관대합니다. 매니페스트는 이미 손에 있는 직렬화 도구로 작성되기 때문입니다:

  • toolsets는 객체 배열 또는 name → toolset 맵일 수 있습니다.

  • 인수는 args, arguments 또는 params 아래에, 객체 배열, 이름만 있는 배열, 또는 name → { type, description } 맵으로 존재할 수 있습니다.

  • 잘못된 도구는 치명적이지 않고 삭제됩니다. 하나의 잘못된 항목이 전체 인스턴스를 오프라인으로 만들면 안 됩니다.

/tools가 404를 반환해도 아무것도 깨지지 않습니다. 브리지는 계약 수준 도구만 포함된 내장 매니페스트로 대체하고, 게임이 명령 목록을 게시하지 않으므로 raw_command를 통해 작업하고 /state를 읽으라고 에이전트에게 알립니다. 인스턴스는 그에 따라 live 또는 live-no-manifest로 보고되며, --manifest ./my-game.json은 변경할 수 없는 게임을 위해 파일에서 매니페스트를 제공합니다.

2. 자체 등록

포트 스캐닝은 발견의 약한 형태입니다: 누군가 추측한 범위로 제한되고, 게임이 응답할 때까지 정체성에 대해 침묵하며, 시작 중에 오탐(false negative)이 발생하기 쉽습니다 — 에이전트가 가장 찾아볼 가능성이 높은 바로 그 순간입니다.

그래서 디버그 포트에 성공적으로 바인딩한 게임은 자신을 밝히는 작은 JSON 파일 하나를 작성합니다:

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

cwd는 의도적입니다: 같은 게임의 여러 체크아웃이 동시에 실행될 수 있으며, "이 빌드가 어느 것인가?"는 프로세스 외부에서는 달리 답할 수 없습니다.

작성자가 따라야 할 규칙:

  • 포트가 바인딩된 이후에 항목을 작성하고, 절대 그 이전에 작성하지 마십시오. 결코 점유되지 않은 포트에 대한 항목은 항목이 없는 것보다 더 나쁩니다.

  • 정상 종료 시 삭제하십시오.

  • 레지스트리 실패가 게임을 망가뜨리게 두지 마십시오. 쓰기 불가능한 디렉터리, 읽기 전용 홈 디렉터리, 샌드박스 — 게임은 여전히 시작되어야 하고 엔드포인트를 계속 제공해야 합니다. 이것은 광고이지 인프라가 아닙니다.

  • GAME_BRIDGE_INSTANCES(항목 디렉터리) 또는 GAME_BRIDGE_HOME(그 상위 디렉터리) 중 하나가 설정되어 있으면 이를 존중하십시오.

독자가 반드시 따라야 할 규칙 — 그리고 이것들이 더 중요합니다:

  • 항목은 참고용이지, 절대 권위가 아닙니다. 크래시나 강제 종료는 파일을 남겨 둡니다. 실제로 이런 일은 끊임없이 발생합니다.

  • 모든 항목을 믿기 전에 GET /health로 검증하십시오. 포트가 응답하지 않는 항목은 실행 중인 게임이 아니라 오래된 파일이며, 인스턴스가 아니라 그렇게 보고되어야 합니다.

  • 항목을 실시간 게임보다 신뢰하지 마십시오. 브리지는 게임이 응답할 때 이름과 버전을 /tools에서 가져오며, 항목은 와이어가 말할 수 없는 것(pid, 작업 디렉터리, 시작 시간)에만 사용합니다.

  • 기본적으로 다른 프로세스의 파일을 삭제하지 마십시오. 아직 포트를 바인딩 중인 게임은 1~2초 동안은 크래시된 것과 구분할 수 없습니다. 브리지는 명시적인 prune: true가 있을 때만, 그리고 포트가 죽었음을 확인한 후에만 정리합니다.

  • 스캔도 계속하십시오. 레지스트리보다 먼저 존재하는 게임들이 있습니다. 브리지는 레지스트리 항목과 포트 스캔을 병합하고 포트별로 중복을 제거하여, 각 인스턴스의 discoveryregistry, scan 또는 both로 보고합니다.

3. 실행 선언

프로젝트는 시작 방법을 한 번만 선언하므로, 어떤 호출자도 빌드 명령을 입력하거나 포트를 고를 필요가 없습니다. 프로젝트 루트에 gamebridge.json을 두십시오 — 브리지는 다른 모든 JS 도구가 설정을 찾는 것과 같은 방식으로 작업 디렉터리에서 위로 올라가며 이를 찾고, --config <file>이 이를 재정의합니다.

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

필드

의미

command

셸 명령줄. {port}가 치환됩니다. 포트는 여기서부터 게임에 도달해야 합니다 — 이것이 전체 메커니즘입니다.

argv

command의 대안: ["./run-game", "--port", "{port}"], 셸 없이 실행됩니다.

cwd

작업 디렉터리, 이 파일 기준으로 해석됩니다 — MCP 클라이언트가 브리지를 시작한 위치 기준이 아닙니다. 그 위치는 거의 항상 프로젝트가 아닙니다.

portRange

런처가 점유할 수 있는 포트. 기본값 7820-7839, 사람들이 수동으로 나눠주는 포트인 7777과 7800-7810을 의도적으로 피합니다.

readyTimeoutMs

/health를 기다리는 시간. 콜드 빌드에 JVM까지 있으면 수십 초가 걸립니다. 기본값은 180000입니다.

env, extraArgs

추가 환경 변수와 후행 인자.

런처가 보장하는 것:

  • 포트가 두 번 검증되어 비어 있음이 확인됩니다 — 아무것도 바인딩되어 있지 않고, 헬스 체크에 응답하는 것도 없음 — 게임이 시작 중일 때는 수 밀리초 전에 바인드 테스트를 실패하면서도 중요한 방식으로 포트를 점유했기 때문입니다. 선언된 범위가 가득 차면 OS가 할당한 포트로 폴백합니다.

  • launch_instance/health가 응답할 때만 반환합니다, 따라서 호출자는 재시도 루프를 작성할 필요가 없습니다.

  • 부팅 실패는 자식 프로세스의 출력과 함께 크게 실패합니다. 게임이 시작에 실패하면, 스택 트레이스가 전체 답입니다:

    BridgeUsageError: Launch failed on port 7820: the process exited with code 1.
    Command: ./gradlew lwjgl3:run -PdebugPort=7820 --console=plain
    Working directory: /home/dev/orbital
    Full log: /tmp/game-bridge-logs/instance-7820-1787264781573.log
    
    Last output:
    'gradlew' is not recognized as an internal or external command,
    operable program or batch file.
  • stdout과 stderr는 인스턴스의 수명 동안 그 로그 파일에 캡처되며, 마지막 200줄은 instance_log를 위해 메모리에 보관됩니다.

  • 자식 프로세스는 수거됩니다. stop_instance 시, 그리고 서버 종료, SIGINT, SIGTERM 또는 클라이언트 연결 해제 시, 시작된 모든 인스턴스가 닫힙니다 — 게임 자체의 close 명령이 먼저, 그 다음에 프로세스 트리가 종료되지 않으면 종료됩니다. 닫힌 세션은 데스크톱에 게임 창을 남기지 않습니다.

깨끗한 종료를 넘어선 확대는 이 브리지가 생성하고 여전히 추적 중인 프로세스에만 적용됩니다. 다른 포트에 대한 stop_instance는 거부하고 게임 스스로 닫도록 요청하라고 알려줍니다.


도구

도구

인자

하는 일

launch_instance

port?, timeoutMs?

게임을 시작하고, 빈 포트를 고르고, /health를 기다리고, 핸들을 반환합니다.

list_instances

range?, registry?, scan?, prune?

레지스트리와 포트 스캔. 이름, 버전, pid, 작업 디렉터리, 화면. 읽기 전용.

stop_instance

port?, graceMs?

깨끗한 종료, 그다음 확대 — 이 브리지가 시작한 인스턴스에만 해당.

instance_log

port?, lines?

시작된 인스턴스의 캡처된 stdout/stderr.

list_toolsets

port?

해당 인스턴스의 도구 세트, 스스로 설명하는 대로.

describe_toolset

port?, name

전체 JSON 스키마. bridge는 브리지 자체 도구, passthrough는 미공개 명령.

call_tool

port?, name, arguments?

도구를 실행하고, 게임이 확인할 때까지 기다리고, 결과 다이제스트를 반환합니다.

이 일곱 개만 광고됩니다. 게임 자체의 도구는 call_tool을 통해 접근합니다. MCP 클라이언트는 연결 시 도구 목록을 한 번 받고 다시 묻지 않기 때문입니다 — 고정 목록은 아직 작성 중인 게임에는 오래된 것이고, 한 세션이 두 개의 다른 빌드를 구동할 때는 단순히 틀린 것입니다. (--eager는 디스커버리 경로를 걸을 수 없는 클라이언트를 위해 모든 것을 앞에서 평평하게 만듭니다.)

브리지 자체 도구 세트

준수하는 모든 게임에 제공되며, 무엇이든:

도구

설명

get_state

전체 /state 스냅샷, 또는 summary: true로 간결한 다이제스트.

get_health

활성 상태와 프레임 카운터.

raw_command

이름으로 모든 명령, 공개 여부와 무관하게.

wait_for

/state를 폴링하여 필드가 값에 도달하거나, 필드가 변경되거나, 이벤트가 나타날 때까지. 이것이 시작한 명령이 보고할 수 없는 것을 기다리는 방법입니다 — 대기 중인 스크린샷이 디스크에 도달하는 것, 시뮬레이션이 프레임 N에 도달하는 것.

close

깨끗한 종료; 포트가 조용해지는 것이 확인입니다.

call_tool이 이름을 해석하는 방법

  1. 브리지의 복합 도구, 호스트 애플리케이션이 등록한 것을 포함. 복합 도구는 같은 이름의 게임 명령을 가리며, 이는 항상 놀라움이 아니라 개선입니다: 복합 도구는 원시 명령이 요청한 일이 일어나기 전에 반환하기 때문에 정확히 그 이름을 갖습니다.

  2. 게임의 매니페스트 — 누락 시 한 번 다시 가져오므로, 새 명령이 있는 재빌드된 게임이 세션 중간에 잡힙니다.

  3. 패스스루 — 그 외의 것은 원시 명령으로 전송됩니다. 게임에 존재하지만 매니페스트에 없는 명령도 오늘도 작동합니다. 게임이 알 수 없는 것으로 거부하면, 수용하는 명령 목록을 받습니다.

port가 해석되는 방법

모든 도구는 선택적 port(최상위 또는 arguments 내부)를 받습니다. 다음 순서로 해석됩니다:

  1. 호출의 명시적 port,

  2. 명령줄의 --port,

  3. 환경의 GAME_BRIDGE_PORT,

  4. 7777.

따라서 단일 인스턴스 설정은 포트에 대해 생각할 필요가 없고, 다중 인스턴스 세션은 두 번째 서버가 필요하지 않습니다.


두 인스턴스를 동시에 구동하기

이것이 만들어진 시나리오: 같은 게임의 두 빌드, 나란히, 하나의 에이전트, 하나의 세션.

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

포트 7801은 /tools가 없는 오래된 빌드입니다: 여전히 완전히 구동 가능하지만, 자기 설명적이지 않습니다. 포트 7820은 이 브리지가 시작한 것입니다.

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

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

각각은 명령이 적용된 이후의 상태를 반환하므로, 두 개는 직접 비교 가능합니다:

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

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

문제가 있을 때

브리지는 외부에서 동일해 보이는 실패를 구분합니다:

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

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

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

첫 번째 메시지에 명명된 명령을 --launch-hint "make run PORT={port}"로 설정하십시오 (또는 launch_instance가 시작하도록 하십시오).


CLI

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

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

환경: GAME_BRIDGE_PORT, GAME_BRIDGE_SCAN_RANGE (또는 GAME_BRIDGE_SCAN), GAME_BRIDGE_LAUNCH_HINT (또는 GAME_BRIDGE_LAUNCH), GAME_BRIDGE_MANIFEST, GAME_BRIDGE_CONFIG, GAME_BRIDGE_INSTANCES, GAME_BRIDGE_HOME.

브리지가 기록하는 모든 것은 stderr로 갑니다. stdout은 MCP 전송이며, 그 위에 한 줄이라도 흘러들면 프로토콜 스트림이 손상됩니다.


자신의 프로젝트에서 사용하기

조각들은 CLI로 제공될 뿐만 아니라 내보내집니다. 게임에 여러 명령을 연결하는 도구가 필요하다면 — "드롭, 그다음 보드가 안정될 때까지 기다리고, 그다음 점수 차이를 보고" — 이를 복합 도구로 등록하고 프로토콜, 런처, 디스커버리, 오류 메시지를 상속받아 두 번째 복사본을 유지하지 마십시오.

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

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

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

복합 도구는 하나의 인스턴스에 범위가 지정된 컨텍스트를 받습니다 — state, health, command, commandAndSync, call (다른 도구), manifest, summarise, sleep — 따라서 포트에 대해 생각할 필요가 없습니다. only는 매니페스트의 game.name과 대조하여 적합한 게임을 지정합니다. 제네릭을 주장하는 브리지는 비행 시뮬레이터에 drop_and_settle을 제공해서는 안 됩니다.

복합 도구에 속하는 것의 규칙: 여러 명령을 연결하거나 /command가 보고할 수 없는 것을 기다리는 것입니다. 하나의 명령과 하나의 인자 집합인 것은 게임 자체의 매니페스트에 속하며, 구현하는 코드와 보조를 맞춥니다.

더 낮은 수준의 조각 — Bridge, GameClient, Launcher, readRegistry, normaliseManifest — 도 내보내집니다. BridgeGameClient는 선택적 fetchImpl을 받으며, 이것이 테스트 스위트가 게임이나 소켓 없이 전체를 구동하는 방법입니다.


개발

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

실행 중인 게임이 필요 없는 81개의 테스트: 포트 해석 순서, 매니페스트 캐싱 및 그 세 가지 무효화 경로, /tools 404 폴백, 명령/폴링/확인 주기 및 프레임 고급 저하, 오래되었거나 잘못된 항목이 있는 레지스트리 읽기, 런처 포트 선택, 부팅 실패 및 하위 프로세스 정리, 그리고 인메모리 전송을 통해 구동되는 MCP 표면 자체입니다.

게시

아직 npm에 게시되지 않았습니다. 게시되면:

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

package.jsonfiles는 tarball을 dist/, README.mdLICENSE로 제한합니다. prepare는 git에서 설치할 때 빌드하므로, 체크인된 dist/ 없이도 git 설치 의존성이 작동합니다.

라이선스

MIT — LICENSE를 참조하세요.

Install Server
A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • A MCP server built for developers enabling Git based project management with project and personal…

  • An MCP server that gives your AI access to the source code and docs of all public github repos

  • MCP server exposing the Backtest360 engine API as tools for AI agents.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wildware-uk/game-bridge-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server