mgba_read32
Read a 32-bit unsigned value from a 4-byte aligned GBA memory address. Useful for inspecting emulator memory state.
Instructions
Read an unsigned 32-bit little-endian value from a GBA memory address. Address should be 4-byte aligned.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | GBA memory address (must be 4-byte aligned) |
Implementation Reference
- src/tools.ts:305-308 (handler)The handler case for mgba_read32: calls the mGBA bridge's 'read32' RPC method with the address parameter and formats the result as hex.
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)}`); } - src/tools.ts:80-89 (schema)The tool definition with name 'mgba_read32', description, and input schema requiring an integer address.
name: "mgba_read32", description: "Read an unsigned 32-bit little-endian value from a GBA memory address. Address should be 4-byte aligned.", inputSchema: { type: "object", required: ["address"], properties: { address: { type: "integer", description: "GBA memory address (must be 4-byte aligned)" }, }, }, }, - src/tools.ts:258-411 (registration)The registration function that wires up the tool definitions (TOOLS array) and the CallToolRequestSchema handler (which contains all switch cases including mgba_read32) to the MCP server.
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}`); } }); }