Doramagic 项目包 · 项目说明书

mcp-pine 项目

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

项目介绍

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

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 核心组件

继续阅读本节完整说明和来源证据。

章节 连接与自检

继续阅读本节完整说明和来源证据。

章节 游戏信息查询

继续阅读本节完整说明和来源证据。

概述

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

资料来源:README.md

项目背景与目标

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

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

资料来源: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

系统架构

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

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

核心组件

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

资料来源:src/pine.tssrc/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_read88 位单字节读取
pine_read1616 位2 字节小端序
pine_read3232 位4 字节小端序,用于指针、RGBA 颜色
pine_read6464 位8 字节完整 PS2 EE 指针、大 ID
pine_read_range可变自动选择最大对齐批量读取最多 4096 字节

内存写入

工具名数据宽度对齐要求风险提示
pine_write88 位直接写入,无撤销
pine_write1616 位2 字节覆盖式写入,绕过 TLB
pine_write3232 位4 字节32 位 Cheats/Pokes
pine_write6464 位8 字节完整 64 位值写入

状态管理

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

资料来源:src/tools.ts

配置与环境变量

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

环境变量默认值用途
PINE_TARGETpcsx2指定模拟器名称,用于 Unix socket 文件路径前缀
PINE_SLOT28011PINE 插槽号(Linux/macOS)或 TCP 端口(Windows)
PINE_PIPELINE_BATCH1批量请求数,控制性能与稳定性权衡

连接路径说明

操作系统连接方式路径格式
LinuxUnix Socket$XDG_RUNTIME_DIR/<target>.sock.<slot>$TMPDIR/<target>.sock.<slot>/tmp/<target>.sock.<slot>
macOSUnix Socket同 Linux
WindowsTCP127.0.0.1:<slot>

资料来源:README.md

安装与部署

方式一:npm 全局安装

npm install -g mcp-pine

方式二:npx 临时运行

npx -y mcp-pine

方式三:源码开发

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

Claude Code 集成

claude mcp add pine --scope user mcp-pine

验证连接:

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
{
  "mcpServers": {
    "pine": {
      "command": "mcp-pine"
    }
  }
}

资料来源: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 msPCSX2 v2.6.3,loopback TCP
单次 pine_ping<1 ms本地连接
状态保存/加载取决于存档大小通过 PINE 协议传输

资料来源:README.mdCHANGELOG.md

项目依赖

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

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

开发依赖:

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

资料来源:package.json

开发指南

本地开发

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

冒烟测试

在运行 PCSX2 并启用 PINE Server 后:

node .scratch/smoke.cjs

相关项目

  • mcp-mgba — 姐妹项目,支持 mGBA Game Boy Advance 模拟器,包含按钮输入和截图功能(mcp-pine 不支持)
  • PINE 协议规范 — 底层 IPC 标准文档

资料来源:README.md

版本历史

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

资料来源:CHANGELOG.md

许可证

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

资料来源:README.md

快速开始

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

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 方式一:全局安装(推荐)

继续阅读本节完整说明和来源证据。

章节 方式二:npx 免安装运行

继续阅读本节完整说明和来源证据。

章节 方式三:源码本地开发

继续阅读本节完整说明和来源证据。

架构概览

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 CodeAI 助手界面
操作系统Windows / macOS / Linux跨平台支持

安装方式

方式一:全局安装(推荐)

npm install -g mcp-pine

安装完成后,mcp-pine 命令将全局可用:

mcp-pine

资料来源:README.md:安装方法

方式二:npx 免安装运行

如仅需临时使用,无需安装依赖:

npx -y mcp-pine

资料来源:README.md:npx 安装

方式三:源码本地开发

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

开发模式热重载:

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

资料来源:README.md:clone and develop

环境变量配置

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

