# dmang-dev/mcp-dolphin [Health: Active]

**Category:** 🎮 Gaming  
**Repository:** https://github.com/dmang-dev/mcp-dolphin  
**GitHub Stars:** 2  
**npm Downloads (last month):** 86  
**Views:** 2  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/dmang-dev-mcp-dolphin

## Description
Drive the Dolphin GameCube/Wii emulator from any MCP client: read/write PowerPC memory (MEM1/MEM2), GameCube + Wii Remote input (buttons, IR pointer, accelerometer, MotionPlus), reset, save/load state, and frame advance. Python bridge inside Felk's scripting fork + Node MCP server.

## Tools
Capabilities this server exposes over MCP:

- **dolphin_ping** — PURPOSE: Verify the Dolphin Python bridge is reachable and responding. USAGE: Call once at session start before other tool calls. Issues the bridge's `bridge.ping` method — doubles as a liveness probe and bridge-version sniff. BEHAVIOR: No side effects. mcp-dolphin connects to the bridge on demand (TCP 127.0.0.1:55355 by default). The bridge must be loaded inside Dolphin via Scripting → Add New Script → mcp_bridge.py. 10-second timeout if the bridge isn't running, Dolphin isn't running, or the port is wrong. RETURNS: Single line 'OK — bridge vBRIDGE_VERSION (DOLPHIN_LABEL)'.
- **dolphin_get_info** — PURPOSE: Report what the bridge knows about its environment (bridge version, Dolphin label). v0.1.0 doesn't query game metadata — Felk's API doesn't expose disc ID / title directly, those have to be read from OS_GLOBALS at 0x80000020 yourself via dolphin_read_range. USAGE: Diagnostic. For game state, use dolphin_read_range(0x80000000, 32) and decode: bytes 0-3 are the disc ID (4-char ASCII), 4-5 are maker code, 6 is disc number, 7 is disc version. BEHAVIOR: No side effects. Same underlying call as dolphin_ping but presents fields explicitly. RETURNS: Multi-line text — Bridge version, Dolphin label.
- **dolphin_read8** — PURPOSE: Read an unsigned 8-bit byte from PowerPC memory at the given absolute address. USAGE: Use for single-byte fields — flags, counters, small enums. For 16/32/64-bit values use dolphin_read16/read32/read64. For spans of more than ~4 bytes use dolphin_read_range. PowerPC is big-endian — so for multi-byte values you almost always want the dedicated width tool, not this one. BEHAVIOR: No side effects — pure read. No alignment requirement. Returns an error on unmapped address, bridge disconnect, or bridge FAIL.

GameCube + Wii main address space landmarks (PowerPC, big-endian):
  0x80000000-0x817FFFFF  MEM1 main RAM (24 MiB) — GameCube + Wii game code & data
                          GameCube games stay entirely within MEM1.
                          Wii games use MEM1 for code and frequently-accessed data.
  0x80000020             OS_GLOBALS — game-info struct (disc ID, FST, etc.)
  0x80000034             OS_ARENA_LO (start of free MEM1 heap)
  0x80003100             OS_REPORT (developer-console mirror, varies by SDK)
  0x90000000-0x93FFFFFF  MEM2 (64 MiB) — Wii ONLY. Larger texture/asset data,
                          IOS work areas. Reading MEM2 on a GameCube game
                          returns garbage / FAIL.
  0xCC000000-0xCC00FFFF  Hollywood I/O (Wii) / Flipper I/O (GameCube) — DMA,
                          GPU FIFO, AI, EXI registers. Reads are usually safe,
                          writes can wedge the emulator. Avoid.
  0xCD000000-0xCD007FFF  Wii-only Hollywood registers.

Notes:
  • All multi-byte values are BIG-ENDIAN on the real hardware. Felk's
    memory.read_u*/write_u* helpers handle the byte swap for you —
    the value you see is the value the game sees as a u32.
  • Addresses are 32-bit; Felk truncates the high bits of any u64
    address argument.
  • Pointers in MEM1 are often stored as 4-byte addresses with the
    high bit set (e.g. 0x81234567). Dereferencing them requires no
    masking — pass the raw value back into memory.read_*.

RETURNS: Single line 'ADDR_HEX: VAL_DEC (0xVAL_HEX)', e.g. '0x80003000: 99 (0x63)'.
- **dolphin_read16** — PURPOSE: Read an unsigned 16-bit big-endian value from PowerPC memory at the given absolute address. USAGE: For 16-bit fields — HP, score, coordinates on many GC/Wii titles. For single bytes use dolphin_read8; for 32/64-bit use dolphin_read32/read64. Value is interpreted big-endian (PowerPC native); the byte at `address` is the high byte. BEHAVIOR: No side effects — pure read. Address MUST be 2-byte aligned. Returns an error on unmapped address, bridge disconnect, or FAIL.

