loading…
Search for a command to run...
loading…
MCP server for PCSX2 and other emulators that speak the PINE protocol. Read and write 8/16/32/64-bit emulator memory and control save states for PlayStation-fam
MCP server for PCSX2 and other emulators that speak the PINE protocol. Read and write 8/16/32/64-bit emulator memory and control save states for PlayStation-family emulation.
npm version npm downloads CI License: MIT
An MCP server for emulators that speak PINE (Protocol for Instrumentation of Network Emulators) — exposes memory read/write and savestate control to MCP-compatible clients (Claude Desktop, Claude Code, etc.).
What you can't do (because PINE itself doesn't expose these):
This makes mcp-pine well-suited for memory inspection, cheat / RAM hunting, savestate automation, and reverse engineering, but not for "play games via Claude." For input + screenshot capability on Game Boy Advance, see the sister project mcp-mgba.
+----------------+ stdio +----------------+ PINE socket +-----------------+
| MCP client | JSON-RPC | mcp-pine | (TCP or Unix) | Emulator |
| (Claude etc.) | -----------> | (Node.js) | ---------------> | (PINE server) |
+----------------+ +----------------+ +-----------------+
mcp-pine opens a loopback connection to the emulator's PINE server (TCP on Windows, Unix domain socket on Linux/macOS) and translates each MCP tool call into a binary PINE message.
| Emulator | Platform | PINE built in? | Default slot |
|---|---|---|---|
| PCSX2 ≥ 1.7 (setup) | PlayStation 2 | ✅ Yes (toggle in settings) | 28011 |
| RPCS3 (setup) | PlayStation 3 | ⚠️ Has IPC with PINE-compatible opcodes — verify before relying on it | varies |
| Duckstation | PlayStation 1 | ⚠️ PINE has been discussed in upstream issues; check current build | varies |
Other emulators implementing the PINE spec should work out of the box once you point mcp-pine at the right slot — open an issue if you've tested one and it works.
npm install -g mcp-pine
Verify with mcp-pine (it prints a startup line and waits for stdio — Ctrl+C to exit).
npx (no install)npx -y mcp-pine
git clone https://github.com/dmang-dev/mcp-pine
cd mcp-pine
npm install # also runs the build via the `prepare` hook
PINE_SLOT for mcp-pine.That's it — no scripts, no console commands. PINE is always-on once the toggle is set.
RPCS3 has its own IPC implementation that mirrors PINE's opcode set, but the wire-level compatibility hasn't been thoroughly tested with this client. To try it:
PINE_TARGET=rpcs3 PINE_SLOT=<port> mcp-pine.If something doesn't work, please file an issue with details.
Check whether your build of Duckstation includes a PINE server (this varies by version). If yes, set PINE_TARGET=duckstation PINE_SLOT=<port>.
claude mcp add pine --scope user mcp-pine
Verify:
claude mcp list
# pine: mcp-pine - ✓ Connected
Edit claude_desktop_config.json:
| Platform | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
{
"mcpServers": {
"pine": {
"command": "mcp-pine"
}
}
}
Restart Claude Desktop after editing.
mcp-pine speaks standard MCP over stdio. Run it and connect any compatible client.
| Env var | Default | Purpose |
|---|---|---|
PINE_TARGET |
pcsx2 |
Emulator name — used as the prefix in the Unix socket file path on Linux/macOS (<target>.sock.<slot>). Ignored on Windows (TCP only). |
PINE_SLOT |
28011 |
PINE slot — also the TCP port on Windows |
PINE_HOST |
127.0.0.1 |
Override the host (TCP only) |
PINE_SOCKET_PATH |
(auto) | Override the full Unix socket path on Linux/macOS, bypassing automatic resolution |
| Tool | Description |
|---|---|
pine_ping |
Verify the connection by querying the emulator version |
pine_get_info |
Title, serial (e.g. SLUS-21274), disc CRC, game version, status |
pine_get_status |
Just the running/paused/shutdown state |
pine_read8 / pine_read16 / pine_read32 / pine_read64 |
Read memory |
pine_read_range |
Bulk read up to 4096 bytes (client-side pipelined PINE calls) |
pine_write8 / pine_write16 / pine_write32 / pine_write64 |
Write memory (RAM only — ROM writes are silently dropped) |
pine_save_state |
Trigger save state to a numbered slot (0-255) |
pine_load_state |
Trigger load state from a numbered slot (0-255) |
See docs/RECIPES.md for end-to-end examples (RAM hunting, struct decoding, snapshot-experiment-restore).
| Range | Region |
|---|---|
0x00000000 |
EE main RAM (32 MiB) — start here for game data |
0x10000000 |
Hardware registers (DMA, GIF, VIF) |
0x11000000 |
VU0 / VU1 memory |
0x12000000 |
GS privileged registers |
0x1C000000 |
IOP RAM (2 MiB) |
0x1F800000 |
IOP scratchpad |
0x70000000 |
EE scratchpad (16 KiB) |
| Symptom | Cause / Fix |
|---|---|
Cannot reach PINE server |
Emulator isn't running, PINE isn't enabled in its settings, or the slot/port doesn't match. Check PINE_SLOT. |
PINE FAIL response (0xFF) |
The emulator rejected the request — most often because no game is loaded, or the address is unmapped. |
| Reads return zeros | Address is in an unallocated region. Try 0x00100000 first (almost always inside loaded EE RAM). |
| Tool calls work but values look corrupted | Check endianness expectations — PINE returns little-endian; if you're interpreting strings, use read_range-style byte reads. |
PINE call timed out (10s) from pine_ping after some heavy use |
PCSX2's PINE server can wedge. Its request queue is fragile — if a third-party tool pipelines too aggressively (more than ~6 in-flight requests) it silently drops requests, and from then on every reply is mis-aligned with the wrong waiting client. Symptom: even a fresh pine_ping times out. Fix: fully restart PCSX2. Reconnecting alone won't help — the corruption is on the emulator side. |
pine_read_range slower than mGBA's read_range |
Expected. PINE has no native bulk read, so we issue calls serially (pipelining can wedge PCSX2 — see above). Loopback TCP is fast enough that this isn't usually a problem: measured ~52 ms for a full 4096-byte read on PCSX2 v2.6.3. For workloads that need lower latency and can tolerate occasional emulator restarts, set PINE_PIPELINE_BATCH=2. |
npm install
npm run dev # tsc --watch
Quick smoke test against a running PCSX2:
node .scratch/smoke.cjs
Run in your terminal:
claude mcp add mcp-pine -- npx