环境变量默认值说明
PINE_TARGETpcsx2模拟器标识名称,用于生成 Unix 套接字路径 <target>.sock.<slot>
PINE_SLOT28011PINE 槽位/端口号
PINE_HOST127.0.0.1TCP 目标主机(Windows 默认使用 TCP)
PINE_SOCKET_PATH自动解析Unix 套接字路径,优先级最高
PINE_PIPELINE_BATCH1请求流水线批次大小,建议保持默认

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

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. 运行命令:
PINE_TARGET=rpcs3 PINE_SLOT=<端口号> mcp-pine

资料来源:README.md:RPCS3

Duckstation 设置

  1. 确认 Duckstation 构建版本包含 PINE 服务器(并非所有版本都包含)
  2. 如包含,设置环境变量后运行:
PINE_TARGET=duckstation PINE_SLOT=<端口号> mcp-pine

资料来源:README.md:Duckstation

MCP 客户端配置

Claude Code (CLI)

添加 MCP 服务器:

claude mcp add pine --scope user mcp-pine

验证连接状态:

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

添加服务器配置:

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

修改配置后需重启 Claude Desktop。

资料来源:README.md:Claude Desktop

其他 MCP 客户端

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

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:工具定义

快速验证流程

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"

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

# 步骤 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

下一步

资料来源:README.md:安装方法

系统架构

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

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 3.1 MCP Server

继续阅读本节完整说明和来源证据。

章节 3.2 PineClient

继续阅读本节完整说明和来源证据。

章节 3.3 工具注册系统

继续阅读本节完整说明和来源证据。

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
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 是整个应用的入口点,负责初始化和启动服务。

// 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()获取模拟器和游戏信息

连接传输方式:

// 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 数组定义,每个工具包含完整的元数据:

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

工具处理流程:

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 协议采用二进制格式,消息结构如下:

字段大小字节序说明
Size4 字节Little-endian消息总长度
Opcode1 字节-操作码
PayloadN 字节Little-endian操作数据

Opcode 定义:

操作码功能
Version0x01获取模拟器版本
Title0x02获取游戏标题
ID0x03获取游戏序列号
UUID0x04获取光盘 CRC
GameVersion0x05获取游戏版本
Status0x06获取运行状态
Read80x10读取 8 位
Read160x11读取 16 位
Read320x12读取 32 位
Read640x13读取 64 位
Write80x14写入 8 位
Write160x15写入 16 位
Write320x16写入 32 位
Write640x17写入 64 位
SaveState0x30保存状态
LoadState0x31加载状态

资料来源:src/pine.ts:1-50

4.2 请求队列管理

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

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

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

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() 方法实现了高效的批量内存读取:

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_BATCH1每批并发请求数

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

5. 配置系统

5.1 环境变量配置

变量名默认值说明
PINE_TARGETpcsx2模拟器名称,用于 Unix socket 文件路径前缀
PINE_SLOT28011PINE 槽位号/端口号
PINE_HOST127.0.0.1TCP 主机地址
PINE_SOCKET_PATH-自定义 Unix socket 路径
PINE_PIPELINE_BATCH1批量读取并发数

5.2 Socket 路径解析

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_read81 字节读取字节
pine_read162 字节2 字节读取 16 位整数
pine_read324 字节4 字节读取 32 位整数
pine_read648 字节8 字节读取 64 位整数
pine_write81 字节写入字节
pine_write162 字节2 字节写入 16 位整数
pine_write324 字节4 字节写入 32 位整数
pine_write648 字节8 字节写入 64 位整数
pine_read_range1-4096 字节自动适配批量读取内存区域

6.3 状态管理工具

工具名参数说明
pine_save_stateslot: 0-255保存游戏状态到指定槽位
pine_load_stateslot: 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 模拟器状态枚举

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

状态值映射:

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

8.2 64 位值处理

由于 JavaScript Number 类型精度限制(最大安全整数 2^53),64 位值通过字符串格式传输:

// 返回值格式
"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. 依赖关系

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 秒超时防止请求永久挂起

资料来源:src/index.ts:1-50

PINE 协议详解

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

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 1.1 支持的模拟器

