mgba_run
Run Game Boy, GBC, or GBA ROMs for a specified number of frames and capture screenshots for automated testing and game analysis.
Instructions
Run a GB/GBC/GBA ROM for a specified number of frames and capture a screenshot
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| rom_path | Yes | Path to the ROM file (.gb, .gbc, .gba) | |
| frames | No | Number of frames to run (default: 60) | |
| savestate_path | No | Optional path to a savestate file to load |
Implementation Reference
- src/mgba_mcp/emulator.py:98-122 (handler)Core handler implementing the mgba_run tool logic: runs mGBA headless for specified frames using Lua frame callback to capture screenshot and quit.def run_frames( self, rom_path: str, frames: int = 60, savestate_path: Optional[str] = None, screenshot: bool = True, ) -> EmulatorResult: """Run emulator for specified number of frames.""" lua_script = f""" local frame = 0 local target_frames = {frames} local take_screenshot = {'true' if screenshot else 'false'} callbacks:add("frame", function() frame = frame + 1 if frame >= target_frames then if take_screenshot then emu:screenshot("screenshot.png") end emu:quit() end end) """ return self._run_with_lua(rom_path, lua_script, savestate_path)
- src/mgba_mcp/server.py:213-231 (handler)MCP server tool dispatch handler for 'mgba_run': calls emulator.run_frames and formats text/image response.if name == "mgba_run": result = emu.run_frames( rom_path=arguments["rom_path"], frames=arguments.get("frames", 60), savestate_path=arguments.get("savestate_path"), screenshot=True, ) if result.success: result_content.append(TextContent(type="text", text="Emulator ran successfully")) if result.screenshot: result_content.append(ImageContent( type="image", data=base64.b64encode(result.screenshot).decode(), mimeType="image/png", )) else: result_content.append(TextContent(type="text", text=f"Error: {result.error}"))
- src/mgba_mcp/server.py:34-56 (registration)Registers the 'mgba_run' tool with the MCP server, including name, description, and input schema.Tool( name="mgba_run", description="Run a GB/GBC/GBA ROM for a specified number of frames and capture a screenshot", inputSchema={ "type": "object", "properties": { "rom_path": { "type": "string", "description": "Path to the ROM file (.gb, .gbc, .gba)", }, "frames": { "type": "integer", "description": "Number of frames to run (default: 60)", "default": 60, }, "savestate_path": { "type": "string", "description": "Optional path to a savestate file to load", }, }, "required": ["rom_path"], }, ),
- src/mgba_mcp/emulator.py:31-97 (helper)Helper function that executes mGBA subprocess with Lua script, captures screenshot and JSON output, used by all tools including mgba_run.def _run_with_lua( self, rom_path: str, lua_script: str, savestate_path: Optional[str] = None, timeout: int = 30, ) -> EmulatorResult: """Run mGBA with a Lua script and return results.""" # Write Lua script to temp file lua_file = self.temp_dir / "script.lua" lua_file.write_text(lua_script) # Build command cmd = [] if self.use_xvfb: cmd.extend(["xvfb-run", "-a"]) cmd.extend([self.mgba_path, rom_path]) if savestate_path: cmd.extend(["-t", savestate_path]) cmd.extend(["--script", str(lua_file), "-l", "0"]) try: result = subprocess.run( cmd, capture_output=True, text=True, timeout=timeout, cwd=str(self.temp_dir), ) # Check for output files screenshot_path = self.temp_dir / "screenshot.png" output_path = self.temp_dir / "output.json" screenshot = None if screenshot_path.exists(): screenshot = screenshot_path.read_bytes() output_data = None if output_path.exists(): try: output_data = json.loads(output_path.read_text()) except json.JSONDecodeError: pass return EmulatorResult( success=result.returncode == 0, screenshot=screenshot, output=result.stdout, error=result.stderr if result.returncode != 0 else None, data=output_data, ) except subprocess.TimeoutExpired: return EmulatorResult( success=False, error=f"Emulator timed out after {timeout}s", ) except Exception as e: return EmulatorResult( success=False, error=str(e), )