mgba_write8
Write a single byte value to any RAM address in the Game Boy Advance emulator, using direct memory access that bypasses cartridge bus effects. Writes to ROM regions are ignored.
Instructions
Write a single byte value to a memory address. Only works on RAM regions; writes to ROM are no-ops.
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 | RAM address | |
| value | Yes | Byte value (0-255) |
Implementation Reference
- src/tools.ts:90-101 (schema)Tool definition (name, description, inputSchema) for mgba_write8, registered in the TOOLS array. Schema requires address (integer) and value (integer 0-255).
{ name: "mgba_write8", description: `Write a single byte value to a memory address. Only works on RAM regions; writes to ROM are no-ops.\n\n${MBC_CAVEAT}`, inputSchema: { type: "object", required: ["address", "value"], properties: { address: { type: "integer", description: "RAM address" }, value: { type: "integer", minimum: 0, maximum: 255, description: "Byte value (0-255)" }, }, }, }, - src/tools.ts:310-313 (handler)Handler for mgba_write8: calls mgba.call('write8', {address, value}) via the RPC client and returns a formatted success message.
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()}`); } - src/tools.ts:258-261 (registration)The registerTools function registers all tools (including mgba_write8) via server.setRequestHandler(ListToolsRequestSchema).
export function registerTools(server: Server, mgba: MgbaClient): void { server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS })); server.setRequestHandler(CallToolRequestSchema, async (req) => { - src/tools.ts:247-254 (helper)Helper functions ok() and formatHex() used by the mgba_write8 handler to format its response.
function ok(text: string) { return { content: [{ type: "text" as const, text }] }; } function formatHex(n: unknown): string { if (typeof n !== "number") return String(n); return `${n} (0x${n.toString(16).toUpperCase()})`; } - src/mgba.ts:89-131 (helper)MgbaClient.call() method — the RPC transport used to send the 'write8' method to the mGBA Lua bridge.
async call<T = unknown>( method: string, params?: Record<string, unknown>, ): Promise<T> { // Lazy (re)connect — bridge.lua reloads kill the socket, and the user // shouldn't have to restart the MCP host every time they edit the script. if (!this.socket || this.socket.destroyed) { try { await this.connect(); } catch (err) { throw new Error( `Cannot reach mGBA bridge at ${this.host}:${this.port}. ` + `Make sure mGBA is running with bridge.lua loaded (Tools > Scripting). ` + `Underlying error: ${(err as Error).message}`, ); } } return new Promise<T>((resolve, reject) => { const sock = this.socket; if (!sock) { reject(new Error("socket vanished after connect")); return; } const id = this.nextId++; this.pending.set(id, (resp) => { if (resp.error) { reject(new Error(`mGBA RPC error [${resp.error.code}]: ${resp.error.message}`)); } else { resolve(resp.result as T); } }); const msg = JSON.stringify({ id, method, params: params ?? {} }) + "\n"; sock.write(msg, (err) => { if (err) { this.pending.delete(id); reject(err); } }); }); }