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

生成时间：2026-05-17 20:22:23 UTC

## 目录

- [项目介绍](#page-introduction)
- [快速开始](#page-quickstart)
- [系统架构](#page-architecture)
- [PINE 协议详解](#page-pine-protocol)
- [工具参考](#page-tools-reference)
- [内存操作指南](#page-memory-operations)
- [存档状态管理](#page-savestate)
- [安装指南](#page-installation)
- [模拟器配置](#page-emulator-setup)
- [配置参考](#page-configuration)
- [使用范例](#page-recipes)
- [故障排除](#page-troubleshooting)

<a id='page-introduction'></a>

## 项目介绍

### 相关页面

相关主题：[系统架构](#page-architecture), [快速开始](#page-quickstart)

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

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

- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [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)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
</details>

# 项目介绍

## 概述

mcp-pine 是一个基于 **Model Context Protocol (MCP)** 的桥接服务器，用于连接 MCP 客户端（如 Claude Code、Claude Desktop）与支持 PINE 协议的 PlayStation 系列模拟器。该项目使 AI 助手能够直接读取和写入模拟器内存、保存/加载游戏状态，从而实现自动化游戏调试、内存修改、状态快照实验等高级功能。

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

## 项目背景与目标

在传统的游戏逆向工程和模拟器调试中，开发者需要手动使用调试工具或编写专用脚本与模拟器交互。mcp-pine 的出现旨在将这种能力抽象为一个标准化的 MCP 工具集，使 AI 助手能够：

- 实时查询游戏运行状态和元数据
- 读取任意内存地址的数据
- 写入内存实现游戏修改（Cheats/Pokes）
- 保存和恢复游戏快照
- 执行自动化的内存搜索和结构解码

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

## 支持的模拟器

mcp-pine 目前支持以下模拟器：

| 模拟器 | 状态 | 说明 |
|--------|------|------|
| **PCSX2** | 完整支持 | 1.7.x Qt 或更高版本，支持 PINE Server |
| **RPCS3** | 实验性支持 | 有独立的 IPC 实现，与 PINE 操作码兼容 |
| **Duckstation** | 部分支持 | 取决于具体编译版本是否包含 PINE Server |

对于 PCSX2，用户只需在 `Settings → Advanced → Enable PINE Server` 中启用即可，无需脚本或控制台命令。默认插槽为 **28011**。

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

## 系统架构

mcp-pine 采用典型的客户端-服务器分层架构：

```mermaid
graph TD
    A[MCP 客户端<br/>Claude Code/Desktop] -->|MCP 协议<br/>stdio| B[mcp-pine<br/>桥接服务器]
    B -->|PINE 协议<br/>Unix Socket| C[PCSX2 PINE Server]
    B -->|PINE 协议<br/>TCP| D[RPCS3 IPC Server]
    B -->|PINE 协议<br/>Socket| E[Duckstation PINE]
    
    F[EE 主内存<br/>0x00100000-0x01FFFFFF] --> C
    G[IOP RAM<br/>0x1C000000+] --> C
```

### 核心组件

| 组件 | 文件位置 | 职责 |
|------|----------|------|
| **PineClient** | `src/pine.ts` | 底层 PINE 协议通信，处理 socket 连接、请求队列、响应解析 |
| **工具注册器** | `src/tools.ts` | 定义 MCP 工具 schema，实现工具调用路由 |
| **入口点** | `src/index.ts` | MCP 服务器初始化，工具注册，stdin/stdout 管道 |

资料来源：[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)

## MCP 工具集详解

mcp-pine 提供以下 MCP 工具，分为四个类别：

### 连接与自检

| 工具名 | 功能描述 | 返回值 |
|--------|----------|--------|
| `pine_ping` | 检查与模拟器的连接，获取模拟器版本 | `OK — emulator: VERSION` |

### 游戏信息查询

| 工具名 | 功能描述 | 返回值示例 |
|--------|----------|------------|
| `pine_get_info` | 批量获取游戏元数据（标题、序列号、CRC、版本、状态） | `Title: GameName\nSerial: SLUS-12345\nDisc CRC: ABCD1234\nGame version: 1.00\nStatus: running` |
| `pine_get_status` | 获取模拟器运行状态 | `Status: running/paused/shutdown/unknown` |

### 内存读取

| 工具名 | 数据宽度 | 对齐要求 | 说明 |
|--------|----------|----------|------|
| `pine_read8` | 8 位 | 无 | 单字节读取 |
| `pine_read16` | 16 位 | 2 字节 | 小端序 |
| `pine_read32` | 32 位 | 4 字节 | 小端序，用于指针、RGBA 颜色 |
| `pine_read64` | 64 位 | 8 字节 | 完整 PS2 EE 指针、大 ID |
| `pine_read_range` | 可变 | 自动选择最大对齐 | 批量读取最多 4096 字节 |

### 内存写入

| 工具名 | 数据宽度 | 对齐要求 | 风险提示 |
|--------|----------|----------|----------|
| `pine_write8` | 8 位 | 无 | 直接写入，无撤销 |
| `pine_write16` | 16 位 | 2 字节 | 覆盖式写入，绕过 TLB |
| `pine_write32` | 32 位 | 4 字节 | 32 位 Cheats/Pokes |
| `pine_write64` | 64 位 | 8 字节 | 完整 64 位值写入 |

### 状态管理

| 工具名 | 功能描述 | 参数 |
|--------|----------|------|
| `pine_save_state` | 保存当前游戏状态到指定槽位 | `slot: 0-255` |
| `pine_load_state` | 从指定槽位加载游戏状态 | `slot: 0-255` |

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

## 配置与环境变量

mcp-pine 通过环境变量进行配置：

| 环境变量 | 默认值 | 用途 |
|----------|--------|------|
| `PINE_TARGET` | `pcsx2` | 指定模拟器名称，用于 Unix socket 文件路径前缀 |
| `PINE_SLOT` | `28011` | PINE 插槽号（Linux/macOS）或 TCP 端口（Windows） |
| `PINE_PIPELINE_BATCH` | `1` | 批量请求数，控制性能与稳定性权衡 |

### 连接路径说明

| 操作系统 | 连接方式 | 路径格式 |
|----------|----------|----------|
| Linux | Unix Socket | `$XDG_RUNTIME_DIR/<target>.sock.<slot>` 或 `$TMPDIR/<target>.sock.<slot>` 或 `/tmp/<target>.sock.<slot>` |
| macOS | Unix Socket | 同 Linux |
| Windows | TCP | `127.0.0.1:<slot>` |

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

## 安装与部署

### 方式一：npm 全局安装

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

### 方式二：npx 临时运行

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

### 方式三：源码开发

```bash
git clone https://github.com/dmang-dev/mcp-pine
cd mcp-pine
npm install
```

### Claude Code 集成

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

验证连接：

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

### Claude Desktop 集成

编辑配置文件：

| 平台 | 路径 |
|------|------|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| Linux | `~/.config/Claude/claude_desktop_config.json` |

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

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

## 已知问题与限制

### PCSX2 PINE 服务器脆弱性

PCSX2 的 PINE 服务器请求队列非常脆弱。当有超过约 **6-7 个飞行中的请求**时，服务器会静默丢弃请求，导致回复管道失同步。一旦失同步，即使新的 `pine_ping` 也会超时，只能通过完全重启 PCSX2 恢复。

**缓解措施**：
- `pine_read_range` 默认以完全串行方式发出请求
- 使用 `PINE_PIPELINE_BATCH=2` 或更高值可提升延迟，但有失同步风险

### 内存访问注意事项

| 问题 | 原因 | 解决方案 |
|------|------|----------|
| 读取返回零值 | 地址在未分配区域 | 尝试 `0x00100000`（几乎总在 EE RAM 内） |
| 数值看起来损坏 | 对齐问题 | PINE 不强制对齐，未对齐的多字节读取会返回对齐地址下的数据 |
| 字符串解析错误 | 字节序问题 | PINE 返回小端序，字符串应使用 `read_range` 按字节读取 |
| 写入 IOP ROM 无效 | 只读区域 | BIOS、IOP ROM 区域写入会被静默丢弃 |

### 性能基准

| 操作 | 耗时 | 说明 |
|------|------|------|
| 完整 4096 字节读取 | ~52 ms | PCSX2 v2.6.3，loopback TCP |
| 单次 `pine_ping` | <1 ms | 本地连接 |
| 状态保存/加载 | 取决于存档大小 | 通过 PINE 协议传输 |

资料来源：[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)

## 项目依赖

mcp-pine 的核心依赖非常精简：

| 依赖 | 版本 | 用途 |
|------|------|------|
| `@modelcontextprotocol/sdk` | ^1.12.0 | MCP 协议 SDK，处理 stdio 通信 |

开发依赖：

| 依赖 | 版本 | 用途 |
|------|------|------|
| `typescript` | ^5.5.0 | TypeScript 编译 |
| `@types/node` | ^22.0.0 | Node.js 类型定义 |

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

## 开发指南

### 本地开发

```bash
npm install
npm run dev      # tsc --watch 监听文件变化
```

### 冒烟测试

在运行 PCSX2 并启用 PINE Server 后：

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

### 相关项目

- **[mcp-mgba](https://github.com/dmang-dev/mcp-mgba)** — 姐妹项目，支持 mGBA Game Boy Advance 模拟器，包含按钮输入和截图功能（mcp-pine 不支持）
- **[PINE 协议规范](https://github.com/GovanifY/pine)** — 底层 IPC 标准文档

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

## 版本历史

| 版本 | 日期 | 主要变更 |
|------|------|----------|
| 0.2.1 | 2026-05-15 | 工具描述质量改进，完整 TDQS 模板重构 |
| 0.2.0 | 2026-05-10 | 新增 `pine_read_range`，10 秒超时，文档化 PCSX2 管道问题 |
| 0.1.0 | 初始版本 | 基础 MCP 工具集 |

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

## 许可证

本项目采用 **MIT** 许可证开源。

---

*最后更新：基于 mcp-pine 仓库当前主分支内容生成*

---

<a id='page-quickstart'></a>

## 快速开始

### 相关页面

相关主题：[安装指南](#page-installation), [模拟器配置](#page-emulator-setup), [配置参考](#page-configuration)

<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)
- [CHANGELOG.md](https://github.com/dmang-dev/mcp-pine/blob/main/CHANGELOG.md)
</details>

# 快速开始

本页面介绍如何快速部署和配置 **mcp-pine**，这是一个基于 Model Context Protocol (MCP) 的桥接工具，用于连接 Claude 等 AI 助手与支持 PINE 协议的模拟器（PCSX2、RPCS3、Duckstation），从而实现对 PlayStation 模拟器的内存读取、写入和状态管理。

## 架构概览

```mermaid
graph TD
    subgraph "MCP 客户端"
        A[Claude Desktop / Claude Code]
    end
    
    subgraph "mcp-pine 桥接层"
        B[MCP Server<br/>stdio 传输]
        C[PINE Client<br/>网络通信]
    end
    
    subgraph "目标模拟器"
        D[PCSX2 / RPCS3 / Duckstation]
        E[PINE Server]
    end
    
    A -->|"MCP 协议"| B
    B -->|"工具调用"| C
    C -->|"PINE 协议"| E
    E -->|"游戏状态"| D
    
    style B fill:#e1f5fe
    style C fill:#fff3e0
    style E fill:#f3e5f5
```

**工作原理**：mcp-pine 作为 MCP 服务器运行在 stdio 管道上，将 MCP 工具调用转换为 PINE 协议的二进制请求，通过 TCP 或 Unix 域套接字发送至模拟器的 PINE Server，从而实现对模拟器内存空间的读写操作。

## 前置要求

| 组件 | 要求 | 说明 |
|------|------|------|
| Node.js | ≥ 18.0.0 | 用于运行 mcp-pine |
| 包管理器 | npm / npx | 安装和执行 |
| 模拟器 | PCSX2 1.7.x+ / RPCS3 / Duckstation | 支持 PINE 协议 |
| MCP 客户端 | Claude Desktop / Claude Code | AI 助手界面 |
| 操作系统 | Windows / macOS / Linux | 跨平台支持 |

## 安装方式

### 方式一：全局安装（推荐）

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

安装完成后，`mcp-pine` 命令将全局可用：

```bash
mcp-pine
```

资料来源：[README.md:安装方法]()

### 方式二：npx 免安装运行

如仅需临时使用，无需安装依赖：

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

资料来源：[README.md:npx 安装]()

### 方式三：源码本地开发

```bash
git clone https://github.com/dmang-dev/mcp-pine
cd mcp-pine
npm install        # 同时运行 build（prepare hook 触发）
```

开发模式热重载：

```bash
npm run dev        # tsc --watch 监听源码变更
```

资料来源：[README.md:clone and develop]()

## 环境变量配置

mcp-pine 通过环境变量控制连接目标和通信方式：

| 环境变量 | 默认值 | 说明 |
|----------|--------|------|
| `PINE_TARGET` | `pcsx2` | 模拟器标识名称，用于生成 Unix 套接字路径 `<target>.sock.<slot>` |
| `PINE_SLOT` | `28011` | PINE 槽位/端口号 |
| `PINE_HOST` | `127.0.0.1` | TCP 目标主机（Windows 默认使用 TCP） |
| `PINE_SOCKET_PATH` | 自动解析 | Unix 套接字路径，优先级最高 |
| `PINE_PIPELINE_BATCH` | `1` | 请求流水线批次大小，建议保持默认 |

**跨平台套接字路径解析规则**：

```mermaid
graph TD
    A[启动 mcp-pine] --> B{操作系统?}
    B -->|Windows| C[使用 TCP<br/>127.0.0.1:PINE_SLOT]
    B -->|Linux/macOS| D[检查 XDG_RUNTIME_DIR]
    D -->|存在| E[使用 $XDG_RUNTIME_DIR/<target>.sock.<slot>]
    D -->|不存在| F[检查 TMPDIR]
    F -->|存在| G[使用 $TMPDIR/<target>.sock.<slot>]
    F -->|不存在| H[使用 /tmp/<target>.sock.<slot>]
    
    style C fill:#ffcdd2
    style E fill:#c8e6c9
    style G fill:#c8e6c9
    style H fill:#c8e6c9
```

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

## 模拟器配置

### PCSX2 设置

1. 启动 PCSX2（1.7.x Qt 或更高版本）
2. 进入 **Settings → Advanced**
3. 启用 **Enable PINE Server** 选项
4. 默认槽位为 **28011**（如需修改，记下新端口并设置 `PINE_SLOT`）
5. 加载任意游戏

> **注意**：无需脚本或控制台命令，PINE 启用后始终保持运行状态。

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

### RPCS3 设置

RPCS3 实现了兼容 PINE 操作码的 IPC 机制，但线级兼容性尚未完全测试：

1. 进入 **Configuration → Advanced**
2. 启用 **IPC Server**（具体菜单位置请参考当前 RPCS3 文档）
3. 记录配置的端口号
4. 运行命令：

```bash
PINE_TARGET=rpcs3 PINE_SLOT=<端口号> mcp-pine
```

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

### Duckstation 设置

1. 确认 Duckstation 构建版本包含 PINE 服务器（并非所有版本都包含）
2. 如包含，设置环境变量后运行：

```bash
PINE_TARGET=duckstation PINE_SLOT=<端口号> mcp-pine
```

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

## MCP 客户端配置

### Claude Code (CLI)

添加 MCP 服务器：

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

验证连接状态：

```bash
claude mcp list
# 输出示例：pine: mcp-pine - ✓ Connected
```

资料来源：[README.md:Claude Code (CLI)]()

### Claude Desktop

编辑配置文件 `claude_desktop_config.json`：

| 平台 | 配置文件路径 |
|------|--------------|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| Linux | `~/.config/Claude/claude_desktop_config.json` |

添加服务器配置：

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

修改配置后需重启 Claude Desktop。

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

### 其他 MCP 客户端

mcp-pine 使用标准 MCP over stdio 协议，可连接任何兼容 MCP 的客户端：

```bash
mcp-pine    # 直接运行，stdin/stdout 用于通信
```

## 可用工具一览

连接成功后，以下 MCP 工具将自动注册到客户端：

| 工具名称 | 功能描述 | 用途场景 |
|----------|----------|----------|
| `pine_ping` | 获取模拟器版本 | 连接验证 |
| `pine_get_info` | 获取游戏完整信息 | 游戏识别 |
| `pine_get_status` | 获取运行状态 | 状态监控 |
| `pine_read8/16/32/64` | 读取指定地址内存 | 内存读取 |
| `pine_write8/16/32/64` | 写入指定地址内存 | 内存修改 |
| `pine_read_range` | 批量读取内存区域 | 大块数据读取 |
| `pine_save_state` | 保存游戏状态 | 存档快照 |
| `pine_load_state` | 加载游戏状态 | 恢复存档 |

**地址参数说明**：
- 地址为 EE 主地址空间的绝对字节地址
- 多字节访问需对齐（`read16` 需 2 字节对齐，`read32` 需 4 字节对齐）
- 推荐范围：`0x00100000-0x01FFFFFF`（EE 主内存，99% 游戏状态所在区域）
- 未映射地址返回 PINE FAIL 响应

资料来源：[src/tools.ts:工具定义]()

## 快速验证流程

```mermaid
sequenceDiagram
    participant User as 用户
    participant MCP as Claude MCP
    participant Bridge as mcp-pine
    participant Emu as PCSX2

    User->>Emu: 1. 启动 PCSX2 并启用 PINE Server
    User->>MCP: 2. 配置并启动 Claude Desktop
    MCP->>Bridge: 3. 启动 mcp-pine 进程
    Bridge->>Emu: 4. 建立 PINE 连接
    User->>MCP: 5. 调用 pine_ping
    MCP->>Bridge: 6. 转发工具调用
    Bridge->>Emu: 7. PINE Version 请求
    Emu-->>Bridge: 8. 返回版本信息
    Bridge-->>MCP: 9. 返回工具结果
    MCP-->>User: 10. 显示 "OK — emulator: PCSX2 v2.x.x"
```

首次使用建议按以下顺序测试：

```bash
# 步骤 1：验证连接
pine_ping
# 预期输出：OK — emulator: PCSX2 v2.x.x

# 步骤 2：获取游戏信息
pine_get_info
# 预期输出：Title, Serial, Disc CRC, Game version, Status

# 步骤 3：读取内存（示例：EE RAM 起始地址）
pine_read32 address=0x00100000
# 预期输出：ADDR_HEX: VAL_DEC (0xVAL_HEX)

# 步骤 4：保存当前状态
pine_save_state slot=0
# 预期输出：State saved to slot 0

# 步骤 5：测试写入（谨慎操作）
pine_write32 address=0x00100000 value=0
# 预期输出：Wrote 0 → ADDR_HEX
```

## 常见问题排查

| 问题现象 | 原因 | 解决方案 |
|----------|------|----------|
| `Cannot reach PINE server` | 模拟器未运行、PINE 未启用、端口不匹配 | 检查 `PINE_SLOT` 配置 |
| `PINE FAIL response (0xFF)` | 模拟器拒绝请求（无游戏加载、地址未映射） | 加载游戏、检查地址有效性 |
| 读取返回全零 | 地址在未分配区域 | 尝试 `0x00100000`（几乎总是 EE RAM 内部） |
| 数值看起来损坏 | 字节序错误 | PINE 返回小端序，字符串读取使用 `read_range` |
| `pine_ping` 超时（10s） | PCSX2 PINE 服务器卡死 | 完全重启 PCSX2（重新连接无效） |

**重要提示**：PCSX2 的 PINE 服务器请求队列较脆弱，当超过约 6 个飞行中请求时会静默丢弃请求，导致回复错位与错误客户端配对。一旦卡死，只能通过完全重启模拟器恢复。mcp-pine 默认使用完全串行请求（`PINE_PIPELINE_BATCH=1`），实测 Loopback TCP 速度足够（4096 字节读取约 52ms）。

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

## 下一步

- 阅读 [工具详细文档](./工具详细文档.md)，了解每个工具的完整参数说明
- 参考 [内存狩猎指南](./内存狩猎指南.md)，学习定位游戏状态地址
- 查看 [架构设计](./架构设计.md)，深入理解 PINE 协议实现

---

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

## 系统架构

### 相关页面

相关主题：[PINE 协议详解](#page-pine-protocol), [工具参考](#page-tools-reference)

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

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

- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [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)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
</details>

# 系统架构

## 1. 概述

mcp-pine 是一个基于 Model Context Protocol (MCP) 的桥接服务器，用于连接 MCP 客户端（如 Claude Desktop、Claude Code）与游戏模拟器的 PINE (Programmable Interface for Networked Emulation) 协议接口。

该项目的核心功能是让 AI 助手能够通过标准化的 MCP 工具接口与运行中的模拟器进行交互，实现内存读取、内存写入、保存/加载游戏状态等操作。资料来源：[README.md]()

## 2. 整体架构

mcp-pine 采用分层架构设计，从上到下依次为：

| 层级 | 组件 | 职责 |
|------|------|------|
| MCP 协议层 | MCP Server | 暴露标准化的工具接口，处理 MCP 协议的请求/响应 |
| 工具定义层 | Tools Registry | 定义所有可用的 MCP 工具及其参数模式 |
| PINE 客户端层 | PineClient | 实现 PINE 协议的二进制通信 |
| 传输层 | Socket/TCP | 处理底层网络通信，支持 Unix Domain Socket 和 TCP |

```mermaid
graph TD
    A[MCP 客户端<br/>Claude Desktop/Code] -->|stdio| B[MCP Server]
    B -->|工具调用| C[Tools Registry]
    C -->|调用方法| D[PineClient]
    D -->|TCP/Unix Socket| E[模拟器 PINE Server]
    
    F[src/index.ts] --> B
    G[src/tools.ts] --> C
    H[src/pine.ts] --> D
```

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

## 3. 核心组件

### 3.1 MCP Server

MCP Server 是整个应用的入口点，负责初始化和启动服务。

```typescript
// src/index.ts 核心逻辑
const server = new Server(
  { name: "mcp-pine", version: "0.2.0" },
  { capabilities: { tools: {} } },
);

registerTools(server, pine);

const transport = new StdioServerTransport();
await server.connect(transport);
```

关键特性：
- 使用 `@modelcontextprotocol/sdk` 包提供的 Server 类
- 通过 StdioServerTransport 实现标准输入/输出通信
- 仅声明 `tools` 能力，不使用资源或提示功能
- 工具注册由 `registerTools()` 函数完成

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

### 3.2 PineClient

PineClient 是 PINE 协议的客户端实现，负责与模拟器的 PINE 服务器进行二进制通信。

**主要职责：**

| 功能 | 方法 | 说明 |
|------|------|------|
| 连接管理 | `connect()` | 建立 TCP 或 Unix Socket 连接 |
| 内存读取 | `read8/16/32/64()` | 按指定宽度读取内存 |
| 内存写入 | `write8/16/32/64()` | 按指定宽度写入内存 |
| 批量读取 | `readRange()` | 连续内存区域读取 |
| 状态管理 | `saveState()` / `loadState()` | 保存/加载游戏状态 |
| 信息查询 | `getVersion/Tittle/Id/Uuid/Status()` | 获取模拟器和游戏信息 |

**连接传输方式：**

```typescript
// Unix Domain Socket (Linux/macOS)
net.createConnection({ path: this.descriptor.path })

// TCP 连接 (Windows)
net.createConnection({ host: this.descriptor.host, port: this.descriptor.port })
```

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

### 3.3 工具注册系统

工具系统基于 TOOLS 数组定义，每个工具包含完整的元数据：

```typescript
const TOOLS: Tool[] = [
  {
    name: "pine_ping",
    description: "PURPOSE: ...",
    inputSchema: { ... }
  },
  // ... 其他工具
];
```

工具处理流程：

```mermaid
graph LR
    A[MCP 请求] -->|name + arguments| B[switch 语句]
    B -->|匹配工具名| C[执行 PineClient 方法]
    C -->|结果| D[ok() 格式化]
    D -->|{content: [...]} | E[MCP 响应]
```

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

## 4. 通信协议

### 4.1 PINE Wire Protocol

PINE 协议采用二进制格式，消息结构如下：

| 字段 | 大小 | 字节序 | 说明 |
|------|------|--------|------|
| Size | 4 字节 | Little-endian | 消息总长度 |
| Opcode | 1 字节 | - | 操作码 |
| Payload | N 字节 | Little-endian | 操作数据 |

**Opcode 定义：**

| 操作码 | 值 | 功能 |
|--------|-----|------|
| Version | 0x01 | 获取模拟器版本 |
| Title | 0x02 | 获取游戏标题 |
| ID | 0x03 | 获取游戏序列号 |
| UUID | 0x04 | 获取光盘 CRC |
| GameVersion | 0x05 | 获取游戏版本 |
| Status | 0x06 | 获取运行状态 |
| Read8 | 0x10 | 读取 8 位 |
| Read16 | 0x11 | 读取 16 位 |
| Read32 | 0x12 | 读取 32 位 |
| Read64 | 0x13 | 读取 64 位 |
| Write8 | 0x14 | 写入 8 位 |
| Write16 | 0x15 | 写入 16 位 |
| Write32 | 0x16 | 写入 32 位 |
| Write64 | 0x17 | 写入 64 位 |
| SaveState | 0x30 | 保存状态 |
| LoadState | 0x31 | 加载状态 |

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

### 4.2 请求队列管理

PineClient 内部维护一个待处理请求队列：

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

接收数据时的帧解析流程：

```mermaid
graph TD
    A[接收数据 chunk] --> B[追加到 buffer]
    B --> C{buffer.length >= 4?}
    C -->|否| F[等待更多数据]
    C -->|是| D[读取 size 字段]
    D --> E{buffer.length >= size?}
    E -->|否| F
    E -->|是| G[提取完整帧]
    G --> H[出队匹配]
    H --> I[resolve/reject]
    I --> B
```

每个请求包含 10 秒超时，超时后自动 reject，防止请求永久挂起。资料来源：[src/pine.ts:100-140]()

### 4.3 批量读取实现

`readRange()` 方法实现了高效的批量内存读取：

```mermaid
graph TD
    A[输入: 地址 + 长度] --> B[计算最优分块]
    B --> C{地址对齐检查}
    C -->|8字节对齐| D[使用 read64]
    C -->|4字节对齐| E[使用 read32]
    C -->|2字节对齐| F[使用 read16]
    C -->|其他| G[使用 read8]
    D --> H[按 PIPELINE_BATCH 分批]
    E --> H
    F --> H
    G --> H
    H --> I[Promise.all 并行]
    I --> J[合并结果到 Buffer]
    J --> K[返回字节数组]
```

**关键参数：**

| 参数 | 默认值 | 说明 |
|------|--------|------|
| `PINE_PIPELINE_BATCH` | 1 | 每批并发请求数 |

默认完全串行执行以避免 PCSX2 PINE 服务器请求队列丢失问题。资料来源：[src/pine.ts:180-240]()

## 5. 配置系统

### 5.1 环境变量配置

| 变量名 | 默认值 | 说明 |
|--------|--------|------|
| `PINE_TARGET` | `pcsx2` | 模拟器名称，用于 Unix socket 文件路径前缀 |
| `PINE_SLOT` | `28011` | PINE 槽位号/端口号 |
| `PINE_HOST` | `127.0.0.1` | TCP 主机地址 |
| `PINE_SOCKET_PATH` | - | 自定义 Unix socket 路径 |
| `PINE_PIPELINE_BATCH` | 1 | 批量读取并发数 |

### 5.2 Socket 路径解析

```mermaid
graph TD
    A[resolveSocket] --> B{平台判断}
    B -->|Windows| C[TCP: 127.0.0.1:PINE_SLOT]
    B -->|Linux/macOS| D{检查 PINE_SOCKET_PATH}
    D -->|已设置| E[使用自定义路径]
    D -->|未设置| F{检查 XDG_RUNTIME_DIR}
    F -->|已设置| G[使用 $XDG_RUNTIME_DIR/<target>.sock.<slot>]
    F -->|未设置| H[使用 /tmp/<target>.sock.<slot>]
```

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

## 6. MCP 工具清单

### 6.1 连接与信息工具

| 工具名 | 功能 | 返回值示例 |
|--------|------|-----------|
| `pine_ping` | 检测连接，获取模拟器版本 | `OK — emulator: PCSX2 2.6.3` |
| `pine_get_info` | 获取完整游戏信息 | 标题、序列号、CRC、版本、状态 |
| `pine_get_status` | 获取运行状态 | `Status: running` |

### 6.2 内存读写工具

| 工具名 | 操作数 | 对齐要求 | 说明 |
|--------|--------|----------|------|
| `pine_read8` | 1 字节 | 无 | 读取字节 |
| `pine_read16` | 2 字节 | 2 字节 | 读取 16 位整数 |
| `pine_read32` | 4 字节 | 4 字节 | 读取 32 位整数 |
| `pine_read64` | 8 字节 | 8 字节 | 读取 64 位整数 |
| `pine_write8` | 1 字节 | 无 | 写入字节 |
| `pine_write16` | 2 字节 | 2 字节 | 写入 16 位整数 |
| `pine_write32` | 4 字节 | 4 字节 | 写入 32 位整数 |
| `pine_write64` | 8 字节 | 8 字节 | 写入 64 位整数 |
| `pine_read_range` | 1-4096 字节 | 自动适配 | 批量读取内存区域 |

### 6.3 状态管理工具

| 工具名 | 参数 | 说明 |
|--------|------|------|
| `pine_save_state` | `slot: 0-255` | 保存游戏状态到指定槽位 |
| `pine_load_state` | `slot: 0-255` | 从指定槽位加载游戏状态 |

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

## 7. 错误处理

### 7.1 已知错误模式

| 错误类型 | 表现 | 原因与处理 |
|----------|------|-----------|
| `Cannot reach PINE server` | 连接失败 | 模拟器未运行或 PINE 未启用 |
| `PINE FAIL response (0xFF)` | 请求被拒绝 | 无游戏加载或地址未映射 |
| 读取返回零值 | 返回 0x0 | 地址在未分配内存区域 |
| 值损坏 | 数据异常 | 字节序或对齐问题 |
| `PINE call timed out (10s)` | 超时 | PCSX2 PINE 服务器请求队列错位，需完全重启模拟器 |

### 7.2 PCSX2 PINE 服务器限制

PCSX2 的 PINE 服务器存在已知的请求队列脆弱性问题：

- 约 7-9 个在途请求时开始出现丢包
- 丢包后服务器回复管道永久错位
- 任何后续请求都会超时
- 仅重启模拟器可恢复

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

## 8. 数据模型

### 8.1 模拟器状态枚举

```typescript
type EmuStatus = "running" | "paused" | "shutdown" | "unknown";
```

状态值映射：

| 原始值 | 枚举值 | 含义 |
|--------|--------|------|
| 0 | `running` | 游戏正在运行 |
| 1 | `paused` | 游戏已暂停 |
| 2 | `shutdown` | 模拟器已关闭 |
| 其他 | `unknown` | 未知状态 |

### 8.2 64 位值处理

由于 JavaScript Number 类型精度限制（最大安全整数 2^53），64 位值通过字符串格式传输：

```typescript
// 返回值格式
"12345678901234567890 (0xB54A3E8F9A4D6E2)"

// 使用 BigInt 内部处理
const n = v as bigint;
for (let j = 0; j < 8; j++) {
  out[off + j] = Number((n >> BigInt(8 * j)) & 0xFFn);
}
```

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

## 9. 依赖关系

```mermaid
graph TD
    A[package.json] --> B[dependencies]
    A --> C[devDependencies]
    
    B --> D["@modelcontextprotocol/sdk ^1.12.0"]
    
    C --> E["@types/node ^22.0.0"]
    C --> F["typescript ^5.5.0"]
```

项目使用 TypeScript 开发，通过 `npm run dev` 启动监听模式进行开发调试。资料来源：[package.json:10-20]()

## 10. 总结

mcp-pine 的架构设计体现了几个关键原则：

1. **分层解耦**：MCP 协议层、工具定义层、PINE 客户端层完全分离
2. **传输透明**：根据平台自动选择 TCP 或 Unix Domain Socket
3. **安全优先**：默认串行请求避免模拟器 PINE 服务丢包
4. **跨平台兼容**：Windows/Linux/macOS 全平台支持
5. **超时保护**：10 秒超时防止请求永久挂起

---

<a id='page-pine-protocol'></a>

## PINE 协议详解

### 相关页面

相关主题：[系统架构](#page-architecture), [模拟器配置](#page-emulator-setup)

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

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

- [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)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
</details>

# PINE 协议详解

## 1. 概述

PINE（PlayStation Interactive Network Emulator）是一种用于 PlayStation 系列模拟器的进程间通信（IPC）协议。它允许外部工具直接读取和写入模拟器进程的内存空间，实现游戏状态检查、作弊修改、存档管理等高级功能。

mcp-pine 项目是一个 PINE 协议的 MCP（Model Context Protocol）服务端实现，使 AI 助手（如 Claude）能够通过标准化的工具接口与运行中的模拟器交互。

### 1.1 支持的模拟器

| 模拟器 | 协议实现 | 连接方式 | 备注 |
|--------|----------|----------|------|
| PCSX2 | 原生 PINE | Unix Socket / TCP | 推荐使用 v1.7.x 及以上版本 |
| RPCS3 | 镜像 PINE | TCP | 兼容性未完全测试 |
| Duckstation | 原生 PINE | Unix Socket / TCP | 部分构建版本支持 |

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

## 2. 架构设计

### 2.1 系统架构图

```mermaid
graph TB
    subgraph "主机系统"
        A[Claude / MCP 客户端] --> B[mcp-pine 服务端]
        B --> C[PineClient]
        C --> D{连接类型}
        D -->|Linux/macOS| E[Unix Socket]
        D -->|Windows| F[TCP 127.0.0.1]
    end
    
    subgraph "模拟器进程"
        E --> G[PCSX2 PINE Server]
        F --> G
    end
    
    G --> H[EE 主内存 0x00100000-0x01FFFFFF]
    G --> I[IOP 内存 0x1C000000+]
    G --> J[Scratchpad]
```

### 2.2 核心组件

**PineClient** 是协议的核心实现类，负责：

- 底层的 Socket 连接管理
- PINE 操作码的发送与响应解析
- 读写请求的批量处理
- 超时控制与错误处理

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

## 3. PINE 操作码定义

### 3.1 操作码表

| 操作码名称 | 数值 | 功能描述 | 返回类型 |
|------------|------|----------|----------|
| `Op.Version` | 0x01 | 获取模拟器版本 | UTF-8 字符串 |
| `Op.Title` | 0x02 | 获取游戏标题 | UTF-8 字符串 |
| `Op.ID` | 0x03 | 获取游戏序列号 | UTF-8 字符串 |
| `Op.UUID` | 0x04 | 获取光盘 CRC | UTF-8 字符串 |
| `Op.GameVersion` | 0x05 | 获取游戏版本 | UTF-8 字符串 |
| `Op.Status` | 0x0F | 获取模拟器运行状态 | 32 位整数 |
| `Op.SaveState` | 0x10 | 保存当前状态到指定槽位 | 无 |
| `Op.LoadState` | 0x11 | 从指定槽位加载状态 | 无 |
| `Op.Read8` | 0x20 | 读取 8 位数据 | 字节 |
| `Op.Read16` | 0x21 | 读取 16 位数据 | 小端整数 |
| `Op.Read32` | 0x22 | 读取 32 位数据 | 小端整数 |
| `Op.Read64` | 0x23 | 读取 64 位数据 | 小端整数 |
| `Op.Write8` | 0x30 | 写入 8 位数据 | 无 |
| `Op.Write16` | 0x31 | 写入 16 位数据 | 无 |
| `Op.Write32` | 0x32 | 写入 32 位数据 | 无 |
| `Op.Write64` | 0x33 | 写入 64 位数据 | 无 |

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

### 3.2 状态码定义

模拟器运行状态通过 32 位小端整数返回：

| 状态值 | 含义 |
|--------|------|
| 0 | 运行中 (running) |
| 1 | 暂停 (paused) |
| 2 | 已关闭 (shutdown) |
| 其他 | 未知 (unknown) |

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

## 4. 协议帧格式

### 4.1 请求帧结构

```
+----------------+----------------+----------------+
|  Frame Size    |  Opcode (1B)   |  Arguments...  |
|  (UInt32 LE)   |                |                |
+----------------+----------------+----------------+
```

- **Frame Size**: 4 字节，小端无符号整数，表示整个帧的字节数（包括自身）
- **Opcode**: 1 字节，操作码标识符
- **Arguments**: 可选参数数据

### 4.2 响应帧结构

```
+----------------+----------------+----------------+
|  Frame Size    |  Status (1B)   |  Payload...    |
|  (UInt32 LE)   |  0x00=OK 0xFF=FAIL              |
+----------------+----------------+----------------+
```

- **Status**: `0x00` 表示成功，`0xFF` 表示失败
- **Payload**: 成功时包含返回数据，失败时可能为空

### 4.3 帧解析流程

```mermaid
graph TD
    A[接收数据块] --> B{缓冲区长度 >= 4?}
    B -->|否| C[等待更多数据]
    B -->|是| D[读取 Frame Size]
    D --> E{缓冲区长度 >= Frame Size?}
    E -->|否| F[等待更多数据]
    E -->|是| G[提取完整帧]
    G --> H[解析 Status 字节]
    H --> I{Status == 0x00?}
    I -->|是| J[解析 Payload]
    I -->|否| K[抛出 PINE FAIL 错误]
    J --> L[匹配 Pending 请求]
    K --> L
    L --> M[返回结果给调用者]
```

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

## 5. 连接管理

### 5.1 连接参数

| 参数 | 环境变量 | 默认值 | 说明 |
|------|----------|--------|------|
| 模拟器名称 | `PINE_TARGET` | `pcsx2` | Unix Socket 文件名前缀 |
| 槽位/端口 | `PINE_SLOT` | `28011` | Unix Socket 序号或 TCP 端口 |

### 5.2 连接路径解析

```typescript
// Linux/macOS: Unix Socket
$XDG_RUNTIME_DIR/<target>.sock.<slot>
$TMPDIR/<target>.sock.<slot>
/tmp/<target>.sock.<slot>

// Windows: TCP
127.0.0.1:<slot>
```

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

### 5.3 超时控制

每个 PINE 调用都设置了 **10 秒超时**。如果模拟器未响应，请求将自动拒绝，防止无限等待。

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

## 6. 内存读写机制

### 6.1 地址空间

PS2 模拟器的主要内存区域：

| 区域 | 地址范围 | 大小 | 说明 |
|------|----------|------|------|
| EE 主内存 | 0x00100000 - 0x01FFFFFF | ~31 MB | 游戏状态主要存储区 |
| IOP 内存 | 0x1C000000+ | 可变 | I/O 处理器内存 |
| Scratchpad | 特定区域 | 较小 | 高速缓存 |

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

### 6.2 数据编码

所有多字节数据均使用 **小端序**（Little Endian）编码：

```
地址:     [0x00] [0x01] [0x02] [0x03]
数据:     LSB    ...    ...    MSB
```

字符串使用 **UTF-8 编码**，以空字符 (`\0`) 结尾，读取时自动去除尾部空字符。

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

### 6.3 对齐要求

| 操作宽度 | 对齐要求 | 未对齐时的行为 |
|----------|----------|----------------|
| 8 位 | 无 | 正常工作 |
| 16 位 | 2 字节对齐 | 返回对齐地址下方的数据，静默损坏 |
| 32 位 | 4 字节对齐 | 返回对齐地址下方的数据，静默损坏 |
| 64 位 | 8 字节对齐 | 返回对齐地址下方的数据，静默损坏 |

**重要警告**: PCSX2 的 PINE 服务端**不强制**对齐访问，未对齐的地址会静默返回错误数据而无任何错误提示。

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

### 6.4 批量读取实现

由于 PINE 协议本身不提供原生批量读取功能，`read_range` 工具通过客户端实现的序列读取实现：

```mermaid
graph LR
    A[请求: 4096 字节] --> B{计算最优步长}
    B --> C[起始地址 % 8 == 0 且剩余 >= 8?]
    C -->|是| D[read64]
    C -->|否| E{起始地址 % 4 == 0 且剩余 >= 4?}
    E -->|是| F[read32]
    E -->|否| G{起始地址 % 2 == 0?}
    G -->|是| H[read16]
    G -->|否| I[read8]
    D --> J[移动游标]
    F --> J
    H --> J
    I --> J
    J --> K{还有剩余?}
    K -->|是| B
    K -->|否| L[组装 Buffer 返回]
```

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

## 7. PCSX2 已知限制

### 7.1 请求队列脆弱性

PCSX2 的 PINE 服务端存在一个关键缺陷：

- 当 **同时发送约 7-9 个未完成请求**时，服务端可能静默丢弃某些请求
- 一旦发生请求丢失，响应管道将与客户端失去同步
- 之后**所有**请求都会超时，包括 `pine_ping`
- **唯一恢复方法**: 完全重启 PCSX2

### 7.2 性能数据

| 操作 | 耗时 | 说明 |
|------|------|------|
| 单次 read64 | ~0.1 ms | 单次往返延迟 |
| 完整 4096 字节读取 | ~52 ms | 串行执行，约两帧 |

### 7.3 流水线配置

| 环境变量 | 默认值 | 说明 |
|----------|--------|------|
| `PINE_PIPELINE_BATCH` | 1 | 每批发送的请求数，增大可降低延迟但有同步风险 |

资料来源：[CHANGELOG.md:40-60]()

## 8. 错误处理

### 8.1 错误类型

| 错误现象 | 可能原因 | 解决方案 |
|----------|----------|----------|
| `Cannot reach PINE server` | 模拟器未运行、PINE 未启用、端口不匹配 | 检查 `PINE_SLOT` 设置 |
| `PINE FAIL response (0xFF)` | 无游戏加载、地址未映射 | 确认游戏已加载，尝试 0x00100000 |
| 读取返回全零 | 地址在未分配区域 | 尝试 EE 主内存起始地址 |
| 数据看起来损坏 | 字节序误解 | PINE 返回小端序 |
| `PINE call timed out (10s)` | PCSX2 队列同步失败 | 完全重启 PCSX2 |

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

## 9. API 参考

### 9.1 核心方法签名

```typescript
class PineClient {
  // 元数据查询
  async getVersion(): Promise<string>
  async getTitle(): Promise<string>
  async getId(): Promise<string>
  async getUuid(): Promise<string>
  async getGameVersion(): Promise<string>
  async getStatus(): Promise<EmuStatus>

  // 内存读取
  async read8(addr: number): Promise<number>
  async read16(addr: number): Promise<number>
  async read32(addr: number): Promise<number>
  async read64(addr: number): Promise<bigint>
  async readRange(addr: number, length: number): Promise<Buffer>

  // 内存写入
  async write8(addr: number, value: number): Promise<void>
  async write16(addr: number, value: number): Promise<void>
  async write32(addr: number, value: number): Promise<void>
  async write64(addr: number, value: bigint): Promise<void>

  // 存档管理
  async saveState(slot: number): Promise<void>
  async loadState(slot: number): Promise<void>
}
```

### 9.2 64 位值处理

由于 JavaScript 的 `number` 类型只能安全表示 2^53 以内的整数，`read64` 和 `write64` 方法使用 `bigint` 类型：

```typescript
// 读取
const value: bigint = await pine.read64(0x12345678)

// 写入
await pine.write64(0x12345678, 12345678901234n)
```

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

## 10. 与 MCP 工具的映射

| MCP 工具名称 | 底层 PINE 操作 | 功能 |
|--------------|----------------|------|
| `pine_ping` | Version | 连接测试 |
| `pine_get_info` | Title + ID + UUID + GameVersion + Status | 批量获取游戏信息 |
| `pine_get_status` | Status | 获取运行状态 |
| `pine_read8/16/32/64` | Read8/16/32/64 | 单值读取 |
| `pine_read_range` | 串行调用 Read* | 批量读取 |
| `pine_write8/16/32/64` | Write8/16/32/64 | 单值写入 |
| `pine_save_state` | SaveState | 保存存档 |
| `pine_load_state` | LoadState | 加载存档 |

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

## 11. 项目信息

| 项目元数据 | 值 |
|------------|-----|
| 项目名称 | mcp-pine |
| 许可证 | MIT |
| 主要依赖 | @modelcontextprotocol/sdk ^1.12.0 |
| 运行时 | Node.js / TypeScript |

资料来源：[package.json:1-30]()

---

<a id='page-tools-reference'></a>

## 工具参考

### 相关页面

相关主题：[内存操作指南](#page-memory-operations), [存档状态管理](#page-savestate)

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

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

- [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)
- [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>

# 工具参考

mcp-pine 提供了一套完整的 MCP 工具，用于与支持 PINE（Platform Independent Network Environment）协议的模拟器进行交互通信。通过这些工具，用户可以实现对模拟器运行状态的监控、内存读写操作以及存档管理等功能。

## 工具分类概览

mcp-pine 的工具集按照功能可分为四大类别：

| 类别 | 工具数量 | 用途 |
|------|----------|------|
| 连接与自检 | 2 | 连接验证、模拟器信息获取 |
| 内存读取 | 5 | 单字节到64位值的读取，支持范围读取 |
| 内存写入 | 4 | 8/16/32/64位值写入 |
| 存档管理 | 2 | 游戏状态保存与加载 |

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

## 连接与自检工具

### pine_ping

**用途**：验证与模拟器 PINE 服务器的连接状态，并获取模拟器版本信息。

**参数**：无

**返回格式**：`OK — emulator: <version>`

**使用场景**：在执行其他操作前验证连接是否正常。如果返回"Cannot reach PINE server"错误，表明模拟器未运行、PINE 未启用或端口配置不匹配。资料来源：[src/tools.ts:95-98]()

### pine_get_info

**用途**：获取当前运行游戏的完整信息摘要，包括游戏标题、序列号、Disc CRC、游戏版本和运行状态。

**参数**：无

**返回格式**：

```
Title:        <游戏标题>
Serial:       <序列号>
Disc CRC:     <CRC校验值>
Game version: <游戏版本>
Status:       <运行状态>
```

**使用场景**：快速确认当前加载的游戏及其状态，适用于多游戏环境下的上下文切换。资料来源：[src/tools.ts:100-115]()

### pine_get_status

**用途**：获取模拟器当前的运行状态。

**参数**：无

**返回格式**：`Status: <running|paused|shutdown|unknown>`

**使用场景**：在执行存档操作前确认游戏状态，或监控长时间运行任务的状态变化。资料来源：[src/tools.ts:117-119]()

## 内存读取工具

所有内存读取工具均操作 PS2 主机的 EE（Emotion Engine）主地址空间，采用小端字节序。地址参数支持十六进制字面量（如 `0x00200000`）。

### 地址参数通用说明

| 字段 | 描述 |
|------|------|
| 有效范围 | `0x00100000-0x01FFFFFF`（EE 主 RAM，99%的游戏状态在此区域）|
| 对齐要求 | 多字节访问必须按对应字节数对齐；PCSX2 的 PINE 不强制对齐，未对齐访问会静默返回损坏数据 |
| 错误处理 | 未映射或无效地址返回 PINE FAIL 响应 |

> **重要**：如果需要读取未对齐的多字节数据，应使用 `pine_read_range` 并自行组装字节。

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

### pine_read8

**用途**：读取单个字节。

**对齐要求**：无对齐要求。

**返回格式**：`ADDR_HEX: VAL_DEC (0xVAL_HEX)`

### pine_read16

**用途**：读取16位无符号小端值，适用于字符编码、游戏事件标志等。

**对齐要求**：2字节对齐。

**返回格式**：与 `pine_read8` 格式相同。

### pine_read32

**用途**：读取32位无符号小端值，适用于 PS2 指针、计时器、分数等常见游戏状态字段。

**对齐要求**：4字节对齐。

**返回格式**：与 `pine_read8` 格式相同。

### pine_read64

**用途**：读取64位无符号值，适用于完整的 PS2 指针、大型 ID、压缩双字状态。PS2 EE 是128位 MIPS 处理器，大量游戏状态确实存在于64位槽位中。

**对齐要求**：8字节对齐。

**返回值说明**：由于 JavaScript 无法精确表示超过 2^53 的整数，64位值以十进制字符串形式返回。资料来源：[src/tools.ts:120-145]()

### pine_read_range

**用途**：批量读取最多4096字节的连续内存区域。

**参数**：

| 参数 | 类型 | 描述 |
|------|------|------|
| address | integer | 起始地址 |
| length | integer | 要读取的字节数（最大4096）|

**实现原理**：PINE 协议本身没有原生批量读取功能，`pine_read_range` 在客户端通过序列化调用序列实现。每次调用选择最大对齐宽度（从8到1递减）。资料来源：[src/pine.ts:90-130]()

**性能指标**：

- 完整4096字节读取耗时约52毫秒（PCSX2 v2.6.3，loopback TCP）
- 少于两个模拟帧，适合大多数工作负载

**注意事项**：PCSX2 的 PINE 服务器存在请求队列脆弱性问题。超过约7个飞行中请求时会静默丢弃请求，导致回复管道错位，后续所有请求超时，直至模拟器重启。因此默认情况下调用完全序列化执行。可通过环境变量 `PINE_PIPELINE_BATCH` 调整批处理大小（默认为1）。资料来源：[src/pine.ts:95-110]()

## 内存写入工具

所有写入工具均具有破坏性，会覆盖指定地址的现有数据。

### pine_write8 / pine_write16 / pine_write32 / pine_write64

**用途**：向模拟器内存写入指定宽度的值。

**参数**：

| 参数 | 类型 | 描述 |
|------|------|------|
| address | integer | 目标地址（必须符合对应宽度对齐要求）|
| value | integer/bigint | 要写入的值 |

**返回格式**：`Wrote VAL_HEX → ADDR_HEX`

**对齐要求**：与对应的读取工具相同。未对齐写入可能导致静默数据损坏。

**错误场景**：

- 地址未对齐：数据写入错误位置
- 地址未映射：PINE FAIL 响应
- 写入只读区域：行为取决于模拟器实现

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

## 存档管理工具

### pine_save_state

**用途**：将当前游戏状态保存到指定槽位。

**参数**：

| 参数 | 类型 | 范围 | 描述 |
|------|------|------|------|
| slot | integer | 0-255 | 存档槽位编号 |

**槽位约定**：PCSX2 图形界面通常使用 F1-F10 对应槽位0-9，但 PINE 协议支持完整的 0-255 范围。存档文件存储在模拟器的游戏专属目录中：

- Windows：`%USERPROFILE%\Documents\PCSX2\sstates`
- Linux/macOS：`~/.config/PCSX2/sstates`

**文件命名格式**：`<serial> (<crc>).<slot>.p2s`

**警告**：保存到已有存档的槽位会覆盖原有数据，此操作不可逆。资料来源：[src/tools.ts:70-85]()

### pine_load_state

**用途**：从指定槽位加载游戏状态。

**参数**：与 `pine_save_state` 相同。

**返回格式**：`Loaded state from slot <n>`

**使用场景**：快速恢复之前的游戏进度，适用于：

- 尝试不同游戏决策前的快照
- 回归测试
- 调试时的状态重现

**前置条件**：需要先加载对应游戏的 ISO 文件，否则存档可能不兼容。

## 工具调用流程

以下流程图展示了典型工具调用序列的执行路径：

```mermaid
graph TD
    A[MCP 客户端发起调用] --> B{工具类型}
    
    B -->|查询类<br/>ping/get_info/get_status| C[构建请求帧]
    B -->|读取类<br/>read8/16/32/64/range| C
    B -->|写入类<br/>write8/16/32/64| C
    B -->|存档类<br/>save/load_state| C
    
    C --> D[加入待处理队列]
    D --> E[PINE 协议编码]
    E --> F{连接状态}
    
    F -->|已连接| G[发送请求]
    F -->|未连接| H[建立连接<br/>TCP Unix Socket]
    H --> G
    
    G --> I{等待响应}
    I -->|超时 10s| J[抛出错误]
    I -->|收到响应| K{响应码}
    
    K -->|成功 0x00| L[解码响应]
    K -->|失败 0xFF| M[返回 PINE FAIL]
    
    L --> N[返回格式化结果]
    M --> O[错误处理]
```

## 环境变量配置

| 变量名 | 默认值 | 说明 |
|--------|--------|------|
| `PINE_TARGET` | `pcsx2` | 模拟器标识名，用于 Unix socket 文件路径前缀（Linux/macOS）或 TCP 连接标识 |
| `PINE_SLOT` | `28011` | PINE 槽位/端口号 |
| `PINE_HOST` | `127.0.0.1` | TCP 连接主机地址 |
| `PINE_SOCKET_PATH` | 自动解析 | Unix socket 路径，覆盖其他 socket 相关配置 |
| `PINE_PIPELINE_BATCH` | `1` | 批量请求数量，仅在了解 PCSX2 PINE 限制时调整 |

**Socket 路径解析逻辑**（Linux/macOS）：

1. 优先使用 `XDG_RUNTIME_DIR`
2. 其次尝试 `TMPDIR`
3. 最后回退到 `/tmp`

资料来源：[README.md:40-55]()

## 错误处理与故障排除

| 错误现象 | 可能原因 | 解决方案 |
|----------|----------|----------|
| `Cannot reach PINE server` | 模拟器未运行、PINE 未启用、端口不匹配 | 检查 `PINE_SLOT` 配置，确认模拟器设置中已启用 PINE |
| `PINE FAIL response` (0xFF) | 未加载游戏或地址未映射 | 确保游戏已加载，尝试地址 `0x00100000` |
| 读取返回全零 | 地址在未分配区域 | 从 EE RAM 常用区域开始（`0x00100000`）|
| 值看起来损坏 | 字节序误解 | PINE 返回小端序；字符串使用 `read_range` 逐字节读取 |
| `PINE call timed out (10s)` ping 后频繁使用 | PCSX2 PINE 请求队列错位 | 完全重启 PCSX2（仅重新连接无效）|

### PCSX2 PINE 服务器已知限制

PCSX2 的 PINE 服务器存在一个已知的脆弱性问题：当飞行中请求超过约6个时，服务器会静默丢弃请求，导致回复管道错位。一旦发生这种情况，即使 `pine_ping` 也会超时，唯一恢复方法是完全重启模拟器。

为避免此问题：

- 默认情况下 `mcp-pine` 完全序列化所有请求
- Loopback TCP 速度足够快，完整4KB读取仅需约52毫秒
- 如需更低延迟且可容忍偶发的模拟器重启，可设置 `PINE_PIPELINE_BATCH=2` 或更高

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

## 工具描述质量标准

mcp-pine 的每个工具描述都遵循 Glama 的工具定义质量评分（TDQS）标准，确保以下方面完整：

1. **目的明确性**：每个工具一句话说明其操作
2. **使用指南**：何时使用此工具而非其兄弟工具
3. **行为透明**：副作用、错误条件、破坏性操作说明
4. **参数语义**：超出 JSON Schema 的上下文信息
5. **简洁性**：无冗余描述
6. **上下文完整性**：错误模式、对齐要求、返回值格式

资料来源：[CHANGELOG.md:20-35]()

## 快速参考表

| 工具名 | 参数 | 返回类型 | 破坏性 |
|--------|------|----------|--------|
| `pine_ping` | - | string | 否 |
| `pine_get_info` | - | string | 否 |
| `pine_get_status` | - | string | 否 |
| `pine_read8` | address | string | 否 |
| `pine_read16` | address | string | 否 |
| `pine_read32` | address | string | 否 |
| `pine_read64` | address | string | 否 |
| `pine_read_range` | address, length | string | 否 |
| `pine_write8` | address, value | string | 是 |
| `pine_write16` | address, value | string | 是 |
| `pine_write32` | address, value | string | 是 |
| `pine_write64` | address, value | string | 是 |
| `pine_save_state` | slot | string | 是 |
| `pine_load_state` | slot | string | 是 |

---

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

## 内存操作指南

### 相关页面

相关主题：[工具参考](#page-tools-reference), [使用范例](#page-recipes)

<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)
- [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>

# 内存操作指南

## 概述

mcp-pine 提供的核心功能之一是通过 PINE（PlayStation Interface for Networked Entertainment）协议对运行中的模拟器进行实时内存读写操作。该功能允许用户直接访问 PS2/PS3/PSP 等平台的内存地址空间，实现游戏状态检测、作弊修改、运行时数据分析等高级操作。

内存操作由 8 个 MCP 工具组成，分为**读取**和**写入**两大类：

| 类别 | 工具 | 数据宽度 |
|------|------|----------|
| 读取 | `pine_read8` | 1 字节 |
| 读取 | `pine_read16` | 2 字节 |
| 读取 | `pine_read32` | 4 字节 |
| 读取 | `pine_read64` | 8 字节 |
| 读取 | `pine_read_range` | 批量（最大 4096 字节） |
| 写入 | `pine_write8` | 1 字节 |
| 写入 | `pine_write16` | 2 字节 |
| 写入 | `pine_write32` | 4 字节 |
| 写入 | `pine_write64` | 8 字节 |

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

## 地址空间与内存布局

### PS2 EE 主内存

PS2 的 Emotion Engine（EE）主内存地址空间是最常用的访问区域：

| 地址范围 | 说明 |
|----------|------|
| `0x00100000` - `0x01FFFFFF` | EE 主 RAM（游戏状态主要存储区） |
| `0x1C000000`+ | IOP RAM（声音/输入子系统） |
| 其他 | 预留/映射区域 |

> 💡 建议从 `0x00100000` 开始探测，该地址几乎所有游戏都会加载到 EE RAM 中。

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

### 连接传输方式

| 平台 | 传输方式 | 地址格式 |
|------|----------|----------|
| Linux/macOS | Unix Domain Socket | `$XDG_RUNTIME_DIR/<PINE_TARGET>.sock.<PINE_SLOT>` |
| Windows | TCP | `127.0.0.1:<PINE_SLOT>` |

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

## 读取操作

### 单值读取工具

| 工具 | 对齐要求 | 返回格式 |
|------|----------|----------|
| `pine_read8` | 无 | `ADDR: VAL_DEC (0xVAL_HEX)` |
| `pine_read16` | 2 字节对齐 | `ADDR: VAL_DEC (0xVAL_HEX)` |
| `pine_read32` | 4 字节对齐 | `ADDR: VAL_DEC (0xVAL_HEX)` |
| `pine_read64` | 8 字节对齐 | 字符串格式（JS 无法原生表示完整 u64） |

#### 64 位值处理

由于 JavaScript Number 类型最大只能精确表示到 `2^53`，`pine_read64` 和 `pine_write64` 采用**十进制字符串**作为值编码，避免精度丢失。

```typescript
// 资料来源：src/pine.ts:55-60
async read64(addr: number): Promise<bigint> {
  const r = await this.call(Op.Read64, this._addr(addr));
  return r.readBigUInt64LE(0);
}
```

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

### 批量读取：pine_read_range

`pine_read_range` 是最高效的批量读取工具，单次调用最多读取 4096 字节：

```typescript
// 资料来源：src/pine.ts:75-95
async readRange(start: number, length: number): Promise<Buffer> {
  // 计算最优读取步骤：优先使用最大对齐宽度
  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;
}
```

#### 读取策略

工具内部采用**自适应分块策略**，在每个步骤选择最大可用对齐宽度：

```mermaid
graph TD
    A[开始读取] --> B{地址 % 8 === 0 ?}
    B -->|是 且 剩余 ≥ 8| C[read64 - 8字节]
    B -->|否| D{地址 % 4 === 0 ?}
    D -->|是 且 剩余 ≥ 4| E[read32 - 4字节]
    D -->|否| F{地址 % 2 === 0 ?}
    F -->|是 且 剩余 ≥ 2| G[read16 - 2字节]
    F -->|否| H[read8 - 1字节]
    C --> I[移动指针]
    E --> I
    G --> I
    H --> I
    I --> J{还有数据?}
    J -->|是| B
    J -->|否| K[组装结果 Buffer]
```

#### 流水线控制

PINE 协议本身**没有原生批量读取指令**，`pine_read_range` 通过发送多个单次读取请求实现。默认配置为**完全串行**执行以避免 PCSX2 请求队列错位：

| 环境变量 | 默认值 | 说明 |
|----------|--------|------|
| `PINE_PIPELINE_BATCH` | `1` | 每批发送请求数；`1` = 完全串行（安全） |

> ⚠️ PCSX2 的 PINE 服务器存在已知缺陷：当流水线中有约 7-9 个请求时，会静默丢弃请求，导致后续所有回复与客户端错位，此时即使 `pine_ping` 也会超时，只能重启模拟器恢复。

实测性能（PCSX2 v2.6.3，localhost）：

| 操作 | 耗时 |
|------|------|
| 完整 4096 字节读取 | ~52 ms |
| 单次 read32 | ~0.1 ms |

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

## 写入操作

### 写入工具

| 工具 | 对齐要求 | 参数类型 |
|------|----------|----------|
| `pine_write8` | 无 | `number` |
| `pine_write16` | 2 字节对齐 | `number` |
| `pine_write32` | 4 字节对齐 | `number` |
| `pine_write64` | 8 字节对齐 | `number`（JS 会损失精度，模拟器端可能截断） |

> ⚠️ **破坏性操作**：写入会直接修改游戏内存，可能导致游戏崩溃或存档损坏。

```typescript
// 资料来源：src/tools.ts:62-70
case "pine_write8": {
  await pine.write8(addr(), p.value as number);
  return ok(`Wrote ${fmtHex(p.value as number)} → ${addrHex(addr())}`);
}
```

## 对齐要求与边界处理

### PCSX2 对齐特性

**关键警告**：PCSX2 的 PINE 实现**不强制对齐检查**。对未对齐地址的多字节访问会静默返回对齐地址的数据，造成数据损坏。

| 访问宽度 | 对齐要求 | 错误行为 |
|----------|----------|----------|
| 8 位 (read8/write8) | 无 | 无 |
| 16 位 (read16/write16) | 地址 % 2 === 0 | 未对齐时返回对齐地址数据 |
| 32 位 (read32/write32) | 地址 % 4 === 0 | 未对齐时返回对齐地址数据 |
| 64 位 (read64/write64) | 地址 % 8 === 0 | 未对齐时返回对齐地址数据 |

### 未对齐访问方案

如需读取未对齐地址的数据，建议：

1. 使用 `pine_read_range` 读取足够宽的字节范围
2. 在客户端自行组装字节序

```typescript
// 示例：读取未对齐的 32 位值
const bytes = await pine.readRange(0x00102001, 4);  // 从 0x00102000 开始读 4 字节
const value = bytes.readUInt32LE(1);  // 从偏移 1 开始解释
```

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

## 字节序

PINE 协议使用 **小端序（Little-Endian）** 编码多字节值：

- LSB 存储在起始地址
- MSB 存储在起始地址 + 宽度 - 1

```mermaid
graph LR
    subgraph "32 位值 0x12345678 在地址 0x00100000"
        A0["0x00100000: 0x78 (LSB)"]
        A1["0x00100001: 0x56"]
        A2["0x00100002: 0x34"]
        A3["0x00100003: 0x78 (MSB)"]
    end
```

> 💡 字符串读取（`getTitle`、`getId` 等）使用 UTF-8 编码，通过 `readString` 方法处理截断空字节。

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

## 超时与错误处理

### 超时机制

每个 PINE 调用都有 **10 秒超时**。超时后抛出 `PINE call timed out` 错误：

```
原因：
1. 模拟器未运行
2. PINE 服务器未启用（PCSX2: Settings → Advanced → Enable PINE Server）
3. PINE_SLOT 与模拟器配置不匹配
4. PCSX2 PINE 请求队列错位（需重启模拟器）
```

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

### 常见错误

| 错误信息 | 原因 | 解决方案 |
|----------|------|----------|
| `Cannot reach PINE server` | 连接失败 | 检查模拟器运行状态和 PINE_SLOT |
| `PINE FAIL response (0xFF)` | 地址无映射或无游戏加载 | 确认游戏已加载，使用 `0x00100000` 探测 |
| 返回全零 | 地址未分配 | 尝试 `0x00100000` |
| 数据异常 | 字节序误判或对齐错误 | 检查对齐，使用 `read_range` 手动组装 |

## 完整使用流程

```mermaid
graph TD
    A[启动模拟器] --> B[启用 PINE 服务器]
    B --> C[运行 mcp-pine]
    C --> D[调用 pine_ping 验证连接]
    D --> E{连接成功?}
    E -->|否| F[检查配置和模拟器状态]
    F --> B
    E -->|是| G[调用 pine_get_info 获取游戏信息]
    G --> H[选择目标地址]
    H --> I[调用 read/write 工具]
    I --> J{操作成功?}
    J -->|否| K[检查对齐/地址/超时]
    K --> I
    J -->|是| L[处理返回值]
```

## 工具调用示例

### 读取玩家分数（假设在 0x00201000）

```
工具: pine_read32
参数: { "address": 2113536 }
返回值: "0x00201000: 9500 (0x0000251c)"
```

### 批量扫描内存

```
工具: pine_read_range
参数: { "address": 1048576, "length": 4096 }
返回值: <Buffer: 4096 bytes>
```

### 修改生命值

```
工具: pine_write32
参数: { "address": 2097152, "value": 999 }
返回值: "Wrote 0x000003e7 → 0x00200000"
```

## 环境变量配置

| 变量 | 默认值 | 说明 |
|------|--------|------|
| `PINE_TARGET` | `pcsx2` | 模拟器名称前缀（socket 文件名） |
| `PINE_SLOT` | `28011` | PINE 槽位号（Linux/macOS 为 socket 后缀，Windows 为 TCP 端口） |
| `PINE_HOST` | `127.0.0.1` | 主机地址（可覆盖） |
| `PINE_SOCKET_PATH` | 自动 | 完整 socket 路径（完全覆盖自动解析） |
| `PINE_PIPELINE_BATCH` | `1` | 批量请求数（建议仅在非 PCSX2 模拟器上增加） |

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

## 安全注意事项

1. **写入操作不可逆**：修改内存会导致游戏状态永久改变，可能造成存档损坏
2. **不要过度流水线**：PCSX2 在超过 ~6 个并行请求时会静默失败
3. **定期保存状态**：使用 `pine_save_state` 在修改前备份当前游戏状态
4. **验证对齐**：未对齐写入会产生静默数据损坏

## 相关工具

| 工具 | 功能 |
|------|------|
| `pine_ping` | 验证连接（会话开始时调用） |
| `pine_get_info` | 获取游戏元数据（标题、序列号、CRC） |
| `pine_get_status` | 获取运行状态（running/paused/shutdown） |
| `pine_save_state` | 保存当前游戏状态到槽位 |
| `pine_load_state` | 从槽位加载游戏状态 |

---

*最后更新：基于 mcp-pine v0.2.1*

---

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

## 存档状态管理

### 相关页面

相关主题：[工具参考](#page-tools-reference), [使用范例](#page-recipes)

<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)
- [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>

# 存档状态管理

## 概述

存档状态管理（Save State Management）是 mcp-pine 项目为 PlayStation 2/3 模拟器提供的核心功能之一。该模块通过 PINE（Plugin Interface for Networked Emulation）协议实现模拟器内存状态的保存与恢复，允许 MCP 客户端在不中断游戏进程的情况下快速保存和加载游戏进度。

mcp-pine 暴露了两个主要工具：

| 工具名称 | 功能 |
|---------|------|
| `pine_save_state` | 将当前模拟器状态保存到指定槽位 |
| `pine_load_state` | 从指定槽位加载模拟器状态 |

资料来源：[src/tools.ts:工具定义区域]()

## 系统架构

### 组件层次

```
┌─────────────────────────────────────────────┐
│           MCP 客户端 (Claude Code)          │
└─────────────────────┬───────────────────────┘
                      │ 标准 MCP 协议 (stdio)
┌─────────────────────▼───────────────────────┐
│              mcp-pine 桥接服务               │
│  ┌─────────────────────────────────────┐    │
│  │        tools.ts - 工具定义层        │    │
│  │  • pine_save_state                  │    │
│  │  • pine_load_state                  │    │
│  └──────────────┬──────────────────────┘    │
│  ┌──────────────▼──────────────────────┐    │
│  │      pine.ts - PINE 客户端实现       │    │
│  │  • saveState(slot)                  │    │
│  │  • loadState(slot)                  │    │
│  └──────────────┬──────────────────────┘    │
└─────────────────┼───────────────────────────┘
                  │ TCP / Unix Socket
┌─────────────────▼───────────────────────────┐
│           模拟器 PINE 服务器                 │
│  • PCSX2 (Qt 版本 ≥ 1.7.x)                 │
│  • RPCS3 (IPC 服务器)                       │
│  • Duckstation (部分版本)                   │
└─────────────────────────────────────────────┘
```

### 数据流

```mermaid
sequenceDiagram
    participant Client as MCP 客户端
    participant Bridge as mcp-pine 桥接
    participant Pine as PINE 服务器
    participant Emu as 模拟器核心

    Client->>Bridge: pine_save_state { slot: 5 }
    Bridge->>Pine: Op.SaveState (0x09) + slot=5
    Pine->>Emu: 触发状态保存
    Emu-->>Pine: 保存完成确认
    Pine-->>Bridge: PINE 回复帧
    Bridge-->>Client: "Saved state → Slot 5"

    Client->>Bridge: pine_load_state { slot: 5 }
    Bridge->>Pine: Op.LoadState (0x0A) + slot=5
    Pine->>Emu: 触发状态加载
    Emu-->>Pine: 加载完成确认
    Pine-->>Bridge: PINE 回复帧
    Bridge-->>Client: "Loaded state from Slot 5"
```

## API 实现

### PineClient 类方法

`src/pine.ts` 中定义了 `PineClient` 类的两个核心异步方法：

```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);
}
```

**参数说明：**

| 参数 | 类型 | 范围 | 说明 |
|------|------|------|------|
| `slot` | `number` | 0-255 | 存档槽位编号 |

**协议细节：**

- 槽位参数写入 1 字节 Buffer
- 使用 `Op.SaveState`（0x09）和 `Op.LoadState`（0x0A）操作码
- 调用通过 `this.call()` 统一请求方法，携带 10 秒超时
- 返回 `void`，操作成功时静默完成

资料来源：[src/pine.ts:saveState方法定义]()

### 协议层交互

```mermaid
graph LR
    A[saveState/loadState] --> B[构造 1 字节参数 Buffer]
    B --> C[call Op.SaveState/Op.LoadState]
    C --> D{请求发送}
    D -->|成功| E[PINE 服务器处理]
    E --> F[模拟器核心执行]
    F --> G[返回确认帧]
    D -->|超时| H[抛出 TimeoutError]
    G --> I[解析响应 - void]
```

## 工具定义

### pine_save_state

```json
{
  "name": "pine_save_state",
  "description": "PURPOSE: Save the current emulator memory and execution state to a numbered slot...\nBEHAVIOR: DESTRUCTIVE: overwrites any existing state in the target slot without prompting...",
  "inputSchema": {
    "type": "object",
    "required": ["slot"],
    "properties": {
      "slot": {
        "type": "integer",
        "minimum": 0,
        "maximum": 255,
        "description": "Save state slot number (0-255)..."
      }
    }
  }
}
```

**用途说明：**

- 保存当前模拟器的完整运行状态到指定槽位
- 包括 CPU 寄存器、内存快照、硬件状态等
- 覆盖操作不可逆，无确认提示

### pine_load_state

```json
{
  "name": "pine_load_state",
  "description": "PURPOSE: Load and restore the emulator to a previously saved state in the given slot...",
  "inputSchema": {
    "type": "object",
    "required": ["slot"],
    "properties": {
      "slot": {
        "type": "integer",
        "minimum": 0,
        "maximum": 255,
        "description": "Save state slot number (0-255)..."
      }
    }
  }
}
```

**用途说明：**

- 从指定槽位恢复之前保存的模拟器状态
- 加载后模拟器立即进入加载的运行状态
- 不存在的槽位会返回 PINE FAIL 响应

资料来源：[src/tools.ts:工具定义完整内容]()

## 槽位系统

### 槽位编号规范

| 槽位范围 | 典型用途 | 说明 |
|---------|---------|------|
| 0-9 | 快捷键映射 | PCSX2 GUI 中 F1-F10 对应槽位 0-9 |
| 10-99 | 常规存档 | 用户手动保存位置 |
| 100-255 | 扩展槽位 | 自动化脚本、批量实验使用 |

### 存档文件位置

| 平台 | 路径 |
|------|------|
| Windows | `%USERPROFILE%\Documents\PCSX2\sstates` |
| Linux | `~/.config/PCSX2/sstates` |
| macOS | `~/.config/PCSX2/sstates` |

**文件名格式：**

```
<游戏序列号> (<Disc CRC>).<slot>.p2s
```

例如：`SLUS-21274 (ABCD1234).5.p2s` 表示序列号为 SLUS-21274、CRC 为 ABCD1234 的游戏存档在第 5 槽位。

资料来源：[src/tools.ts:SLOT_PARAM_DESC常量定义]()

## 配置参数

存档状态管理涉及以下环境变量配置：

| 环境变量 | 默认值 | 说明 |
|---------|--------|------|
| `PINE_TARGET` | `pcsx2` | 模拟器名称，用于 Unix socket 文件路径前缀 |
| `PINE_SLOT` | `28011` | PINE 通信槽位/端口号 |

### 连接配置差异

| 平台 | 连接方式 | 地址格式 |
|------|---------|---------|
| Linux/macOS | Unix Socket | `$XDG_RUNTIME_DIR/<target>.sock.<slot>`，回退到 `$TMPDIR` 或 `/tmp` |
| Windows | TCP | `127.0.0.1:<slot>` |

## 工作流程示例

### 基础保存-加载循环

```mermaid
graph TD
    A[启动模拟器] --> B[加载游戏]
    B --> C[正常游戏]
    C --> D[关键时刻]
    D --> E[pine_save_state slot=5]
    E --> F[继续游戏]
    F --> G[出错/想重来]
    G --> H[pine_load_state slot=5]
    H --> I[恢复到存档点]
    I --> F
```

### 自动化实验工作流

```
1. pine_get_info          # 确认当前游戏
2. pine_save_state 0      # 保存基准状态
3. [执行多次实验]
   3a. 修改内存
   3b. 测试假设
   3c. pine_load_state 0  # 快速重置到基准
4. pine_save_state 99    # 最终保存
```

## 已知问题与限制

### PCSX2 PINE 服务器稳定性

根据项目发现并记录的问题：

| 问题 | 原因 | 解决方式 |
|------|------|---------|
| 请求队列脆弱 | PINE 服务器对过多请求处理不稳定 | 限制并发请求数量 |
| 请求丢失静默 | 服务器丢弃请求时不报错 | 重启模拟器恢复 |
| 超时后状态不一致 | 错误响应与正确响应混淆 | 确保单一请求链 |

资料来源：[CHANGELOG.md:PCSX2 pipeline drop bug说明]()

### 常见错误响应

| 错误信息 | 可能原因 |
|---------|---------|
| `PINE FAIL response (0xFF)` | 游戏未加载、地址无映射、槽位不存在 |
| `PINE call timed out (10s)` | 服务器无响应或队列错位 |
| `Cannot reach PINE server` | 模拟器未运行、PINE 未启用、端口不匹配 |

## 与其他工具的配合

存档状态管理通常与以下工具配合使用：

| 工具 | 配合场景 |
|------|---------|
| `pine_get_info` | 保存前确认游戏和 CRC |
| `pine_get_status` | 加载前确认模拟器状态 |
| `pine_read_*` | 分析内存结构，决定保存时机 |
| `pine_write_*` | 修改状态后保存为实验快照 |

## 技术规格

| 规格项 | 值 |
|-------|-----|
| 槽位范围 | 0-255（16 位无符号） |
| 单次调用超时 | 10 秒 |
| 协议操作码 | SaveState=0x09, LoadState=0x0A |
| 参数编码 | 单字节小端序 |

资料来源：[src/pine.ts:协议操作码定义]()

## 总结

mcp-pine 的存档状态管理模块通过 PINE 协议与模拟器深度集成，提供了简洁但功能完整的保存/加载接口。开发者可以通过 MCP 客户端在 Claude Code 等工具中直接调用 `pine_save_state` 和 `pine_load_state`，实现自动化测试、内存分析、实验回溯等工作流程。

---

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

## 安装指南

### 相关页面

相关主题：[快速开始](#page-quickstart), [配置参考](#page-configuration)

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

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

- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [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>

# 安装指南

## 概述

mcp-pine 是一个基于 Model Context Protocol (MCP) 的服务器工具，用于连接 PlayStation 模拟器（PCSX2、RPCS3、Duckstation）的 PINE IPC 接口。通过该工具，AI 助手（如 Claude）可以直接与运行中的模拟器交互，执行内存读取、写入、保存状态等操作。

本指南涵盖三种安装方式、MCP 客户端配置以及各模拟器的 PINE 服务启用步骤。

---

## 前置要求

| 组件 | 版本要求 | 说明 |
|------|----------|------|
| Node.js | ≥ 22.0.0 | npm 包管理器内置 |
| npm | 最新版 | 用于安装 mcp-pine |
| PlayStation 模拟器 | 参见下方 | PCSX2 1.7.x Qt 或更高版本推荐 |

资料来源：[package.json:24-26]()

---

## 安装方式

### 方式一：npm 全局安装（推荐）

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

全局安装后，`mcp-pine` 命令可直接在终端运行。

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

### 方式二：npx 免安装运行

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

npx 会临时下载并执行包，无需本地安装，适合一次性使用场景。

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

### 方式三：源码克隆开发

```bash
git clone https://github.com/dmang-dev/mcp-pine
cd mcp-pine
npm install        # 同时运行 build（通过 prepare hook）
```

适用于需要修改代码或参与开发的场景。

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

---

## MCP 客户端配置

mcp-pine 通过标准 stdio 协议与 MCP 客户端通信。以下是各平台的配置方法。

### Claude Code (CLI)

添加 MCP 服务器到用户级配置：

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

验证连接状态：

```bash
claude mcp list
# 输出示例: pine: mcp-pine - ✓ Connected
```

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

### Claude Desktop

编辑配置文件 `claude_desktop_config.json`，路径因平台而异：

| 平台 | 配置文件路径 |
|------|-------------|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| Linux | `~/.config/Claude/claude_desktop_config.json` |

在 `mcpServers` 下添加 pine 配置：

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

配置完成后需重启 Claude Desktop。

资料来源：[README.md:22-37]()

### 其他 MCP 客户端

mcp-pine 兼容任何支持 stdio 传输的标准 MCP 客户端：

```bash
mcp-pine
```

直接运行即可，客户端通过标准输入/输出与其通信。

资料来源：[README.md:38-40]()

---

## 环境变量配置

| 环境变量 | 默认值 | 说明 |
|----------|--------|------|
| `PINE_TARGET` | `pcsx2` | 模拟器名称，用于 Unix socket 文件路径前缀（`<target>.sock.<slot>`）。Windows 平台忽略此变量，仅使用 TCP 连接。 |
| `PINE_SLOT` | `28011` | PINE 端口号/槽位，连接 PCSX2/RPCS3 时指定端口 |
| `PINE_PIPELINE_BATCH` | `1` | 批量请求数，用于控制内存读取的并发程度。默认值为 1（完全串行）以避免 PCSX2 PINE 服务请求队列崩溃 |

### 连接方式差异

| 平台 | 连接方式 | 地址格式 |
|------|----------|----------|
| Linux/macOS | Unix Domain Socket | `$XDG_RUNTIME_DIR/<target>.sock.<slot>`，备用 `$TMPDIR` 或 `/tmp` |
| Windows | TCP | `127.0.0.1:<slot>` |

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

---

## 模拟器 PINE 服务配置

### PCSX2（推荐）

1. 启动 PCSX2（1.7.x Qt 或更新版本）
2. 进入 **Settings → Advanced → Enable PINE Server**
3. 默认槽位为 **28011**，如需更改同步修改 `PINE_SLOT` 环境变量
4. 加载任意游戏

> **注意**：PINE 服务启用后始终处于运行状态，无需额外脚本或控制台命令。

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

### Duckstation

1. 确认 Duckstation 构建版本包含 PINE 服务器（并非所有版本都有）
2. 如包含，设置环境变量：
   ```bash
   PINE_TARGET=duckstation PINE_SLOT=<port> mcp-pine
   ```

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

### RPCS3

RPCS3 使用独立 IPC 实现，兼容 PINE 操作码集，但线级兼容性尚未全面测试。

1. 进入 **Configuration → Advanced → Enable IPC server**
2. 记下配置的端口
3. 启动命令：
   ```bash
   PINE_TARGET=rpcs3 PINE_SLOT=<port> mcp-pine
   ```

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

---

## 验证安装

### 快速测试脚本

克隆仓库后可运行冒烟测试：

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

该脚本会连接运行中的模拟器并执行基础调用。

### MCP 工具列表

安装成功后，通过 MCP 客户端可调用以下工具：

| 工具名称 | 功能 |
|----------|------|
| `pine_ping` | 检测连接，获取模拟器版本 |
| `pine_get_info` | 获取游戏元数据（标题、序列号、CRC、版本、运行状态） |
| `pine_get_status` | 获取模拟器运行状态（running/paused/shutdown） |
| `pine_read8/16/32/64` | 读取内存（按字节宽度） |
| `pine_read_range` | 批量读取内存（最多 4096 字节） |
| `pine_write8/16/32/64` | 写入内存 |
| `pine_save_state` | 保存状态到指定槽位 |
| `pine_load_state` | 从指定槽位加载状态 |

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

---

## 架构概览

```mermaid
graph TD
    subgraph "MCP 客户端"
        A[Claude Code / Claude Desktop]
    end
    
    subgraph "mcp-pine 服务器"
        B[index.ts - 主入口]
        C[tools.ts - 工具定义]
        D[pine.ts - PINE 客户端]
    end
    
    subgraph "底层通信"
        E[StdioTransport]
        F[net.Socket]
    end
    
    subgraph "目标模拟器"
        G[PCSX2 / RPCS3 / Duckstation]
        H[PINE Server]
    end
    
    A -->|stdio| B
    B --> C
    C --> D
    D -->|StdioServerTransport| E
    D -->|TCP / Unix Socket| F
    F -->|PINE Protocol| G
    G --> H
    
    style A fill:#e1f5fe
    style G fill:#fff3e0
    style H fill:#f3e5f5
```

---

## 故障排查

| 问题 | 可能原因 | 解决方案 |
|------|----------|----------|
| `Cannot reach PINE server` | 模拟器未运行、PINE 未启用、端口不匹配 | 检查 `PINE_SLOT` 设置，确认模拟器 PINE 服务已开启 |
| `PINE FAIL response` (0xFF) | 未加载游戏或地址未映射 | 确保已加载游戏，尝试地址 `0x00100000` |
| 读取返回全零 | 地址在未分配区域 | 优先尝试 `0x00100000`（EE 主内存几乎总是映射） |
| `PINE call timed out (10s)` | PCSX2 PINE 请求队列崩溃 | 需完全重启 PCSX2，重连无效 |

> **重要提示**：PCSX2 的 PINE 服务请求队列脆弱，当飞行中请求超过约 6 个时会静默丢弃请求，导致回复错位。一旦发生此问题，即使 `pine_ping` 也会超时，只能通过重启模拟器恢复。

资料来源：[README.md:83-101]()

---

## 开发相关

### 本地开发

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

### 依赖关系

```mermaid
graph LR
    A[mcp-pine] --> B[@modelcontextprotocol/sdk]
    A --> C[@types/node]
    
    style A fill:#e8f5e9
    style B fill:#c8e6c9
    style C fill:#c8e6c9
```

资料来源：[package.json:16-22]()

---

## 许可证

本项目采用 MIT 许可证。

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

---

## 相关项目

| 项目 | 平台 | 特性 |
|------|------|------|
| [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | mGBA (Game Boy Advance) | 含按钮输入、截图功能 |

资料来源：[README.md:124-126]()

---

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

## 模拟器配置

### 相关页面

相关主题：[配置参考](#page-configuration), [故障排除](#page-troubleshooting)

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

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

- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [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)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
</details>

# 模拟器配置

## 概述

mcp-pine 是一个基于 Model Context Protocol (MCP) 的桥接工具，用于连接 Claude 等 AI 助手与支持 PINE 协议的 PS2/PS3/PSP 模拟器。通过标准化的 MCP 工具接口，用户可以读取/写入模拟器内存、保存/加载存档状态以及获取游戏元数据。

当前项目支持的模拟器包括 **PCSX2**、**RPCS3** 和 **Duckstation**，每种模拟器在 PINE 功能的实现和配置方式上存在差异。

## 支持的模拟器

| 模拟器 | 平台 | PINE 状态 | 备注 |
|--------|------|-----------|------|
| PCSX2  | Qt 1.7.x+ | ✅ 原生支持 | 主要测试平台，协议实现最完整 |
| RPCS3  | 最新版 | ⚠️ 部分兼容 | 使用自定义 IPC 实现，兼容性未充分测试 |
| Duckstation | 特定构建 | ⚠️ 需检查 | 部分构建版本包含 PINE 服务器 |

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

## 环境变量配置

mcp-pine 通过环境变量控制连接行为，无需配置文件。

### 核心参数

| 环境变量 | 默认值 | 说明 |
|----------|--------|------|
| `PINE_TARGET` | `pcsx2` | 模拟器名称，用于构建 Unix socket 文件路径（Linux/macOS）或 TCP 连接标识（Windows） |
| `PINE_SLOT` | `28011` | PINE 槽位编号，对应模拟器中配置的端口号 |
| `PINE_PIPELINE_BATCH` | `1` | 请求流水线批次大小，控制并发请求数量 |

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

### 连接地址解析

连接目标根据操作系统和配置的 `PINE_TARGET` 值自动确定：

```mermaid
graph TD
    A[启动 mcp-pine] --> B{操作系统}
    B -->|Linux/macOS| C{连接类型}
    B -->|Windows| D[TCP 连接]
    C -->|Unix Socket| E[使用 Unix Socket]
    C -->|TCP| D
    D --> F[127.0.0.1:{PINE_SLOT}]
    E --> G[{$XDG_RUNTIME_DIR}/{PINE_TARGET}.sock.{PINE_SLOT}]
    G --> H{fallback: TMPDIR}
    H -->|失败| I[/tmp/{PINE_TARGET}.sock.{PINE_SLOT}]
```

- **Unix Socket 路径**：`{PINE_TARGET}.sock.{PINE_SLOT}`
  - 优先使用 `$XDG_RUNTIME_DIR`
  - 降级使用 `$TMPDIR`
  - 最终降级到 `/tmp`

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

## PCSX2 配置指南

PCSX2 是项目的主要测试平台，提供最完整的 PINE 支持。

### 启用 PINE 服务器

1. 启动 PCSX2（Qt 版本 1.7.x 或更高）
2. 进入 **Settings → Advanced → Enable PINE Server**
3. 默认槽位为 **28011**，如需更改则同步设置 `PINE_SLOT` 环境变量
4. 加载任意游戏

> 注意：PINE 服务器启用后始终保持运行，无需额外脚本或控制台命令。

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

### 连接配置

**Linux/macOS：**
```bash
PINE_TARGET=pcsx2 PINE_SLOT=28011 mcp-pine
```

**Windows（TCP 强制）：**
```bash
set PINE_SLOT=28011
mcp-pine
```

## RPCS3 配置指南

RPCS3 使用自有的 IPC 实现，其操作码集合与 PINE 类似，但线级兼容性尚未经过充分测试。

### 启用 IPC 服务器

1. 进入 **Configuration → Advanced → Enable IPC server**（菜单位置可能因版本而异）
2. 记录配置的端口号
3. 使用以下命令运行：

```bash
PINE_TARGET=rpcs3 PINE_SLOT=<端口号> mcp-pine
```

资料来源：[README.md:65-72]()

## Duckstation 配置指南

Duckstation 的 PINE 支持因构建版本而异，并非所有发行版都包含该功能。

### 检查 PINE 支持

确认你的 Duckstation 构建版本包含 PINE 服务器后，使用以下配置：

```bash
PINE_TARGET=duckstation PINE_SLOT=<端口号> mcp-pine
```

其中 `<端口号>` 需要与 Duckstation 中配置的槽位端口一致。

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

## MCP 客户端集成

### Claude Code (CLI)

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

验证连接：
```bash
claude mcp list
# 输出: pine: mcp-pine - ✓ Connected
```

资料来源：[README.md:15-22]()

### Claude Desktop

编辑配置文件：

| 操作系统 | 配置文件路径 |
|----------|--------------|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| Linux | `~/.config/Claude/claude_desktop_config.json` |

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

修改配置后需重启 Claude Desktop。

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

## 性能调优

### 批量读取配置

`PINE_PIPELINE_BATCH` 环境变量控制并发请求数量：

| 值 | 行为 | 延迟 | 风险 |
|----|------|------|------|
| `1` | 完全串行（默认） | ~52ms/4KB | 无 |
| `2` 或更高 | 流水线并发 | 降低 | PCSX2 可能丢包 |

> ⚠️ PCSX2 的 PINE 服务器请求队列脆弱，约 7-9 个飞行中请求即可导致无声丢包，进而使回复管道永久失步。

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

### 测量结果

在 PCSX2 v2.6.3 上通过 loopback TCP 测量：

- 完整 4096 字节读取：约 52ms
- 相当于不到两个模拟帧的时间

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

## 故障排除

| 症状 | 原因 | 解决方案 |
|------|------|----------|
| `Cannot reach PINE server` | 模拟器未运行、PINE 未启用、端口不匹配 | 检查 `PINE_SLOT` 设置 |
| `PINE FAIL response` (0xFF) | 模拟器拒绝请求，通常因为未加载游戏或地址未映射 | 确保已加载游戏，使用有效地址 |
| 读取返回零值 | 地址在未分配区域 | 尝试 `0x00100000`（EE 主 RAM） |
| 数值看起来损坏 | 字节序问题 | PINE 返回小端序 |
| `pine_ping` 超时（10s） | PCSX2 PINE 服务器卡死 | **完全重启 PCSX2**，重连无效 |

### PCSX2 PINE 服务器卡死问题

**现象**：即使 ping 也超时

**原因**：请求管道失步，回复与等待客户端错位

**恢复**：必须完全重启 PCSX2，仅重连无法解决问题

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

## 可用工具一览

配置完成后，以下 MCP 工具可用于与模拟器交互：

| 工具名称 | 功能 | PINE 调用次数 |
|----------|------|---------------|
| `pine_ping` | 获取模拟器版本 | 1 |
| `pine_get_info` | 获取游戏标题、序列号、CRC、版本、状态 | 5（并行） |
| `pine_get_status` | 获取运行状态（running/paused/shutdown） | 1 |
| `pine_read8/16/32/64` | 读取指定宽度的内存值 | 1 |
| `pine_read_range` | 批量读取最多 4096 字节 | N（串行） |
| `pine_write8/16/32/64` | 写入指定宽度的内存值 | 1 |
| `pine_save_state` | 保存游戏状态到槽位 | 1 |
| `pine_load_state` | 从槽位加载游戏状态 | 1 |

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

## 地址空间参考

### PS2 (PCSX2) 地址区域

| 地址范围 | 描述 |
|----------|------|
| `0x00100000 - 0x01FFFFFF` | EE 主内存（99% 游戏状态所在） |
| `0x1C000000+` | IOP 内存 |
| 特定区域 | Scratchpad 等 |

> ⚠️ 多字节读写（16/32/64 位）必须对齐地址。PCSX2 的 PINE 不强制对齐，非对齐访问会静默返回损坏数据。

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

## 安装方式

### 方式 A：npm 全局安装

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

### 方式 B：npx 临时运行

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

### 方式 C：源码开发

```bash
git clone https://github.com/dmang-dev/mcp-pine
cd mcp-pine
npm install
```

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

## 开发调试

运行开发模式（TypeScript 监视编译）：

```bash
npm run dev
```

针对运行中的 PCSX2 进行冒烟测试：

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

资料来源：[README.md:105-112]()

---

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

## 配置参考

### 相关页面

相关主题：[模拟器配置](#page-emulator-setup), [安装指南](#page-installation)

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

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

- [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)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
</details>

# 配置参考

本文档详细说明 mcp-pine 的所有配置选项，包括环境变量、连接参数、运行时行为调优，以及不同平台下的连接机制差异。

## 概述

mcp-pine 通过 PINE（PlayStation Interactive Networked Entertainment）协议与模拟器进行 IPC 通信。项目采用零配置默认值设计，用户只需在模拟器中启用 PINE 服务即可开箱即用。高级用户可通过环境变量或代码级配置自定义连接目标、传输方式及请求管道行为。

配置分为三个层级：

| 层级 | 来源 | 优先级 | 适用场景 |
|------|------|--------|----------|
| 环境变量 | `process.env` | 最高 | 容器化部署、CLI 用户 |
| 代码选项 | `PineConnectOptions` | 中 | SDK 集成开发者 |
| 编译默认值 | 源码硬编码 | 最低 | 快速尝鲜 |

## 环境变量配置

环境变量是用户最常用的配置方式，适用于所有运行场景。

### 完整配置表

| 环境变量 | 默认值 | 类型 | 说明 |
|----------|--------|------|------|
| `PINE_TARGET` | `pcsx2` | string | 模拟器标识名，用于 Unix socket 文件路径前缀 |
| `PINE_SLOT` | `28011` | number | PINE 槽位号，TCP 模式下作为端口号 |
| `PINE_HOST` | `127.0.0.1` | string | TCP 连接模式下的目标主机（覆盖自动检测） |
| `PINE_SOCKET_PATH` | 自动解析 | string | Unix socket 文件路径（覆盖自动检测） |
| `PINE_PIPELINE_BATCH` | `1` | number | 请求管道批大小，1=完全串行 |

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

### PINE_TARGET

指定目标模拟器名称，该值作为 Unix socket 文件路径的前缀部分。

```bash
# 连接到 PCSX2（默认）
PINE_TARGET=pcsx2 mcp-pine

# 连接到 Duckstation
PINE_TARGET=duckstation PINE_SLOT=28013 mcp-pine

# 连接到 RPCS3
PINE_TARGET=rpcs3 PINE_SLOT=28014 mcp-pine
```

在 Linux/macOS 上，socket 路径格式为 `<socket_dir>/<target>.sock.<slot>`。

### PINE_SLOT

PINE 槽位号，映射到模拟器内部的 PINE 服务端口或 Unix socket 编号。

```bash
# 使用非标准槽位
PINE_SLOT=28015 mcp-pine
```

槽位必须与模拟器 PINE 设置中的配置一致。PCSX2 默认槽位为 `28011`，RPCS3 可能因版本而异。

### PINE_HOST 与 PINE_SOCKET_PATH

这两个变量用于覆盖自动检测的连接方式：

```bash
# 强制使用 TCP 连接到指定主机
PINE_HOST=192.168.1.100 PINE_SLOT=28011 mcp-pine

# 强制使用指定的 Unix socket 路径
PINE_SOCKET_PATH=/var/run/pcsx2.sock.28011 mcp-pine
```

通常无需手动设置，除非需要连接非本机模拟器或使用非标准 socket 位置。

### PINE_PIPELINE_BATCH

控制 `pine_read_range` 等批量读取操作的并行请求数。

```bash
# 完全串行（默认，最安全）
PINE_PIPELINE_BATCH=1 mcp-pine

# 允许 2 个请求并行（中等风险）
PINE_PIPELINE_BATCH=2 mcp-pine

# 允许 N 个请求并行（高风险）
PINE_PIPELINE_BATCH=8 mcp-pine
```

> **警告**：PCSX2 的 PINE 服务器请求队列存在已知缺陷，当在飞请求超过约 6-7 个时会静默丢弃请求，导致回复管道永久错位。详情见故障排除章节。

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

## 连接选项接口

对于通过 SDK 集成的开发者，`PineClient` 构造函数接受 `PineConnectOptions` 对象：

```typescript
interface PineConnectOptions {
  target?: string;      // 模拟器标识，默认为 "pcsx2"
  slot?: number;        // 槽位号，默认为 28011
  host?: string;        // 覆盖 TCP 主机
  socketPath?: string;  // 覆盖 Unix socket 路径
}
```

使用示例：

```typescript
import { PineClient } from "mcp-pine";

const pine = new PineClient({
  target: "pcsx2",
  slot: 28011,
});

// 或指定自定义连接
const pine2 = new PineClient({
  host: "192.168.1.100",
  slot: 28011,
});
```

## 传输层架构

### 平台自动检测

mcp-pine 根据运行平台自动选择最优传输方式：

```mermaid
graph TD
    A[启动 mcp-pine] --> B{平台检测}
    B -->|Windows| C[TCP 连接]
    B -->|Linux/macOS| D[Unix Domain Socket]
    
    C --> E[127.0.0.1:PINE_SLOT]
    D --> F{XDG_RUNTIME_DIR}
    F -->|存在| G[XDG_RUNTIME_DIR/target.sock.slot]
    F -->|不存在| H{TMPDIR}
    H -->|存在| I[TMPDIR/target.sock.slot]
    H -->|不存在| J[/tmp/target.sock.slot]
    
    style C fill:#e1f5fe
    style D fill:#fff3e0
    style E fill:#e1f5fe
    style G fill:#e8f5e9
    style I fill:#e8f5e9
    style J fill:#e8f5e9
```

### Socket 路径解析优先级

在 Linux/macOS 上，Unix socket 路径按以下优先级确定：

| 优先级 | 环境变量 | 示例路径 |
|--------|----------|----------|
| 1 | `PINE_SOCKET_PATH`（显式覆盖） | 用户指定 |
| 2 | `$XDG_RUNTIME_DIR` | `/run/user/1000/pcsx2.sock.28011` |
| 3 | `$TMPDIR` | `/tmp/pcsx2.sock.28011` |
| 4 | `/tmp`（最终回退） | `/tmp/pcsx2.sock.28011` |

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

### TCP 连接模式

在 Windows 或显式指定 `PINE_HOST` 时，mcp-pine 使用标准 TCP 连接：

```mermaid
sequenceDiagram
    participant MCP as MCP 客户端
    participant Bridge as mcp-pine
    participant PCSX2 as PCSX2 PINE
    
    Note over Bridge: TCP 模式初始化
    MCP->>Bridge: 连接请求
    Bridge->>PCSX2: net.createConnection<br/>host: 127.0.0.1
    PCSX2-->>Bridge: 连接成功
    Bridge-->>MCP: 就绪
```

连接地址格式：`127.0.0.1:<PINE_SLOT>`

## 请求处理机制

### PINE 协议帧格式

mcp-pine 使用二进制 PINE 协议进行通信，帧格式如下：

```mermaid
graph LR
    subgraph 发送帧
        A[uint32<br/>总长度] --> B[uint8<br/>操作码] --> C[可变长度<br/>载荷数据]
    end
    
    subgraph 接收帧
        D[uint32<br/>总长度] --> E[uint8<br/>状态] --> F[可变长度<br/>响应数据]
    end
```

所有多字节整数均采用小端序（Little-Endian）编码。

### 操作码映射

| 操作码 | 名称 | 方向 | 说明 |
|--------|------|------|------|
| 0x01 | Version | R | 获取模拟器版本 |
| 0x02 | Title | R | 获取游戏标题 |
| 0x03 | ID | R | 获取游戏序列号 |
| 0x04 | UUID | R | 获取光盘 CRC |
| 0x05 | GameVersion | R | 获取游戏版本 |
| 0x06 | Status | R | 获取运行状态 |
| 0x10 | SaveState | W | 保存状态到槽位 |
| 0x11 | LoadState | W | 从槽位加载状态 |
| 0x20-0x23 | Read8/16/32/64 | R | 读取内存 |
| 0x30-0x33 | Write8/16/32/64 | W | 写入内存 |

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

### 批量读取实现

`pine_read_range` 通过组合多种宽度的读取操作实现高效批量读取：

```mermaid
flowchart TD
    A[pine_read_range<br/>length=4096] --> B{对齐检测}
    
    B -->|cursor%8==0 且 remaining>=8| C[read64]
    B -->|cursor%4==0 且 remaining>=4| D[read32]
    B -->|cursor%2==0 且 remaining>=2| E[read16]
    B -->|其他情况| F[read8]
    
    C --> G{下一个字节}
    D --> G
    E --> G
    F --> G
    
    G -->|remaining>0| B
    G -->|remaining=0| H[组装结果缓冲区]
    
    I{PIPELINE_BATCH}
    I -->|=1| J[串行执行<br/>每批1个请求]
    I -->|>1| K[并行执行<br/>每批N个请求]
    
    J --> L[安全但延迟较高]
    K --> M[低延迟但可能丢包]
    
    style J fill:#c8e6c9
    style K fill:#ffcdd2
```

默认 `PIPELINE_BATCH=1` 表示完全串行执行，避免 PCSX2 PINE 服务器的队列问题。

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

## 模拟器配置要求

### PCSX2 设置

1. 启动 PCSX2 1.7.x 或更新版本
2. 进入 **Settings → Advanced → Enable PINE Server**
3. 默认槽位为 **28011**，如需更改同步修改环境变量

无需额外脚本或控制台命令，PINE 启用后始终可用。

### RPCS3 设置

RPCS3 实现了兼容 PINE 的 IPC 接口，但线级兼容性尚未完全测试：

1. 进入 **Configuration → Advanced → Enable IPC server**
2. 记下配置的端口
3. 使用 `PINE_TARGET=rpcs3 PINE_SLOT=<port> mcp-pine` 运行

### Duckstation 设置

部分 Duckstation 构建包含 PINE 服务器：

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

## 故障排除

### 连接问题诊断

```mermaid
flowchart TD
    A[连接失败] --> B{PING 工具测试}
    
    B -->|超时| C{模拟器运行中?}
    C -->|否| D[启动模拟器并加载游戏]
    C -->|是| E[PINE 已启用?]
    E -->|否| F[在模拟器设置中启用 PINE]
    E -->|是| G{端口匹配?}
    G -->|否| H[对齐 PINE_SLOT 和模拟器设置]
    
    B -->|FAIL 响应| I{是否有游戏加载?}
    I -->|否| J[加载游戏后重试]
    I -->|是| K[地址无效或未映射]
    
    K --> L[从 0x00100000 开始尝试]
    
    style D fill:#c8e6c9
    style F fill:#c8e6c9
    style H fill:#c8e6c9
    style J fill:#c8e6c9
    style L fill:#c8e6c9
```

### PCSX2 PINE 服务器卡死

PCSX2 的 PINE 服务器在收到约 7 个以上并行请求时会静默丢弃请求，导致回复管道永久错位。

**症状**：即使 `pine_ping` 也超时（10秒后）。

**解决方案**：完全重启 PCSX2。重新连接无效，损坏发生在模拟器端。

**预防措施**：
- 保持 `PINE_PIPELINE_BATCH=1`
- 如需更高性能，确保请求数量不超过 6 个

资料来源：[README.md:98-115]()

### 内存读取问题

| 症状 | 可能原因 | 解决方案 |
|------|----------|----------|
| 返回全零 | 地址未分配 | 从 `0x00100000` 开始尝试 |
| 数据损坏 | 未对齐访问 | 使用 `pine_read_range` 自行组装 |
| 值不符合预期 | 大端序误解 | PINE 返回小端序 |

## 配置示例

### 基本用法（默认 PCSX2）

```bash
# 使用所有默认值
mcp-pine
```

等价于：
```bash
PINE_TARGET=pcsx2 PINE_SLOT=28011 mcp-pine
```

### 连接远程模拟器

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

### 自定义 Unix Socket 路径

```bash
PINE_SOCKET_PATH=/home/user/my-socket mcp-pine
```

### 性能调优（风险自负）

```bash
# 允许 2 个并行请求
PINE_PIPELINE_BATCH=2 mcp-pine
```

### NPM 方式运行

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

## 环境变量速查表

```
PINE_TARGET          默认: pcsx2        模拟器标识名
PINE_SLOT            默认: 28011        槽位号/端口
PINE_HOST            默认: 127.0.0.1    TCP 主机
PINE_SOCKET_PATH     默认: 自动解析     Unix socket 路径
PINE_PIPELINE_BATCH  默认: 1            并行请求批大小
```

## 相关文档

- [快速开始指南](README.md) — 安装与基础使用
- [工具参考](src/tools.ts) — MCP 工具完整列表
- [PINE 协议规范](https://github.com/GovanifY/pine) — 底层 IPC 标准
- [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) — 同系 Game Boy Advance 客户端

---

<a id='page-recipes'></a>

## 使用范例

### 相关页面

相关主题：[内存操作指南](#page-memory-operations), [存档状态管理](#page-savestate), [故障排除](#page-troubleshooting)

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

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

- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [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)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
</details>

# 使用范例

## 概述

mcp-pine 是一个基于 Model Context Protocol (MCP) 的桥接工具，用于连接 Claude 等 AI 助手与支持 PINE（PlayStation 2 Inter-Process Communication）协议的模拟器（如 PCSX2、RPCS3、Duckstation）。通过 mcp-pine，用户可以让 AI 直接读取和写入模拟器的内存、获取游戏状态信息、保存和加载存档。

该项目的主要功能包括：

- **内存读写**：支持 8/16/32/64 位数值读取以及批量内存读取
- **游戏状态查询**：获取游戏标题、序列号、CRC、版本信息
- **存档管理**：保存和加载指定槽位的存档
- **跨模拟器支持**：兼容 PCSX2、RPCS3、Duckstation 等主流模拟器

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

## 系统架构

```mermaid
graph TD
    A["Claude / MCP 客户端"] -->|MCP stdio| B["mcp-pine 桥接工具"]
    B -->|PINE 协议| C["PCSX2 PINE Server"]
    B -->|PINE 协议| D["RPCS3 IPC Server"]
    B -->|PINE 协议| E["Duckstation PINE Server"]
    
    F["EE 主内存 0x00100000-0x01FFFFFF"] --> C
    G["IOP 内存 0x1C000000+"] --> C
    H["PS3 主内存"] --> D
```

mcp-pine 作为中间层，将 MCP 协议请求转换为 PINE 协议调用，与模拟器的内置 PINE 服务器通信。不同模拟器使用不同的连接方式：Unix 域套接字（Linux/macOS）或 TCP（Windows）。

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

## 安装方式

### 方式一：npm 全局安装

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

### 方式二：npx 直接运行

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

### 方式三：源码安装

```bash
git clone https://github.com/dmang-dev/mcp-pine
cd mcp-pine
npm install
```

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

## MCP 客户端配置

### Claude Code (CLI)

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

验证连接：

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

### Claude Desktop

根据操作系统编辑配置文件：

| 平台 | 配置文件路径 |
|------|-------------|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| Linux | `~/.config/Claude/claude_desktop_config.json` |

配置内容：

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

修改配置后需重启 Claude Desktop。

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

## 环境变量配置

| 环境变量 | 默认值 | 说明 |
|----------|--------|------|
| `PINE_TARGET` | `pcsx2` | 模拟器名称，用于构建 Unix 套接字文件路径（`<target>.sock.<slot>`）。Windows 系统忽略此变量，仅使用 TCP 连接。 |
| `PINE_SLOT` | `28011` | PINE 槽位号，对应 PCSX2 中的端口或槽位号。 |
| `PINE_PIPELINE_BATCH` | `1` | 批量流水线深度。默认为 1（完全串行），设为更高值可降低延迟但可能导致 PCSX2 请求队列错位。 |

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

## 模拟器配置

### PCSX2 配置步骤

1. 启动 PCSX2（1.7.x Qt 或更高版本）
2. 进入 **Settings → Advanced → Enable PINE Server**
3. 默认槽位为 **28011**，如需更改则在启动 mcp-pine 时设置 `PINE_SLOT`
4. 加载任意游戏

> 注意：PINE 服务启用后始终处于开启状态，无需脚本或控制台命令。

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

### RPCS3 配置步骤

1. 进入 **Configuration → Advanced → Enable IPC server**
2. 记下配置的端口号
3. 运行命令：`PINE_TARGET=rpcs3 PINE_SLOT=<端口> mcp-pine`

> 注意：RPCS3 的 IPC 实现参考了 PINE 操作码，但协议层面的兼容性尚未经过充分测试。

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

### Duckstation 配置步骤

检查当前构建的 Duckstation 是否包含 PINE 服务器（如有则设置 `PINE_TARGET=duckstation PINE_SLOT=<端口>`）。

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

## 工具清单

mcp-pine 提供以下 MCP 工具：

| 工具名称 | 功能 | 用途场景 |
|----------|------|----------|
| `pine_ping` | 检测连接状态 | 验证模拟器 PINE 服务是否可用 |
| `pine_get_info` | 获取游戏元数据 | 获取游戏标题、序列号、CRC、版本、运行状态 |
| `pine_get_status` | 获取运行状态 | 快速检查模拟器是运行中、暂停还是已关闭 |
| `pine_read8/16/32/64` | 定点内存读取 | 按指定字节宽度读取单个值 |
| `pine_read_range` | 批量内存读取 | 一次性读取最多 4096 字节的连续内存区域 |
| `pine_write8/16/32/64` | 定点内存写入 | 向指定地址写入数值 |
| `pine_save_state` | 保存存档 | 将当前状态保存到指定槽位 |
| `pine_load_state` | 加载存档 | 从指定槽位恢复存档 |

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

## 典型使用流程

```mermaid
graph TD
    A[启动 PCSX2 并加载游戏] --> B[启动 mcp-pine]
    B --> C{连接成功?}
    C -->|是| D[调用 pine_ping 验证]
    D --> E[调用 pine_get_info 获取游戏信息]
    E --> F{需要读取内存?}
    F -->|是| G[使用 pine_read_range 批量读取]
    G --> H[分析内存数据]
    F -->|否| I[使用 pine_read8/16/32/64 定点读取]
    I --> H
    H --> J{需要修改状态?}
    J -->|是| K[使用 pine_write* 写入]
    J -->|否| L[完成]
    K --> L
    C -->|否| M[检查 PINE_SLOT 配置]
    M --> C
```

## 内存地址说明

### PS2 内存布局（PCSX2）

| 地址范围 | 说明 |
|----------|------|
| `0x00100000` - `0x01FFFFFF` | EE 主内存（99% 的游戏状态位于此处） |
| `0x1C000000`+ | IOP 内存 |
| 0x10000000 区域 | Scratchpad（高速缓存） |

> 重要提示：对于 16/32/64 位读取，地址**必须对齐**（即地址值能被读写宽度整除）。PCSX2 的 PINE 服务**不强制对齐**，未对齐的地址会静默返回错误数据。如需读取未对齐的数据，请使用 `pine_read_range` 并自行组装字节。

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

## 工具使用详解

### 连接验证

```typescript
// 调用 pine_ping
工具输入: {}
预期输出: "OK — emulator: <版本号>"
```

### 获取游戏信息

```typescript
// 调用 pine_get_info
工具输入: {}
预期输出:
"Title:        <游戏标题>
Serial:       <序列号>
Disc CRC:     <CRC值>
Game version: <版本号>
Status:       <运行状态>"
```

此工具并行发送 5 个 PINE 操作码（Title、ID、UUID、GameVersion、Status），任一字段失败时返回 `(unavailable)` 而不影响其他字段。

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

### 内存读取示例

#### 定点读取

```typescript
// 读取 32 位无符号整数
工具输入: { "address": 0x00100000 }
预期输出: "0x00100000: 12345 (0x3039)"

// 读取 64 位值（返回字符串形式的十进制数，因为 JS 无法精确表示超过 2^53 的整数）
工具输入: { "address": 0x00200000 }
预期输出: "0x00200000: 18446744073709551615 (0xFFFFFFFFFFFFFFFF)"
```

#### 批量读取

`pine_read_range` 是最高效的批量读取方式，内部实现为串行调用最大对齐宽度的读取操作。实测 PCSX2 v2.6.3 下读取 4096 字节约需 52ms。

```typescript
工具输入: { "address": 0x00100000, "length": 256 }
预期输出: "0x00100000: <256字节的十六进制数据>"
```

> 默认情况下请求完全串行执行，以避免 PCSX2 请求队列错位。可通过设置 `PINE_PIPELINE_BATCH` 环境变量调整流水线深度。

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

### 内存写入示例

```typescript
// 写入 8 位值
工具输入: { "address": 0x00100000, "value": 255 }

// 写入 32 位值
工具输入: { "address": 0x00100004, "value": 12345678 }
预期输出: "Wrote 12345678 (0xBC614E) → 0x00100004"
```

> 注意：内存写入是**破坏性操作**，会覆盖原有数据。

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

### 存档管理

```typescript
// 保存到槽位 3
工具输入: { "slot": 3 }
预期输出: "Saved state to slot 3"

// 从槽位 5 加载
工具输入: { "slot": 5 }
预期输出: "Loaded state from slot 5"
```

PCSX2 存档文件通常位于：
- Windows: `%USERPROFILE%\Documents\PCSX2\sstates`
- Linux: `~/.config/PCSX2/sstates`

文件名格式：`<序列号> (<CRC>).<槽位号>.p2s`

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

## 常见问题排查

| 问题症状 | 原因与解决方案 |
|----------|---------------|
| `Cannot reach PINE server` | 模拟器未运行、PINE 未启用、或槽位号不匹配。检查 `PINE_SLOT` 配置。 |
| `PINE FAIL response` (0xFF) | 模拟器拒绝请求，通常是因为未加载游戏或地址未映射。 |
| 读取返回零值 | 地址位于未分配区域，尝试从 `0x00100000` 开始（几乎总是在 EE RAM 范围内）。 |
| 数据看起来损坏 | 检查字节序，PINE 返回小端序；字符串应使用 `read_range` 风格的字节读取。 |
| `pine_ping` 超时（10秒） | **PCSX2 PINE 服务器可能卡死**。请求队列在超过约 6 个飞行中请求时会静默丢包，导致后续所有回复错位。**解决方案：完全重启 PCSX2**，仅重新连接无效。 |

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

## 开发相关

### 本地开发

```bash
npm install
npm run dev      # 启动 tsc --watch 监听文件变化
```

### 快速测试

在运行 PCSX2 的环境下执行冒烟测试：

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

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

## 版本历史

| 版本 | 日期 | 主要变更 |
|------|------|----------|
| 0.2.1 | 2026-05-15 | 工具描述质量改进，符合 Glama Tool Definition Quality Score 规范 |
| 0.2.0 | 2026-05-10 | 新增 `pine_read_range` 批量读取、10秒超时机制 |
| 0.1.x | 早期版本 | 基础功能实现 |

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

## 相关项目

- [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) — mcp-pine 的姊妹项目，支持 mGBA 模拟器（Game Boy Advance），额外包含按键输入和截图功能
- [PINE 协议规范](https://github.com/GovanifY/pine) — 底层 IPC 标准文档

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

---

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

## 故障排除

### 相关页面

相关主题：[模拟器配置](#page-emulator-setup), [配置参考](#page-configuration), [使用范例](#page-recipes)

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

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

- [README.md](https://github.com/dmang-dev/mcp-pine/blob/main/README.md)
- [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)
- [package.json](https://github.com/dmang-dev/mcp-pine/blob/main/package.json)
</details>

# 故障排除

本文档提供 mcp-pine 与 PINE 协议模拟器通信时遇到的常见问题诊断与解决方案。

## 连接问题

### 无法连接 PINE 服务器

**症状**: 调用任何工具时返回 `Cannot reach PINE server` 错误。

**可能原因**:

| 原因 | 检查方法 | 解决方案 |
|------|----------|----------|
| 模拟器未运行 | 检查模拟器进程是否启动 | 启动 PCSX2/RPCS3/Duckstation |
| PINE 功能未启用 | 模拟器设置中搜索 "PINE" | Settings → Advanced → Enable PINE Server |
| 端口/插槽号不匹配 | 检查 `PINE_SLOT` 环境变量 | 设置 `PINE_SLOT=28011` (PCSX2 默认值) |
| 模拟器未加载游戏 | 确认游戏已加载 | 加载任意游戏后再尝试 |

**排查步骤**:

```mermaid
graph TD
    A[连接失败] --> B{模拟器运行中?}
    B -->|否| C[启动模拟器]
    B -->|是| D{PINE已启用?}
    D -->|否| E[启用PINE Server]
    D -->|是| F{游戏已加载?}
    F -->|否| G[加载游戏]
    F -->|是| H{端口匹配?}
    H -->|否| I[设置PINE_SLOT]
    H -->|是| J[检查防火墙/权限]
```

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

### 连接方式差异

| 操作系统 | 连接方式 | 路径/地址格式 |
|----------|----------|---------------|
| Linux/macOS | Unix Domain Socket | `$XDG_RUNTIME_DIR/<target>.sock.<slot>` 或 `$TMPDIR/<target>.sock.<slot>` |
| Windows | TCP | `127.0.0.1:<slot>` |
| 默认目标 | PCSX2 | `PINE_TARGET=pcsx2` |
| 替代目标 | RPCS3/Duckstation | `PINE_TARGET=rpcs3` 或 `PINE_TARGET=duckstation` |

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

## PINE 协议错误响应

### PINE FAIL 响应 (0xFF)

**症状**: 返回 `PINE FAIL response` (0xFF) 错误。

**可能原因**:

| 原因 | 诊断方法 | 解决方案 |
|------|----------|----------|
| 未加载游戏 | 检查模拟器状态 | 加载游戏后重试 |
| 地址未映射 | 尝试 `0x00100000` (EE RAM) | 使用已确认有效的地址 |
| 只读区域写入 | 检查目标区域类型 | BIOS/IOP ROM 写入会被静默丢弃 |

**地址空间参考**:

| 区域 | 地址范围 | 说明 |
|------|----------|------|
| EE Main RAM | `0x00100000` - `0x01FFFFFF` | 99% 的游戏状态在此区域 |
| IOP RAM | `0x1C000000+` | IOP 处理器内存 |
| Scratchpad | 特定区域 | 高速缓存区域 |

资料来源：[README.md:54]() [src/tools.ts:35-39]()

## 内存读取问题

### 读取返回全零

**症状**: `pine_read8/16/32/64` 返回值全为 0。

**诊断流程**:

```mermaid
graph LR
    A[读取返回0] --> B{地址有效?}
    B -->|尝试0x00100000| C{仍然返回0?}
    C -->|是| D[游戏未正确加载]
    C -->|否| E[原地址在未分配区域]
    B -->|无效地址| F[使用有效地址重试]
```

**解决方案**: 首先尝试 `0x00100000`，这是 EE 主 RAM 的起始地址，几乎总是可访问的。

### 数据损坏/值看起来不正确

**症状**: 读取的值看起来错误或损坏。

**可能原因**: 字节序问题。PINE 协议返回小端序数据。

| 操作类型 | 字节序 | 处理方式 |
|----------|--------|----------|
| 字符串读取 | UTF-8 | 使用 `read_range` 逐字节读取 |
| 数值读取 | Little-Endian | LSB 在低位地址，MSB 在高位地址 |

**解决方案**: 对于字符串，使用 `pine_read_range` 进行字节级读取。对于数值，确认解析时使用小端序。

## 超时问题

### PINE 调用超时 (10秒)

**症状**: `pine_ping` 在某些高频使用后开始超时。

**根本原因**: PCSX2 的 PINE 服务器请求队列存在已知问题。

```mermaid
graph TD
    A[PCSX2 PINE Server] --> B[请求队列]
    B --> C{请求数量 <= 6}
    C -->|是| D[正常处理]
    C -->|否| E[请求被静默丢弃]
    E --> F[回复流水线失步]
    F --> G[所有后续请求超时]
    G --> H[甚至ping也超时]
```

**已知限制**:

- PCSX2 的 PINE 服务器请求队列脆弱
- 同时有超过约 6 个进行中的请求时会静默丢弃请求
- 一旦失步，即使 `pine_ping` 也会超时
- **重新连接无法恢复，必须完全重启 PCSX2**

资料来源：[README.md:55-56]() [CHANGELOG.md:45-52]() [src/pine.ts:60-68]()

**恢复步骤**:

1. 完全关闭 PCSX2（不只是暂停）
2. 重新启动 PCSX2
3. 重新加载游戏
4. 重新连接 mcp-pine

## 性能问题

### `pine_read_range` 速度较慢

**现象**: 大范围内存读取比 mGBA 的 `read_range` 慢。

**原因分析**:

| 特性 | PINE | mGBA |
|------|------|------|
| 原生批量读取 | ❌ 无 | ✅ 有 |
| 实现方式 | 串行发送多个 read64/32/16/8 | 单次批量请求 |
| 4096字节读取耗时 | ~52ms (PCSX2 v2.6.3) | 显著更快 |

**延迟基准**:

| 操作 | 耗时 | 说明 |
|------|------|------|
| 完整 4096 字节读取 | ~52ms | 循环回程 TCP 性能 |
| 相当于模拟帧数 | < 2 帧 | 60fps 下约 33ms/帧 |

资料来源：[README.md:57-58]() [CHANGELOG.md:37-40]()

### 流水线批处理选项

**环境变量**: `PINE_PIPELINE_BATCH`

| 值 | 行为 | 风险 |
|----|------|------|
| 1 (默认) | 完全串行请求 | 无 |
| >= 2 | 启用流水线 | 可能导致 PCSX2 失步 |

```typescript
// src/pine.ts 中的实现逻辑
const PIPELINE_BATCH = Number.parseInt(process.env.PINE_PIPELINE_BATCH ?? "1", 10) || 1;

for (let i = 0; i < steps.length; i += PIPELINE_BATCH) {
    const batch = steps.slice(i, i + PIPELINE_BATCH);
    const promises = batch.map((s) => /* ... */);
    const results = await Promise.all(promises);
}
```

**警告**: 启用流水线可能导致 PCSX2 PINE 服务器失步。仅在能够容忍偶尔模拟器重启的情况下使用。

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

## 对齐问题

### 未对齐地址访问

**症状**: 多字节读取返回值看起来错误或损坏。

**根本原因**: PINE on PCSX2 **不强制对齐要求**。

| 操作 | 对齐要求 | 未对齐行为 |
|------|----------|------------|
| `pine_read8` / `pine_write8` | 无 | 正常工作 |
| `pine_read16` / `pine_write16` | 2字节对齐 | 返回对齐地址以下的字节 |
| `pine_read32` / `pine_write32` | 4字节对齐 | 返回对齐地址以下的字节 |
| `pine_read64` / `pine_write64` | 8字节对齐 | 返回对齐地址以下的字节 |

**解决方案**:

1. 确保传入对齐的地址
2. 如需未对齐访问，使用 `pine_read_range` 逐字节读取后自行组装

```mermaid
graph LR
    A[需要读取0x1003] --> B{可接受的访问方式?}
    B --> C[使用read_range读取0x1000-0x1007]
    B --> D[忽略不对齐的write64]
    C --> E[自行组装字节]
```

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

## 工具调用错误

### 各工具的错误条件汇总

| 工具 | 失败模式 | 错误信息 |
|------|----------|----------|
| `pine_ping` | 连接失败/PINE 失步 | `Cannot reach PINE server` / 超时 |
| `pine_get_info` | 连接失败/部分字段不可用 | 返回 `(unavailable)` |
| `pine_get_status` | 连接失败 | `PINE FAIL response` |
| `pine_read*` | 无效地址/未对齐 | PINE FAIL 或错误值 |
| `pine_write*` | 只读区域/无效地址 | PINE FAIL (静默丢弃) |
| `pine_save_state` | 插槽超出范围 | Schema 拒绝 (0-255) |
| `pine_load_state` | 插槽无存档 | PINE FAIL |

### 存档状态槽位

| 槽位范围 | 约定 | 实际协议支持 |
|----------|------|--------------|
| 0-255 | 完整协议支持 | ✅ |
| 0-9 | PCSX2 GUI 映射到 F1-F10 | 推荐使用 |

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

## 环境变量参考

| 变量名 | 默认值 | 说明 |
|--------|--------|------|
| `PINE_TARGET` | `pcsx2` | 模拟器名称，决定 Unix socket 文件前缀 |
| `PINE_SLOT` | `28011` | PINE 插槽号，也是 TCP 端口号 |
| `PINE_PIPELINE_BATCH` | `1` | 流水线批处理大小，1=完全串行 |

资料来源：[README.md:29-32]() [src/pine.ts:70]()

## 调试技巧

### 快速冒烟测试

```bash
# 确保模拟器运行且 PINE 已启用
node .scratch/smoke.cjs
```

### 推荐的调试工作流

1. **首先验证连接**: 使用 `pine_ping`
2. **获取基本信息**: 使用 `pine_get_info` 确认游戏加载
3. **检查状态**: 使用 `pine_get_status`
4. **从已知地址开始**: 尝试 `0x00100000` 验证读取功能
5. **逐步深入**: 确认基础功能后再访问特定内存区域

### 连接质量检查

```mermaid
graph TD
    A[开始调试] --> B[ping成功?]
    B -->|否| C[检查模拟器/网络]
    B -->|是| D[get_info成功?]
    D -->|否| E[无游戏加载]
    D -->|是| F[测试已知地址]
    F --> G{0x00100000返回非零?}
    G -->|否| H[EE RAM未映射]
    G -->|是| I[基础连接正常]
```

## 已知限制

| 限制 | 描述 | 状态 |
|------|------|------|
| PCSX2 请求队列脆弱 | >6 流水线请求会导致失步 | 已知问题，无法自动恢复 |
| 无原生批量读取 | `read_range` 串行实现 | 设计限制，性能可接受 |
| 未对齐访问静默损坏 | PCSX2 不强制对齐 | 需客户端保证 |
| RPCS3 兼容性未充分测试 | Wire-level 兼容性待验证 | 实验性支持 |

资料来源：[README.md:45-51]() [CHANGELOG.md:48-54]()

## 获取帮助

如遇到本文档未覆盖的问题，请：

1. 确认问题可重现
2. 记录模拟器版本、PINE 设置、错误信息
3. 在 [GitHub Issues](https://github.com/dmang-dev/mcp-pine/issues) 创建 Issue

---

---

## Doramagic 踩坑日志

项目：dmang-dev/mcp-pine

摘要：发现 8 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：安装坑 - 来源证据：Submit listing PR to punkpeye/awesome-mcp-servers。

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

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

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

- 严重度：medium
- 证据强度：source_linked
- 发现：项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。
- 对用户的影响：安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。
- 建议检查：列出会写入的配置文件、目录和卸载/回滚步骤。
- 防护动作：涉及宿主配置目录时必须给回滚路径，不能只给安装命令。
- 证据：capability.host_targets | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | host_targets=mcp_host, claude

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

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 建议检查：将假设转成下游验证清单。
- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。
- 证据：capability.assumptions | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | README/documentation is current enough for a first validation pass.

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

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。
- 证据：evidence.maintainer_signals | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | last_activity_observed missing

## 5. 安全/权限坑 · 下游验证发现风险项

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：下游已经要求复核，不能在页面中弱化。
- 建议检查：进入安全/权限治理复核队列。
- 防护动作：下游风险存在时必须保持 review/recommendation 降级。
- 证据：downstream_validation.risk_items | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | no_demo; severity=medium

## 6. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 建议检查：把风险写入边界卡，并确认是否需要人工复核。
- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。
- 证据：risks.scoring_risks | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | no_demo; severity=medium

## 7. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。
- 防护动作：issue/PR 响应未知时，必须提示维护风险。
- 证据：evidence.maintainer_signals | github_repo:1234265030 | https://github.com/dmang-dev/mcp-pine | issue_or_pr_quality=unknown

## 8. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。
- 证据：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 -->
