# https://github.com/dmang-dev/mcp-pine 项目说明书

生成时间：2026-05-17 20:33:44 UTC

## 目录

- [Project Overview](#overview)
- [Installation Guide](#installation)
- [Emulator Setup](#emulator-setup)
- [System Architecture](#system-architecture)
- [Configuration Reference](#configuration)
- [Memory Operations](#memory-operations)
- [Savestate Management](#savestate-management)
- [System Query Tools](#system-queries)
- [Development Guide](#development-guide)
- [Troubleshooting Guide](#troubleshooting)

<a id='overview'></a>

## Project Overview

### 相关页面

相关主题：[System Architecture](#system-architecture), [Emulator Setup](#emulator-setup)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
- [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)
- [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)
- [CHANGELOG.md](https://github.com/dmang-dev/mcp-pine/blob/main/CHANGELOG.md)
</details>

# Project Overview

`mcp-pine` is a Model Context Protocol (MCP) server that bridges AI coding assistants (primarily Claude) with PINE-enabled PlayStation emulators. It exposes a suite of memory reading, memory writing, and save state management tools, enabling AI agents to introspect and manipulate live game state in real-time.

## Project Purpose and Scope

The project serves as an intermediary layer between an AI assistant and emulator internals. Instead of requiring manual memory hunting or external tools, developers and power users can query game state through natural language, with the MCP server translating those requests into PINE protocol calls.

**Core capabilities include:**

- Reading memory at arbitrary addresses (8/16/32/64-bit values and bulk byte ranges)
- Writing memory values to live game state
- Querying emulator metadata (game title, serial, CRC, status)
- Saving and loading emulator states to named slots
- Supporting multiple emulator backends through a unified interface

资料来源：[README.md:1](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## System Architecture

```mermaid
graph TD
    subgraph "MCP Host (Claude)"
        A[Claude AI Assistant]
    end
    
    subgraph "mcp-pine"
        B[MCP Server<br/>src/index.ts]
        C[Tool Handler<br/>src/tools.ts]
        D[PINE Client<br/>src/pine.ts]
    end
    
    subgraph "Emulator"
        E[PCSX2 / RPCS3 / Duckstation]
        F[PINE Server]
    end
    
    A -->|MCP Protocol| B
    B --> C
    C --> D
    D -->|PINE Wire Protocol| F
    F --> E
    
    style A fill:#e1f5fe
    style E fill:#fff3e0
    style D fill:#e8f5e9
```

The system consists of three main layers:

| Layer | Component | Purpose |
|-------|-----------|---------|
| MCP Host | Claude Desktop / Claude Code | User interface; issues tool calls via MCP |
| Bridge | `mcp-pine` (Node.js) | Translates MCP requests to PINE protocol; manages connection lifecycle |
| Emulator | PCSX2 / RPCS3 / Duckstation | Executes game; exposes PINE server for IPC |

资料来源：[README.md:23-51](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## Supported Emulators

| Emulator | Platform | Status | Notes |
|----------|----------|--------|-------|
| PCSX2 | Windows / Linux / macOS | **Primary** | Full PINE support; default target |
| RPCS3 | Windows / Linux | Compatible | IPC implementation mirrors PINE; wire-level compatibility untested |
| Duckstation | Multi-platform | Compatible | Varies by build; requires PINE-enabled build |

PCSX2 is the reference implementation. It is recommended to use PCSX2 1.7.x Qt or newer with PINE enabled via **Settings → Advanced → Enable PINE Server**.

资料来源：[README.md:29-47](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## MCP Tools Reference

The server exposes 13 MCP tools organized into four functional categories.

### Connectivity & Introspection

| Tool | Description |
|------|-------------|
| `pine_ping` | Returns emulator version string. Use to verify connectivity. |
| `pine_get_info` | Batch-retrieves title, serial, disc CRC, game version, and status in one round-trip. |
| `pine_get_status` | Returns emulator run state: `running`, `paused`, `shutdown`, or `unknown`. |

资料来源：[src/tools.ts:45-85](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)

### Memory Reads

| Tool | Width | Alignment | Use Case |
|------|-------|-----------|----------|
| `pine_read8` | 8-bit | None | Status flags, counters, single bytes |
| `pine_read16` | 16-bit | 2-byte | 16-bit counters, flags |
| `pine_read32` | 32-bit | 4-byte | Pointers, flags, game state values |
| `pine_read64` | 64-bit | 8-byte | Large IDs, EE pointers, double-word state |
| `pine_read_range` | Variable | Adaptive | Bulk reads up to 4096 bytes; uses largest aligned width at each step |

> **Important:** PCSX2 does not enforce alignment. Unaligned multi-byte reads silently return corrupted data from the aligned address below. Use `pine_read_range` for unaligned spans.

资料来源：[src/tools.ts:87-200](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)

### Memory Writes

| Tool | Width | Destructive | Notes |
|------|-------|-------------|-------|
| `pine_write8` | 8-bit | Yes | Single-byte overwrite |
| `pine_write16` | 16-bit | Yes | Requires 2-byte alignment |
| `pine_write32` | 32-bit | Yes | Requires 4-byte alignment |
| `pine_write64` | 64-bit | Yes | Requires 8-byte alignment; values encoded as decimal strings |

资料来源：[src/tools.ts:200-260](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)

### Save State Management

| Tool | Description |
|------|-------------|
| `pine_save_state` | Serializes current emulator state to a numbered slot (0-255). **Overwrites existing slot.** |
| `pine_load_state` | Restores emulator state from a numbered slot. |

Save state files are stored in emulator-specific locations:

- **PCSX2 Windows:** `%USERPROFILE%\Documents\PCSX2\sstates`
- **PCSX2 Linux:** `~/.config/PCSX2/sstates`
- Filename format: `<serial> (<crc>).<slot>.p2s`

资料来源：[src/tools.ts:260-310](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)

## Configuration

### Environment Variables

| Variable | Default | Platform | Purpose |
|----------|---------|----------|---------|
| `PINE_TARGET` | `pcsx2` | Linux/macOS | Emulator name; used as Unix socket filename prefix (`<target>.sock.<slot>`) |
| `PINE_SLOT` | `28011` | All | PINE slot number (also port for TCP on Windows) |
| `PINE_HOST` | `127.0.0.1` | Windows | TCP host override |
| `PINE_SOCKET_PATH` | Auto-resolved | Unix | Full socket path override |
| `PINE_PIPELINE_BATCH` | `1` | All | Number of serial reads to batch; higher values risk desyncing PCSX2's PINE server |

资料来源：[README.md:52-60](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

### Socket Resolution

| Platform | Transport | Path Resolution |
|----------|-----------|-----------------|
| Linux/macOS | Unix Domain Socket | `$XDG_RUNTIME_DIR/<target>.sock.<slot>` → `$TMPDIR/<target>.sock.<slot>` → `/tmp/<target>.sock.<slot>` |
| Windows | TCP | `127.0.0.1:<PINE_SLOT>` |

资料来源：[src/pine.ts:1-80](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)

## PINE Protocol Implementation

The `PineClient` class implements the binary PINE wire format:

```mermaid
sequenceDiagram
    participant C as MCP Bridge
    participant P as PineClient
    participant E as Emulator PINE Server
    
    C->>P: pine_read32(0x00100000)
    P->>P: Buffer.alloc(9)<br/>[4-byte size][opcode][4-byte addr]
    P->>E: TCP/Unix Socket
    E-->>P: Reply frame
    P->>P: Parse response
    P-->>C: number value
```

**Wire format per call:**

| Field | Size | Encoding |
|-------|------|----------|
| Frame size | 4 bytes | UInt32LE (includes opcode + payload) |
| Opcode | 1 byte | UInt8 |
| Payload | Variable | Little-endian |

**Opcodes:**

| Opcode | Name | Direction | Payload |
|--------|------|-----------|---------|
| 0x01 | Version | Read | None |
| 0x02 | Title | Read | None |
| 0x03 | ID | Read | None |
| 0x04 | UUID | Read | None |
| 0x05 | GameVersion | Read | None |
| 0x06 | SaveState | Write | 1 byte (slot) |
| 0x07 | LoadState | Write | 1 byte (slot) |
| 0x08 | Read8 | Read | 4 bytes (address) |
| 0x09 | Read16 | Read | 4 bytes (address) |
| 0x0A | Read32 | Read | 4 bytes (address) |
| 0x0B | Read64 | Read | 4 bytes (address) |
| 0x0C | Write8 | Write | 1 byte (value) + 4 bytes (address) |
| 0x0D | Write16 | Write | 2 bytes (value) + 4 bytes (address) |
| 0x0E | Write32 | Write | 4 bytes (value) + 4 bytes (address) |
| 0x0F | Status | Read | None |
| 0x10 | Write64 | Write | 8 bytes (value) + 4 bytes (address) |

资料来源：[src/pine.ts:81-200](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)

## Installation

### Package Distribution

| Method | Command | Use Case |
|--------|---------|----------|
| npm global | `npm install -g mcp-pine` | System-wide installation |
| npx (on-demand) | `npx -y mcp-pine` | Temporary testing |
| Source | `git clone` + `npm install` | Development |

资料来源：[README.md:61-72](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

### Claude Desktop Integration

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "pine": {
      "command": "mcp-pine"
    }
  }
}
```

Config location by platform:

| 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` |

资料来源：[README.md:14-35](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## Technical Constraints and Known Issues

### PCSX2 PINE Server Fragility

PCSX2's PINE server has a **fragile request queue**. Dropping any single request (which occurs silently when too many requests are pipelined) desyncs the reply pipeline. Once desynced, every subsequent reply is misaligned, causing all tools to timeout until the emulator is restarted.

| Setting | Value | Latency | Safety |
|---------|-------|---------|--------|
| `PINE_PIPELINE_BATCH=1` | Serial | ~52ms for 4096 bytes | Safe (default) |
| `PINE_PIPELINE_BATCH=2+` | Batched | Lower | Risk of desync |

The default serial mode completes a full 4KB read in under two emulated frames, making pipelining unnecessary for most use cases.

资料来源：[CHANGELOG.md:15-40](https://github.com/dmang-dev/mcp-pine/blob/main/CHANGELOG.md)

### Troubleshooting Reference

| Symptom | Cause | Fix |
|---------|-------|-----|
| `Cannot reach PINE server` | Emulator not running, PINE disabled, port mismatch | Check `PINE_SLOT` and emulator settings |
| `PINE FAIL response (0xFF)` | No game loaded, address unmapped | Load a game; verify address range |
| Reads return zeros | Address in unallocated region | Try `0x00100000` (EE main RAM) |
| Values look corrupted | Endianness mismatch | PINE returns little-endian |
| `PINE call timed out (10s)` after heavy use | PCSX2 PINE server desynced | **Fully restart PCSX2** |

资料来源：[README.md:95-120](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## Dependencies

```json
{
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.12.0"
  },
  "devDependencies": {
    "@types/node": "^22.0.0",
    "typescript": "^5.5.0"
  }
}
```

The project targets Node.js and uses TypeScript for type safety. The `@modelcontextprotocol/sdk` package provides the MCP server infrastructure.

资料来源：[package.json:1-30](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)

## Related Projects

| Project | Repository | Description |
|---------|------------|-------------|
| mcp-mgba | [dmang-dev/mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | Sister MCP server for mGBA (Game Boy Advance); includes button input and screenshot support |
| PINE Protocol | [GovanifY/pine](https://github.com/GovanifY/pine) | Underlying IPC specification |

资料来源：[README.md:140-145](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

---

<a id='installation'></a>

## Installation Guide

### 相关页面

相关主题：[Configuration Reference](#configuration), [Troubleshooting Guide](#troubleshooting)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
- [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)
- [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)
- [src/index.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/index.ts)
</details>

# Installation Guide

This guide covers all supported methods for installing and configuring `mcp-pine`, a Model Context Protocol (MCP) server that bridges MCP clients to emulators via the PINE protocol.

## Overview

`mcp-pine` enables AI assistants like Claude to interact with PlayStation emulators (PCSX2, RPCS3, Duckstation) through the PINE IPC protocol. It exposes memory read/write tools, save state management, and emulator introspection as MCP tools.

| Component | Technology | Purpose |
|-----------|------------|---------|
| MCP Server | TypeScript + Node.js | Bridges MCP clients to PINE protocol |
| Transport | stdio | Standard MCP communication |
| Emulator IPC | PINE protocol | Binary memory/state access |
| Connections | TCP/Unix Socket | Platform-specific transport |

资料来源：[README.md:1-10]()

## Installation Methods

### Method 1: Global npm Install

Install globally via npm for system-wide access:

```bash
npm install -g mcp-pine
```

This makes `mcp-pine` available as a command-line tool accessible from any terminal session.

资料来源：[README.md:44-47]()

### Method 2: Direct Execution with npx

Run without installation using npx:

```bash
npx -y mcp-pine
```

This downloads and executes the package temporarily, useful for testing or one-off usage.

资料来源：[README.md:49-51]()

### Method 3: Clone and Develop

For development or customization:

```bash
git clone https://github.com/dmang-dev/mcp-pine
cd mcp-pine
npm install        # also runs the build via the `prepare` hook
```

For live development with TypeScript watching:

```bash
npm run dev      # tsc --watch
```

资料来源：[README.md:53-60]()

## Emulator Setup

### PCSX2 (Recommended)

PCSX2 1.7.x and newer include native PINE server support:

1. Launch PCSX2 (1.7.x Qt or newer)
2. Navigate to **Settings → Advanced → Enable PINE Server**
3. Default slot is **28011**

> **Note:** If the option is in a different submenu, search settings for "PINE".

Once enabled, PINE is always-on—no scripts or console commands required. Load any game to start interacting.

资料来源：[README.md:23-33]()

### RPCS3

RPCS3 uses an IPC implementation that mirrors PINE's opcode set:

1. Navigate to **Configuration → Advanced → Enable IPC server**
2. Note the configured port
3. Run with: `PINE_TARGET=rpcs3 PINE_SLOT=<port> mcp-pine`

> **Note:** Wire-level compatibility with RPCS3 hasn't been thoroughly tested. File issues if problems occur.

资料来源：[README.md:35-44]()

### Duckstation

Duckstation builds vary in PINE support:

1. Verify your build includes a PINE server
2. Set `PINE_TARGET=duckstation PINE_SLOT=<port>`

资料来源：[README.md:46-48]()

## MCP Client Registration

### Claude Code (CLI)

Register for user-wide access:

```bash
claude mcp add pine --scope user mcp-pine
```

Verify the connection:

```bash
claude mcp list
# pine: mcp-pine - ✓ Connected
```

资料来源：[README.md:11-17]()

### Claude Desktop

Edit the configuration file for your platform:

| 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` |

Add the server configuration:

```json
{
  "mcpServers": {
    "pine": {
      "command": "mcp-pine"
    }
  }
}
```

Restart Claude Desktop after editing.

资料来源：[README.md:19-32]()

### Other MCP Clients

`mcp-pine` speaks standard MCP over stdio. Run the binary and connect any compatible client:

```bash
mcp-pine
```

资料来源：[README.md:45-46]()

## Configuration

### Environment Variables

| Env Variable | Default | Purpose |
|--------------|---------|---------|
| `PINE_TARGET` | `pcsx2` | Emulator name—used as Unix socket prefix on Linux/macOS (`<target>.sock.<slot>`). Ignored on Windows (TCP only). |
| `PINE_SLOT` | `28011` | PINE slot number—also the TCP port on Windows. |
| `PINE_HOST` | `127.0.0.1` | Override the connection host |
| `PINE_SOCKET_PATH` | Auto-resolved | Override the Unix socket path |
| `PINE_PIPELINE_BATCH` | `1` | Number of pipelined requests (see Performance Notes) |

资料来源：[README.md:34-43]()

### Socket Path Resolution

Connection transport varies by platform:

```mermaid
graph TD
    A[Start] --> B{Platform?}
    B -->|Windows| C[TCP 127.0.0.1:PINE_SLOT]
    B -->|Linux/macOS| D{Look for XDG_RUNTIME_DIR}
    D -->|Set| E[Use $XDG_RUNTIME_DIR/<target>.sock.<slot>]
    D -->|Not Set| F{ TMPDIR set?}
    F -->|Yes| G[Use $TMPDIR/<target>.sock.<slot>]
    F -->|No| H[Use /tmp/<target>.sock.<slot>]
```

资料来源：[src/pine.ts:60-75]()

## Smoke Testing

Test against a running emulator:

```bash
node .scratch/smoke.cjs
```

资料来源：[README.md:66-69]()

## Troubleshooting

### Common Issues

| Symptom | Cause / Fix |
|---------|-------------|
| `Cannot reach PINE server` | Emulator isn't running, PINE isn't enabled in settings, or slot/port doesn't match. Check `PINE_SLOT`. |
| `PINE FAIL response` (0xFF) | Emulator rejected request—usually no game loaded or address is unmapped. |
| Reads return zeros | Address is in an unallocated region. Try `0x00100000` first (almost always inside EE RAM). |
| Tool calls work but values look corrupted | Check endianness—PINE returns little-endian. Use `read_range`-style byte reads for strings. |
| `pine_ping` times out after heavy use | **PCSX2 PINE server is wedged.** Only a full emulator restart recovers. Reconnecting alone won't help. |

资料来源：[README.md:68-78]()

### PCSX2 Pipeline Drop Bug

PCSX2's PINE server has a fragile request queue. If more than ~6 in-flight requests are pipelined, it silently drops requests, desyncing the reply pipeline. Once desynced, every reply is misaligned—only an emulator restart fixes this.

| Operation | Latency | Notes |
|-----------|---------|-------|
| Full 4096-byte read | ~52 ms | Fully serial requests over loopback TCP |
| Pipelined requests | Faster but risky | `PINE_PIPELINE_BATCH=2` for experimental use |

资料来源：[src/pine.ts:115-125]()

## Project Structure

```
mcp-pine/
├── src/
│   ├── index.ts      # Main entry point, MCP server setup
│   ├── pine.ts       # PINE protocol client implementation
│   └── tools.ts      # MCP tool definitions
├── .scratch/
│   └── smoke.cjs     # Quick smoke test script
├── package.json      # Dependencies and scripts
└── README.md         # Documentation
```

## Dependencies

| Package | Version | Purpose |
|---------|---------|---------|
| `@modelcontextprotocol/sdk` | ^1.12.0 | MCP server framework |
| `@types/node` | ^22.0.0 | TypeScript types |
| `typescript` | ^5.5.0 | Build tooling |

资料来源：[package.json:8-14]()

## See Also

- [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) — Sister MCP server for mGBA (includes button input + screenshot)
- [PINE protocol spec](https://github.com/GovanifY/pine) — Underlying IPC standard
- [docs/RECIPES.md](docs/RECIPES.md) — Cookbook for common workflows (RAM hunting, struct decoding, snapshot-experiment-restore)

---

<a id='emulator-setup'></a>

## Emulator Setup

### 相关页面

相关主题：[Configuration Reference](#configuration), [Troubleshooting Guide](#troubleshooting)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)
- [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
</details>

# Emulator Setup

This page documents how to configure and connect PlayStation 2 emulators to the mcp-pine MCP server. mcp-pine acts as a bridge between AI assistants (via the Model Context Protocol) and the PINE IPC (PlayStation 2 Interactive Interface) server embedded in compatible emulators.

## Overview

mcp-pine requires a running emulator with PINE server support enabled. The server communicates with the emulator through either TCP (Windows) or Unix domain sockets (Linux/macOS), allowing AI assistants to read/write memory, query game metadata, and manage save states.

**Supported emulators:**

| Emulator | Platform | PINE Support | Notes |
|----------|----------|--------------|-------|
| PCSX2 (1.7.x Qt+) | All | Native | Full support; recommended |
| RPCS3 | All | Partial | IPC implementation mirrors PINE; wire compatibility untested |
| Duckstation | All | Varies | Build-dependent; check your version |

资料来源：[README.md:1-50](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## Architecture

The connection flow between mcp-pine and the emulator follows a client-server pattern:

```mermaid
graph LR
    subgraph "Host System"
        A["Claude / MCP Client"] --> B["mcp-pine"]
        B --> C["Emulator PINE Server"]
    end
    
    D["PlayStation 2 Game"] --> C
    
    C -->|TCP 127.0.0.1:28011<br/>Unix Socket<br/>/tmp/pcsx2.sock.28011| B
    
    style C fill:#90EE90
    style B fill:#87CEEB
```

**Connection transport selection:**

- **Windows:** TCP socket to `127.0.0.1:<PINE_SLOT>`
- **Linux/macOS:** Unix domain socket at `<TMPDIR or /tmp>/<PINE_TARGET>.sock.<PINE_SLOT>`

资料来源：[src/pine.ts:150-200](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)

## Configuration

### Environment Variables

| Variable | Default | Purpose |
|----------|---------|---------|
| `PINE_TARGET` | `pcsx2` | Emulator name—used as Unix socket filename prefix on Linux/macOS |
| `PINE_SLOT` | `28011` | PINE slot number (port on Windows, socket suffix on Unix) |
| `PINE_PIPELINE_BATCH` | `1` | Number of serial PINE requests to batch (higher = faster but riskier) |

资料来源：[README.md:60-75](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

### Socket Path Resolution

The `PineClient` class resolves the socket path based on platform and options:

```mermaid
graph TD
    A["PineClient constructor"] --> B{opts.kind explicitly set?}
    B -->|Yes| C["Use opts.host/opts.path"]
    B -->|No| D{Platform = Windows?}
    D -->|Yes| E["TCP: 127.0.0.1:PINE_SLOT"]
    D -->|No| F{Platform = Linux/macOS?}
    F -->|Yes| G["Unix: XDG_RUNTIME_DIR<br/>or TMPDIR<br/>/<target>.sock.<slot>"]
    F -->|No| H["TCP fallback: localhost:PINE_SLOT"]
    
    style G fill:#90EE90
    style E fill:#87CEEB
```

资料来源：[src/pine.ts:100-180](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)

## PCSX2 Setup

PCSX2 provides native, stable PINE server support starting from version 1.7.x Qt.

### Prerequisites

- PCSX2 1.7.x (Qt build) or newer
- A loaded PlayStation 2 game

### Configuration Steps

1. Launch PCSX2
2. Navigate to **Settings → Advanced → Enable PINE Server**
   - The option location may vary slightly by build version
   - Use the settings search function to find "PINE" if the menu structure differs
3. Verify the default slot is **28011**
4. Load any PlayStation 2 game

No console commands or external scripts are required—PINE is always-on once the toggle is enabled.

资料来源：[README.md:30-45](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## RPCS3 Setup

RPCS3 implements its own IPC mechanism that mirrors PINE's opcode set, but wire-level compatibility with this client has not been thoroughly tested.

### Configuration Steps

1. Navigate to **Configuration → Advanced → Enable IPC server**
2. Note the configured port number
3. Run mcp-pine with the target override:

```bash
PINE_TARGET=rpcs3 PINE_SLOT=<port> mcp-pine
```

**Note:** Full compatibility is not guaranteed. If issues arise, please file a bug report with connection logs and emulator version information.

资料来源：[README.md:46-55](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## Duckstation Setup

Duckstation includes PINE server support in some builds, but availability varies by version and distribution.

### Configuration

If your Duckstation build includes PINE support:

```bash
PINE_TARGET=duckstation PINE_SLOT=<port> mcp-pine
```

**Note:** Check your Duckstation build version to confirm PINE server availability.

资料来源：[README.md:56-60](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## MCP Client Registration

After the emulator is configured, register mcp-pine with your MCP client.

### Claude Code (CLI)

```bash
claude mcp add pine --scope user mcp-pine
```

Verify registration:

```bash
claude mcp list
# pine: mcp-pine - ✓ Connected
```

资料来源：[README.md:85-95](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

### Claude Desktop

Edit the configuration file at your platform-specific location:

| 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` |

Add the mcp-pine server entry:

```json
{
  "mcpServers": {
    "pine": {
      "command": "mcp-pine"
    }
  }
}
```

Restart Claude Desktop after editing.

资料来源：[README.md:96-115](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## Available Tools

Once connected, the following tools are available through the MCP interface:

| Tool | Purpose | Call Type |
|------|---------|-----------|
| `pine_ping` | Verify connection to emulator | 1 round-trip |
| `pine_get_info` | Get game title, serial, CRC, version, and status | 5 parallel calls |
| `pine_get_status` | Get emulator run state (running/paused/shutdown) | 1 round-trip |
| `pine_read8/16/32/64` | Read bytes from EE memory | 1 round-trip each |
| `pine_read_range` | Bulk read up to 4096 bytes | Serial sequence |
| `pine_write8/16/32/64` | Write bytes to EE memory | 1 round-trip each |
| `pine_save_state` | Save emulator state to slot | 1 round-trip |
| `pine_load_state` | Load emulator state from slot | 1 round-trip |

### Address Parameter Notes

All address parameters reference the **EE main address space**. Key memory regions:

| Region | Address Range | Description |
|--------|---------------|-------------|
| EE Main RAM | `0x00100000` – `0x01FFFFFF` | Primary game state memory (99% of use cases) |
| IOP RAM | `0x1C000000`+ | Input/Output Processor memory |
| Scratchpad | `0x70000000` – `0x70003FFF` | Fast local memory |

**Alignment requirements:**

| Width | Alignment | Notes |
|-------|-----------|-------|
| 8-bit | None | Safe to use at any address |
| 16-bit | 2-byte | Misaligned access silently corrupts data |
| 32-bit | 4-byte | Misaligned access silently corrupts data |
| 64-bit | 8-byte | Misaligned access silently corrupts data |

**Important:** PCSX2's PINE implementation does NOT enforce alignment. Misaligned multi-byte access returns bytes from the aligned address below, silently corrupting values.

资料来源：[src/tools.ts:1-100](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)

## Troubleshooting

### Common Issues

| Symptom | Cause | Fix |
|---------|-------|-----|
| `Cannot reach PINE server` | Emulator not running, PINE not enabled, or slot mismatch | Check `PINE_SLOT` matches emulator setting |
| `PINE FAIL response` (0xFF) | No game loaded, or address unmapped | Load a game; try `0x00100000` first |
| Reads return zeros | Address in unallocated region | Use `0x00100000` (EE RAM base) |
| Values look corrupted | Wrong endianness or alignment | PINE returns little-endian; use `pine_read_range` for byte-level control |
| `PINE call timed out (10s)` after heavy use | PCSX2 PINE queue desync | Full PCSX2 restart required—reconnecting alone won't help |

资料来源：[README.md:130-150](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

### PCSX2 PINE Queue Desync

PCSX2's PINE server has a fragile request queue. If more than approximately 6 in-flight requests are issued, the server silently drops requests, corrupting the reply pipeline alignment. Once desynced, every subsequent reply is misaligned, causing timeouts on even simple operations like `pine_ping`.

**Symptoms:**
- Fresh `pine_ping` calls timing out after heavy use
- Intermittent read/write failures
- Non-deterministic response values

**Fix:**
1. Fully restart PCSX2
2. Reconnect mcp-pine
3. Reduce `PINE_PIPELINE_BATCH` to `1` (default)

资料来源：[README.md:155-165](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)  
资料来源：[src/pine.ts:60-90](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)

### Performance Considerations

`pine_read_range` issues PINE calls serially by default to avoid queue desync. Measured performance on PCSX2 v2.6.3:

| Operation | Latency |
|-----------|---------|
| Full 4096-byte read | ~52 ms |
| Per 64-bit word | ~13 ms |

Loopback TCP is fast enough that serial reads complete in less than two emulated frames. For lower latency with acceptable risk, set `PINE_PIPELINE_BATCH=2` or higher.

**Warning:** Higher batch values increase the probability of triggering PCSX2's queue drop behavior.

资料来源：[README.md:166-175](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## Development Setup

For testing against a running emulator:

```bash
git clone https://github.com/dmang-dev/mcp-pine
cd mcp-pine
npm install        # Runs build via prepare hook

# Development mode with TypeScript watching
npm run dev

# Smoke test
node .scratch/smoke.cjs
```

The project builds using TypeScript 5.5+ with Node 22+ support.

资料来源：[README.md:175-190](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)  
资料来源：[package.json:1-30](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)

---

<a id='system-architecture'></a>

## System Architecture

### 相关页面

相关主题：[Memory Operations](#memory-operations), [Savestate Management](#savestate-management), [System Query Tools](#system-queries)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/index.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/index.ts)
- [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)
- [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)
</details>

# System Architecture

## Overview

mcp-pine is an MCP (Model Context Protocol) server that bridges AI assistants (such as Claude) with PlayStation 2 emulators (PCSX2, RPCS3, Duckstation) via the PINE (Platform Independent Networked Environment) protocol. It exposes emulator memory, save states, and game information as MCP tools, enabling AI-driven game analysis, memory hacking, and automation workflows.

The architecture follows a layered client-server model with three distinct subsystems: the MCP protocol layer, the PINE protocol client, and the cross-platform transport layer.

## High-Level Architecture

```mermaid
graph TD
    subgraph "MCP Host (Claude)"
        A["Claude AI"]
    end
    
    subgraph "mcp-pine"
        B["MCP Server<br/>(@modelcontextprotocol/sdk)"]
        C["PineClient<br/>(Protocol Layer)"]
        D["Transport Layer<br/>(TCP / Unix Socket)"]
    end
    
    subgraph "Emulator"
        E["PINE Server"]
        F["EE Memory<br/>IOP Memory<br/>Save States"]
    end
    
    A <-->|"MCP stdio"| B
    B <-->|"Tool Calls"| C
    C <-->|"PINE Protocol"| D
    D <-->|"TCP:127.0.0.1<br/>Unix:/tmp/*.sock"| E
    E <--> F
```

**资料来源：** [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md) - Project overview and configuration documentation

## Component Architecture

### Layer 1: MCP Server

The MCP server layer implements the Model Context Protocol specification using the `@modelcontextprotocol/sdk`. It registers tool handlers and routes incoming tool calls to the PINE client.

| Component | File | Responsibility |
|-----------|------|----------------|
| `registerTools()` | `src/tools.ts` | Registers all 13 MCP tools with the SDK |
| Tool dispatcher | `src/tools.ts` | Routes `CallToolRequest` to corresponding PINE operations |
| Response formatter | `src/tools.ts` | Formats PINE responses for MCP protocol |

**资料来源：** [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts) - MCP tool registration and handler implementation

### Layer 2: PINE Protocol Client

The `PineClient` class (`src/pine.ts`) implements the binary PINE wire format specification. It handles request encoding, response decoding, and protocol state management.

```mermaid
graph LR
    A["Tool Request"] --> B["Encode Opcode<br/>+ Payload"]
    B --> C["Buffer<br/>(4-byte size prefix)"]
    C --> D["Socket Write"]
    D --> E["Response Read"]
    E --> F["Parse Size"]
    F --> G["Extract Opcode<br/>+ Data"]
    G --> H["Decode Value"]
    H --> I["Return to Tool"]
```

**资料来源：** [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts) - PINE client implementation

#### Opcode Mapping

| Operation | Opcode | Direction | Description |
|-----------|--------|-----------|-------------|
| `getVersion` | `Op.Version` | Read | Emulator version string |
| `getTitle` | `Op.Title` | Read | Game title |
| `getId` | `Op.ID` | Read | Game serial number |
| `getUuid` | `Op.UUID` | Read | Disc CRC hash |
| `getGameVersion` | `Op.GameVersion` | Read | Game version string |
| `getStatus` | `Op.Status` | Read | Emulator state (running/paused/shutdown) |
| `read8/16/32/64` | `Op.Read*` | Read | Memory reads at specified width |
| `write8/16/32/64` | `Op.Write*` | Write | Memory writes at specified width |
| `saveState` | `Op.SaveState` | Write | Save to slot (0-255) |
| `loadState` | `Op.LoadState` | Write | Load from slot (0-255) |

**资料来源：** [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts) - Opcode constants and operation implementations

### Layer 3: Transport Layer

The transport layer provides cross-platform connectivity using the appropriate socket type for each operating system.

```mermaid
graph TD
    A["Platform Detection"] --> B{OS?}
    B -->|Windows| C["TCP Socket<br/>127.0.0.1:SLOT"]
    B -->|Linux/macOS| D["Unix Domain Socket"]
    D --> E["$XDG_RUNTIME_DIR<br/>/<target>.sock.<slot>"]
    D --> F["$TMPDIR<br/>/<target>.sock.<slot>"]
    D --> G["/tmp<br/>/<target>.sock.<slot>"]
```

**资料来源：** [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts) - `resolveSocket()` function and transport abstraction

#### Socket Resolution Strategy

| Priority | Linux/macOS Path | Windows |
|----------|------------------|---------|
| 1 | `$XDG_RUNTIME_DIR/<target>.sock.<slot>` | TCP `127.0.0.1:<slot>` |
| 2 | `$TMPDIR/<target>.sock.<slot>` | — |
| 3 | `/tmp/<target>.sock.<slot>` | — |

**资料来源：** [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md) - Configuration and transport documentation

## Request Queue Management

The `PineClient` maintains an internal request queue to handle concurrent tool calls and ensure responses are matched to their originating requests.

```mermaid
sequenceDiagram
    participant Tool1 as Tool Call 1
    participant Tool2 as Tool Call 2
    participant Queue as Request Queue
    participant Client as PineClient
    participant Socket as Network Socket
    
    Tool1->>Queue: Enqueue request
    Tool2->>Queue: Enqueue request
    Queue->>Socket: Write Request 1
    Queue->>Socket: Write Request 2
    Socket-->>Client: Receive Response 1
    Client->>Queue: Resolve Promise 1
    Socket-->>Client: Receive Response 2
    Client->>Queue: Resolve Promise 2
```

**资料来源：** [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts) - Request queue implementation

### Pending Request Structure

```typescript
interface Pending {
  resolve: (value: Buffer) => void;
  reject: (err: Error) => void;
}
```

Each pending request holds references to its `resolve` and `reject` functions, allowing the response handler to deliver results to the correct caller even when multiple requests are in-flight.

**资料来源：** [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts) - Pending interface definition

## Bulk Read Implementation

The `readRange()` method implements efficient bulk memory reads by combining multiple aligned PINE operations.

```mermaid
graph TD
    A["readRange(addr, length)"] --> B["Calculate Steps"]
    B --> C{"Aligned?"}
    C -->|8-byte| D["read64"]
    C -->|4-byte| E["read32"]
    C -->|2-byte| F["read16"]
    C -->|1-byte| G["read8"]
    D --> H["PIPELINE_BATCH"]
    E --> H
    F --> H
    G --> H
    H --> I["Promise.all(batch)"]
    I --> J{"More steps?"}
    J -->|Yes| H
    J -->|No| K["Return Buffer"]
```

**资料来源：** [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts) - `readRange()` implementation

### Pipelining Configuration

| Env Variable | Default | Effect |
|--------------|---------|--------|
| `PINE_PIPELINE_BATCH` | `1` | Number of concurrent requests (1=serial, 2+=parallel) |

> **Warning:** PCSX2's PINE server silently drops requests when too many are pipelined (~7+ in-flight). This desyncs the reply pipeline, causing all subsequent requests to time out until emulator restart.

**资料来源：** [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts) - Pipeline batch configuration

## Tool Registration Flow

```mermaid
graph LR
    A["MCP Server<br/>Instantiation"] --> B["PineClient<br/>Creation"]
    B --> C["registerTools()<br/>called"]
    C --> D["ListToolsRequestHandler<br/>registered"]
    C --> E["CallToolRequestHandler<br/>registered"]
    F["MCP Host<br/>connects"] --> G["ListTools<br/>request"]
    G --> H["TOOLS[]<br/>schema returned"]
    F --> I["Tool Call<br/>invoked"]
    I --> J["switch(name)<br/>dispatch"]
    J --> K["PineClient<br/>operation"]
```

**资料来源：** [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts) - Tool registration and dispatch

## Memory Address Space

The PINE protocol operates on PlayStation 2 memory regions. All address parameters use absolute byte addresses in the EE (Emotion Engine) main address space.

| Region | Address Range | Size | Description |
|--------|---------------|------|-------------|
| EE Main RAM | `0x00100000` - `0x01FFFFFF` | ~31 MB | Primary game state storage |
| IOP RAM | `0x1C000000`+ | Variable | I/O Processor memory |
| Scratchpad | Special range | 16 KB | Fast-access cache |

> **Alignment Note:** Multi-byte reads/writes (16/32/64-bit) must be aligned to their width. PINE on PCSX2 does NOT enforce alignment — unaligned access silently returns corrupted data.

**资料来源：** [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts) - Address parameter descriptions

## 64-bit Value Handling

JavaScript's `Number` type loses precision beyond `2^53`. The implementation handles 64-bit values as decimal strings.

| Operation | Input Format | Output Format | Reason |
|-----------|-------------|---------------|--------|
| `pine_write64` | Decimal string (`"18446744073709551615"`) | — | Preserve full u64 range |
| `pine_read64` | — | Decimal string | Preserve full u64 range |

**资料来源：** [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts) - 64-bit parameter descriptions

## Configuration Environment Variables

| Variable | Default | Platform | Purpose |
|----------|---------|----------|---------|
| `PINE_TARGET` | `pcsx2` | All | Emulator name prefix for Unix socket path |
| `PINE_SLOT` | `28011` | All | PINE slot number (also port on Windows) |
| `PINE_HOST` | `127.0.0.1` | Windows | TCP host override |
| `PINE_SOCKET_PATH` | Auto | All | Custom Unix socket path |
| `PINE_PIPELINE_BATCH` | `1` | All | Concurrent request batching |
| `PIPELINE_BATCH` | `1` | All | Alias for `PINE_PIPELINE_BATCH` |

**资料来源：** [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md) - Configuration table

## Error Handling

| Error | Cause | Fix |
|-------|-------|-----|
| `Cannot reach PINE server` | Emulator not running or PINE disabled | Check `PINE_SLOT` matches emulator settings |
| `PINE FAIL response (0xFF)` | No game loaded or address unmapped | Load a game; verify address range |
| Reads return zeros | Address in unallocated region | Try `0x00100000` first (EE RAM base) |
| Values look corrupted | Endianness mismatch | PINE returns little-endian; check parsing |
| `PINE call timed out (10s)` | PCSX2 PINE server wedged | Full emulator restart required |

**资料来源：** [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md) - Troubleshooting section

## Lazy Reconnect Behavior

The MCP server implements lazy reconnection — if the emulator is restarted, the PINE client automatically reconnects without requiring the MCP host to restart.

```mermaid
graph TD
    A["Tool Call"] --> B{"Connected?"}
    B -->|No| C["Connect()"]
    C --> D{"Success?"}
    D -->|Yes| E["Send Request"]
    D -->|No| F["Error (retry next call)"]
    B -->|Yes| E
    E --> G["Response"]
```

**资料来源：** [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts) - Connection management

## Package Dependencies

| Package | Version | Purpose |
|---------|---------|---------|
| `@modelcontextprotocol/sdk` | `^1.12.0` | MCP protocol implementation |
| `typescript` | `^5.5.0` | TypeScript compilation (dev) |
| `@types/node` | `^22.0.0` | Node.js type definitions (dev) |

**资料来源：** [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json) - Dependencies section

## Supported Emulators

| Emulator | Platform | Status | Notes |
|----------|----------|--------|-------|
| PCSX2 | All | Primary | Full PINE support; Qt 1.7.x+ |
| RPCS3 | All | Experimental | IPC implementation mirrors PINE; wire compatibility untested |
| Duckstation | All | Varies | Depends on build; PINE server availability varies |

**资料来源：** [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md) - Emulator setup documentation

---

<a id='configuration'></a>

## Configuration Reference

### 相关页面

相关主题：[Emulator Setup](#emulator-setup), [System Architecture](#system-architecture)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)
- [src/index.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/index.ts)
- [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
</details>

# Configuration Reference

## Overview

The `mcp-pine` project provides a Model Context Protocol (MCP) server that bridges MCP clients (such as Claude Code or Claude Desktop) to PlayStation 2/3 emulators via the PINE (Platform Independent Networked Environment) protocol. Configuration is driven entirely through environment variables, allowing users to customize connection targets, communication protocols, and runtime behavior without modifying code.

This reference documents all supported environment variables, their default values, acceptable ranges, and behavioral implications.

---

## Environment Variables Summary

| Variable | Default | Purpose |
|----------|---------|---------|
| `PINE_TARGET` | `pcsx2` | Emulator identifier for socket path resolution |
| `PINE_SLOT` | `28011` | PINE slot/port number for connection |
| `PINE_HOST` | `127.0.0.1` | Host address for TCP connections |
| `PINE_SOCKET_PATH` | auto-generated | Override Unix socket or TCP path |
| `PINE_PIPELINE_BATCH` | `1` | Number of concurrent in-flight PINE requests |

---

## Connection Configuration

### `PINE_TARGET`

Specifies the target emulator name, which determines the Unix socket file prefix on Linux/macOS systems.

**Type:** string  
**Default:** `pcsx2`  
**Valid Values:** `pcsx2`, `rpcs3`, `duckstation`

```mermaid
graph LR
    A[PINE_TARGET] --> B{Platform?}
    B -->|Linux/macOS| C[Unix Socket Path]
    B -->|Windows| D[TCP Connection]
    C --> E["<target>.sock.<slot>"]
    D --> F["127.0.0.1:<slot>"]
```

On Linux/macOS, the socket path follows the pattern `<target>.sock.<slot>`. The system resolves the directory using:

1. `$XDG_RUNTIME_DIR` (Linux common)
2. `$TMPDIR` (macOS common)
3. `/tmp` (fallback)

**Example:**

```bash
PINE_TARGET=pcsx2 PINE_SLOT=28011 mcp-pine
# Linux socket: /run/user/1000/pcsx2.sock.28011
```

资料来源：[README.md:45-50]()

### `PINE_SLOT`

Defines the PINE slot number used for communication. This value serves as:

- The TCP port number on Windows (`127.0.0.1:<slot>`)
- The Unix socket suffix on Linux/macOS (`<target>.sock.<slot>`)

**Type:** integer  
**Default:** `28011`  
**Valid Range:** 0–65535 (though PINE protocol reserves 0–255 for official slot semantics)

```mermaid
graph TD
    A[Emulator PINE Server] --> B{Slot Configured?}
    B -->|Default 28011| C[PCSX2 Qt 1.7.x]
    B -->|Custom Port| D[RPCS3 / Duckstation]
    A --> E[PCSX2 Settings]
    E --> F[Settings > Advanced > Enable PINE Server]
```

资料来源：[README.md:46-47]()

### `PINE_HOST`

Specifies the hostname or IP address for TCP connections on Windows systems.

**Type:** string  
**Default:** `127.0.0.1`  
**Valid Values:** Any valid IPv4/IPv6 address or hostname

On Windows, TCP is used exclusively instead of Unix sockets. This variable allows connection to remote emulators if needed.

```typescript
// Connection resolution logic (src/pine.ts)
const descriptor = resolveSocket(opts);
// Returns { kind: "tcp", host, port } or { kind: "unix", path }
```

资料来源：[src/pine.ts:100-110]()

### `PINE_SOCKET_PATH`

Provides a complete override for the socket path, bypassing automatic resolution based on `PINE_TARGET` and `PINE_SLOT`.

**Type:** string  
**Default:** auto-generated  
**Format:** Absolute path for Unix sockets, or `host:port` for TCP

This variable is useful for:

- Custom socket locations
- Docker containers with volume-mounted sockets
- Testing with mock PINE servers

资料来源：[package.json:5-10]()

---

## Runtime Behavior Configuration

### `PINE_PIPELINE_BATCH`

Controls the number of concurrent in-flight PINE requests when performing bulk reads via `pine_read_range`.

```mermaid
graph TD
    A[pine_read_range call] --> B{How many steps?}
    B --> C[Split into steps]
    C --> D{PIPELINE_BATCH}
    D -->|1 (default)| E[Serial execution<br/>Safe: no queue corruption]
    D -->|2+| F[Batch execution<br/>⚠️ Risk: PCSX2 queue desync]
    E --> G[~52ms for 4KB]
    F --> H[Lower latency<br/>Potential reply misalignment]
```

**Type:** integer  
**Default:** `1`  
**Valid Range:** Positive integers

| Value | Behavior | Latency | Risk Level |
|-------|----------|---------|------------|
| `1` | Fully serial execution | ~52ms for 4KB | None |
| `2` | Batches of 2 concurrent requests | Lower | Low |
| `>6` | Aggressive pipelining | Lowest | High (queue corruption) |

#### Why Pipelining Can Break PCSX2

PCSX2's PINE server has a **fragile request queue**. When more than approximately 6-9 requests are in-flight simultaneously, the server silently drops requests. This causes the reply pipeline to become desynchronized, and every subsequent request times out—even `pine_ping`.

**Symptoms of queue corruption:**

```
PINE call timed out (10s) from pine_ping
```

**Recovery:** Complete PCSX2 restart required. Reconnecting alone does not fix the desync.

资料来源：[src/pine.ts:70-85]()

---

## Connection Flow Architecture

```mermaid
sequenceDiagram
    participant MCP as MCP Client
    participant Server as mcp-pine Server
    participant Pine as PINE Client
    participant Emu as Emulator PINE Server

    MCP->>Server: Stdio connection
    Server->>Pine: Connect via resolveSocket()
    Note over Server,Pine: Platform detection<br/>TCP vs Unix socket

    Pine->>Emu: Initial connection
    Emu-->>Pine: Connected

    loop Per tool call
        MCP->>Server: CallToolRequest
        Server->>Pine: Typed method (read8, write32, etc.)
        Pine->>Emu: PINE binary frame
        Emu-->>Pine: PINE reply frame
        Pine-->>Server: Parsed result
        Server-->>MCP: ToolResponse
    end
```

### Socket Resolution Logic

```mermaid
graph TD
    A[resolveSocket options] --> B{Target platform?}
    B -->|Windows| C[Use TCP]
    B -->|Linux/macOS| D[Use Unix Socket]

    C --> E["net.createConnection<br/>host:port"]
    D --> F{PINE_SOCKET_PATH set?}
    F -->|Yes| G["Use custom path"]
    F -->|No| H["Build from TARGET + SLOT"]
    H --> I[XDG_RUNTIME_DIR]
    H --> J[TMPDIR]
    H --> K[/tmp fallback]

    I --> L["<dir>/<target>.sock.<slot>"]
    J --> L
    K --> L
```

资料来源：[src/pine.ts:95-120]()

---

## Timeout Configuration

Each PINE call has a **10-second timeout** enforced by the client. This prevents the MCP server from hanging indefinitely if:

- The emulator drops a reply
- The PINE server becomes unresponsive
- Network latency exceeds normal bounds

**Implementation:**

```typescript
// From src/pine.ts
private readonly TIMEOUT_MS = 10_000;

const result = await Promise.race([
    this.call(Op.Read64, args),
    new Promise((_, reject) =>
        setTimeout(() => reject(new Error("PINE call timed out")), TIMEOUT_MS)
    )
]);
```

资料来源：[src/pine.ts:25-30]()

---

## Environment Variable Precedence

When multiple variables could affect the same aspect of connection, the following precedence applies:

| Priority | Variable | Override Behavior |
|----------|----------|-------------------|
| 1 (highest) | `PINE_SOCKET_PATH` | Complete path override |
| 2 | `PINE_HOST` + `PINE_SLOT` | TCP connection details |
| 3 | `PINE_TARGET` + `PINE_SLOT` | Auto-generated Unix socket |

---

## Configuration Examples

### PCSX2 (Default)

```bash
# Uses defaults: pcsx2.sock.28011 on Linux, 127.0.0.1:28011 on Windows
mcp-pine
```

### RPCS3

```bash
PINE_TARGET=rpcs3 PINE_SLOT=28012 mcp-pine
```

### Duckstation

```bash
PINE_TARGET=duckstation PINE_SLOT=28013 mcp-pine
```

### Custom Socket Path

```bash
PINE_SOCKET_PATH=/tmp/custom-pine.sock.28011 mcp-pine
```

### Aggressive Pipelining (Not Recommended)

```bash
PINE_PIPELINE_BATCH=4 mcp-pine
# ⚠️ May cause PCSX2 queue corruption
```

### Remote Connection

```bash
PINE_HOST=192.168.1.100 PINE_SLOT=28011 mcp-pine
```

---

## Quick Reference Card

| Scenario | Recommended Variables |
|----------|----------------------|
| PCSX2 on Linux | None (defaults work) |
| PCSX2 on Windows | None (defaults work) |
| RPCS3 | `PINE_TARGET=rpcs3` |
| Duckstation | `PINE_TARGET=duckstation` |
| Custom port | `PINE_SLOT=<port>` |
| Docker/special socket | `PINE_SOCKET_PATH=<path>` |
| Performance testing | `PINE_PIPELINE_BATCH=2` |
| Debugging queue issues | `PINE_PIPELINE_BATCH=1` (default) |

---

## Error States and Diagnostics

| Error Message | Cause | Fix |
|---------------|-------|-----|
| `Cannot reach PINE server` | Emulator not running, PINE disabled, port mismatch | Verify emulator PINE settings |
| `PINE FAIL response (0xFF)` | No game loaded, unmapped address | Load game, check address |
| Reads return zeros | Unmapped memory region | Try `0x00100000` (EE RAM start) |
| Values look corrupted | Endianness mismatch | PINE is little-endian |
| `PINE call timed out (10s)` | Queue desync | Full PCSX2 restart required |

资料来源：[README.md:80-95]()

---

<a id='memory-operations'></a>

## Memory Operations

### 相关页面

相关主题：[Savestate Management](#savestate-management), [System Query Tools](#system-queries)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)
- [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)
- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
</details>

# Memory Operations

## Overview

Memory Operations in mcp-pine provide read and write access to the emulated PlayStation 2's (PS2) Emotion Engine (EE) address space through the PINE (Plugin Interface for Networked Emulation) protocol. These operations enable AI assistants and MCP clients to inspect and modify game state in real-time while an emulator runs.

The primary use cases include:

- **Game state inspection** — reading RAM to discover health, score, position, or other variables
- **Cheat development** — writing values to memory addresses to create or test cheats
- **Debugging** — inspecting memory regions during gameplay to understand game logic
- **Save state management** — snapshotting and restoring emulator state through specific slots

Memory operations in mcp-pine are exposed as MCP tools that bridge the AI assistant to the underlying PINE protocol implementation in `src/pine.ts`.

资料来源：[src/tools.ts:1-50]()

## Architecture

### Component Hierarchy

```mermaid
graph TD
    subgraph "MCP Client Layer"
        A["AI Assistant / Claude"]
    end
    
    subgraph "MCP Bridge (mcp-pine)"
        B["src/tools.ts<br/>Tool Definitions"]
        C["src/pine.ts<br/>PineClient"]
        D["PINE Protocol Encoder/Decoder"]
    end
    
    subgraph "Transport Layer"
        E["Unix Socket<br/>Linux/macOS"]
        F["TCP Socket<br/>Windows"]
    end
    
    subgraph "Emulator"
        G["PCSX2 / RPCS3 / Duckstation<br/>PINE Server"]
    end
    
    A --> B
    B --> C
    C --> D
    D --> E
    D --> F
    E --> G
    F --> G
```

### Request-Response Flow

```mermaid
sequenceDiagram
    participant AI as AI Assistant
    participant MCP as MCP Bridge
    participant PC as PineClient
    participant PINE as PINE Server
    
    AI->>MCP: pine_read32(0x00100000)
    MCP->>PC: read32() call
    PC->>PINE: Op.Read32 + addr (12 bytes)
    PINE-->>PC: Reply frame (12 bytes)
    PC-->>MCP: number value
    MCP-->>AI: "0x00100000: 1234 (0x4D2)"
```

### Key Components

| Component | File | Responsibility |
|-----------|------|-----------------|
| `PineClient` | `src/pine.ts` | Socket management, request queuing, protocol encoding/decoding |
| Tool definitions | `src/tools.ts` | MCP tool schemas, parameter validation, response formatting |
| Opcode enum | `src/pine.ts` | PINE protocol opcodes (Op.Read32, Op.Write8, etc.) |

资料来源：[src/pine.ts:1-80]()

## Read Operations

mcp-pine provides four aligned read operations for accessing EE memory:

| Tool | Width | Opcode | Alignment |
|------|-------|--------|-----------|
| `pine_read8` | 8-bit / 1 byte | `Op.Read8` | None required |
| `pine_read16` | 16-bit / 2 bytes | `Op.Read16` | 2-byte |
| `pine_read32` | 32-bit / 4 bytes | `Op.Read32` | 4-byte |
| `pine_read64` | 64-bit / 8 bytes | `Op.Read64` | 8-byte |

All read operations return values as little-endian unsigned integers. The return format follows a consistent pattern: `ADDR_HEX: VAL_DEC (0xVAL_HEX)`.

### Address Parameter

The `address` parameter for all read/write operations accepts an absolute byte address in the EE main address space:

```
Absolute byte address in the EE main address space (NOT a per-domain offset).
Pass as a number; hex literals like 0x00200000 are fine.
```

**PS2 Memory Landmarks:**

| Region | Address Range | Description |
|--------|---------------|-------------|
| EE Main RAM | `0x00100000` - `0x01FFFFFF` | Where 99% of game state lives |
| IOP RAM | `0x1C000000`+ | Input/Output Processor memory |
| Scratchpad | `0x70000000` - `0x70003FFF` | Fast 16KB scratchpad |

资料来源：[src/tools.ts:30-45]()

### Usage Examples

```javascript
// Read 32-bit value at game state pointer
pine_read32(0x00200000)

// Read 8-bit byte for flag detection
pine_read8(0x00201004)

// Read 64-bit EE pointer
pine_read64(0x00203000)
```

### Alignment Caveats

> **Important:** PINE on PCSX2 does NOT enforce alignment. Unaligned multi-byte access returns whatever bytes are at the aligned address below, silently corrupting the value.

| Operation | Required Alignment | Misaligned Behavior |
|-----------|-------------------|---------------------|
| `read8` | None | Correct |
| `read16` | 2-byte | Returns wrong value silently |
| `read32` | 4-byte | Returns wrong value silently |
| `read64` | 8-byte | Returns wrong value silently |

If you need an unaligned multi-byte read, use `pine_read_range` and assemble the bytes yourself.

资料来源：[src/tools.ts:30-40]()

## Write Operations

Write operations modify memory in the emulated EE address space:

| Tool | Width | Opcode | Value Encoding |
|------|-------|--------|----------------|
| `pine_write8` | 8-bit | `Op.Write8` | Number `0-255` |
| `pine_write16` | 16-bit | `Op.Write16` | Number `0-65535` |
| `pine_write32` | 32-bit | `Op.Write32` | Number `0-4294967295` |
| `pine_write64` | 64-bit | `Op.Write64` | Decimal string `0-18446744073709551615` |

### Destructive Behavior Notes

- Writes **bypass TLB protection** and DMA mediation
- Writes to **read-only regions** (BIOS, IOP ROM) are silently dropped
- **No undo mechanism** — changes are permanent until emulator restart or explicit restoration

### 64-bit Value Encoding

64-bit values use decimal string encoding because JavaScript's number type cannot represent the full `uint64` range (max safe integer is `2^53 - 1`):

```javascript
// Write maximum 64-bit value
pine_write64(0x00200000, "18446744073709551615")
```

The schema enforces this with `pattern: "^[0-9]+$"` to reject non-numeric input.

资料来源：[src/tools.ts:140-180]()

### Usage Examples

```javascript
// Infinite health cheat
pine_write32(0x00201000, 9999)

// Set RGBA color (packed 32-bit)
pine_write32(0x00300000, 0xFFFFFFFF)

// Write large 64-bit ID
pine_write64(0x00204000, "12345678901234567")
```

## Bulk Read Operation

### `pine_read_range`

Reads up to 4096 consecutive bytes in a single tool call. Since PINE has no native bulk read opcode, this is implemented client-side as a serial sequence of aligned reads.

**Implementation Strategy:**

```mermaid
graph TD
    A["read_range(addr, length)"] --> B["Calculate read steps"]
    B --> C{"Remaining bytes?"}
    C -->|≥8 & addr%8==0| D["read64"]
    C -->|≥4 & addr%4==0| E["read32"]
    C -->|≥2 & addr%2==0| F["read16"]
    C -->|else| G["read8"]
    D --> H["cursor += 8"]
    E --> I["cursor += 4"]
    F --> J["cursor += 2"]
    G --> K["cursor += 1"]
    H --> C
    I --> C
    J --> C
    K --> C
    C -->|0| L["Return Buffer"]
```

**Performance Characteristics:**

| Configuration | Measured Time (4KB) |
|---------------|---------------------|
| Serial (`PINE_PIPELINE_BATCH=1`) | ~52 ms |
| With pipelining (`PINE_PIPELINE_BATCH=2+`) | Lower latency, higher risk |

> Measured on PCSX2 v2.6.3 over loopback TCP.

### Pipelining and PCSX2 Fragility

PCSX2's PINE server has a **fragile request queue**: dropping any single request silently desyncs the reply pipeline, causing all subsequent requests to timeout until the emulator restarts.

```mermaid
sequenceDiagram
    participant Client
    participant PCSX2 as PCSX2 PINE Server
    
    Note over Client,PCSX2: Normal operation (≤6 in-flight)
    Client->>PCSX2: Request 1
    Client->>PCSX2: Request 2
    Client->>PCSX2: Request 3
    PCSX2-->>Client: Reply 1
    PCSX2-->>Client: Reply 2
    PCSX2-->>Client: Reply 3
    
    Note over Client,PCSX2: Pipeline saturation (≥7 in-flight)
    Client->>PCSX2: Request 1
    Client->>PCSX2: Request 2
    Client->>PCSX2: Request 3
    Client->>PCSX2: Request 4
    Client->>PCSX2: Request 5
    Client->>PCSX2: Request 6
    Client->>PCSX2: Request 7
    PCSX2->>PCSX2: Dropped!
    Note over Client,PCSX2: All subsequent replies misaligned!
```

**Recommendation:** Use serial mode by default. Only set `PINE_PIPELINE_BATCH=2` or higher if you can tolerate occasional emulator restarts.

资料来源：[src/pine.ts:60-100]()

## Save State Operations

The save state operations provide snapshot and restore functionality through PINE slots:

| Tool | Opcode | Description |
|------|--------|-------------|
| `pine_save_state` | `Op.SaveState` | Save current emulator state to slot |
| `pine_load_state` | `Op.LoadState` | Load emulator state from slot |

### Slot Numbering

- **Range:** 0-255
- **PCSX2 convention:** Slots 0-9 mapped to F1-F10 in GUI
- **Storage location:** Per-game savestate folder

### Slot File Naming

```
<serial> (<crc>).<slot>.p2s
```

Example: `SCUS-97211 (ABC12345).3.p2s`

资料来源：[src/tools.ts:180-220]()

## Error Handling

### Connection Failures

| Error | Cause | Fix |
|-------|-------|-----|
| `Cannot reach PINE server` | Emulator not running, PINE disabled, wrong slot | Check `PINE_SLOT` setting |
| `PINE FAIL response (0xFF)` | Emulator rejected request | Ensure game loaded, check address validity |
| Timeout (10s) | Reply dropped | Restart emulator if PCSX2 PINE is wedged |

### Data Corruption

| Symptom | Cause | Fix |
|---------|-------|-----|
| Reads return zeros | Address in unallocated region | Try `0x00100000` first |
| Values look corrupted | Wrong endianness interpretation | PINE returns little-endian |
| Silent wrong values | Unaligned access | Align addresses or use `read_range` |

资料来源：[README.md:80-100]()

## Configuration

### Environment Variables

| Variable | Default | Purpose |
|----------|---------|---------|
| `PINE_TARGET` | `pcsx2` | Emulator name prefix for Unix socket path |
| `PINE_SLOT` | `28011` | PINE slot / port number |
| `PINE_PIPELINE_BATCH` | `1` | Parallel request count (use with caution) |

### Socket Path Resolution

```mermaid
graph TD
    A["Start"] --> B{"OS?"}
    B -->|Windows| C["TCP 127.0.0.1:<PINE_SLOT>"]
    B -->|Linux/macOS| D{"XDG_RUNTIME_DIR set?"}
    D -->|Yes| E["$XDG_RUNTIME_DIR/<PINE_TARGET>.sock.<PINE_SLOT>"]
    D -->|No| F{"TMPDIR set?"}
    F -->|Yes| G["$TMPDIR/<PINE_TARGET>.sock.<PINE_SLOT>"]
    F -->|No| H["/tmp/<PINE_TARGET>.sock.<PINE_SLOT>"]
```

资料来源：[src/pine.ts:20-50]()

## Tool Reference Summary

| Tool | Input Schema | Return Format |
|------|--------------|---------------|
| `pine_ping` | None | `OK — emulator: <version>` |
| `pine_get_info` | None | Multi-line status with title, serial, CRC, version |
| `pine_get_status` | None | `Status: running\|paused\|shutdown` |
| `pine_read8` | `{address: integer}` | `ADDR_HEX: VAL (0xVAL_HEX)` |
| `pine_read16` | `{address: integer}` | `ADDR_HEX: VAL (0xVAL_HEX)` |
| `pine_read32` | `{address: integer}` | `ADDR_HEX: VAL (0xVAL_HEX)` |
| `pine_read64` | `{address: integer}` | `ADDR_HEX: VAL (0xVAL_HEX)` |
| `pine_read_range` | `{address: integer, length: 1-4096}` | Raw bytes (base64 or hex) |
| `pine_write8` | `{address: integer, value: number}` | `Wrote VAL → ADDR` |
| `pine_write16` | `{address: integer, value: number}` | `Wrote VAL → ADDR` |
| `pine_write32` | `{address: integer, value: number}` | `Wrote VAL → ADDR` |
| `pine_write64` | `{address: integer, value: string}` | `Wrote VAL → ADDR` |
| `pine_save_state` | `{slot: 0-255}` | `Saved state to slot <N>` |
| `pine_load_state` | `{slot: 0-255}` | `Loaded state from slot <N>` |

资料来源：[src/tools.ts:50-250]()

---

<a id='savestate-management'></a>

## Savestate Management

### 相关页面

相关主题：[Memory Operations](#memory-operations), [System Query Tools](#system-queries)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)
- [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)
</details>

# Savestate Management

## Overview

Savestate Management provides MCP clients with the ability to programmatically save and load emulator states for PlayStation 2 games running in PCSX2 (or other PINE-compatible emulators). This enables workflows such as checkpoint-based experimentation, automated testing, and stateful memory analysis where the user can snapshot game state, perform operations, and restore to a known baseline.

The feature is implemented through two MCP tools (`pine_save_state` and `pine_load_state`) that wrap the PINE protocol's `SaveState` and `LoadState` opcodes. These tools interact directly with the emulator's running instance, writing savestate files to the emulator's native storage location.

## Architecture

### Component Overview

```mermaid
graph TD
    A["MCP Client<br/>(Claude Code, Claude Desktop)"] --> B["mcp-pine Bridge"]
    B --> C["PineClient<br/>(src/pine.ts)"]
    C --> D["PINE Protocol<br/>(TCP/Unix Socket)"]
    D --> E["PCSX2 PINE Server"]
    E --> F["Savestate Files<br/>(~/.config/PCSX2/sstates)"]
    
    G["src/tools.ts"] -->|Tool Definitions| B
```

### Savestate Workflow

```mermaid
sequenceDiagram
    participant MCP as MCP Client
    participant Bridge as mcp-pine Bridge
    participant Pine as PineClient
    participant Emu as PCSX2 PINE Server
    participant FS as File System

    Note over MCP, FS: Save State Flow
    MCP->>Bridge: pine_save_state(slot: N)
    Bridge->>Pine: saveState(slot)
    Pine->>Emu: PINE SaveState opcode + slot byte
    Emu->>FS: Write <serial>.<crc>.<slot>.p2s
    Emu-->>Pine: PINE OK response
    Pine-->>Bridge: Promise resolves
    Bridge-->>MCP: "State saved to slot N"

    Note over MCP, FS: Load State Flow
    MCP->>Bridge: pine_load_state(slot: N)
    Bridge->>Pine: loadState(slot)
    Pine->>Emu: PINE LoadState opcode + slot byte
    Emu->>FS: Read <serial>.<crc>.<slot>.p2s
    Emu-->>Pine: PINE OK response
    Pine-->>Bridge: Promise resolves
    Bridge-->>MCP: "State loaded from slot N"
```

## MCP Tools

### pine_save_state

Saves the current emulator state to a specified slot.

| Property | Value |
|----------|-------|
| **Tool Name** | `pine_save_state` |
| **Source** | [src/tools.ts:1-20](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts) |

**Parameters:**

| Parameter | Type | Constraints | Description |
|-----------|------|-------------|-------------|
| `slot` | integer | 0-255 | Save state slot number |

**Description (from source):**

```
PURPOSE: Atomically snapshot the full emulator state (CPU registers, RAM, VRAM, 
         SPU, device states) to the specified slot and persist it to disk. USAGE: 
         Save checkpoints before risky operations (memory edits, patch applications, 
         speedrun route branches). Use pine_load_state to restore. Slot 0 is 
         conventional for "current run", slots 1-9 map to F1-F10 in PCSX2's GUI. 
         BEHAVIOR: DESTRUCTIVE — overwrites any existing savestate in the same 
         slot without prompting. Requires a game to be loaded; returns PINE FAIL 
         if invoked from the BIOS. Emulator retains the saved data across sessions 
         (survives emulator restart). RETURNS: "State saved to slot N" on success.
```

### pine_load_state

Restores the emulator state from a specified slot.

| Property | Value |
|----------|-------|
| **Tool Name** | `pine_load_state` |
| **Source** | [src/tools.ts:1-20](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts) |

**Parameters:**

| Parameter | Type | Constraints | Description |
|-----------|------|-------------|-------------|
| `slot` | integer | 0-255 | Save state slot number |

**Description (from source):**

```
PURPOSE: Atomically restore the full emulator state (CPU registers, RAM, VRAM, 
         SPU, device states) from a previously saved slot. USAGE: Restore after 
         experimental memory edits, reset to a known checkpoint, or implement 
         trial-and-error workflows (save → modify → load → try again). 
         BEHAVIOR: DESTRUCTIVE — immediately overwrites all emulator state with 
         the slot's contents. Does not verify the slot contains a valid savestate 
         before restoring (PINE FAIL if slot is empty/missing). The restored state 
         reflects the exact game position at the time of save, including any 
         unsaved progress. RETURNS: "State loaded from slot N" on success.
```

## Implementation

### PineClient Methods

The `PineClient` class in `src/pine.ts` implements the savestate operations:

```typescript
async saveState(slot: number): Promise<void> {
  const args = Buffer.alloc(1); args.writeUInt8(slot, 0);
  await this.call(Op.SaveState, args);
}

async loadState(slot: number): Promise<void> {
  const args = Buffer.alloc(1); args.writeUInt8(slot, 0);
  await this.call(Op.LoadState, args);
}
```

**资料来源:** [src/pine.ts:1-10](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)

### Tool Registration

The tools are registered in `registerTools()` which handles the MCP request routing:

```typescript
case "pine_save_state": {
  await pine.saveState(p.slot as number);
  return ok(`State saved to slot ${p.slot}`);
}
case "pine_load_state": {
  await pine.loadState(p.slot as number);
  return ok(`State loaded from slot ${p.slot}`);
}
```

**资料来源:** [src/tools.ts:1-20](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)

## Slot Management

### Slot Number Conventions

| Slot Range | Conventional Use | GUI Mapping |
|------------|------------------|-------------|
| 0 | Current run / temporary checkpoint | Manual |
| 1-9 | Quick save slots | F1-F10 |
| 10-99 | Scene-specific saves | Named folders |
| 100-255 | Long-term snapshots | Archive |

PCSX2 conventionally uses slots 0-9 mapped to function keys F1-F10 in the GUI. The PINE protocol accepts the full 0-255 range, but slots beyond 9 are only accessible programmatically.

### File Location

Savestate files are stored in the emulator's per-game savestate folder:

| Platform | Path |
|----------|------|
| Linux | `~/.config/PCSX2/sstates/` |
| macOS | `~/.config/PCSX2/sstates/` |
| Windows | `%USERPROFILE%\Documents\PCSX2\sstates\` |

**Filename format:** `<serial> (<crc>).<slot>.p2s`

## Usage Patterns

### Checkpoint Workflow

```mermaid
graph LR
    A[Game Running] --> B["pine_save_state<br/>slot=0"]
    B --> C[Perform Memory Edits]
    C --> D{Results OK?}
    D -->|Yes| E[Continue Playing]
    D -->|No| F["pine_load_state<br/>slot=0"]
    F --> A
```

### Memory Analysis Workflow

```mermaid
graph TD
    A[Save Baseline] -->|"slot=0"| B
    B[Find Target Address] -->|"pine_read32"| C
    C[Edit Memory] -->|"pine_write32"| D
    D[Verify Change] -->|"pine_read32"| E
    E{Correct?} -->|Yes| F[Continue]
    E{No} -->|"pine_load_state slot=0"| B
```

### Example Tool Calls

**Save state:**
```json
{
  "name": "pine_save_state",
  "arguments": { "slot": 0 }
}
```

**Load state:**
```json
{
  "name": "pine_load_state",
  "arguments": { "slot": 0 }
}
```

## Error Handling

### Common Failure Modes

| Error | Cause | Fix |
|-------|-------|-----|
| PINE FAIL response | No game loaded, or slot is invalid | Load a game before saving |
| Slot contains garbage | Corrupted savestate file | Delete file and re-save |
| Load restores wrong game | Serial/CRC mismatch | Use correct game or different slot |

### Connection Requirements

The emulator must be running with PINE enabled:

1. Launch PCSX2 (1.7.x Qt or newer)
2. Navigate to **Settings → Advanced → Enable PINE Server**
3. Default slot is **28011** (configurable via `PINE_SLOT`)

**资料来源:** [README.md:1-20](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## Configuration

Savestate operations are affected by the following environment variables:

| Variable | Default | Effect |
|----------|---------|--------|
| `PINE_SLOT` | `28011` | Sets the PINE slot used for communication |
| `PINE_TARGET` | `pcsx2` | Emulator name prefix for Unix socket path |
| `PINE_TIMEOUT` | `10000` (ms) | Per-call timeout; affects savestate operations |

## Related Tools

| Tool | Purpose |
|------|---------|
| `pine_get_info` | Get game metadata before saving (title, serial, CRC) |
| `pine_get_status` | Check if emulator is running/paused before operations |
| `pine_read_*` | Read memory from restored state |
| `pine_write_*` | Modify memory after loading a state |

## See Also

- [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) — sister MCP server for mGBA with button input support
- [PINE protocol spec](https://github.com/GovanifY/pine) — underlying IPC standard

---

<a id='system-queries'></a>

## System Query Tools

### 相关页面

相关主题：[Memory Operations](#memory-operations), [Savestate Management](#savestate-management)

<details>
<summary>Relevant Source Files</summary>

以下源码文件用于生成本页说明：

- [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)
- [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)
</details>

# System Query Tools

The System Query Tools in mcp-pine provide MCP (Model Context Protocol) clients with a comprehensive interface to query and interact with PINE-enabled PlayStation 2 emulators. These tools expose low-level emulator introspection capabilities—including game metadata retrieval, memory reading/writing, and save state management—through the standardized MCP tool interface.

## Overview

mcp-pine bridges the gap between AI assistants (primarily Claude) and PlayStation 2 emulators by implementing the PINE (Platform for Interactive Nintendo/Network Environments) protocol. The System Query Tools form the public API layer that MCP clients interact with.

### Architecture

```mermaid
graph TD
    subgraph "MCP Client Layer"
        A[Claude / MCP Host]
    end
    
    subgraph "mcp-pine Bridge"
        B[tools.ts<br/>Tool Definitions]
        C[pine.ts<br/>PineClient]
    end
    
    subgraph "Emulator Layer"
        D[PCSX2 / RPCS3 / Duckstation]
    end
    
    A -->|CallToolRequest| B
    B -->|PINE Protocol| C
    C -->|TCP / Unix Socket| D
    
    style B fill:#f9f,color:#000
    style C fill:#9ff,color:#000
```

### Tool Categories

| Category | Tools | Purpose |
|----------|-------|---------|
| **Connectivity** | `pine_ping` | Verify emulator connection and retrieve version |
| **Introspection** | `pine_get_info`, `pine_get_status` | Query game metadata and emulator state |
| **Memory Read** | `pine_read8`, `pine_read16`, `pine_read32`, `pine_read64`, `pine_read_range` | Read from emulator's EE address space |
| **Memory Write** | `pine_write8`, `pine_write16`, `pine_write32`, `pine_write64` | Write to emulator's memory |
| **State Management** | `pine_save_state`, `pine_load_state` | Manipulate emulator save states |

资料来源：[src/tools.ts:47-140]()

## Connectivity & Introspection

### pine_ping

A lightweight health check that retrieves the emulator's PINE protocol version.

```typescript
{
  name: "pine_ping",
  description:
    "PURPOSE: Verify connectivity to the emulator's PINE server and retrieve its version string. " +
    "USAGE: Call first when starting a session or debugging connection issues. Unlike pine_get_info, " +
    "this makes only one PINE round-trip (Status opcode) — fastest way to confirm the link is alive. " +
    "BEHAVIOR: No side effects. Issues PINE Version opcode (0x08). Times out after ~10s if the " +
    "emulator is unresponsive or the PINE queue is desynced. " +
    "RETURNS: 'OK — emulator: VERSION_STRING'.",
  inputSchema: { type: "object", properties: {} },
}
```

资料来源：[src/tools.ts:48-54]()

**Returns:** `OK — emulator: <version_string>`

### pine_get_info

Retrieves comprehensive game and emulator metadata in a single batched call.

```typescript
{
  name: "pine_get_info",
  description:
    "PURPOSE: Fetch all available game metadata (title, serial, disc CRC, game version, run state) in one tool call. " +
    "USAGE: Use at session start to identify the loaded game. For repeated status-only checks, pine_get_status is cheaper (1 opcode vs 5). " +
    "BEHAVIOR: No side effects — pure reads. Batches PINE opcodes: Title (0x01), ID (0x02), UUID (0x03), GameVersion (0x05), Status (0x0F). " +
    "Each field falls back to '(unavailable)' if the emulator returns PINE FAIL. " +
    "RETURNS: Multi-line string with Title, Serial, Disc CRC, Game version, Status.",
  inputSchema: { type: "object", properties: {} },
}
```

资料来源：[src/tools.ts:56-62]()

**Implementation:**

```typescript
case "pine_get_info": {
  const [title, id, uuid, gameVer, status] = await Promise.all([
    pine.getTitle().catch(() => "(unavailable)"),
    pine.getId().catch(() => "(unavailable)"),
    pine.getUuid().catch(() => "(unavailable)"),
    pine.getGameVersion().catch(() => "(unavailable)"),
    pine.getStatus(),
  ]);
  return ok(
    `Title:        ${title}\n` +
    `Serial:       ${id}\n` +
    `Disc CRC:     ${uuid}\n` +
    `Game version: ${gameVer}\n` +
    `Status:       ${status}`,
  );
}
```

资料来源：[src/tools.ts:16-27]()

**Returns:**
```
Title:        <game title>
Serial:       <game serial>
Disc CRC:     <disc CRC UUID>
Game version: <version string>
Status:       <running|paused|shutdown|unknown>
```

### pine_get_status

Queries only the emulator's run state, optimized for repeated checks.

```typescript
{
  name: "pine_get_status",
  description:
    "PURPOSE: Get the emulator run state — 'running', 'paused', 'shutdown', or 'unknown'. " +
    "USAGE: Cheap (1 PINE round-trip) check before timing-sensitive sequences — writes work while paused but only take visible effect after unpause. " +
    "For game metadata (title, serial, CRC) use pine_get_info. PINE has no pause/resume opcode; this tool only reports state. " +
    "BEHAVIOR: No side effects. Issues PINE Status opcode (0x0F), decodes the 32-bit response (0=running, 1=paused, 2=shutdown). " +
    "RETURNS: 'Status: STATE' where STATE ∈ {running, paused, shutdown, unknown}.",
  inputSchema: { type: "object", properties: {} },
}
```

资料来源：[src/tools.ts:95-101]()

**Status Mapping:**

| PINE Response | Emulator Status |
|---------------|-----------------|
| `0` | `running` |
| `1` | `paused` |
| `2` | `shutdown` |
| Other | `unknown` |

资料来源：[src/pine.ts:20-22]()

## Memory Read Operations

### Single-Value Reads

The `pine_read8`, `pine_read16`, `pine_read32`, and `pine_read64` tools read fixed-width values from the emulator's EE (Emotion Engine) address space.

```typescript
case "pine_read8":  return ok(`${addrHex(addr())}: ${fmtHex(await pine.read8(addr()))}`);
case "pine_read16": return ok(`${addrHex(addr())}: ${fmtHex(await pine.read16(addr()))}`);
case "pine_read32": return ok(`${addrHex(addr())}: ${fmtHex(await pine.read32(addr()))}`);
case "pine_read64": return ok(`${addrHex(addr())}: ${fmtHex(await pine.read64(addr()))}`);
```

资料来源：[src/tools.ts:29-32]()

#### Address Parameter

```typescript
const ADDRESS_PARAM_DESC = (widthBytes: number) => {
  const alignNote = widthBytes === 1
    ? "No alignment requirement for byte access."
    : `MUST be ${widthBytes}-byte aligned (address % ${widthBytes} === 0). PINE on PCSX2 does NOT enforce ` +
      `alignment — unaligned ${widthBytes * 8}-bit access typically returns whatever bytes are at the ` +
      `aligned address below, silently corrupting the value. If you need an unaligned multi-byte read, ` +
      `use pine_read_range and assemble the bytes yourself.`;
  return (
    `Absolute byte address in the EE main address space (NOT a per-domain offset).
    ...
    Useful range: 0x00100000-0x01FFFFFF for EE main RAM (where 99% of game state lives).`
  );
};
```

资料来源：[src/tools.ts:1-18]()

#### Alignment Requirements

| Tool | Width | Alignment | Corruption Risk |
|------|-------|-----------|-----------------|
| `pine_read8` | 1 byte | None | None |
| `pine_read16` | 2 bytes | 2-byte | Silently returns wrong value |
| `pine_read32` | 4 bytes | 4-byte | Silently returns wrong value |
| `pine_read64` | 8 bytes | 8-byte | Silently returns wrong value |

资料来源：[src/tools.ts:3-9]()

#### Tool Descriptions

**pine_read8**
```typescript
description:
  "PURPOSE: Read an unsigned 8-bit byte from the emulator's EE address space at the given absolute address. " +
  "USAGE: Use for single-byte fields — status flags, counters, 8-bit enums, character bytes..."
```

**pine_read16**
```typescript
description:
  "PURPOSE: Read an unsigned 16-bit little-endian value from the emulator's EE address space..."
```

**pine_read32**
```typescript
description:
  "PURPOSE: Read an unsigned 32-bit little-endian value from the emulator's EE address space..." +
  "little-endian (LSB at `address`, MSB at `address+3`). Address MUST be 4-byte aligned..."
```

**pine_read64**
```typescript
description:
  "PURPOSE: Read an unsigned 64-bit little-endian value from the emulator's EE address space..." +
  "The PS2 EE is a 128-bit MIPS (Emotion Engine), and a lot of game state genuinely lives in 64-bit slots..."
```

资料来源：[src/tools.ts:103-134]()

**Returns Format:** `ADDR_HEX: VAL_DEC (0xVAL_HEX)`

**64-bit Value Encoding:** Due to JavaScript's number precision limit (2^53), 64-bit values are returned as decimal strings to preserve full precision.

### pine_read_range (Bulk Read)

Reads a contiguous byte span up to 4096 bytes in a single tool call.

```typescript
{
  name: "pine_read_range",
  description:
    "PURPOSE: Read a contiguous byte span (1-4096 bytes) from the emulator's EE address space in one tool call. " +
    "USAGE: Use for structs, strings, buffers, or any multi-byte region. Prefer over multiple single reads to minimize round-trips (1 call vs N). " +
    "BEHAVIOR: No side effects — pure read. Internally dispatches read64/read32/read16/read8 calls, choosing the largest aligned width at each step...",
}
```

资料来源：[src/tools.ts:136-140]()

#### Implementation

```typescript
async readRange(address: number, length: number): Promise<Buffer> {
  const out = Buffer.alloc(length);
  let cursor = address;
  let outOffset = 0;
  let remaining = length;
  
  while (remaining > 0) {
    let n: 1 | 2 | 4 | 8;
    if      (cursor % 8 === 0 && remaining >= 8) n = 8;
    else if (cursor % 4 === 0 && remaining >= 4) n = 4;
    else if (cursor % 2 === 0 && remaining >= 2) n = 2;
    else                                          n = 1;
    steps.push({ op: n, addr: cursor, outOffset });
    cursor    += n;
    outOffset += n;
    remaining -= n;
  }
  // ...
}
```

资料来源：[src/pine.ts:24-45]()

#### Pipelining Behavior

```mermaid
graph LR
    A[read_range call] --> B{env: PINE_PIPELINE_BATCH}
    B -->|1| C[Fully Serial]
    B -->|2+| D[Batched Pipeline]
    C --> E[Safe<br/>~52ms for 4KB]
    D --> F[Fast but risky<br/>May desync PCSX2]
```

资料来源：[src/pine.ts:47-60]()

**Performance:** ~52 ms for full 4096-byte read on PCSX2 v2.6.3 over loopback TCP.

**Pipeline Warning:** PCSX2's PINE server has a fragile request queue. Dropping ANY request (occurs with ~7+ in-flight requests) desyncs the reply pipeline, causing all subsequent requests to timeout. Default is fully serial (`PINE_PIPELINE_BATCH=1`).

## Memory Write Operations

### pine_write8 through pine_write64

Write fixed-width little-endian values to the emulator's EE address space.

```typescript
case "pine_write8": {
  await pine.write8(addr(), p.value as number);
  return ok(`Wrote ${fmtHex(p.value as number)} → ${addrHex(addr())}`);
}
case "pine_write16": {
  await pine.write16(addr(), p.value as number);
  return ok(`Wrote ${fmtHex(p.value as number)} → ${addrHex(addr())}`);
}
case "pine_write32": {
  await pine.write32(addr(), p.value as number);
  return ok(`Wrote ${fmtHex(p.value as number)} → ${addrHex(addr())}`);
}
```

资料来源：[src/tools.ts:34-41]()

#### Write Tool Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `address` | integer | Absolute byte address in EE address space |
| `value` | integer | Value to write (decimal or hex) |

#### Alignment Requirements

Same as read operations—multi-byte writes must be aligned, or data corruption occurs silently.

#### Behavior Notes

- **DESTRUCTIVE:** Overwrites existing memory contents
- Side effects persist after the call completes
- Writes work while emulator is paused but changes only take effect after unpause
- Returns PINE FAIL on unmapped addresses

资料来源：[src/tools.ts:75-82]()

## Save State Management

### pine_save_state

Saves the current emulator state to a numbered slot.

```typescript
{
  name: "pine_save_state",
  description:
    "PURPOSE: Capture a full emulator snapshot and write it to a numbered save-state slot. " +
    "USAGE: Use before experimental memory writes or to bookmark a checkpoint for later restoration. " +
    "Save states are emulator-process snapshots — they persist across emulator restarts. " +
    "BEHAVIOR: DESTRUCTIVE: Overwrites any existing state in the target slot. Issues PINE SaveState opcode (0x10). " +
    "Slot files are stored in PCSX2's per-game savestate folder...",
  inputSchema: {
    type: "object",
    required: ["slot"],
    properties: {
      slot: { type: "integer", minimum: 0, maximum: 255, description: SLOT_PARAM_DESC },
    },
    additionalProperties: false,
  },
}
```

资料来源：[src/tools.ts:143-152]()

#### Slot Parameter

```typescript
const SLOT_PARAM_DESC =
  "Save state slot number (0-255). PCSX2 conventionally uses slots 0-9 (mapped to F1-F10 in the GUI), " +
  "but the PINE protocol accepts the full 0-255 range. Slot files live in PCSX2's per-game savestate " +
  "folder (typically %USERPROFILE%/Documents/PCSX2/sstates on Windows, ~/.config/PCSX2/sstates on Linux) " +
  "with filenames like '<serial> (<crc>).<slot>.p2s'. Slot numbers are independent of any path.";
```

资料来源：[src/tools.ts:21-25]()

### pine_load_state

Restores the emulator state from a numbered slot.

```typescript
{
  name: "pine_load_state",
  description:
    "PURPOSE: Load a previously saved emulator snapshot from a save-state slot. " +
    "USAGE: Use to restore a checkpoint (e.g., after experimental memory writes that didn't work as expected). " +
    "BEHAVIOR: DESTRUCTIVE: Replaces the current running state with the saved snapshot. " +
    "Issues PINE LoadState opcode (0x11). Returns PINE FAIL if the slot is empty or corrupted.",
  inputSchema: {
    type: "object",
    required: ["slot"],
    properties: {
      slot: { type: "integer", minimum: 0, maximum: 255, description: SLOT_PARAM_DESC },
    },
    additionalProperties: false,
  },
}
```

资料来源：[src/tools.ts:154-163]()

#### Implementation

```typescript
async saveState(slot: number): Promise<void> {
  const args = Buffer.alloc(1); args.writeUInt8(slot, 0);
  await this.call(Op.SaveState, args);
}
async loadState(slot: number): Promise<void> {
  const args = Buffer.alloc(1); args.writeUInt8(slot, 0);
  await this.call(Op.LoadState, args);
}
```

资料来源：[src/pine.ts:15-20]()

## Tool Registration

Tools are registered with the MCP server through `registerTools()`:

```typescript
export function registerTools(server: Server, pine: PineClient): 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>;
    const addr = () => p.address as number;

    switch (name) {
      case "pine_ping": {
        const v = await pine.getVersion();
        return ok(`OK — emulator: ${v}`);
      }
      // ... other cases
    }
  });
}
```

资料来源：[src/tools.ts:158-173]()

### Tool Definition Schema

Each tool follows a consistent structure:

| Field | Purpose |
|-------|---------|
| `name` | Unique identifier for the tool |
| `description` | PURPOSE / USAGE / BEHAVIOR / RETURNS template |
| `inputSchema` | JSON Schema for parameters |

## Error Handling

All tools implement consistent error handling:

| Error Condition | Response |
|-----------------|----------|
| Connection failure | Tool call rejects with error |
| PINE FAIL response | Error message returned |
| Timeout (10s default) | Tool call rejects |
| Invalid address | PINE FAIL response |

```typescript
const ok = (text: string) => {
  return { content: [{ type: "text" as const, text }] };
};
```

资料来源：[src/tools.ts:144-147]()

## Configuration

| Environment Variable | Default | Purpose |
|---------------------|---------|---------|
| `PINE_TARGET` | `pcsx2` | Emulator name for socket path |
| `PINE_SLOT` | `28011` | PINE slot / port number |
| `PINE_PIPELINE_BATCH` | `1` | Read range batch size |

资料来源：[README.md](./README.md)

---

<a id='development-guide'></a>

## Development Guide

### 相关页面

相关主题：[Troubleshooting Guide](#troubleshooting), [Project Overview](#overview)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
- [src/index.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/index.ts)
- [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)
- [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)
- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [CHANGELOG.md](https://github.com/dmang-dev/mcp-pine/blob/main/CHANGELOG.md)
</details>

# Development Guide

## Overview

This guide covers the development workflow, architecture, and contribution guidelines for `mcp-pine`, an MCP (Model Context Protocol) server that bridges AI assistants like Claude to PlayStation 2/3 emulators via the PINE protocol.

The project enables read/write access to emulator memory, save state management, and game information retrieval through standardized MCP tool calls.

## Project Structure

```
mcp-pine/
├── src/
│   ├── index.ts       # Entry point, MCP server initialization
│   ├── pine.ts        # PineClient - low-level PINE protocol implementation
│   └── tools.ts       # MCP tool definitions and handlers
├── .scratch/
│   └── smoke.cjs      # Quick smoke test script
├── package.json
├── tsconfig.json
└── Dockerfile
```

### Key Modules

| Module | Responsibility |
|--------|----------------|
| `src/index.ts` | MCP server bootstrap, connection lifecycle, signal handling |
| `src/pine.ts` | Socket communication, PINE opcodes, read/write operations |
| `src/tools.ts` | Tool definitions, input schemas, result formatting |

## Architecture

### System Components

```mermaid
graph TD
    A["MCP Client<br/>(Claude, etc.)"] --> B["mcp-pine<br/>MCP Server"]
    B --> C["PineClient<br/>(TCP/Unix Socket)"]
    C --> D["Emulator PINE Server<br/>(PCSX2/RPCS3/Duckstation)"]
    
    B --> E["Tool Definitions<br/>(src/tools.ts)"]
    C --> F["PINE Protocol<br/>(src/pine.ts)"]
```

### PINE Protocol Flow

```mermaid
sequenceDiagram
    participant MCP as MCP Client
    participant Bridge as mcp-pine
    participant PINE as PINE Server
    participant Emu as Emulator
    
    MCP->>Bridge: call_tool(pine_read32)
    Bridge->>PINE: TCP/Unix Socket
    PINE->>Emu: Memory Read Request
    Emu-->>PINE: Memory Value
    PINE-->>Bridge: PINE Response Frame
    Bridge-->>MCP: {content: text}
```

## Development Setup

### Prerequisites

| Requirement | Version | Notes |
|-------------|---------|-------|
| Node.js | ≥ 22.0.0 | LTS recommended |
| npm | Bundled with Node | For package management |
| PCSX2 | ≥ 1.7.x | PINE-enabled build |
| TypeScript | ^5.5.0 | Development dependency |

### Installation

```bash
# Clone the repository
git clone https://github.com/dmang-dev/mcp-pine
cd mcp-pine

# Install dependencies (runs build via prepare hook)
npm install
```

The `prepare` script in `package.json` automatically runs the build after installation:

```json
"scripts": {
  "prepare": "tsc"
}
```
资料来源：[package.json:8-10]()

### Development Workflow

```bash
# Watch mode - recompile on file changes
npm run dev

# Manual build (if not using dev)
npm run build   # or npx tsc

# Quick smoke test against running emulator
node .scratch/smoke.cjs
```
资料来源：[README.md:1]()

## Source Code Analysis

### Entry Point (src/index.ts)

The entry point initializes the MCP server with the SDK, creates a `PineClient` instance based on environment variables, and registers all tools.

**Key initialization flow:**

1. Parse environment variables for connection options
2. Create `PineClient` with resolved socket/TCP descriptor
3. Connect to emulator's PINE server
4. Register tools with the MCP server
5. Start server on stdio

### PineClient (src/pine.ts)

The `PineClient` class handles low-level protocol communication.

**Connection Modes:**

| Platform | Method | Path/Address |
|----------|--------|--------------|
| Linux/macOS | Unix Socket | `$XDG_RUNTIME_DIR/<target>.sock.<slot>` |
| Linux fallback | Unix Socket | `/tmp/<target>.sock.<slot>` |
| Windows | TCP | `127.0.0.1:<slot>` |

**Supported Operations:**

| Opcode | Operation | Description |
|--------|-----------|-------------|
| 0x01 | Version | Get emulator PINE version |
| 0x02 | Title | Get loaded game title |
| 0x03 | ID | Get game serial ID |
| 0x04 | UUID | Get disc CRC |
| 0x05 | GameVersion | Get game version string |
| 0x10 | Status | Get emulator status |
| 0x20 | Read8 | Read 8-bit value |
| 0x21 | Read16 | Read 16-bit value |
| 0x22 | Read32 | Read 32-bit value |
| 0x23 | Read64 | Read 64-bit value |
| 0x30 | Write8 | Write 8-bit value |
| 0x31 | Write16 | Write 16-bit value |
| 0x32 | Write32 | Write 32-bit value |
| 0x33 | Write64 | Write 64-bit value |
| 0x40 | SaveState | Save to slot |
| 0x41 | LoadState | Load from slot |

### Tool Definitions (src/tools.ts)

Each MCP tool follows the TDQS (Tool Definition Quality Score) rubric with explicit:

- **PURPOSE**: Single action sentence
- **USAGE**: When to use vs. sibling tools
- **BEHAVIOR**: Side effects, error conditions
- **RETURNS**: Exact output shape

**Tool Categories:**

| Category | Tools |
|----------|-------|
| Connectivity | `pine_ping`, `pine_get_info` |
| Read | `pine_read8`, `pine_read16`, `pine_read32`, `pine_read64`, `pine_read_range` |
| Write | `pine_write8`, `pine_write16`, `pine_write32`, `pine_write64` |
| State | `pine_save_state`, `pine_load_state` |

## Configuration

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `PINE_TARGET` | `pcsx2` | Emulator name prefix for Unix socket path |
| `PINE_SLOT` | `28011` | PINE slot number (also TCP port on Windows) |
| `PINE_PIPELINE_BATCH` | `1` | Number of pipelined requests (see Warning below) |
| `XDG_RUNTIME_DIR` | - | Unix socket directory (Linux/macOS) |
| `TMPDIR` | - | Unix socket fallback directory |

资料来源：[README.md:1]()

### Alignment Requirements

**Critical**: PINE on PCSX2 does NOT enforce alignment. Multi-byte access at unaligned addresses silently returns corrupted data from the aligned-below address.

| Access Width | Alignment Required |
|--------------|-------------------|
| 8-bit (write8/read8) | None |
| 16-bit (write16/read16) | 2-byte |
| 32-bit (write32/read32) | 4-byte |
| 64-bit (write64/read64) | 8-byte |

## Testing

### Smoke Test

Run the provided smoke test against a running emulator:

```bash
# Start PCSX2 with PINE enabled, load a game
node .scratch/smoke.cjs
```

### Manual Verification

```bash
# Test connection
claude mcp add pine --scope user mcp-pine
claude mcp list
# pine: mcp-pine - ✓ Connected

# Run a ping
claude -p "call pine_ping"
```

## Building

### TypeScript Compilation

```bash
npm run build
# or
npx tsc
```

Output is placed in `dist/` directory with the same structure as `src/`.

### Docker

A `Dockerfile` is provided for containerized deployment:

```bash
docker build -t mcp-pine .
docker run mcp-pine
```

## Known Limitations

### PCSX2 PINE Server Fragility

PCSX2's PINE server has a **fragile request queue** that drops requests silently when too many are pipelined. This desyncs the reply pipeline, causing all subsequent requests to time out until emulator restart.

| Setting | Safety | Latency |
|---------|--------|---------|
| `PINE_PIPELINE_BATCH=1` | Safe (default) | ~52ms for 4KB read |
| `PINE_PIPELINE_BATCH=2+` | Risky | Lower latency |

资料来源：[src/pine.ts:150-160]()

### Error Modes

| Symptom | Cause | Fix |
|---------|-------|-----|
| `Cannot reach PINE server` | Emulator not running, PINE disabled, wrong slot | Check `PINE_SLOT` |
| `PINE FAIL response` | No game loaded, unmapped address | Load game, check address |
| Reads return zeros | Unallocated memory region | Try `0x00100000` (EE RAM) |
| Tool calls work but values corrupted | Endianness mismatch | PINE returns little-endian |
| `PINE call timed out (10s)` after heavy use | PCSX2 PINE queue desync | Full emulator restart |

## Emulator Support

### PCSX2 (Primary)

1. Launch PCSX2 1.7.x Qt or newer
2. **Settings → Advanced → Enable PINE Server**
3. Default slot is **28011**
4. Load any game

资料来源：[README.md:1]()

### RPCS3 (Experimental)

```bash
PINE_TARGET=rpcs3 PINE_SLOT=<port> mcp-pine
```

Wire-level compatibility with PINE protocol not thoroughly tested.

### Duckstation

```bash
PINE_TARGET=duckstation PINE_SLOT=<port> mcp-pine
```

Requires PINE-enabled Duckstation build.

## Contribution Guidelines

1. **Tool descriptions**: Follow TDQS rubric in `src/tools.ts`
2. **Error handling**: All async operations must handle rejection
3. **Alignment**: Document alignment requirements in parameter descriptions
4. **Testing**: Verify changes against live PCSX2 before submitting
5. **Documentation**: Update CHANGELOG.md with changes

## Version History

| Version | Date | Key Changes |
|---------|------|-------------|
| 0.2.1 | 2026-05-15 | Tool description quality pass |
| 0.2.0 | 2026-05-10 | Bulk read, 10s timeout, robustness |
| 0.1.0 | Earlier | Initial release |

资料来源：[CHANGELOG.md:1-30]()

---

<a id='troubleshooting'></a>

## Troubleshooting Guide

### 相关页面

相关主题：[Emulator Setup](#emulator-setup), [Configuration Reference](#configuration)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [src/pine.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)
- [src/tools.ts](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)
- [CHANGELOG.md](https://github.com/dmang-dev/mcp-pine/blob/main/CHANGELOG.md)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
</details>

# Troubleshooting Guide

This guide covers common issues encountered when using **mcp-pine**, an MCP server that bridges the Model Context Protocol to the PINE IPC system used by PlayStation 2/3 emulators like PCSX2, RPCS3, and Duckstation.

## Connection Troubleshooting

### Cannot Reach PINE Server

**Symptom:** The MCP client reports it cannot connect to the PINE server.

**Root Causes:**

| Cause | Description | Fix |
|-------|-------------|-----|
| Emulator not running | PCSX2/RPCS3/Duckstation is not launched | Start the emulator with a game loaded |
| PINE not enabled | The PINE server toggle is off in emulator settings | Enable it in emulator settings |
| Slot/Port mismatch | `PINE_SLOT` doesn't match the emulator's configured port | Verify `PINE_SLOT` matches emulator configuration |
| Game not loaded | Some PINE operations require an active game session | Load any game before using tools |

**Verification Steps:**

```bash
# Check if mcp-pine is recognized by Claude Code
claude mcp list
# Expected output: pine: mcp-pine - ✓ Connected

# Test connection manually
PINE_TARGET=pcsx2 PINE_SLOT=28011 node .scratch/smoke.cjs
```

**资料来源：** [README.md:70-73](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

### Transport Layer Differences

| Platform | Transport | Path/Address |
|----------|-----------|--------------|
| Windows | TCP | `127.0.0.1:<PINE_SLOT>` |
| Linux/macOS | Unix Socket | `$XDG_RUNTIME_DIR/<PINE_TARGET>.sock.<PINE_SLOT>` with `$TMPDIR`/`/tmp` fallbacks |

The connection transport is automatically selected based on the operating system. Windows uses TCP loopback while Unix-like systems use Unix domain sockets.

**资料来源：** [src/pine.ts:80-88](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)

## PINE Response Errors

### PINE FAIL Response (0xFF)

**Symptom:** Tool returns "PINE FAIL response" error.

**Common Causes:**

1. **No game loaded** — Most PINE operations require an active game session
2. **Unmapped address** — The memory address doesn't map to any allocated region
3. **Invalid opcode** — The emulator doesn't support the requested operation

**Diagnostic Approach:**

```typescript
// Try reading from a known-good address first (EE main RAM)
const test = await pine.read32(0x00100000);
```

The address `0x00100000` is almost always inside loaded EE RAM and serves as a good sanity check.

**资料来源：** [README.md:74-76](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

### Reads Return Zeros

**Symptom:** Memory reads return all zeros instead of expected values.

**Cause:** The address falls in an unallocated memory region.

**Solution:** Start with `0x00100000` (EE main RAM base). The valid EE main RAM range is `0x00100000` to `0x01FFFFFF`.

```typescript
// Verify address is in valid range
// EE main RAM: 0x00100000 - 0x01FFFFFF
// IOP RAM: 0x1C000000+
// Scratchpad: 0x1F800000 - 0x1F8003FF
```

**资料来源：** [src/tools.ts:55-60](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)

### Corrupted Values / Wrong Data

**Symptom:** Read values appear garbled or incorrect.

**Root Cause:** Endianness mismatch.

PINE returns data in **little-endian** format. When interpreting multi-byte values or strings, ensure your code handles little-endian encoding.

```typescript
// For strings, use read_range (byte-level read)
const bytes = await pine.readRange(0x00100000, 64);
const str = bytes.toString('utf8').replace(/\0+$/, '');

// For multi-byte integers, PINE handles conversion automatically
const value = await pine.read32(0x00100000); // Already little-endian decoded
```

**资料来源：** [README.md:77-80](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## PCSX2-Specific Issues

### PINE Server Wedging

**Symptom:** `pine_ping` times out after heavy use, even though the emulator appears to be running.

**Root Cause:** PCSX2's PINE server has a **fragile request queue** that silently drops requests when too many are pipelined. As few as 7 in-flight requests can trigger this behavior. When any request is dropped, the reply pipeline becomes desynchronized — every subsequent reply is delivered to the wrong waiting client.

```mermaid
graph TD
    A[Normal Operation] -->|~7 in-flight requests| B[Request Dropped]
    B --> C[Reply Pipeline Desync]
    C --> D[All Replies Misaligned]
    D --> E[Every Call Times Out]
    E --> F[Emulator Must Be Fully Restarted]
```

**Recovery Steps:**

1. Fully quit PCSX2 (not just close the game)
2. Restart PCSX2
3. Load the game
4. Reconnect the MCP client

> **Note:** Simply reconnecting the client does NOT fix the desync — the corruption is on the emulator side.

**资料来源：** [README.md:83-91](https://github.com/dmang-dev/mcp-pine/blob/main/README.md), [CHANGELOG.md:45-52](https://github.com/dmang-dev/mcp-pine/blob/main/CHANGELOG.md)

### Bulk Read Performance

**Symptom:** `pine_read_range` feels slow compared to mGBA's `read_range`.

**Explanation:** PINE has no native bulk read opcode. The client issues reads **serially** by default, choosing the largest aligned width at each step (read64 on 8-byte boundaries, falling back to 32/16/8).

| Operation | Latency | Notes |
|-----------|---------|-------|
| Full 4096-byte read | ~52 ms | Measured on PCSX2 v2.6.3 over loopback |
| Frame budget at 60fps | ~16.6 ms | Bulk read takes ~3 frames |

**Optimization Option:** Set `PINE_PIPELINE_BATCH=2` to enable limited pipelining. This reduces latency but risks desyncing PCSX2's PINE server if the emulator's queue becomes overloaded.

```bash
# More aggressive pipelining (at your own risk)
PINE_PIPELINE_BATCH=2 mcp-pine
```

**资料来源：** [README.md:92-95](https://github.com/dmang-dev/mcp-pine/blob/main/README.md), [src/pine.ts:95-105](https://github.com/dmang-dev/mcp-pine/blob/main/src/pine.ts)

## Memory Access Issues

### Alignment Requirements

**Critical:** Multi-byte memory operations have alignment requirements that PCSX2 does NOT enforce.

| Operation | Alignment | Unaligned Behavior |
|-----------|-----------|-------------------|
| `pine_read8` / `pine_write8` | None | Works correctly |
| `pine_read16` / `pine_write16` | 2-byte | Silently returns corrupted data |
| `pine_read32` / `pine_write32` | 4-byte | Silently returns corrupted data |
| `pine_read64` / `pine_write64` | 8-byte | Silently returns corrupted data |

**Safe Alternative:** For unaligned access, use `pine_read_range` and assemble the bytes manually.

```typescript
// Unaligned 32-bit read at 0x00100003
const bytes = await pine.readRange(0x00100003, 4);
const value = bytes.readUInt32LE(0);
```

**资料来源：** [src/tools.ts:42-50](https://github.com/dmang-dev/mcp-pine/blob/main/src/tools.ts)

### 64-bit Value Precision

JavaScript loses precision for integers beyond `2^53`. For 64-bit operations, values are exchanged as **decimal strings**.

```typescript
// Writing a large 64-bit value
await pine.write64(0x00100000, "18446744073709551615" as unknown as bigint);

// Reading returns string-encoded decimal
const largeValue = await pine.read64(0x00100000);
// Returns: "18446744073709551615" (as string)
```

**资料来源：** [CHANGELOG.md:28-30](https://github.com/dmang-dev/mcp-pine/blob/main/CHANGELOG.md)

## Timeout Issues

### 10-Second Call Timeout

Every PINE call has a **10-second timeout**. If the emulator drops a reply (e.g., due to the wedging issue), the call rejects cleanly rather than hanging indefinitely.

**Timeouts indicate:**
- PCSX2 PINE server is wedged (most common)
- Network/connection interruption
- Emulator is unresponsive

**If you experience frequent timeouts:**
1. Check if PCSX2's PINE server has wedged
2. Verify no other tool is aggressive pipelining
3. Consider restarting the emulator

**资料来源：** [CHANGELOG.md:26-29](https://github.com/dmang-dev/mcp-pine/blob/main/CHANGELOG.md)

## Emulator-Specific Setup

### PCSX2 (Recommended)

1. Launch PCSX2 1.7.x Qt or newer
2. Navigate to **Settings → Advanced → Enable PINE Server**
3. Default slot is **28011** — only change `PINE_SLOT` if you configure a different port
4. Load any game

> PINE is always-on once enabled; no scripts or console commands needed.

**资料来源：** [README.md:44-54](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

### RPCS3

RPCS3 uses its own IPC implementation that mirrors PINE's opcode set. Wire-level compatibility hasn't been thoroughly tested.

1. Enable IPC server in **Configuration → Advanced**
2. Note the configured port
3. Run with:
   ```bash
   PINE_TARGET=rpcs3 PINE_SLOT=<port> mcp-pine
   ```

**资料来源：** [README.md:58-65](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

### Duckstation

Duckstation includes a PINE server only in **specific builds**. Check whether your build includes it:

1. Set `PINE_TARGET=duckstation`
2. Configure `PINE_SLOT` to match the port shown in Duckstation's settings
3. If connection fails, your build likely doesn't include PINE support

**资料来源：** [README.md:5-9](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## Environment Variables Reference

| Variable | Default | Purpose |
|----------|---------|---------|
| `PINE_TARGET` | `pcsx2` | Emulator name — used as prefix in Unix socket path on Linux/macOS |
| `PINE_SLOT` | `28011` | PINE slot / port number |
| `PINE_HOST` | `127.0.0.1` | TCP host override (Windows always uses this) |
| `PINE_SOCKET_PATH` | auto | Full Unix socket path override |
| `PINE_PIPELINE_BATCH` | `1` | Number of serial reads to batch together (higher = faster but riskier) |

**资料来源：** [README.md:34-40](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)

## Diagnostic Checklist

When reporting issues, include the following information:

- [ ] Emulator name and version (e.g., PCSX2 v2.6.3)
- [ ] Operating system and version
- [ ] `PINE_TARGET` and `PINE_SLOT` values
- [ ] Whether a game is currently loaded
- [ ] Exact error message received
- [ ] Steps to reproduce
- [ ] Whether restarting the emulator resolves the issue

## Getting Help

If issues persist after following this guide:

1. Search existing [GitHub Issues](https://github.com/dmang-dev/mcp-pine/issues)
2. File a new issue with diagnostic information
3. Include the output of the smoke test:
   ```bash
   node .scratch/smoke.cjs
   ```

**资料来源：** [README.md:1-3](https://github.com/dmang-dev/mcp-pine/blob/main/README.md), [package.json:8-9](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)

---

---

## Doramagic Pitfall Log

Project: dmang-dev/mcp-pine

Summary: Found 8 potential pitfall items; 0 are high/blocking. Highest priority: installation - 来源证据：Submit listing PR to punkpeye/awesome-mcp-servers.

## 1. installation · 来源证据：Submit listing PR to punkpeye/awesome-mcp-servers

- Severity: medium
- Evidence strength: source_linked
- Finding: GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Submit listing PR to punkpeye/awesome-mcp-servers
- User impact: 可能阻塞安装或首次运行。
- Suggested check: 来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。
- Guardrail action: 不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- Evidence: community_evidence:github | cevd_540ae479012f437fb2cb5e7d33636f1f | https://github.com/dmang-dev/mcp-pine/issues/2 | 来源讨论提到 npm 相关条件，需在安装/试用前复核。

## 2. configuration · 可能修改宿主 AI 配置

- Severity: medium
- Evidence strength: source_linked
- Finding: 项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。
- User impact: 安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。
- Suggested check: 列出会写入的配置文件、目录和卸载/回滚步骤。
- Guardrail action: 涉及宿主配置目录时必须给回滚路径，不能只给安装命令。
- Evidence: capability.host_targets | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | host_targets=mcp_host, claude

## 3. capability · 能力判断依赖假设

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: 假设不成立时，用户拿不到承诺的能力。
- Suggested check: 将假设转成下游验证清单。
- Guardrail action: 假设必须转成验证项；没有验证结果前不能写成事实。
- Evidence: capability.assumptions | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | README/documentation is current enough for a first validation pass.

## 4. maintenance · 维护活跃度未知

- Severity: medium
- Evidence strength: source_linked
- Finding: 未记录 last_activity_observed。
- User impact: 新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- Suggested check: 补 GitHub 最近 commit、release、issue/PR 响应信号。
- Guardrail action: 维护活跃度未知时，推荐强度不能标为高信任。
- Evidence: evidence.maintainer_signals | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | last_activity_observed missing

## 5. security_permissions · 下游验证发现风险项

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: 下游已经要求复核，不能在页面中弱化。
- Suggested check: 进入安全/权限治理复核队列。
- Guardrail action: 下游风险存在时必须保持 review/recommendation 降级。
- Evidence: downstream_validation.risk_items | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | no_demo; severity=medium

## 6. security_permissions · 存在评分风险

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: 风险会影响是否适合普通用户安装。
- Suggested check: 把风险写入边界卡，并确认是否需要人工复核。
- Guardrail action: 评分风险必须进入边界卡，不能只作为内部分数。
- Evidence: risks.scoring_risks | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | no_demo; severity=medium

## 7. maintenance · issue/PR 响应质量未知

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: 用户无法判断遇到问题后是否有人维护。
- Suggested check: 抽样最近 issue/PR，判断是否长期无人处理。
- Guardrail action: issue/PR 响应未知时，必须提示维护风险。
- Evidence: evidence.maintainer_signals | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | issue_or_pr_quality=unknown

## 8. maintenance · 发布节奏不明确

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: 安装命令和文档可能落后于代码，用户踩坑概率升高。
- Suggested check: 确认最近 release/tag 和 README 安装命令是否一致。
- Guardrail action: 发布节奏未知或过期时，安装说明必须标注可能漂移。
- Evidence: evidence.maintainer_signals | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | release_recency=unknown

<!-- canonical_name: dmang-dev/mcp-pine; human_manual_source: deepwiki_human_wiki -->