继续阅读本节完整说明和来源证据。

章节 2.1 系统架构图

继续阅读本节完整说明和来源证据。

章节 2.2 核心组件

继续阅读本节完整说明和来源证据。

1. 概述

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

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

1.1 支持的模拟器

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

资料来源:README.md:1-50

2. 架构设计

2.1 系统架构图

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.Version0x01获取模拟器版本UTF-8 字符串
Op.Title0x02获取游戏标题UTF-8 字符串
Op.ID0x03获取游戏序列号UTF-8 字符串
Op.UUID0x04获取光盘 CRCUTF-8 字符串
Op.GameVersion0x05获取游戏版本UTF-8 字符串
Op.Status0x0F获取模拟器运行状态32 位整数
Op.SaveState0x10保存当前状态到指定槽位
Op.LoadState0x11从指定槽位加载状态
Op.Read80x20读取 8 位数据字节
Op.Read160x21读取 16 位数据小端整数
Op.Read320x22读取 32 位数据小端整数
Op.Read640x23读取 64 位数据小端整数
Op.Write80x30写入 8 位数据
Op.Write160x31写入 16 位数据
Op.Write320x32写入 32 位数据
Op.Write640x33写入 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 帧解析流程

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_TARGETpcsx2Unix Socket 文件名前缀
槽位/端口PINE_SLOT28011Unix Socket 序号或 TCP 端口

5.2 连接路径解析

// 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 工具通过客户端实现的序列读取实现:

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_BATCH1每批发送的请求数,增大可降低延迟但有同步风险

资料来源: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 核心方法签名

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 以内的整数,read64write64 方法使用 bigint 类型:

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

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

资料来源:src/pine.ts:40-50

10. 与 MCP 工具的映射

MCP 工具名称底层 PINE 操作功能
pine_pingVersion连接测试
pine_get_infoTitle + ID + UUID + GameVersion + Status批量获取游戏信息
pine_get_statusStatus获取运行状态
pine_read8/16/32/64Read8/16/32/64单值读取
pine_read_range串行调用 Read*批量读取
pine_write8/16/32/64Write8/16/32/64单值写入
pine_save_stateSaveState保存存档
pine_load_stateLoadState加载存档

资料来源:src/tools.ts:100-200

11. 项目信息

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

资料来源:package.json:1-30

资料来源:README.md:1-50

工具参考

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

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 pineping

继续阅读本节完整说明和来源证据。

章节 pinegetinfo

继续阅读本节完整说明和来源证据。

章节 pinegetstatus

继续阅读本节完整说明和来源证据。

工具分类概览

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

类别工具数量用途
连接与自检2连接验证、模拟器信息获取
内存读取5单字节到64位值的读取,支持范围读取
内存写入48/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字节的连续内存区域。

参数

