{"id":50719047,"url":"https://github.com/dmang-dev/mcp-bizhawk","last_synced_at":"2026-06-09T22:01:14.827Z","repository":{"id":358137639,"uuid":"1240026532","full_name":"dmang-dev/mcp-bizhawk","owner":"dmang-dev","description":"MCP server for BizHawk — drive NES/SNES/GB/GBC/GBA/Genesis/N64/PSX/Saturn and more through one Lua bridge","archived":false,"fork":false,"pushed_at":"2026-05-16T00:04:52.000Z","size":59,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-16T00:11:32.505Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dmang-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-15T17:33:56.000Z","updated_at":"2026-05-16T00:04:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dmang-dev/mcp-bizhawk","commit_stats":null,"previous_names":["dmang-dev/mcp-bizhawk"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/dmang-dev/mcp-bizhawk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmang-dev%2Fmcp-bizhawk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmang-dev%2Fmcp-bizhawk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmang-dev%2Fmcp-bizhawk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmang-dev%2Fmcp-bizhawk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmang-dev","download_url":"https://codeload.github.com/dmang-dev/mcp-bizhawk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmang-dev%2Fmcp-bizhawk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34127345,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-09T22:01:13.991Z","updated_at":"2026-06-09T22:01:14.814Z","avatar_url":"https://github.com/dmang-dev.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mcp-bizhawk\n\n[![npm version](https://img.shields.io/npm/v/mcp-bizhawk.svg)](https://www.npmjs.com/package/mcp-bizhawk)\n[![npm downloads](https://img.shields.io/npm/dm/mcp-bizhawk.svg)](https://www.npmjs.com/package/mcp-bizhawk)\n[![CI](https://github.com/dmang-dev/mcp-bizhawk/actions/workflows/ci.yml/badge.svg)](https://github.com/dmang-dev/mcp-bizhawk/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/npm/l/mcp-bizhawk.svg)](LICENSE)\n[![Snyk](https://snyk.io/test/npm/mcp-bizhawk/badge.svg)](https://snyk.io/test/npm/mcp-bizhawk)\n[![Socket](https://img.shields.io/badge/Socket-security-2F7BFF?logo=socket)](https://socket.dev/npm/package/mcp-bizhawk)\n[![Bundlephobia](https://img.shields.io/badge/bundlephobia-size-FF6B81)](https://bundlephobia.com/package/mcp-bizhawk)\n[![npmgraph](https://img.shields.io/badge/npmgraph-dependencies-2496ED)](https://npmgraph.js.org/?q=mcp-bizhawk)\n\nAn [MCP](https://modelcontextprotocol.io) server that exposes [BizHawk](https://github.com/TASEmulators/BizHawk) — the multi-system emulator the TAS community lives in — to any MCP-compatible client (Claude Desktop, Claude Code, etc.).\n\nOne bridge, **many systems**: NES, SNES, Game Boy / GBC / GBA, Sega Master System / Genesis / 32X / Saturn, N64, PlayStation 1, Atari 2600/5200/7800, Lynx, ColecoVision, Intellivision, and more — all through the same MCP tools, with per-system memory domains exposed cleanly.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/sm-claude-play.gif\" alt=\"Claude driving Super Metroid through mcp-bizhawk\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\u003cem\u003eClaude (the agent) drives Samus through the opening of Ceres Station — all input batched through \u003ccode\u003ebizhawk_play_input_sequence\u003c/code\u003e, all motion verified by reading WRAM addresses found via live RAM-hunt. Recording is 2× speed; the actual playback runs at native 60fps emulation. See \u003ca href=\"docs/RECIPES.md\"\u003e\u003ccode\u003edocs/RECIPES.md\u003c/code\u003e\u003c/a\u003e and \u003ca href=\"docs/SUPER-METROID-ADDRESSES.md\"\u003e\u003ccode\u003edocs/SUPER-METROID-ADDRESSES.md\u003c/code\u003e\u003c/a\u003e for the workflow.\u003c/em\u003e\u003c/p\u003e\n\n## How it works\n\n```\n+------------------+    stdio     +------------------+   TCP :8766   +------------------+\n|   MCP client     |   JSON-RPC   |    mcp-bizhawk   |  newline JSON |     BizHawk      |\n| (Claude / etc.)  | ===========\u003e |     (Node.js)    | \u003c============ |    bridge.lua    |\n+------------------+              +------------------+               +------------------+\n```\n\nThe transport is **inverted** compared to most other emulator-MCP bridges: BizHawk's Lua doesn't have native server sockets, only an outbound `comm.socketServer*` client. So `mcp-bizhawk` runs the TCP **listener**, and BizHawk's Lua bridge dials in once per frame to ferry commands and replies.\n\nTwo pieces:\n- **`lua/bridge.lua`** — runs *inside* BizHawk's Lua Console, polls our TCP server once per frame\n- **`dist/index.js`** — the Node.js MCP server, listens on `127.0.0.1:8766` by default, exposes tools over stdio\n\nTrade-off: this design adds **~one frame of latency** per call (≈16ms at 60Hz). Fine for interactive memory hunting, save-state experimentation, and frame-by-frame inspection. Less ideal for high-rate-of-fire scripting.\n\n## Requirements\n\n- [BizHawk](https://github.com/TASEmulators/BizHawk/releases) **2.6.2 or newer** (earlier builds use an older socket-server wire format)\n- **Node.js 18+** (for the MCP server)\n\nTested on BizHawk 2.11.1 across SNES (Super Metroid). Should work on any system BizHawk supports.\n\n## Install\n\n### Option A — install from npm (recommended)\n\n```bash\nnpm install -g mcp-bizhawk\n```\n\n### Option B — `npx` (no install)\n\n```bash\nnpx -y mcp-bizhawk\n```\n\n### Option C — clone and develop\n\n```bash\ngit clone https://github.com/dmang-dev/mcp-bizhawk\ncd mcp-bizhawk\nnpm install        # also runs the build via the `prepare` hook\n```\n\n## Set up the BizHawk bridge\n\nThere are two pieces to configure: telling BizHawk where to connect, and loading the bridge script.\n\n### 1. Point BizHawk at the MCP server\n\nEasiest: launch BizHawk with the socket flags directly.\n\n```bash\nEmuHawk.exe --socket_ip=127.0.0.1 --socket_port=8766 \u003cpath/to/rom\u003e\n```\n\n(Adjust port if you're overriding `BIZHAWK_PORT`.)\n\nAlternative: configure persistently via **Settings → Customize → External Tools** in BizHawk's UI.\n\n### 2. Load the bridge script\n\nIn BizHawk: **Tools → Lua Console → Open Script** → select `lua/bridge.lua` from this repo.\n\nYou should see in the Lua Console:\n```\n[mcp-bizhawk] bridge starting\n[mcp-bizhawk] socket server target: 127.0.0.1:8766\n[mcp-bizhawk] socket receive timeout set to 50ms\n[mcp-bizhawk] frame loop active — bridge is polling once per frame\n```\n\nAnd in the `mcp-bizhawk` process's stderr:\n```\n[mcp-bizhawk] BizHawk client connected (waiting for bridge.lua to start polling)\n[mcp-bizhawk] bridge.lua is polling — bridge ready\n```\n\n## Register with your MCP client\n\n### Claude Code (CLI)\n\n```bash\nclaude mcp add bizhawk --scope user mcp-bizhawk\n```\n\nVerify:\n```bash\nclaude mcp list\n# bizhawk: mcp-bizhawk - ✓ Connected\n```\n\n### Claude Desktop\n\nEdit `claude_desktop_config.json`:\n\n| Platform | Path |\n|---|---|\n| macOS    | `~/Library/Application Support/Claude/claude_desktop_config.json` |\n| Windows  | `%APPDATA%\\Claude\\claude_desktop_config.json` |\n| Linux    | `~/.config/Claude/claude_desktop_config.json` |\n\n```json\n{\n  \"mcpServers\": {\n    \"bizhawk\": {\n      \"command\": \"mcp-bizhawk\"\n    }\n  }\n}\n```\n\nRestart Claude Desktop after editing.\n\n### Other MCP clients\n\nThe server speaks standard MCP over stdio. Run `mcp-bizhawk` and connect any MCP client to its stdio.\n\n## Configuration\n\n| Env var        | Default       | Purpose                              |\n|----------------|---------------|--------------------------------------|\n| `BIZHAWK_HOST` | `127.0.0.1`   | TCP host to listen on for BizHawk    |\n| `BIZHAWK_PORT` | `8766`        | TCP port to listen on for BizHawk    |\n\n## Tools\n\n| Tool | Description |\n|------|-------------|\n| `bizhawk_ping` | Verify bridge connectivity (returns `pong`) |\n| `bizhawk_get_info` | ROM name, ROM hash, framecount, memory domains, capabilities |\n| `bizhawk_list_memory_domains` | List available memory domains for the loaded core |\n| `bizhawk_read8` / `bizhawk_read16` / `bizhawk_read32` | Read u8 / u16-LE / u32-LE from memory |\n| `bizhawk_write8` / `bizhawk_write16` / `bizhawk_write32` | Write to memory |\n| `bizhawk_read_range` | Read up to 4096 bytes as a byte array |\n| `bizhawk_write_range` | Write up to 4096 bytes from a byte array |\n| `bizhawk_press_buttons` | Set joypad state for one player; keys are button names, values booleans |\n| `bizhawk_frame_advance` | Step the emulator by N frames |\n| `bizhawk_pause` / `bizhawk_unpause` | Pause / resume emulation |\n| `bizhawk_reset` | Reset the loaded core |\n| `bizhawk_screenshot` | Save a PNG of the current display to a path |\n| `bizhawk_save_state` / `bizhawk_load_state` | Save / load emulator state to a file path |\n\nAll memory r/w tools take an optional `domain` parameter — if omitted, the active \"current\" memory domain is used. Use `bizhawk_list_memory_domains` to discover the names available on the loaded core.\n\nSee [`docs/RECIPES.md`](docs/RECIPES.md) for end-to-end examples (RAM hunting on SNES/NES/N64, frame-precise input, snapshot-experiment-restore, cross-system regression testing) and [`CHANGELOG.md`](CHANGELOG.md) for release history.\n\n### Memory domains by system (cheat sheet)\n\nNames come straight from BizHawk's core implementation. Use `bizhawk_list_memory_domains` to see the exact set for the loaded ROM.\n\n| System  | Main RAM domain | Other common domains              |\n|---------|-----------------|-----------------------------------|\n| NES     | `RAM`           | `PPU`, `OAM`, `PRG ROM`, `CHR`    |\n| SNES    | `WRAM`          | `VRAM`, `CARTROM`, `CARTRAM`      |\n| GB/GBC  | `WRAM`          | `VRAM`, `HRAM`, `OAM`, `ROM`      |\n| GBA     | `EWRAM`, `IWRAM`| `VRAM`, `PALRAM`, `OAM`, `ROM`    |\n| Genesis | `68K RAM`       | `VRAM`, `Z80 RAM`, `CARTRAM`      |\n| N64     | `RDRAM`         | `SP DMEM`, `SP IMEM`, `PI Reg`    |\n| PSX     | `MainRAM`       | `VRAM`, `Scratchpad`, `BIOS`      |\n\n### Buttons by system\n\nBizHawk's `joypad.set` takes a `{ButtonName=true, ...}` table where button names depend on the core. Common ones:\n\n| System  | Names                                                              |\n|---------|---------------------------------------------------------------------|\n| NES     | `A`, `B`, `Up`, `Down`, `Left`, `Right`, `Start`, `Select`         |\n| SNES    | `A`, `B`, `X`, `Y`, `L`, `R`, `Up`, `Down`, `Left`, `Right`, `Start`, `Select` |\n| GB/GBC  | `A`, `B`, `Up`, `Down`, `Left`, `Right`, `Start`, `Select`         |\n| GBA     | `A`, `B`, `L`, `R`, `Up`, `Down`, `Left`, `Right`, `Start`, `Select` |\n| N64     | `A`, `B`, `Z`, `L`, `R`, `Start`, `Up`, `Down`, `Left`, `Right`, `C-Up`, `C-Down`, `C-Left`, `C-Right` |\n| Genesis | `A`, `B`, `C`, `X`, `Y`, `Z`, `Up`, `Down`, `Left`, `Right`, `Start`, `Mode` |\n\nIf you're unsure, run a probe: `bizhawk_press_buttons {\"A\": true}` and watch the active core's input display in BizHawk.\n\n## Troubleshooting\n\n| Symptom | Cause / Fix |\n|---|---|\n| MCP tool calls hang for 10 seconds, then time out with \"is the bridge.lua script still polling?\" | bridge.lua isn't loaded. In BizHawk: **Tools → Lua Console → Open Script → bridge.lua**. Check the console for `frame loop active`. |\n| BizHawk connects to the server but tool calls still time out | You're on BizHawk older than 2.6.2 — the socket wire format changed then. Upgrade BizHawk. |\n| `[mcp-bizhawk] FATAL: comm.socketServer* not available` in the Lua Console | BizHawk wasn't launched with `--socket_ip` / `--socket_port` flags, and no socket server is configured in **Settings → Customize → External Tools**. |\n| Tools missing in Claude after install | Restart your MCP client; Claude only enumerates servers on startup. |\n| Memory reads return zeros for the first few seconds after boot | The emulator hasn't initialized RAM yet. Either advance some frames (`bizhawk_frame_advance`) or check `bizhawk_get_info` to confirm framecount \u003e 0 before relying on game state. |\n| `unknown memory domain: \u003cname\u003e` | The domain name didn't match anything for the loaded core. Call `bizhawk_list_memory_domains` to see the actual list — names are case-sensitive. |\n| `client.screenshot not available` or `savestate.* not available` | Some BizHawk cores expose a slightly different surface. Check `bizhawk_get_info` — the `capabilities` map shows which optional functions are present on your current build/core combo. |\n\n## Development\n\n```bash\nnpm install\nnpm run dev      # tsc --watch — autobuilds on src/ changes\n```\n\nEnd-to-end smoke test (launches BizHawk, loads ROM + bridge, runs ping/get_info/list_memory_domains/read_range):\n\n```bash\nnode .scratch/test-all.cjs \"I:\\path\\to\\your\\rom.smc\"\n```\n\nSet `DEBUG=1` to dump every RX/TX line.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmang-dev%2Fmcp-bizhawk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdmang-dev%2Fmcp-bizhawk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmang-dev%2Fmcp-bizhawk/lists"}