GameCube + Wii main address space landmarks (PowerPC, big-endian):
  0x80000000-0x817FFFFF  MEM1 main RAM (24 MiB) — GameCube + Wii game code & data
                          GameCube games stay entirely within MEM1.
                          Wii games use MEM1 for code and frequently-accessed data.
  0x80000020             OS_GLOBALS — game-info struct (disc ID, FST, etc.)
  0x80000034             OS_ARENA_LO (start of free MEM1 heap)
  0x80003100             OS_REPORT (developer-console mirror, varies by SDK)
  0x90000000-0x93FFFFFF  MEM2 (64 MiB) — Wii ONLY. Larger texture/asset data,
                          IOS work areas. Reading MEM2 on a GameCube game
                          returns garbage / FAIL.
  0xCC000000-0xCC00FFFF  Hollywood I/O (Wii) / Flipper I/O (GameCube) — DMA,
                          GPU FIFO, AI, EXI registers. Reads are usually safe,
                          writes can wedge the emulator. Avoid.
  0xCD000000-0xCD007FFF  Wii-only Hollywood registers.

Notes:
  • All multi-byte values are BIG-ENDIAN on the real hardware. Felk's
    memory.read_u*/write_u* helpers handle the byte swap for you —
    the value you see is the value the game sees as a u32.
  • Addresses are 32-bit; Felk truncates the high bits of any u64
    address argument.
  • Pointers in MEM1 are often stored as 4-byte addresses with the
    high bit set (e.g. 0x81234567). Dereferencing them requires no
    masking — pass the raw value back into memory.read_*.

RETURNS: Single line 'ADDR_HEX: VAL_DEC (0xVAL_HEX)'.
- **dolphin_read32** — PURPOSE: Read an unsigned 32-bit big-endian value from PowerPC memory at the given absolute address. USAGE: The workhorse — most game state and pointers are 32-bit. Use for timestamps, large counters, RGBA colors, full pointers (PowerPC is a 32-bit ISA so pointers fit here). For 8/16/64-bit values use the corresponding sibling. BEHAVIOR: No side effects — pure read. Address MUST be 4-byte aligned. Returns an error on unmapped address, bridge disconnect, or FAIL.

GameCube + Wii main address space landmarks (PowerPC, big-endian):
  0x80000000-0x817FFFFF  MEM1 main RAM (24 MiB) — GameCube + Wii game code & data
                          GameCube games stay entirely within MEM1.
                          Wii games use MEM1 for code and frequently-accessed data.
  0x80000020             OS_GLOBALS — game-info struct (disc ID, FST, etc.)
  0x80000034             OS_ARENA_LO (start of free MEM1 heap)
  0x80003100             OS_REPORT (developer-console mirror, varies by SDK)
  0x90000000-0x93FFFFFF  MEM2 (64 MiB) — Wii ONLY. Larger texture/asset data,
                          IOS work areas. Reading MEM2 on a GameCube game
                          returns garbage / FAIL.
  0xCC000000-0xCC00FFFF  Hollywood I/O (Wii) / Flipper I/O (GameCube) — DMA,
                          GPU FIFO, AI, EXI registers. Reads are usually safe,
                          writes can wedge the emulator. Avoid.
  0xCD000000-0xCD007FFF  Wii-only Hollywood registers.

Notes:
  • All multi-byte values are BIG-ENDIAN on the real hardware. Felk's
    memory.read_u*/write_u* helpers handle the byte swap for you —
    the value you see is the value the game sees as a u32.
  • Addresses are 32-bit; Felk truncates the high bits of any u64
    address argument.
  • Pointers in MEM1 are often stored as 4-byte addresses with the
    high bit set (e.g. 0x81234567). Dereferencing them requires no
    masking — pass the raw value back into memory.read_*.

RETURNS: Single line 'ADDR_HEX: VAL_DEC (0xVAL_HEX)'.
- **dolphin_read64** — PURPOSE: Read an unsigned 64-bit big-endian value from PowerPC memory at the given absolute address. USAGE: For paired 32-bit slots, doubles, packed flags. PowerPC is 32-bit so true 64-bit fields are less common than on PS2 — usually game state is 32-bit. Use this when you actually have a 64-bit field, not as a convenience for two 32-bit reads. BEHAVIOR: No side effects — pure read. Address MUST be 8-byte aligned. The result is returned as a decimal STRING (not a JSON number) to preserve precision past 2^53. Returns an error on unmapped address, bridge disconnect, or FAIL.

GameCube + Wii main address space landmarks (PowerPC, big-endian):
  0x80000000-0x817FFFFF  MEM1 main RAM (24 MiB) — GameCube + Wii game code & data
                          GameCube games stay entirely within MEM1.
                          Wii games use MEM1 for code and frequently-accessed data.
  0x80000020             OS_GLOBALS — game-info struct (disc ID, FST, etc.)
  0x80000034             OS_ARENA_LO (start of free MEM1 heap)
  0x80003100             OS_REPORT (developer-console mirror, varies by SDK)
  0x90000000-0x93FFFFFF  MEM2 (64 MiB) — Wii ONLY. Larger texture/asset data,
                          IOS work areas. Reading MEM2 on a GameCube game
                          returns garbage / FAIL.
  0xCC000000-0xCC00FFFF  Hollywood I/O (Wii) / Flipper I/O (GameCube) — DMA,
                          GPU FIFO, AI, EXI registers. Reads are usually safe,
                          writes can wedge the emulator. Avoid.
  0xCD000000-0xCD007FFF  Wii-only Hollywood registers.

