mgba_write_range
Write a contiguous range of bytes to emulated RAM for seeding SRAM, patching code, or installing cheats. Supports up to 4096 bytes per call.
Instructions
Write a contiguous range of bytes to emulated RAM in one call. Useful for seeding SRAM, patching code blocks, or installing cheats. Maximum 4096 bytes per call.
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.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Start address | |
| bytes | Yes | Array of byte values (0-255). Length cannot exceed 4096. |
Implementation Reference
- src/tools.ts:337-344 (handler)Handler for the mgba_write_range tool — calls the mGBA bridge's 'write_range' RPC method with address and bytes, then returns the count of bytes written.
case "mgba_write_range": { const r = await mgba.call<{ written: number }>("write_range", { address: p.address, bytes: p.bytes, }); const addr = (p.address as number).toString(16).toUpperCase(); return ok(`Wrote ${r.written} bytes → 0x${addr}`); } - src/tools.ts:138-155 (schema)Schema definition for mgba_write_range — requires 'address' (integer) and 'bytes' (array of integers 0-255, length 1-4096).
{ name: "mgba_write_range", description: `Write a contiguous range of bytes to emulated RAM in one call. Useful for seeding SRAM, patching code blocks, or installing cheats. Maximum 4096 bytes per call.\n\n${MBC_CAVEAT}`, inputSchema: { type: "object", required: ["address", "bytes"], properties: { address: { type: "integer", description: "Start address" }, bytes: { type: "array", items: { type: "integer", minimum: 0, maximum: 255 }, minItems: 1, maxItems: 4096, description: "Array of byte values (0-255). Length cannot exceed 4096.", }, }, }, }, - src/tools.ts:258-411 (registration)Registration of all tools via server.setRequestHandler, including mgba_write_range as a case in the CallToolRequestSchema switch.
export function registerTools(server: Server, mgba: MgbaClient): void { server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS })); server.setRequestHandler(CallToolRequestSchema, async (req) => { const { name, arguments: args = {} } = req.params; const p = args as Record<string, unknown>; switch (name) { case "mgba_ping": { const r = await mgba.call<string>("ping"); return ok(r); } case "mgba_get_info": { const r = await mgba.call<{ title?: string; code?: string; frame?: number; platform?: number | string; capabilities?: Record<string, boolean>; }>("get_info"); const lines = [ `Title: ${r.title ?? "(unavailable)"}`, `Code: ${r.code ?? "(unavailable)"}`, `Platform: ${r.platform ?? "(unavailable)"}`, `Frame: ${r.frame ?? "(unavailable)"}`, ]; if (r.capabilities) { const present = Object.entries(r.capabilities).filter(([, v]) => v).map(([k]) => k); const missing = Object.entries(r.capabilities).filter(([, v]) => !v).map(([k]) => k); lines.push(""); lines.push(`Capabilities present: ${present.length ? present.join(", ") : "(none)"}`); if (missing.length) lines.push(`Missing on this build: ${missing.join(", ")}`); } return ok(lines.join("\n")); } case "mgba_read8": { const v = await mgba.call<number>("read8", { address: p.address }); return ok(`0x${(p.address as number).toString(16).toUpperCase()}: ${formatHex(v)}`); } case "mgba_read16": { const v = await mgba.call<number>("read16", { address: p.address }); return ok(`0x${(p.address as number).toString(16).toUpperCase()}: ${formatHex(v)}`); } case "mgba_read32": { const v = await mgba.call<number>("read32", { address: p.address }); return ok(`0x${(p.address as number).toString(16).toUpperCase()}: ${formatHex(v)}`); } case "mgba_write8": { await mgba.call("write8", { address: p.address, value: p.value }); return ok(`Wrote ${formatHex(p.value)} → 0x${(p.address as number).toString(16).toUpperCase()}`); } case "mgba_write16": { await mgba.call("write16", { address: p.address, value: p.value }); return ok(`Wrote ${formatHex(p.value)} → 0x${(p.address as number).toString(16).toUpperCase()}`); } case "mgba_write32": { await mgba.call("write32", { address: p.address, value: p.value }); return ok(`Wrote ${formatHex(p.value)} → 0x${(p.address as number).toString(16).toUpperCase()}`); } case "mgba_read_range": { const bytes = await mgba.call<number[]>("read_range", { address: p.address, length: p.length, }); const hex = bytes .map((b) => b.toString(16).padStart(2, "0").toUpperCase()) .join(" "); const addr = (p.address as number).toString(16).toUpperCase(); return ok(`0x${addr} [${bytes.length} bytes]:\n${hex}`); } case "mgba_write_range": { const r = await mgba.call<{ written: number }>("write_range", { address: p.address, bytes: p.bytes, }); const addr = (p.address as number).toString(16).toUpperCase(); return ok(`Wrote ${r.written} bytes → 0x${addr}`); } case "mgba_press_buttons": { const r = await mgba.call<{ queued: boolean; queue_size: number }>("press_buttons", { buttons: p.buttons, frames: p.frames ?? 1, release_frames: p.release_frames ?? 1, }); const keys = (p.buttons as string[]).join("+"); return ok( `Queued press: ${keys} ` + `(hold ${p.frames ?? 1}f, release ${p.release_frames ?? 1}f). ` + `Queue size: ${r.queue_size}`, ); } case "mgba_advance_frames": { const frame = await mgba.call<number>("advance_frames", { count: p.count ?? 1 }); return ok(`Advanced ${p.count ?? 1} frame(s). Current frame: ${frame}`); } case "mgba_pause": { await mgba.call("pause"); return ok("Emulation paused"); } case "mgba_unpause": { await mgba.call("unpause"); return ok("Emulation resumed"); } case "mgba_reset": { await mgba.call("reset"); return ok("ROM reset"); } case "mgba_screenshot": { const path = await mgba.call<string>("screenshot", p.path ? { path: p.path } : {}); return ok(`Screenshot saved: ${path}`); } case "mgba_save_state": { if (p.slot === undefined && p.path === undefined) { throw new Error("provide either `slot` (0-9) or `path`"); } const r = await mgba.call<{ slot?: number; path?: string }>("save_state", { ...(p.slot !== undefined ? { slot: p.slot } : {}), ...(p.path !== undefined ? { path: p.path } : {}), }); return ok(r.path ? `Saved state to ${r.path}` : `Saved state to slot ${r.slot}`); } case "mgba_load_state": { if (p.slot === undefined && p.path === undefined) { throw new Error("provide either `slot` (0-9) or `path`"); } const r = await mgba.call<{ slot?: number; path?: string }>("load_state", { ...(p.slot !== undefined ? { slot: p.slot } : {}), ...(p.path !== undefined ? { path: p.path } : {}), }); return ok(r.path ? `Loaded state from ${r.path}` : `Loaded state from slot ${r.slot}`); } default: throw new Error(`Unknown tool: ${name}`); } }); }