参数类型描述
addressinteger起始地址
lengthinteger要读取的字节数(最大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

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

参数

参数类型描述
addressinteger目标地址(必须符合对应宽度对齐要求)
valueinteger/bigint要写入的值

返回格式Wrote VAL_HEX → ADDR_HEX

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

错误场景

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

资料来源:src/tools.ts:145-170

存档管理工具

pine_save_state

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

参数

参数类型范围描述
slotinteger0-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 文件,否则存档可能不兼容。

工具调用流程

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

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_TARGETpcsx2模拟器标识名,用于 Unix socket 文件路径前缀(Linux/macOS)或 TCP 连接标识
PINE_SLOT28011PINE 槽位/端口号
PINE_HOST127.0.0.1TCP 连接主机地址
PINE_SOCKET_PATH自动解析Unix socket 路径,覆盖其他 socket 相关配置
PINE_PIPELINE_BATCH1批量请求数量,仅在了解 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_read8addressstring
pine_read16addressstring
pine_read32addressstring
pine_read64addressstring
pine_read_rangeaddress, lengthstring
pine_write8address, valuestring
pine_write16address, valuestring
pine_write32address, valuestring
pine_write64address, valuestring
pine_save_stateslotstring
pine_load_stateslotstring

资料来源:src/tools.ts:90-140

内存操作指南

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

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 PS2 EE 主内存

继续阅读本节完整说明和来源证据。

章节 连接传输方式

继续阅读本节完整说明和来源证据。

章节 单值读取工具

继续阅读本节完整说明和来源证据。

概述

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

内存操作由 8 个 MCP 工具组成,分为读取写入两大类:

类别工具数据宽度
读取pine_read81 字节
读取pine_read162 字节
读取pine_read324 字节
读取pine_read648 字节
读取pine_read_range批量(最大 4096 字节)
写入pine_write81 字节
写入pine_write162 字节
写入pine_write324 字节
写入pine_write648 字节

资料来源:src/tools.ts:56-130

地址空间与内存布局

PS2 EE 主内存

PS2 的 Emotion Engine(EE)主内存地址空间是最常用的访问区域:

地址范围说明
0x00100000 - 0x01FFFFFFEE 主 RAM(游戏状态主要存储区)
0x1C000000+IOP RAM(声音/输入子系统)
其他预留/映射区域
💡 建议从 0x00100000 开始探测,该地址几乎所有游戏都会加载到 EE RAM 中。

资料来源:src/tools.ts:20-25

连接传输方式

平台传输方式地址格式
Linux/macOSUnix Domain Socket$XDG_RUNTIME_DIR/<PINE_TARGET>.sock.<PINE_SLOT>
WindowsTCP127.0.0.1:<PINE_SLOT>

资料来源:README.md:45-50

读取操作

单值读取工具

工具对齐要求返回格式
pine_read8ADDR: VAL_DEC (0xVAL_HEX)
pine_read162 字节对齐ADDR: VAL_DEC (0xVAL_HEX)
pine_read324 字节对齐ADDR: VAL_DEC (0xVAL_HEX)
pine_read648 字节对齐字符串格式(JS 无法原生表示完整 u64)

#### 64 位值处理

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

// 资料来源: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 字节:

// 资料来源: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;
}

#### 读取策略

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

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_BATCH1每批发送请求数;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_write8number
pine_write162 字节对齐number
pine_write324 字节对齐number
pine_write648 字节对齐number(JS 会损失精度,模拟器端可能截断)
⚠️ 破坏性操作:写入会直接修改游戏内存,可能导致游戏崩溃或存档损坏。
// 资料来源: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. 在客户端自行组装字节序
// 示例:读取未对齐的 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
graph LR
    subgraph "32 位值 0x12345678 在地址 0x00100000"
        A0["0x00100000: 0x78 (LSB)"]
        A1["0x00100001: 0x56"]
        A2["0x00100002: 0x34"]
        A3["0x00100003: 0x78 (MSB)"]
    end
💡 字符串读取(getTitlegetId 等)使用 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 手动组装

