Skip to main content
Glama

mame_mcp

mame_mcp is a Model Context Protocol bridge for MAME-focused reverse engineering. It is aimed at arcade-to-SNES porting work: memory access traces, input injection, ROM audit checks, IO-port discovery, and reproducible headless harnesses.

Stock-MAME compatible — no custom MAME binary required. Two modes, both on stock MAME: the stateless tools drive MAME with generated -autoboot_script Lua sidecars (spawn, run, exit); the live session suite keeps a persistent MAME alive behind a bridge and exposes debugger-style live memory read/write, register access, run/pause, save/load state, and input injection across calls. A deeper MAME source fork is still only needed for the harder stuff (low-overhead instruction-trace ring buffers; device introspection Lua can't reach) — see Fork Roadmap.

Quick Start

python -m pip install -e .

$env:MAME_EXE = "/path/to/mame"      # or leave unset if mame is on PATH

mame-mcp-tools --names
mame-mcp-tools --category trace

Wire it into Codex or another MCP client:

{
  "mcpServers": {
    "mame": {
      "command": "mame-mcp-bridge",
      "env": {
        "MAME_EXE": "/path/to/mame"
      }
    }
  }
}

Restart the MCP client after editing its config.

This repo includes a generic .mcp.json that only starts the bridge. Pass system and rompath in each tool call, or set MAME_SYSTEM and MAME_ROMPATH in your local MCP config for the project you are inspecting.

Related MCP server: mGBA MCP Server

Tools

Two families: stateless one-shot tools (each spawns MAME, does its job, exits) and a live session suite (one persistent MAME kept alive across calls — read/write/run/inject like a debugger). 25 tools total.

Stateless (one-shot)

Tool

Purpose

ping

Echo back an optional payload; verify the MCP bridge is alive.

config_check

Resolve MAME env/config paths and report which required pieces exist.

audit_romset

Run mame -verifyroms <system> and return the audit tail.

get_ioports

Boot a machine briefly and list MAME Lua IO-port fields (for input injection).

trace_memory_access

Install Lua read/write taps over CPU address ranges; log deduped accesses.

trace_cchip_superman

Superman helper: trace $900000-$900FFF C-Chip accesses + the $900803 status verdict.

run_lua_script

Run a caller-supplied MAME Lua autoboot script (by path), headlessly.

run_lua_inline

Run caller-supplied MAME Lua source (string, not a path); optional artifact read-back.

capture_leaf_io

Golden-vector capture for a pure leaf that transforms one word/byte in place — inject inputs via taps, record output+regs+CCR. Independent oracle for a transpiler differential harness.

Live session (persistent MAME, debugger-style)

Call mame_launch first (keeps MAME running across calls); the rest operate on that session.

Tool

Purpose

mame_launch

Launch a PERSISTENT live MAME (headless + bridge). Required before any other mame_* tool.

mame_session_status

Live session status (system, frame, paused).

mame_session_stop

Terminate the live session.

mame_pause / mame_resume

Pause / resume the machine (state stays readable while paused).

mame_run_frames

Run N frames then pause; returns the frame number.

mame_read_memory / mame_write_memory

Read / write a hex block in a device's program space.

mame_get_regs / mame_set_reg

Read all CPU registers (D0-D7/A0-A7/PC/SR/USP/…) / set one.

mame_save_state / mame_load_state

Save / load a MAME save state by name (needs stateDirectory).

mame_send_input

Set an ioport field value (e.g. Coin 1, P1 Right).

mame_exec_lua_live

Run Lua on the live machine (M/machine = manager.machine); returns its value.

mame_capture_game_tick

Run to the Nth GAME_TICK and snapshot regs + a memory region at the prologue read (lockstep primitive).

mame_drive_to_gameplay

Boot-aware drive to a running game: wait for idle, inject clean coin/start edges, confirm GAME_TICK (replay-robust where a fixed .inp desyncs).

The MCP responses return JSON text with command lines, log paths, return codes, stderr/stdout tails, and parsed trace summaries where applicable.

Environment

Env var

Default

Purpose

MAME_EXE

mame

MAME executable or command on PATH.

MAME_SYSTEM

none

Default machine short name, e.g. driver_short_name.

MAME_ROMPATH

none

ROM search path.

MAME_CWD

current directory

Working directory for generated scripts/logs and MAME state.

MAME_WORKDIR

<MAME_CWD>/.mame_mcp

Generated Lua, logs, nvram, cfg, etc.

Generic Trace Example

{
  "system": "driver_short_name",
  "rompath": "/path/to/roms",
  "frames": 1800,
  "ranges": [
    { "name": "device_window", "start": 9437184, "end": 9441279 }
  ],
  "trackReads": [
    { "name": "status", "address": 9439234 }
  ],
  "injectPreset": "none",
  "dryRun": true
}

trace_memory_access installs read/write taps over each range, dedupes by (R/W, PC, address, range), optionally counts values read from selected addresses, and writes a human-readable log plus a parsed JSON summary.

Use "dryRun": true to generate the Lua harness without launching MAME.

Superman C-Chip Helper

trace_cchip_superman is a convenience wrapper for the known Superman C-Chip window. It still requires the caller or environment to provide the ROM path.

{
  "rompath": "/path/to/roms",
  "frames": 1800,
  "injectPreset": "none"
}

It expands to a trace_memory_access call over $900000-$900FFF, tracking reads from $900802/$900803 and reporting whether status $01 and $05 were seen.

Fork Roadmap

The stock-MAME Lua layer can cover a lot:

  • address read/write taps,

  • frame callbacks,

  • input-field injection,

  • ROM audit and machine metadata,

  • screenshots via MAME command-line/video options,

  • reproducible generated scripts and logs.

Already delivered without a fork, via the live-session bridge (stock MAME + a persistent process): a long-lived session, debugger-grade live memory reads/writes, register get/set, run/pause, and save/load state (the mame_* tools above).

A true MAME source fork becomes worthwhile only for what Lua/the bridge can't do well:

  • instruction trace ring buffers with low overhead,

  • tile/sprite/sound device introspection not exposed through Lua,

  • screenshot APIs as one-shot MCP calls.

The MCP tool names and response shapes here are intentionally similar to the Mesen MCP bridge so agents can learn one mental model and apply it to both console and arcade sources.

Available Tools

25 tools
audit_romsetA

Run mame -verifyroms <system> and return the audit output tail.

Inputs: cwd, system, mameExe, rompath, +2 more.

capture_leaf_ioB

Golden-vector capture for a pure leaf that transforms one memory word/byte in place (RNG/counter/accumulator). Injects inputs via taps, records output + regs + CCR. Independent oracle for the transpiler differential harness.

Inputs: inputs (required), entryPc (required), varAddress (required), cwd, +11 more.

config_checkB

Resolve MAME env/config paths and report which required pieces exist.

Inputs: cwd, system, mameExe, rompath, +1 more.

get_ioportsA

Boot a machine briefly and list MAME Lua IO-port fields for input injection.

Inputs: cwd, system, logPath, mameExe, +3 more.

mame_capture_game_tickB

Run to the Nth GAME_TICK ($3A92) and snapshot regs + a memory region AT the prologue read (lockstep regsA/wramA primitive; entry a7 = SP+60).

Inputs: len (required), addr (required), nth, timeout.

mame_drive_to_gameplayA

BOOT-AWARE drive to a running game: wait for the $0818 idle (boot done), inject clean coin/start EDGES, confirm GAME_TICK. Replay-robust where a fixed-frame .inp desyncs (the C-Chip boot handshake isn't bit-reproducible).

Inputs: coin, start, credits.

mame_exec_lua_liveB

Run Lua on the live machine (vars M/machine = manager.machine); returns its value.

Inputs: code (required).

mame_get_regsA

Read all CPU state registers (D0-D7,A0-A7,PC,SR,USP,...).

Inputs: device.

mame_launchA

Launch a PERSISTENT live MAME (headless + bridge) and keep it running across tool calls. Required before any other mame_* live tool.

Inputs: cwd, system, mameExe, rompath, +3 more.

mame_load_stateA

Load a MAME save state by name (needs stateDirectory). Apply with a run_frames after.

Inputs: name (required).

mame_pauseA

Pause the live machine (state stays readable).

Inputs: no named parameters.

mame_read_memoryC

Read a memory block (hex) from a device's program space.

Inputs: len (required), addr (required), space.

mame_resumeB

Resume the live machine.

Inputs: no named parameters.

mame_run_framesA

Run N frames then pause; returns the frame number.

Inputs: n (required).

mame_save_stateB

Save a MAME save state by name.

Inputs: name (required).

mame_send_inputB

Set an ioport field value (e.g. 'Coin 1', 'P1 Right').

Inputs: field (required), value (required).

mame_session_statusB

Live session status (system, frame, paused).

Inputs: no named parameters.

mame_session_stopB

Terminate the live MAME session.

Inputs: no named parameters.

mame_set_regD

Set one CPU register.

Inputs: reg (required), value (required), device.

mame_write_memoryB

Write a hex block to a device's program space.

Inputs: hex (required), addr (required), space.

pingA

Echo back an optional payload. Use to verify the MCP bridge is alive.

Inputs: echo.

run_lua_inlineA

Run caller-supplied MAME Lua source (string, not a path) headlessly; optionally read back an artifact file.

Inputs: lua (required), cwd, frames, system, +5 more.

run_lua_scriptB

Run a caller-supplied MAME Lua autoboot script headlessly.

Inputs: scriptPath (required), cwd, frames, system, +4 more.

trace_cchip_supermanB

Superman helper: trace $900000-$900FFF C-Chip accesses and report $900803 status verdict.

Inputs: cwd, dryRun, frames, system, +6 more.

trace_memory_accessB

Install Lua read/write taps over CPU address ranges and log deduped accesses.

Inputs: cwd, dryRun, frames, ranges, +8 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.8/5.0

    Scored across 25 tools

    Disambiguation2/5

    Multiple tools have overlapping purposes: three different Lua execution tools (mame_exec_lua_live, run_lua_script, run_lua_inline), two tracing tools (trace_memory_access, trace_cchip_superman), and two gameplay automation tools (mame_drive_to_gameplay, mame_capture_game_tick) that are easy to confuse. Descriptions help distinguish them, but an agent would likely struggle to pick the right one without deep domain knowledge.

    Naming Consistency2/5

    Tool names are mixed: some use the mame_ prefix (mame_launch, mame_get_regs), while others do not (ping, audit_romset, trace_memory_access). Verb patterns also vary (run_lua_script vs mame_exec_lua_live, capture_leaf_io vs mame_capture_game_tick). While all use snake_case, the inconsistent prefix and verb choices make the set feel disjointed.

    Tool Count3/5

    25 tools is at the high end of the acceptable range and feels heavy for the server's purpose. Many tools could be consolidated (e.g., Lua execution variants, tracing helpers), which would reduce the surface area without losing functionality. Still, the complexity of MAME emulation and debugging justifies a larger toolset than typical servers.

    Completeness4/5

    The server covers a broad range of MAME operations: session lifecycle, memory/register access, input injection, Lua scripting, state save/load, tracing, and gameplay capture. Minor gaps exist, such as no tool to list save states or enumerate devices, but these are workable. The core workflows for reverse engineering and deterministic gameplay are well supported.

    Maintenance

    ActivityStale
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      B
      maintenance
      Enables AI agents to control an MSX emulator for debugging and reverse-engineering, including memory and code inspection, execution control, and saving annotations via MCP.
      -