Notes:
  • All multi-byte values are BIG-ENDIAN on the real hardware. Felk's
    memory.read_u*/write_u* helpers handle the byte swap for you —
    the value you see is the value the game sees as a u32.
  • Addresses are 32-bit; Felk truncates the high bits of any u64
    address argument.
  • Pointers in MEM1 are often stored as 4-byte addresses with the
    high bit set (e.g. 0x81234567). Dereferencing them requires no
    masking — pass the raw value back into memory.read_*.

RETURNS: Single line 'ADDR_HEX: VAL_DEC (0xVAL_HEX)' — VAL_DEC is a decimal string that may exceed 2^53.
- **dolphin_read_range** — PURPOSE: Read a contiguous range of bytes from PowerPC memory as a hex dump. USAGE: For >4 bytes — far cheaper than looping dolphin_read8 (one bridge round-trip vs N). Max 65536 bytes/call; chunk larger reads in 64 KiB. Powers snapshot-diff RAM hunting, unknown-struct inspection, and region capture. BEHAVIOR: No side effects. The bridge reads byte-by-byte via Felk's memory.read_u8 then returns hex over the wire. No alignment requirement.

GameCube + Wii main address space landmarks (PowerPC, big-endian):
  0x80000000-0x817FFFFF  MEM1 main RAM (24 MiB) — GameCube + Wii game code & data
                          GameCube games stay entirely within MEM1.
                          Wii games use MEM1 for code and frequently-accessed data.
  0x80000020             OS_GLOBALS — game-info struct (disc ID, FST, etc.)
  0x80000034             OS_ARENA_LO (start of free MEM1 heap)
  0x80003100             OS_REPORT (developer-console mirror, varies by SDK)
  0x90000000-0x93FFFFFF  MEM2 (64 MiB) — Wii ONLY. Larger texture/asset data,
                          IOS work areas. Reading MEM2 on a GameCube game
                          returns garbage / FAIL.
  0xCC000000-0xCC00FFFF  Hollywood I/O (Wii) / Flipper I/O (GameCube) — DMA,
                          GPU FIFO, AI, EXI registers. Reads are usually safe,
                          writes can wedge the emulator. Avoid.
  0xCD000000-0xCD007FFF  Wii-only Hollywood registers.

Notes:
  • All multi-byte values are BIG-ENDIAN on the real hardware. Felk's
    memory.read_u*/write_u* helpers handle the byte swap for you —
    the value you see is the value the game sees as a u32.
  • Addresses are 32-bit; Felk truncates the high bits of any u64
    address argument.
  • Pointers in MEM1 are often stored as 4-byte addresses with the
    high bit set (e.g. 0x81234567). Dereferencing them requires no
    masking — pass the raw value back into memory.read_*.