完整使用流程

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_TARGETpcsx2模拟器名称前缀(socket 文件名)
PINE_SLOT28011PINE 槽位号(Linux/macOS 为 socket 后缀,Windows 为 TCP 端口)
PINE_HOST127.0.0.1主机地址(可覆盖)
PINE_SOCKET_PATH自动完整 socket 路径(完全覆盖自动解析)
PINE_PIPELINE_BATCH1批量请求数(建议仅在非 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从槽位加载游戏状态

资料来源:src/tools.ts:56-130

存档状态管理

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

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 组件层次

继续阅读本节完整说明和来源证据。

章节 数据流

继续阅读本节完整说明和来源证据。

章节 PineClient 类方法

继续阅读本节完整说明和来源证据。

概述

存档状态管理(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 (部分版本)                   │
└─────────────────────────────────────────────┘

数据流

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 类的两个核心异步方法:

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

参数说明:

参数类型范围说明
slotnumber0-255存档槽位编号

协议细节:

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

资料来源:src/pine.ts:saveState方法定义

协议层交互

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

{
  "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

{
  "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_TARGETpcsx2模拟器名称,用于 Unix socket 文件路径前缀
PINE_SLOT28011PINE 通信槽位/端口号

连接配置差异

平台连接方式地址格式
Linux/macOSUnix Socket$XDG_RUNTIME_DIR/<target>.sock.<slot>,回退到 $TMPDIR/tmp
WindowsTCP127.0.0.1:<slot>

工作流程示例

基础保存-加载循环

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_statepine_load_state,实现自动化测试、内存分析、实验回溯等工作流程。

资料来源:src/tools.ts:工具定义区域

安装指南

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

章节 相关页面

继续阅读本节完整说明和来源证据。

概述

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

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

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

模拟器配置

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

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 核心参数

继续阅读本节完整说明和来源证据。

章节 连接地址解析

继续阅读本节完整说明和来源证据。

章节 启用 PINE 服务器

继续阅读本节完整说明和来源证据。

概述

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

当前项目支持的模拟器包括 PCSX2RPCS3Duckstation,每种模拟器在 PINE 功能的实现和配置方式上存在差异。

支持的模拟器

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

资料来源:README.md:1-60

环境变量配置

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

核心参数

环境变量默认值说明
PINE_TARGETpcsx2模拟器名称,用于构建 Unix socket 文件路径(Linux/macOS)或 TCP 连接标识(Windows)
PINE_SLOT28011PINE 槽位编号,对应模拟器中配置的端口号
PINE_PIPELINE_BATCH1请求流水线批次大小,控制并发请求数量

资料来源:README.md:40-45

连接地址解析

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

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:

PINE_TARGET=pcsx2 PINE_SLOT=28011 mcp-pine

Windows(TCP 强制):

set PINE_SLOT=28011
mcp-pine

RPCS3 配置指南

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

启用 IPC 服务器

  1. 进入 Configuration → Advanced → Enable IPC server(菜单位置可能因版本而异)
  2. 记录配置的端口号
  3. 使用以下命令运行:
PINE_TARGET=rpcs3 PINE_SLOT=<端口号> mcp-pine

资料来源:README.md:65-72

Duckstation 配置指南

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

检查 PINE 支持

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

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

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

资料来源:README.md:35-38

MCP 客户端集成

Claude Code (CLI)

claude mcp add pine --scope user mcp-pine

验证连接:

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
{
  "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 - 0x01FFFFFFEE 主内存(99% 游戏状态所在)
0x1C000000+IOP 内存
特定区域Scratchpad 等
⚠️ 多字节读写(16/32/64 位)必须对齐地址。PCSX2 的 PINE 不强制对齐,非对齐访问会静默返回损坏数据。

资料来源:src/tools.ts:50-80

安装方式

方式 A:npm 全局安装

npm install -g mcp-pine

方式 B:npx 临时运行

npx -y mcp-pine

方式 C:源码开发

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

资料来源:README.md:42-50

开发调试

运行开发模式(TypeScript 监视编译):

npm run dev

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

node .scratch/smoke.cjs

资料来源:README.md:105-112

资料来源:README.md:1-60

配置参考

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

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 完整配置表

继续阅读本节完整说明和来源证据。

章节 PINETARGET

继续阅读本节完整说明和来源证据。

章节 PINESLOT

继续阅读本节完整说明和来源证据。

概述

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

配置分为三个层级:

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

环境变量配置

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

完整配置表

环境变量默认值类型说明
PINE_TARGETpcsx2string模拟器标识名,用于 Unix socket 文件路径前缀
PINE_SLOT28011numberPINE 槽位号,TCP 模式下作为端口号
PINE_HOST127.0.0.1stringTCP 连接模式下的目标主机(覆盖自动检测)
PINE_SOCKET_PATH自动解析stringUnix socket 文件路径(覆盖自动检测)
PINE_PIPELINE_BATCH1number请求管道批大小,1=完全串行

资料来源:README.md:38-45

PINE_TARGET

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

# 连接到 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 编号。

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

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

PINE_HOST 与 PINE_SOCKET_PATH

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

# 强制使用 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 等批量读取操作的并行请求数。

# 完全串行(默认,最安全)
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 对象:

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

使用示例:

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 根据运行平台自动选择最优传输方式:

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 路径按以下优先级确定:

优先级环境变量示例路径
1PINE_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 连接:

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 协议进行通信,帧格式如下:

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

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

操作码映射

操作码名称方向说明
0x01VersionR获取模拟器版本
0x02TitleR获取游戏标题
0x03IDR获取游戏序列号
0x04UUIDR获取光盘 CRC
0x05GameVersionR获取游戏版本
0x06StatusR获取运行状态
0x10SaveStateW保存状态到槽位
0x11LoadStateW从槽位加载状态
0x20-0x23Read8/16/32/64R读取内存
0x30-0x33Write8/16/32/64W写入内存

资料来源:src/pine.ts:1-28

批量读取实现

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

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 服务器:

PINE_TARGET=duckstation PINE_SLOT=<port> mcp-pine

故障排除

连接问题诊断

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)

# 使用所有默认值
mcp-pine

等价于:

PINE_TARGET=pcsx2 PINE_SLOT=28011 mcp-pine

连接远程模拟器

PINE_HOST=192.168.1.50 PINE_SLOT=28011 mcp-pine

自定义 Unix Socket 路径

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

性能调优(风险自负)

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

NPM 方式运行

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:38-45

使用范例

mcp-pine 是一个基于 Model Context Protocol (MCP) 的桥接工具,用于连接 Claude 等 AI 助手与支持 PINE(PlayStation 2 Inter-Process Communication)协议的模拟器(如 PCSX2、RPCS3、Duckstation)。通过 mcp-pine,用户可以让 AI 直接读取和写入模拟器的内存...

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 方式一:npm 全局安装

继续阅读本节完整说明和来源证据。

章节 方式二:npx 直接运行

继续阅读本节完整说明和来源证据。

章节 方式三:源码安装

继续阅读本节完整说明和来源证据。

概述

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

系统架构

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

安装方式

方式一:npm 全局安装

npm install -g mcp-pine

方式二:npx 直接运行

npx -y mcp-pine

方式三:源码安装

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

资料来源:README.md:40-50

MCP 客户端配置

Claude Code (CLI)

claude mcp add pine --scope user mcp-pine

验证连接:

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

配置内容:

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

修改配置后需重启 Claude Desktop。

资料来源:README.md:18-38

环境变量配置

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

资料来源:README.md:42-48

模拟器配置

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

RPCS3 配置步骤

  1. 进入 Configuration → Advanced → Enable IPC server
  2. 记下配置的端口号
  3. 运行命令:PINE_TARGET=rpcs3 PINE_SLOT=<端口> mcp-pine
注意:RPCS3 的 IPC 实现参考了 PINE 操作码,但协议层面的兼容性尚未经过充分测试。

资料来源:README.md:62-68

Duckstation 配置步骤

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

资料来源:README.md:70-71

工具清单

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

典型使用流程

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 - 0x01FFFFFFEE 主内存(99% 的游戏状态位于此处)
0x1C000000+IOP 内存
0x10000000 区域Scratchpad(高速缓存)
重要提示:对于 16/32/64 位读取,地址必须对齐(即地址值能被读写宽度整除)。PCSX2 的 PINE 服务不强制对齐,未对齐的地址会静默返回错误数据。如需读取未对齐的数据,请使用 pine_read_range 并自行组装字节。

资料来源:src/tools.ts:40-55

工具使用详解

连接验证

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

获取游戏信息

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

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

资料来源:src/tools.ts:75-95

内存读取示例

#### 定点读取

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

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

#### 批量读取

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

工具输入: { "address": 0x00100000, "length": 256 }
预期输出: "0x00100000: <256字节的十六进制数据>"
默认情况下请求完全串行执行,以避免 PCSX2 请求队列错位。可通过设置 PINE_PIPELINE_BATCH 环境变量调整流水线深度。

资料来源:src/pine.ts:80-130

内存写入示例

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

// 写入 32 位值
工具输入: { "address": 0x00100004, "value": 12345678 }
预期输出: "Wrote 12345678 (0xBC614E) → 0x00100004"
注意:内存写入是破坏性操作,会覆盖原有数据。

资料来源:src/tools.ts:96-110

存档管理

// 保存到槽位 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

常见问题排查

问题症状原因与解决方案
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

开发相关

本地开发

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

快速测试

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

node .scratch/smoke.cjs

资料来源:README.md:118-125

版本历史

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

资料来源:CHANGELOG.md:1-50

相关项目

  • mcp-mgba — mcp-pine 的姊妹项目,支持 mGBA 模拟器(Game Boy Advance),额外包含按键输入和截图功能
  • PINE 协议规范 — 底层 IPC 标准文档

资料来源:README.md:128-131

资料来源:README.md:1-5

故障排除

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

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 无法连接 PINE 服务器

继续阅读本节完整说明和来源证据。

章节 连接方式差异

继续阅读本节完整说明和来源证据。

章节 PINE FAIL 响应 (0xFF)

继续阅读本节完整说明和来源证据。

连接问题

无法连接 PINE 服务器

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

可能原因:

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

排查步骤:

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/macOSUnix Domain Socket$XDG_RUNTIME_DIR/<target>.sock.<slot>$TMPDIR/<target>.sock.<slot>
WindowsTCP127.0.0.1:<slot>
默认目标PCSX2PINE_TARGET=pcsx2
替代目标RPCS3/DuckstationPINE_TARGET=rpcs3PINE_TARGET=duckstation

资料来源:src/pine.ts:88-100

PINE 协议错误响应

PINE FAIL 响应 (0xFF)

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

可能原因:

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

地址空间参考:

区域地址范围说明
EE Main RAM0x00100000 - 0x01FFFFFF99% 的游戏状态在此区域
IOP RAM0x1C000000+IOP 处理器内存
Scratchpad特定区域高速缓存区域

资料来源:README.md:54 src/tools.ts:35-39

内存读取问题

读取返回全零

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

诊断流程:

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

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

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

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

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

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

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

超时问题

PINE 调用超时 (10秒)

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

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

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 慢。

原因分析:

特性PINEmGBA
原生批量读取❌ 无✅ 有
实现方式串行发送多个 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 失步
// 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_write162字节对齐返回对齐地址以下的字节
pine_read32 / pine_write324字节对齐返回对齐地址以下的字节
pine_read64 / pine_write648字节对齐返回对齐地址以下的字节

解决方案:

  1. 确保传入对齐的地址
  2. 如需未对齐访问,使用 pine_read_range 逐字节读取后自行组装
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-9PCSX2 GUI 映射到 F1-F10推荐使用

资料来源:src/tools.ts:58-63

环境变量参考

变量名默认值说明
PINE_TARGETpcsx2模拟器名称,决定 Unix socket 文件前缀
PINE_SLOT28011PINE 插槽号,也是 TCP 端口号
PINE_PIPELINE_BATCH1流水线批处理大小,1=完全串行

资料来源:README.md:29-32 src/pine.ts:70

调试技巧

快速冒烟测试

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

推荐的调试工作流

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

连接质量检查

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 创建 Issue

资料来源:README.md:1 README.md:52

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

medium 来源证据:Submit listing PR to punkpeye/awesome-mcp-servers

可能阻塞安装或首次运行。

medium 可能修改宿主 AI 配置

安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。

medium 能力判断依赖假设

假设不成立时,用户拿不到承诺的能力。

medium 维护活跃度未知

新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。

Pitfall Log / 踩坑日志

项目: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

来源:Doramagic 发现、验证与编译记录