# dmang-dev/mcp-mgba [Health: Active]

**Category:** 🎮 Gaming  
**Repository:** https://github.com/dmang-dev/mcp-mgba  
**GitHub Stars:** 2  
**npm Downloads (last month):** 110  
**Views:** 5  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/dmang-dev-mcp-mgba

## Description
Drive the mGBA Game Boy Advance emulator from any MCP client: read/write GBA memory, inject button presses, take screenshots, save/load state, and step the emulator. Lua bridge inside mGBA + Node MCP server.

## Tools
Capabilities this server exposes over MCP:

- **mgba_ping** — PURPOSE: Verify that the mGBA Lua bridge is connected and responding to RPC over the TCP socket. USAGE: Call this once at start-of-session before issuing other tool calls; if it succeeds, every other tool will at least be reachable (individual tools may still fail if the loaded mGBA build doesn't expose a particular emu method — see mgba_get_info → capabilities for that). BEHAVIOR: No side effects — pure liveness probe. Times out after a few seconds with a clear error if mGBA isn't running, isn't pointed at the right host:port, or hasn't loaded the bridge Lua script (Tools → Scripting in mGBA). RETURNS: The literal string 'pong' on success.
- **mgba_get_info** — PURPOSE: Get the loaded ROM's title, internal game code (e.g. 'AGBE' for GBA Pokemon Emerald US, 'BPRE' for FireRed), platform identifier (GBA vs GB/GBC), current frame count, and a `capabilities` map listing which optional emu methods this mGBA build exposes (pause, unpause, frameAdvance, saveStateSlot, saveStateFile, screenshot, etc.). USAGE: Call after mgba_ping at the start of a session to identify the loaded ROM and feature-detect optional capabilities BEFORE invoking tools that depend on them — pause/unpause/reset/save_state/load_state/advance_frames are all build-dependent on mGBA. The platform field tells you whether to address memory using the GBA layout (32-bit, EWRAM 0x02000000) or the GB/GBC layout (16-bit, WRAM 0xC000). BEHAVIOR: No side effects — pure read of emulator metadata. Returns '(unavailable)' for fields the loaded core can't expose (title when no ROM is loaded, code on systems without a header, etc.). Never throws on a partial read. RETURNS: Multi-line text with Title, Code, Platform, Frame, then the lists of present and missing capabilities for this build.
- **mgba_read8** — PURPOSE: Read an unsigned 8-bit byte from emulated memory at the given system bus address. USAGE: Use for single-byte status flags, counters, and 8-bit fields. For 16- or 32-bit values use mgba_read16/read32 (one call instead of multi-byte assembly); for spans of more than ~4 bytes use mgba_read_range (one round-trip instead of N frame-latency hops). Reads work the same way whether emulation is paused or running, so pause is optional but recommended when you need a coherent snapshot across multiple reads. BEHAVIOR: No side effects — pure read. Returns an error if the address is outside the platform's mapped regions or the bridge method is missing on this mGBA build. RETURNS: Single line 'ADDR_HEX: VAL_DEC (0xVAL_HEX)', e.g. '0x2000000: 99 (0x63)'.

GBA address space:
  0x02000000  EWRAM  (256 KiB, general-purpose)
  0x03000000  IWRAM  (32 KiB, fast stack/variables)
  0x04000000  IO registers
  0x05000000  Palette RAM (1 KiB)
  0x06000000  VRAM (96 KiB)
  0x07000000  OAM (1 KiB)
  0x08000000  ROM (up to 32 MiB, read-only)

Game Boy / GBC address space (when running a GB/GBC ROM):
  0x0000      ROM bank 0 (16 KiB, read-only on bus; writes here trigger MBC commands but mgba_write* bypasses the bus)
  0x4000      ROM banked (switchable)
  0x8000      VRAM (8 KiB)
  0xA000      Cartridge SRAM (8 KiB) — disabled by default on MBC1/3/5 carts
  0xC000      WRAM (8 KiB; CGB has banked extension to 0xD000)
  0xFE00      OAM (160 B)
  0xFF00      I/O registers
  0xFF80      HRAM (127 B)
- **mgba_read16** — PURPOSE: Read an unsigned 16-bit little-endian value from emulated memory at the given system bus address. USAGE: Use for 16-bit fields (most game-state values: HP, score, coordinates on 16-bit-flavoured layouts). For single bytes use mgba_read8; for 32-bit values use mgba_read32; for non-aligned spans, big-endian fields, or arbitrary structures use mgba_read_range and decode the bytes yourself (this tool always interprets bytes as little-endian, which matches both GBA and GB/GBC native endianness). BEHAVIOR: No side effects — pure read. Reads two consecutive bytes (low byte at `address`, high byte at `address+1`) and combines them as little-endian. Returns an error if the address is unmapped, the read straddles a region boundary, or the bridge method is missing on this build. RETURNS: Single line 'ADDR_HEX: VAL_DEC (0xVAL_HEX)'.
- **mgba_read32** — PURPOSE: Read an unsigned 32-bit little-endian value from emulated memory at the given system bus address. USAGE: Use for 32-bit fields (timestamps, large counters, pointers on GBA, RGBA colours). For 8/16-bit reads use mgba_read8/read16; for big-endian or unaligned multi-word reads use mgba_read_range and decode yourself. BEHAVIOR: No side effects — pure read. mGBA's native emu.read32 is intermittently flaky when called via pcall on certain builds, so the bridge transparently routes 32-bit reads through readRange(addr, 4) and reassembles them little-endian — you get a stable answer either way. Returns an error only if the address is unmapped or the underlying readRange itself fails. RETURNS: Single line 'ADDR_HEX: VAL_DEC (0xVAL_HEX)'.
- **mgba_read_range** — PURPOSE: Read a contiguous range of bytes from emulated memory and return them as a hex-formatted dump. USAGE: Use whenever you need more than ~4 bytes — one round-trip vs N frame-latency hops compared to looping mgba_read8. Maximum 4096 bytes per call (bridge serialization limit); for larger reads, batch in 4 KiB chunks. The classic two-snapshot RAM-hunt workflow uses this: snapshot before a known change, snapshot after, diff for matching deltas. Also useful for inspecting unknown structures and for 'capture, modify, restore' write_range workflows. This is the same primitive that mgba_read32 routes through internally. BEHAVIOR: No side effects — pure read. Reads `length` consecutive bytes starting at `address`. Returns an error if length > 4096, length < 1, the start address is unmapped, or the read crosses an unmapped region. RETURNS: Header line 'ADDR_HEX [N bytes]:' followed by space-separated 2-digit uppercase hex bytes.
- **mgba_write8** — PURPOSE: Write a single unsigned byte (0-255) to emulated memory at the given system bus address. USAGE: Use for single-byte cheats, debug pokes, and game-state mutations (give a player N lives, unlock a flag, set a counter). For 16/32-bit values prefer mgba_write16/write32 (single call instead of byte-at-a-time); for spans use mgba_write_range. To seed cart save RAM realistically (with proper MBC bank/enable behavior on Game Boy, or to install a known-good progression state on GBA), prefer mgba_save_state / mgba_load_state with a pre-prepared state file rather than poking SRAM bytes here. BEHAVIOR: DESTRUCTIVE: overwrites whatever was at `address` with no undo (snapshot via mgba_save_state first if you need rollback). The write is debug-direct memory access — bypasses MBC bank switches, cartridge mapper side-effects, RAM-enable gates, and bus protections — so it cannot be used to emulate cartridge hardware. Writes to ROM region addresses succeed at the memory level but produce no MBC effect on GB/GBC. Returns an error if the address is unmapped, value < 0 or > 255, or the bridge method is missing. Works whether emulation is paused or running. RETURNS: Single line 'Wrote VAL_DEC (0xVAL_HEX) → ADDR_HEX'.

NOTE: writes use mGBA's debug-direct memory access, which bypasses the cartridge bus model. On Game Boy with an MBC cartridge, this means writes to ROM region (0x0000-0x7FFF) won't trigger MBC bank-switch / RAM-enable commands, and writes to SRAM (0xA000-0xBFFF) hit the underlying buffer regardless of MBC enable state. To seed cartridge SRAM cleanly, use mgba_save_state / mgba_load_state with a pre-prepared state file.
- **mgba_write16** — PURPOSE: Write an unsigned 16-bit little-endian value to emulated memory at the given system bus address. USAGE: Use for 16-bit cheats and pokes (HP, score, coordinates). For single bytes use mgba_write8; for 32-bit use mgba_write32; for big-endian fields, byteswap and use mgba_write_range; for cart save RAM seeding with proper MBC semantics, use mgba_save_state / mgba_load_state. BEHAVIOR: DESTRUCTIVE: overwrites two bytes (low byte at `address`, high byte at `address+1`) with no undo. Debug-direct memory write — no MBC/mapper/DMA mediation, see mgba_write8 notes for the cartridge-bus bypass details. Returns an error if the address is unmapped, address+2 crosses an unmapped boundary, value < 0 or > 65535, or the bridge method is missing. RETURNS: Single line 'Wrote VAL_DEC (0xVAL_HEX) → ADDR_HEX'.

NOTE: writes use mGBA's debug-direct memory access, which bypasses the cartridge bus model. On Game Boy with an MBC cartridge, this means writes to ROM region (0x0000-0x7FFF) won't trigger MBC bank-switch / RAM-enable commands, and writes to SRAM (0xA000-0xBFFF) hit the underlying buffer regardless of MBC enable state. To seed cartridge SRAM cleanly, use mgba_save_state / mgba_load_state with a pre-prepared state file.
- **mgba_write32** — PURPOSE: Write an unsigned 32-bit little-endian value to emulated memory at the given system bus address. USAGE: Use for 32-bit cheats and pokes (timestamps, large counters, pointers on GBA). For 8/16-bit values use mgba_write8/write16; for big-endian layouts byteswap and use mgba_write_range. BEHAVIOR: DESTRUCTIVE: overwrites four bytes starting at `address` with no undo (snapshot via mgba_save_state first if you need rollback). Debug-direct memory write — bypasses MBC/mapper/DMA, see mgba_write8 notes. Returns an error if the address is unmapped, address+4 crosses an unmapped boundary, value < 0, or the bridge method is missing. RETURNS: Single line 'Wrote VAL_DEC (0xVAL_HEX) → ADDR_HEX'.

NOTE: writes use mGBA's debug-direct memory access, which bypasses the cartridge bus model. On Game Boy with an MBC cartridge, this means writes to ROM region (0x0000-0x7FFF) won't trigger MBC bank-switch / RAM-enable commands, and writes to SRAM (0xA000-0xBFFF) hit the underlying buffer regardless of MBC enable state. To seed cartridge SRAM cleanly, use mgba_save_state / mgba_load_state with a pre-prepared state file.
- **mgba_write_range** — PURPOSE: Write a contiguous byte sequence to emulated memory starting at the given system bus address. USAGE: Use whenever you're seeding more than ~4 bytes — one round-trip vs N frame-latency hops compared to looping mgba_write8. Maximum 4096 bytes per call (bridge serialization limit); for larger writes, batch in 4 KiB chunks. Useful for installing cheat tables, patching code blocks, restoring a captured byte window after experiments, and writing big-endian multi-byte values (byteswap them yourself first). For cart save RAM seeding with proper MBC semantics on Game Boy, use mgba_save_state / mgba_load_state instead — those go through the cartridge bus model. BEHAVIOR: DESTRUCTIVE: overwrites N bytes starting at `address` with no undo. Debug-direct memory write — bypasses MBC/mapper/DMA, see mgba_write8 notes for the cartridge-bus bypass details. Bytes are written sequentially address, address+1, ..., address+N-1. Returns an error if the address is unmapped, address+N crosses an unmapped boundary, the array contains a value outside 0-255, the array length is < 1 or > 4096, or the bridge method is missing. RETURNS: Single line 'Wrote N bytes → ADDR_HEX'.

NOTE: writes use mGBA's debug-direct memory access, which bypasses the cartridge bus model. On Game Boy with an MBC cartridge, this means writes to ROM region (0x0000-0x7FFF) won't trigger MBC bank-switch / RAM-enable commands, and writes to SRAM (0xA000-0xBFFF) hit the underlying buffer regardless of MBC enable state. To seed cartridge SRAM cleanly, use mgba_save_state / mgba_load_state with a pre-prepared state file.
- **mgba_press_buttons** — PURPOSE: Append a button-press to mGBA's input FIFO — hold the given buttons for `frames` frames, then release for `release_frames` frames before the next queued press starts. USAGE: Use to drive games with input. Each call APPENDS to the queue rather than overwriting, so consecutive calls produce distinct edge events that ROMs see as separate presses (rather than one continuous hold). To press the same button twice in a row reliably, send two presses — `release_frames` between them gives the ROM time to detect a key-up, which most input handlers require to register the second press. To advance emulation manually (without queueing inputs), use mgba_advance_frames. To inspect input-state side effects, pause first with mgba_pause and read RAM between presses. BEHAVIOR: Modifies the bridge's input queue; the press fires asynchronously on mGBA's frame callback. The call returns immediately with the new queue size — it does NOT block until the press completes. Returns an error if `buttons` contains a name not in the valid-key set, or if the bridge's input handling isn't installed on this build. RETURNS: Single line 'Queued press: KEYS (hold Nf, release Mf). Queue size: K'.

Valid button names: A, B, Select, Start, Right, Left, Up, Down, R, L.
- **mgba_advance_frames** — PURPOSE: Step emulation by exactly N frames synchronously and return the new frame count. USAGE: Use for frame-precise input automation (combine with mgba_press_buttons to time inputs against in-game animation), letting the system initialize after a hard reset (RAM is mostly zero in the first ~30 frames after mgba_reset), or settling state between memory reads. For long jumps (thousands of frames) prefer mgba_save_state / mgba_load_state of a pre-prepared state — advance_frames scales linearly. To resume real-time playback indefinitely instead of stepping, use mgba_unpause. Works whether emulation is currently paused or running and does NOT change the pause state. BEHAVIOR: Advances mGBA's frame clock by N frames inside the bridge's frame callback. Each step costs roughly one real frame (~16ms at 60Hz GBA / ~16.7ms at 60Hz GB) plus one bridge round-trip — so advancing 600 frames takes ~10 seconds wall-clock. This method is build-dependent on mGBA; check `capabilities.frameAdvance` in mgba_get_info first. Returns an error if the capability is missing on this build. RETURNS: Single line 'Advanced N frame(s). Current frame: NEW_COUNT'.
- **mgba_pause** — PURPOSE: Pause emulation — freeze the game-logic clock and hold the current frame on screen. USAGE: Use before a sequence of memory-inspect / write / screenshot calls when you need a stable game state across calls (so the game doesn't advance between your reads). Use mgba_unpause to resume; use mgba_advance_frames to step single frames without leaving pause. Memory reads and writes work the same way whether paused or not, so pause is only required when you specifically need a coherent snapshot — for one-shot reads it's optional. BEHAVIOR: Modifies emulator run state. The Lua bridge keeps polling the socket while paused, so all other tool calls (memory r/w, screenshot, save_state, etc.) still work. This method is build-dependent on mGBA; check `capabilities.pause` in mgba_get_info first to handle missing capability gracefully. Returns an error if the capability is missing on this build. Calling pause when already paused is a no-op. RETURNS: Single line 'Emulation paused'.
- **mgba_unpause** — PURPOSE: Resume emulation after a pause, returning to normal real-time playback. USAGE: Counterpart to mgba_pause. Use after a paused inspection sequence is complete. To advance only a few frames without resuming full speed, use mgba_advance_frames instead. BEHAVIOR: Modifies emulator run state. This method is build-dependent on mGBA; check `capabilities.unpause` in mgba_get_info first. Returns an error if the capability is missing on this build. Calling unpause when not paused is a no-op. RETURNS: Single line 'Emulation resumed'.
- **mgba_reset** — PURPOSE: Reset the loaded ROM — equivalent to pressing the reset button on the GBA / Game Boy. USAGE: Use to start fresh from boot. To return to a specific known-good point instead of boot, use mgba_load_state with a previously saved slot or .ss0/.ss1/etc state file. BEHAVIOR: DESTRUCTIVE: RAM contents become indeterminate (typically the BIOS-zeroed state), CPU returns to the reset vector, frame count resets to 0, input queue clears, and any in-progress audio/video state is discarded. The loaded ROM stays loaded — only volatile state is cleared. UNSAVED IN-GAME PROGRESS IS LOST (anything not committed to cartridge SRAM via the game's save menu, and anything not snapshotted via mgba_save_state). This method is build-dependent on mGBA; check `capabilities.reset` in mgba_get_info first. Returns an error if the capability is missing on this build. RETURNS: Single line 'ROM reset'.
- **mgba_screenshot** — PURPOSE: Save a PNG screenshot of the current emulator display. USAGE: For visual inspection or sequence documentation. To capture a specific frame, pause / advance / load_state first. For full machine state (RAM, registers, mapper) use mgba_save_state instead — screenshots are pixels only, not state. BEHAVIOR: DESTRUCTIVE to `path` if supplied (overwrites without prompt). Errors if `path`'s parent doesn't exist or isn't writable, or if the build doesn't expose screenshot. RETURNS: 'Screenshot saved: PATH' — the path you passed, or mGBA's default-directory filename if `path` was omitted.
- **mgba_save_state** — PURPOSE: Save the entire emulator state (RAM, CPU/PPU/APU registers, mapper state, sound chip state, timing, in-flight DMA) to either an mGBA-managed numbered slot OR an arbitrary file path. USAGE: Use as a rollback point before risky writes, to bookmark interesting game states, to share repro states, or — on Game Boy — to seed cartridge SRAM cleanly without fighting MBC bus semantics that mgba_write* would bypass. EXACTLY ONE of `slot` or `path` must be supplied (passing both, or neither, returns an error). Slots 0-9 are managed by mGBA in its data directory and are ideal for ad-hoc rollback during a session; explicit paths are better for long-term storage and sharing across sessions/machines. The companion mgba_load_state restores from either form. BEHAVIOR: When `path` is supplied, DESTRUCTIVE TO TARGET FILE: overwrites the file at `path` if it exists, with no prompt or backup. When `slot` is supplied, DESTRUCTIVE TO THE NAMED SLOT: overwrites whatever was previously stored in that slot. The state is bound to the EXACT ROM and a compatible mGBA version that produced it — loading it on a different ROM or an incompatible mGBA version typically produces a corrupt run or a hard error. Returns an error if neither `slot` nor `path` is supplied, the path's parent directory doesn't exist, the path isn't writable, the slot is out of range, or the relevant bridge save-state method (saveStateSlot vs saveStateFile) is missing on this build (check `capabilities` in mgba_get_info). RETURNS: Single line 'Saved state to PATH' or 'Saved state to slot N' depending on which form you used.
- **mgba_load_state** — PURPOSE: Restore the emulator from a previously saved slot or .ss state file. USAGE: Counterpart to mgba_save_state. Use to undo a sequence of writes/inputs (the snapshot/experiment/restore workflow), to jump to a bookmarked game state, or to start each tool-call sequence from a known baseline. EXACTLY ONE of `slot` or `path` must be supplied (passing both, or neither, returns an error). To start fresh from console boot instead of a snapshot, use mgba_reset. BEHAVIOR: DESTRUCTIVE TO LIVE STATE: replaces ALL current emulator state (RAM, registers, mapper, audio, frame count, in-flight DMA) with the snapshot's contents. Anything not previously snapshotted is lost (unsaved in-game progress, queued button presses, paused state). The state file/slot MUST come from the same ROM and a compatible mGBA version that produced it — loading mismatched data typically produces a corrupt run or a hard error. Returns an error if neither `slot` nor `path` is supplied, the file doesn't exist or isn't a valid mGBA state, the slot is empty or out of range, or the relevant bridge load-state method (loadStateSlot vs loadStateFile) is missing on this build (check `capabilities` in mgba_get_info). RETURNS: Single line 'Loaded state from PATH' or 'Loaded state from slot N' depending on which form you used.

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "mcp-mgba": {
    "command": "npx",
    "args": ["-y","mcp-mgba"],
    "env": {
      "MGBA_HOST": "",
      "MGBA_PORT": ""
    }
  }
}
```

**Requires environment variables:** `MGBA_HOST`, `MGBA_PORT` — the values above are empty placeholders; fill in real credentials before running (see the repository for what each one is for).

## Documentation

## What dmang-dev/mcp-mgba MCP server does

dmang-dev/mcp-mgba MCP server gives an MCP client control over a running mGBA instance. It supports both Game Boy Advance and Game Boy/Game Boy Color ROMs, with platform information reported through `mgba_get_info`. Agents can inspect emulator metadata, read memory, write values directly to mapped addresses, queue controller input, advance execution by exact frame counts, pause or resume emulation, reset the ROM, save PNG screenshots, and manage emulator save states.

The memory tools cover 8-bit, 16-bit, 32-bit, and contiguous byte-range operations. Save states can use mGBA-managed slots from 0 through 9 or explicit filesystem paths. This makes the server suitable for workflows such as examining game state, applying controlled memory changes, replaying input sequences, and restoring a known baseline after an experiment.

## How it works

The project has two cooperating parts. The Lua script runs inside mGBA's scripting engine and opens a loopback TCP listener on port 8765. The Node.js MCP process communicates with that bridge using newline-delimited JSON, then exposes the emulator operations to the client over standard MCP stdio.

Start a session with `mgba_ping` to check connectivity, then call `mgba_get_info` to identify the loaded ROM and inspect which optional emulator methods are available. Features such as pause, reset, frame advancement, screenshots, and state files depend on the loaded mGBA build. The bridge reports those capabilities so clients can avoid calling unavailable methods.

## Setup and configuration

Use mGBA 0.10 or newer with Lua scripting and Node.js 22 or newer. Install the server from npm with `npx -y mcp-mgba` or install it globally with `npm install -g mcp-mgba`.

In mGBA, load a ROM first, open Tools > Scripting, and load `lua/bridge.lua` from the repository. The MCP process then runs through stdio, while the Lua bridge accepts its emulator requests. Set `MGBA_HOST` to change the bridge host and `MGBA_PORT` to change the TCP port; the defaults are `127.0.0.1` and `8765`.

The README documents Claude Desktop and Claude Code registration. Other clients that support standard MCP stdio can run the same server process. Restart a client after changing its server configuration so it re-enumerates the tools.

## Tools and capabilities

- Check bridge liveness and retrieve ROM title, code, platform, frame count, and optional capabilities.
- Read or write individual 8-, 16-, and 32-bit values, or transfer up to 4096 bytes per range call.
- Queue presses for `A`, `B`, `Select`, `Start`, directional buttons, `R`, and `L`, with configurable hold and release durations.
- Advance the emulator by a specified number of frames without changing its pause state.
- Pause, resume, or reset the loaded ROM when the corresponding mGBA methods are available.
- Save and restore complete emulator state through slots or filesystem paths, and save the current display as a PNG.

## Limitations and notes

Direct memory writes are destructive and bypass the cartridge bus model. On GB/GBC systems, they do not perform MBC bank switching or RAM-enable behavior, so ROM-region writes do not trigger mapper commands and SRAM writes bypass mapper gates. Use a prepared save state when cartridge SRAM needs to be initialized with normal mapper semantics.

Range operations are limited to 4096 bytes and must remain within mapped memory. Save states are tied to the ROM and a compatible mGBA version. Loading a mismatched state can fail or produce a corrupted run. Frame advancement is synchronous but scales with emulation time, so large jumps can take several seconds. The bridge must be loaded only once per mGBA process after a clean restart if a prior script reload leaves an old callback active.

For dmang-dev/mcp-mgba MCP server sessions, pause before a multi-read or write sequence when a consistent snapshot matters, and save state before risky mutations if rollback is required.

_Full upstream README: https://allmcps.com/mcp/dmang-dev-mcp-mgba/readme_