RETURNS: 'ADDR_HEX [N bytes]:' header + space-separated 2-digit uppercase hex bytes.
- **dolphin_write8** — PURPOSE: Write a single unsigned byte (0-255) to PowerPC memory at the given absolute address. USAGE: Use for single-byte cheats, debug pokes, and game-state mutations. For 16/32/64-bit values prefer dolphin_write16/write32/write64 (atomic from the game's perspective). To roll back, dolphin_save_state BEFORE the write and dolphin_load_state to restore. BEHAVIOR: DESTRUCTIVE: overwrites with no undo. Direct memory access — bypasses PowerPC MMU translation and any DMA semantics. Writes to read-only regions (boot ROM at 0xFFF00000, certain I/O ranges) are silently dropped by Dolphin. The write takes effect immediately, but visible effects appear only when the emulator next ticks. No alignment requirement for byte access.

GameCube + Wii main address space landmarks (PowerPC, big-endian):
  0x80000000-0x817FFFFF  MEM1 main RAM (24 MiB) — GameCube + Wii game code & data
                          GameCube games stay entirely within MEM1.
                          Wii games use MEM1 for code and frequently-accessed data.
  0x80000020             OS_GLOBALS — game-info struct (disc ID, FST, etc.)
  0x80000034             OS_ARENA_LO (start of free MEM1 heap)
  0x80003100             OS_REPORT (developer-console mirror, varies by SDK)
  0x90000000-0x93FFFFFF  MEM2 (64 MiB) — Wii ONLY. Larger texture/asset data,
                          IOS work areas. Reading MEM2 on a GameCube game
                          returns garbage / FAIL.
  0xCC000000-0xCC00FFFF  Hollywood I/O (Wii) / Flipper I/O (GameCube) — DMA,
                          GPU FIFO, AI, EXI registers. Reads are usually safe,
                          writes can wedge the emulator. Avoid.
  0xCD000000-0xCD007FFF  Wii-only Hollywood registers.

Notes:
  • All multi-byte values are BIG-ENDIAN on the real hardware. Felk's
    memory.read_u*/write_u* helpers handle the byte swap for you —
    the value you see is the value the game sees as a u32.
  • Addresses are 32-bit; Felk truncates the high bits of any u64
    address argument.
  • Pointers in MEM1 are often stored as 4-byte addresses with the
    high bit set (e.g. 0x81234567). Dereferencing them requires no
    masking — pass the raw value back into memory.read_*.

RETURNS: 'Wrote VAL_DEC (0xVAL_HEX) → ADDR_HEX'.
- **dolphin_write16** — PURPOSE: Write an unsigned 16-bit big-endian value to PowerPC memory. USAGE: For 16-bit cheats/pokes (HP, score, coordinates). For single bytes use dolphin_write8; for 32/64-bit use dolphin_write32/write64. The value is byte-swapped to big-endian by Felk's bridge — pass the value the game logically sees, not its byte order. BEHAVIOR: DESTRUCTIVE: overwrites two bytes with no undo. Address MUST be 2-byte aligned. Returns an error on bridge disconnect or FAIL.

GameCube + Wii main address space landmarks (PowerPC, big-endian):
  0x80000000-0x817FFFFF  MEM1 main RAM (24 MiB) — GameCube + Wii game code & data
                          GameCube games stay entirely within MEM1.
                          Wii games use MEM1 for code and frequently-accessed data.
  0x80000020             OS_GLOBALS — game-info struct (disc ID, FST, etc.)
  0x80000034             OS_ARENA_LO (start of free MEM1 heap)
  0x80003100             OS_REPORT (developer-console mirror, varies by SDK)
  0x90000000-0x93FFFFFF  MEM2 (64 MiB) — Wii ONLY. Larger texture/asset data,
                          IOS work areas. Reading MEM2 on a GameCube game
                          returns garbage / FAIL.
  0xCC000000-0xCC00FFFF  Hollywood I/O (Wii) / Flipper I/O (GameCube) — DMA,
                          GPU FIFO, AI, EXI registers. Reads are usually safe,
                          writes can wedge the emulator. Avoid.
  0xCD000000-0xCD007FFF  Wii-only Hollywood registers.

Notes:
  • All multi-byte values are BIG-ENDIAN on the real hardware. Felk's
    memory.read_u*/write_u* helpers handle the byte swap for you —
    the value you see is the value the game sees as a u32.
  • Addresses are 32-bit; Felk truncates the high bits of any u64
    address argument.
  • Pointers in MEM1 are often stored as 4-byte addresses with the
    high bit set (e.g. 0x81234567). Dereferencing them requires no
    masking — pass the raw value back into memory.read_*.

RETURNS: 'Wrote VAL_DEC (0xVAL_HEX) → ADDR_HEX'.
- **dolphin_write32** — PURPOSE: Write an unsigned 32-bit big-endian value to PowerPC memory at the given absolute address. USAGE: The workhorse for cheats — most game state is 32-bit. For 8/16-bit values use dolphin_write8/write16; for true 64-bit fields use dolphin_write64 (atomic, vs two non-atomic write32s). For floats, reinterpret the IEEE-754 bits as an integer first. BEHAVIOR: DESTRUCTIVE: overwrites four bytes with no undo. Address MUST be 4-byte aligned. Writes to read-only regions are silently dropped.

GameCube + Wii main address space landmarks (PowerPC, big-endian):
  0x80000000-0x817FFFFF  MEM1 main RAM (24 MiB) — GameCube + Wii game code & data
                          GameCube games stay entirely within MEM1.
                          Wii games use MEM1 for code and frequently-accessed data.
  0x80000020             OS_GLOBALS — game-info struct (disc ID, FST, etc.)
  0x80000034             OS_ARENA_LO (start of free MEM1 heap)
  0x80003100             OS_REPORT (developer-console mirror, varies by SDK)
  0x90000000-0x93FFFFFF  MEM2 (64 MiB) — Wii ONLY. Larger texture/asset data,
                          IOS work areas. Reading MEM2 on a GameCube game
                          returns garbage / FAIL.
  0xCC000000-0xCC00FFFF  Hollywood I/O (Wii) / Flipper I/O (GameCube) — DMA,
                          GPU FIFO, AI, EXI registers. Reads are usually safe,
                          writes can wedge the emulator. Avoid.
  0xCD000000-0xCD007FFF  Wii-only Hollywood registers.

Notes:
  • All multi-byte values are BIG-ENDIAN on the real hardware. Felk's
    memory.read_u*/write_u* helpers handle the byte swap for you —
    the value you see is the value the game sees as a u32.
  • Addresses are 32-bit; Felk truncates the high bits of any u64
    address argument.
  • Pointers in MEM1 are often stored as 4-byte addresses with the
    high bit set (e.g. 0x81234567). Dereferencing them requires no
    masking — pass the raw value back into memory.read_*.

RETURNS: 'Wrote VAL_DEC (0xVAL_HEX) → ADDR_HEX'.
- **dolphin_write64** — PURPOSE: Write an unsigned 64-bit big-endian value to PowerPC memory. USAGE: For paired 32-bit slots, doubles, packed flags. Atomic from the game's perspective; preferred over chaining two write32s when ordering matters. BEHAVIOR: DESTRUCTIVE: overwrites eight bytes with no undo. Address MUST be 8-byte aligned. `value` is a DECIMAL STRING (0..18446744073709551615) to preserve precision past JS's 2^53 number limit.

GameCube + Wii main address space landmarks (PowerPC, big-endian):
  0x80000000-0x817FFFFF  MEM1 main RAM (24 MiB) — GameCube + Wii game code & data
                          GameCube games stay entirely within MEM1.
                          Wii games use MEM1 for code and frequently-accessed data.
  0x80000020             OS_GLOBALS — game-info struct (disc ID, FST, etc.)
  0x80000034             OS_ARENA_LO (start of free MEM1 heap)
  0x80003100             OS_REPORT (developer-console mirror, varies by SDK)
  0x90000000-0x93FFFFFF  MEM2 (64 MiB) — Wii ONLY. Larger texture/asset data,
                          IOS work areas. Reading MEM2 on a GameCube game
                          returns garbage / FAIL.
  0xCC000000-0xCC00FFFF  Hollywood I/O (Wii) / Flipper I/O (GameCube) — DMA,
                          GPU FIFO, AI, EXI registers. Reads are usually safe,
                          writes can wedge the emulator. Avoid.
  0xCD000000-0xCD007FFF  Wii-only Hollywood registers.

Notes:
  • All multi-byte values are BIG-ENDIAN on the real hardware. Felk's
    memory.read_u*/write_u* helpers handle the byte swap for you —
    the value you see is the value the game sees as a u32.
  • Addresses are 32-bit; Felk truncates the high bits of any u64
    address argument.
  • Pointers in MEM1 are often stored as 4-byte addresses with the
    high bit set (e.g. 0x81234567). Dereferencing them requires no
    masking — pass the raw value back into memory.read_*.

RETURNS: 'Wrote VAL_DEC (0xVAL_HEX) → ADDR_HEX'.
- **dolphin_press_gc_buttons** — PURPOSE: Set GameCube controller state on a given port for one frame's worth of input. USAGE: Buttons supported: A, B, X, Y, Z, Start, L, R, Up, Down, Left, Right. Analog axes: StickX, StickY, CStickX, CStickY, TriggerLeft, TriggerRight. To 'hold' a button across multiple frames, call repeatedly — Dolphin's input is per-frame, not edge-triggered, so a button you don't include in this call's state is implicitly released. For TAS-style frame-perfect sequences, alternate set + dolphin_frame_advance(1) calls. BEHAVIOR: DESTRUCTIVE to controller state for the addressed port. Overwrites all input — anything you don't include is released. Felk's set_gc_buttons accepts a partial dict; unspecified buttons are false, unspecified analog axes are at neutral (0 for both sticks and triggers). RETURNS: 'Set GC port N: <state-summary>'.
- **dolphin_press_wiimote_buttons** — PURPOSE: Set Wii Remote button state on a given port for one frame's worth of input. USAGE: Buttons supported: A, B, One, Two, Plus, Minus, Home, Up, Down, Left, Right. v0.1.0 covers the basic Wii Remote button surface only — pointer position, accelerometer, swing/shake/tilt, and Nunchuk/Classic Controller attachments are not yet wired (deferred to a future release). For now, games requiring motion or pointer input have limited agent control. BEHAVIOR: DESTRUCTIVE to Wii Remote state for the addressed port. Anything you don't include is released. RETURNS: 'Set Wii Remote port N: <state-summary>'.
- **dolphin_set_wiimote_pointer** — PURPOSE: Set the Wii Remote's IR pointer position on the given port. USAGE: Use for menu navigation in Wii titles that aim via the Remote (Wii Sports, Smash Bros menus, House of the Dead, etc.). Coordinates are normalised floats; the exact useful range depends on the game's calibration but typically `(-1.0, -1.0)` is top-left and `(1.0, 1.0)` is bottom-right relative to the sensor bar zone. To hold a position across multiple frames call repeatedly — Felk's helper uses ClearOn::NextFrame semantics. BEHAVIOR: DESTRUCTIVE to pointer state for the addressed port. Sets the IR X+Y for the next render frame. Combine with dolphin_press_wiimote_buttons for click-and-aim sequences. RETURNS: 'Set Wii Remote port N pointer to (x, y)'.
- **dolphin_set_wiimote_acceleration** — PURPOSE: Set the Wii Remote's accelerometer reading on the given port. USAGE: Use for games that read raw accelerometer data — Wii Sports bowling/golf swings, Mario Galaxy's shake-to-spin, anything that doesn't go through the higher-level swing/shake/tilt helpers (deferred to a future release). Units are roughly g (Earth gravity ≈ 1.0); a Remote held still and pointing forward typically reads about (0, 1, 0). For a single-frame impulse, set the value then dolphin_frame_advance(1) then reset to neutral. BEHAVIOR: DESTRUCTIVE to accelerometer state for the addressed port. ClearOn::NextFrame semantics — set persists for one render frame only. RETURNS: 'Set Wii Remote port N accel to (x, y, z)'.
- **dolphin_set_wiimote_angular_velocity** — PURPOSE: Set the Wii MotionPlus angular velocity on the given port. USAGE: Use for games that read rotation rate from the MotionPlus add-on (Wii Sports Resort, Skyward Sword). Units are radians per second around each axis. The Remote must be a MotionPlus-enabled controller in Dolphin's input config for this to take effect. BEHAVIOR: DESTRUCTIVE to angular-velocity state for the addressed port. ClearOn::NextFrame semantics. RETURNS: 'Set Wii Remote port N angular_velocity to (x, y, z)'.
- **dolphin_reset** — PURPOSE: Tap the GameCube/Wii hardware reset button. USAGE: Equivalent to power-cycling the reset button on the console front — game state is lost. To preserve state across the reset, dolphin_save_state first and dolphin_load_state after. BEHAVIOR: DESTRUCTIVE: clears live RAM, returns the CPU to boot. Movie state (if recording) flags the reset. RETURNS: 'Reset triggered.'
- **dolphin_screenshot** — PURPOSE: Capture the current Dolphin video frame as a PNG image. USAGE: Use to SEE what's on screen — confirm game state, read a menu/HUD, or document a moment — to complement memory reads with vision. Returns the most recently DRAWN frame: near-live while the game runs, or the frozen frame if Dolphin is paused via its GUI. BEHAVIOR: No side effects — pure read of the last rendered framebuffer. The bridge captures frames via Felk's event.on_framedrawn (RGB) and mcp-dolphin encodes the PNG. Returns an error if this Dolphin build doesn't expose on_framedrawn (older Felk builds), or if no frame has been drawn yet (let the game render a frame, then retry). Image dimensions follow Dolphin's output framebuffer, which scales with the internal-resolution setting. RETURNS: A one-line summary (WIDTH×HEIGHT) plus the screenshot as an inline PNG image.
- **dolphin_frame_advance** — PURPOSE: Wait until the emulator has rendered N more frames since this call started. USAGE: TAS-style frame-precise sequencing. Typical loop: pause → set controller state → frame_advance(1) → read memory → repeat. The bridge maintains a monotonic frame counter via Felk's on_frameadvance callback; this tool reads the counter, then waits for it to reach counter+frames. The emulator must be UNPAUSED for the counter to advance — call dolphin_resume first if you've paused. BEHAVIOR: Blocks until the target frame is reached or the per-call timeout fires (15 s by default). If the emulator is paused and stays paused, this will time out. Does NOT pause/resume on its own. RETURNS: 'Advanced to frame N (waited M frames).'
- **dolphin_save_state** — PURPOSE: Save complete emulator state (RAM, registers, GPU, audio, timing) to a numbered slot. USAGE: Rollback point before risky writes, bookmarks, repro sharing. Companion dolphin_load_state restores from the same slot. Dolphin maps slots 1-10 to F1-F10 in the GUI by default; 0 and 11-255 are programmatic-only. BEHAVIOR: DESTRUCTIVE TO TARGET SLOT: silently overwrites prior contents — no prompt, no backup. Bound to the exact game disc and Dolphin build; loading mismatched usually crashes the core. The bridge call returns when Felk schedules the save, NOT when the file is on disk. RETURNS: 'Save state triggered for slot N'.
- **dolphin_load_state** — PURPOSE: Load a previously-saved state from the given slot, replacing all live state. USAGE: Counterpart to dolphin_save_state. The classic snapshot/experiment/restore loop: save_state(N) → run experiment → load_state(N) to undo. BEHAVIOR: DESTRUCTIVE TO LIVE STATE: replaces ALL current emulator state. The state file MUST come from the same game disc and same Dolphin build that produced it; loading an incompatible state typically crashes the core (no recovery without restarting Dolphin). RETURNS: 'Load state triggered for slot N'.

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "mcp-dolphin": {
    "command": "npx",
    "args": ["-y","mcp-dolphin"]
  }
}
```

## Documentation & README

# mcp-dolphin

[![npm version](https://img.shields.io/npm/v/mcp-dolphin.svg)](https://www.npmjs.com/package/mcp-dolphin)
[![npm downloads](https://img.shields.io/npm/dm/mcp-dolphin.svg)](https://www.npmjs.com/package/mcp-dolphin)
[![CI](https://github.com/dmang-dev/mcp-dolphin/actions/workflows/ci.yml/badge.svg)](https://github.com/dmang-dev/mcp-dolphin/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/npm/l/mcp-dolphin.svg)](LICENSE)
[![Snyk](https://snyk.io/test/npm/mcp-dolphin/badge.svg)](https://snyk.io/test/npm/mcp-dolphin)
[![Socket](https://img.shields.io/badge/Socket-security-2F7BFF?logo=socket)](https://socket.dev/npm/package/mcp-dolphin)
[![Bundlephobia](https://img.shields.io/badge/bundlephobia-size-FF6B81)](https://bundlephobia.com/package/mcp-dolphin)
[![npmgraph](https://img.shields.io/badge/npmgraph-dependencies-2496ED)](https://npmgraph.js.org/?q=mcp-dolphin)

An [MCP](https://modelcontextprotocol.io) server for **Dolphin** (GameCube + Wii) — drives memory r/w, controller input (GameCube + Wii Remote), pause/resume/reset, savestates, and frame advance from MCP-compatible clients (Claude Desktop, Claude Code, etc.).

## What you can do with it

- **Read & write emulated PowerPC memory** — 8/16/32/64-bit, MEM1 + MEM2
- **Send controller input** — GameCube (digital + analog sticks + triggers), Wii Remote (buttons + IR pointer + accelerometer + MotionPlus angular velocity)
- **Reset** the emulator (pause/resume not in v0.1.0 — see Known limitations)
- **Save / load state** to numbered slots (0-255; 1-10 map to F1-F10 in Dolphin)
- **Frame advance** — wait N frames synchronously for TAS-style precision

Not yet wired in v0.1.0 (deferred to a later release):
- Wii Remote motion (pointer, accelerometer, swing, shake, tilt)
- Nunchuk / Classic Controller / GBA-via-Wii input
- Memory breakpoints, register access, screenshots

## Architecture (and the hard prerequisite)

```
┌─────────────────────────────────────────────────┐
│ Dolphin (Felk's fork — required, not mainline)  │
│                                                 │
│   mcp_bridge.py loaded via Scripting panel      │
│   └─ TCP server on 127.0.0.1:55355              │
└─────────────────────────────────────────────────┘
                  ↕ TCP loopback (newline-delimited JSON)
┌─────────────────────────────────────────────────┐
│ mcp-dolphin (Node.js — this package)            │
└─────────────────────────────────────────────────┘
                  ↕ MCP stdio
              MCP client (Claude etc.)
```

**Mainline Dolphin does not have Python scripting.** mcp-dolphin talks to [Felk's actively-maintained Dolphin fork](https://github.com/Felk/dolphin) which embeds Python with first-class access to memory, controllers, savestates, and the frame loop. Mainline Dolphin Python PRs ([#7064](https://github.com/dolphin-emu/dolphin/pull/7064)) have been stuck since 2022; the Lua forks ([dolphinWatch](https://github.com/TwitchPlaysPokemon/dolphinWatch), [SwareJonge/Dolphin-Lua-Core](https://github.com/SwareJonge/Dolphin-Lua-Core)) are dead. Felk is the only living scripting path.

## One-time setup

### 1. Install Felk's Dolphin fork

Grab a build from [Felk/dolphin Releases](https://github.com/Felk/dolphin/releases) — currently **Python Scripting Preview 4** (December 2025). Unzip it somewhere you can find. It's a regular Dolphin build plus a **Scripting** panel under the View menu.

If you see Python errors when loading the bridge, enable the Scripting log type: **View → Show Log Configuration → check Scripting** (set verbosity to "Info" or "Error"), then **View → Show Log** so the log window is visible.

### 2. Print the bridge script and load it

```bash
npx -y mcp-dolphin --print-bridge > mcp_bridge.py
```

Then in Felk's Dolphin:
1. **View → Scripting** to open the scripting panel.
2. Click **Add New Script** and pick the `mcp_bridge.py` you just wrote.
3. Verify in Dolphin's Log window — you should see `[mcp-bridge] listening on 127.0.0.1:55355 (bridge v0.1.0)`.

The script keeps running as long as Dolphin is open. Remove it from the Scripting panel to stop the bridge.

### 3. Register mcp-dolphin in your MCP client

**Claude Code:**
```bash
claude mcp add dolphin --scope user mcp-dolphin
```

**Claude Desktop** — edit `claude_desktop_config.json`:
```json
{
  "mcpServers": {
    "dolphin": {
      "command": "npx",
      "args": ["-y", "mcp-dolphin"]
    }
  }
}
```

Restart your MCP client after editing.

### 4. Verify

Load a GameCube or Wii game in Dolphin, then ask the agent to call `dolphin_ping`. You should see `OK — bridge v0.1.0 (Felk Python fork)`.

## Tools

| Tool | Description |
|------|-------------|
| `dolphin_ping` | Liveness probe + bridge-version sniff |
| `dolphin_get_info` | Report bridge version and Dolphin label |
| `dolphin_read8/16/32/64` | Read PowerPC memory (big-endian) |
| `dolphin_read_range` | Bulk read up to 64 KiB as hex dump |
| `dolphin_write8/16/32/64` | Write PowerPC memory |
| `dolphin_press_gc_buttons` | Set GameCube controller state (port + button/axis dict) |
| `dolphin_press_wiimote_buttons` | Set Wii Remote button state |
| `dolphin_set_wiimote_pointer` | Set Wii Remote IR pointer position (port + x + y) |
| `dolphin_set_wiimote_acceleration` | Set Wii Remote accelerometer (port + x + y + z, ~g units) |
| `dolphin_set_wiimote_angular_velocity` | Set Wii MotionPlus angular velocity (port + x + y + z, rad/s) |
| `dolphin_reset` | Emulation soft-reset (pause/resume deferred to v0.2 — see Known limitations) |
| `dolphin_frame_advance` | Wait N frames (TAS sequencing) |
| `dolphin_save_state` / `dolphin_load_state` | Slot-based savestate (0-255) |

## GameCube + Wii address space (cheat sheet)

| Range | Region |
|-------|--------|
| `0x80000000-0x817FFFFF` | MEM1 main RAM (24 MiB) — GC + Wii |
| `0x80000020` | `OS_GLOBALS` — disc ID, FST pointer, etc. |
| `0x90000000-0x93FFFFFF` | MEM2 (64 MiB) — **Wii only** |
| `0xCC000000+` | Flipper / Hollywood I/O — reads usually safe, writes can wedge |
| `0xCD000000+` | Wii-only Hollywood registers |

PowerPC is **big-endian** on hardware. The bridge handles byte-swap on read/write — pass and receive the value the game logically sees, not the byte order.

## Controller input

### GameCube (`dolphin_press_gc_buttons`)

```json
{
  "port": 0,
  "state": {
    "A": true, "B": false, "Start": true,
    "StickX": 200, "StickY": 128,
    "TriggerLeft": 0, "TriggerRight": 255
  }
}
```

- Digital buttons: `A, B, X, Y, Z, Start, L, R, Up, Down, Left, Right`
- Analog axes: `StickX, StickY, CStickX, CStickY` (0-255, 128 = center)
- Triggers: `TriggerLeft, TriggerRight` (0-255, 0 = released)
- Omitted keys default to released / center.

### Wii Remote (`dolphin_press_wiimote_buttons`)

```json
{ "port": 0, "state": { "A": true, "Plus": true, "Up": true } }
```

- Buttons: `A, B, One, Two, Plus, Minus, Home, Up, Down, Left, Right`
- v0.1.0 covers buttons only — motion, pointer, Nunchuk, Classic Controller deferred to a future release.

## Configuration

| Env var | Default | Purpose |
|---|---|---|
| `DOLPHIN_BRIDGE_HOST` | `127.0.0.1` | Bridge host (the Dolphin process is local, so this rarely changes) |
| `DOLPHIN_BRIDGE_PORT` | `55355` | Bridge port (must match `LISTEN_PORT` in `mcp_bridge.py`) |
| `DOLPHIN_TIMEOUT_MS` | `10000` | Per-call timeout |
| `MCP_DOLPHIN_DEBUG` | unset | Set to `1` to trace every TX message on stderr |

If you change the port, edit both `mcp_bridge.py` (in your scripts dir) and set `DOLPHIN_BRIDGE_PORT`.

## Troubleshooting

| Symptom | Cause / Fix |
|---|---|
| `Dolphin bridge not reachable` | Dolphin not running, script not loaded in Scripting panel, or wrong port. Check Dolphin's Log window for `[mcp-bridge] listening on ...`. |
| `unknown method: <something>` from bridge | Bridge script is older than mcp-dolphin. Re-export with `npx mcp-dolphin --print-bridge > mcp_bridge.py` and reload in Dolphin. |
| Memory reads return 0xFFFFFFFF or error | Address is unmapped on the current title. MEM2 (`0x90000000+`) is Wii-only; reading it on a GameCube game returns garbage. |
| Controller input has no effect | Game expects input on a different port. Try `port: 0` first, then 1-3. For Wii games requiring motion, this v0.1.0 doesn't cover Wii Remote pointer/accel yet. |
| Tool calls hang ~10 s then time out | Bridge script crashed inside Dolphin. Open Felk's Scripting panel, remove the script, re-add it. |

## Debugging with the MCP Inspector

Browse and call this server's tools interactively with the [MCP Inspector](https://github.com/modelcontextprotocol/inspector):

```bash
npm run inspector
```

Build first if you've edited `src/` since your last `npm install` (`npm run build`, or keep `npm run dev` running). Override the bridge address with `DOLPHIN_BRIDGE_HOST` / `DOLPHIN_BRIDGE_PORT` (default `127.0.0.1:55355`). `tools/list` works even without Dolphin connected; *calling* a tool needs Felk's Dolphin running `bridge/mcp_bridge.py`.

## License

MIT — see [LICENSE](https://github.com/dmang-dev/mcp-dolphin/blob/HEAD/LICENSE).

