{
  "canonical_name": "dmang-dev/mcp-retroarch",
  "compilation_id": "pack_67aafeb6259246e4a556fb72360423f7",
  "created_at": "2026-05-24T13:33:02.520884+00:00",
  "created_by": "project-pack-compiler",
  "feedback": {
    "carrier_selection_notes": [
      "viable_asset_types=mcp_config, recipe, host_instruction, eval, preflight",
      "recommended_asset_types=mcp_config, recipe, host_instruction, eval, preflight"
    ],
    "evidence_delta": {
      "confirmed_claims": [
        "identity_anchor_present",
        "capability_and_host_targets_present",
        "install_path_declared_or_better"
      ],
      "missing_required_fields": [],
      "must_verify_forwarded": [
        "Run or inspect `npm install -g mcp-retroarch` in an isolated environment.",
        "Confirm the project exposes the claimed capability to at least one target host."
      ],
      "quickstart_execution_scope": "allowlisted_sandbox_smoke",
      "sandbox_command": "npm install -g mcp-retroarch",
      "sandbox_container_image": "node:22-slim",
      "sandbox_execution_backend": "docker",
      "sandbox_planner_decision": "deterministic_isolated_install",
      "sandbox_validation_id": "sbx_a903841bda3144e6ac938b534397cf4e"
    },
    "feedback_event_type": "project_pack_compilation_feedback",
    "learning_candidate_reasons": [],
    "template_gaps": []
  },
  "identity": {
    "canonical_id": "project_0a320c8c620cdec7c6ac378e8b9a9778",
    "canonical_name": "dmang-dev/mcp-retroarch",
    "homepage_url": null,
    "license": "unknown",
    "repo_url": "https://github.com/dmang-dev/mcp-retroarch",
    "slug": "mcp-retroarch",
    "source_packet_id": "phit_385abcd23bea4d0ea85e238d6cb0f2d8",
    "source_validation_id": "dval_b7fb1b1c9baf4a869e745a8f04409775"
  },
  "merchandising": {
    "best_for": "需要工具连接与集成能力，并使用 mcp_host的用户",
    "github_forks": 0,
    "github_stars": 0,
    "one_liner_en": "MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface",
    "one_liner_zh": "MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface",
    "primary_category": {
      "category_id": "tool-integrations",
      "confidence": "high",
      "name_en": "Tool Integrations",
      "name_zh": "工具连接与集成",
      "reason": "matched_keywords:mcp, server, github"
    },
    "target_user": "使用 mcp_host, claude 等宿主 AI 的用户",
    "title_en": "mcp-retroarch",
    "title_zh": "mcp-retroarch 能力包",
    "visible_tags": [
      {
        "label_en": "MCP Tools",
        "label_zh": "MCP 工具",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "product_domain-mcp-tools",
        "type": "product_domain"
      },
      {
        "label_en": "Knowledge Base Q&A",
        "label_zh": "知识库问答",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "user_job-knowledge-base-q-a",
        "type": "user_job"
      },
      {
        "label_en": "Workflow Automation",
        "label_zh": "流程自动化",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "core_capability-workflow-automation",
        "type": "core_capability"
      },
      {
        "label_en": "Node-based Workflow",
        "label_zh": "节点式流程编排",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "workflow_pattern-node-based-workflow",
        "type": "workflow_pattern"
      },
      {
        "label_en": "Local-first",
        "label_zh": "本地优先",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "selection_signal-local-first",
        "type": "selection_signal"
      }
    ]
  },
  "packet_id": "phit_385abcd23bea4d0ea85e238d6cb0f2d8",
  "page_model": {
    "artifacts": {
      "artifact_slug": "mcp-retroarch",
      "files": [
        "PROJECT_PACK.json",
        "QUICK_START.md",
        "PROMPT_PREVIEW.md",
        "HUMAN_MANUAL.md",
        "AI_CONTEXT_PACK.md",
        "BOUNDARY_RISK_CARD.md",
        "PITFALL_LOG.md",
        "REPO_INSPECTION.json",
        "REPO_INSPECTION.md",
        "CAPABILITY_CONTRACT.json",
        "EVIDENCE_INDEX.json",
        "CLAIM_GRAPH.json"
      ],
      "required_files": [
        "PROJECT_PACK.json",
        "QUICK_START.md",
        "PROMPT_PREVIEW.md",
        "HUMAN_MANUAL.md",
        "AI_CONTEXT_PACK.md",
        "BOUNDARY_RISK_CARD.md",
        "PITFALL_LOG.md",
        "REPO_INSPECTION.json"
      ]
    },
    "detail": {
      "capability_source": "Project Hit Packet + DownstreamValidationResult",
      "commands": [
        {
          "command": "npm install -g mcp-retroarch",
          "label": "Node.js / npm · 官方安装入口",
          "source": "https://github.com/dmang-dev/mcp-retroarch#readme",
          "verified": true
        }
      ],
      "display_tags": [
        "MCP 工具",
        "知识库问答",
        "流程自动化",
        "节点式流程编排",
        "本地优先"
      ],
      "eyebrow": "工具连接与集成",
      "glance": [
        {
          "body": "判断自己是不是目标用户。",
          "label": "最适合谁",
          "value": "需要工具连接与集成能力，并使用 mcp_host的用户"
        },
        {
          "body": "先理解能力边界，再决定是否继续。",
          "label": "核心价值",
          "value": "MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface"
        },
        {
          "body": "未完成验证前保持审慎。",
          "label": "继续前",
          "value": "publish to Doramagic.ai project surfaces"
        }
      ],
      "guardrail_source": "Boundary & Risk Card",
      "guardrails": [
        {
          "body": "Prompt Preview 只展示流程，不证明项目已安装或运行。",
          "label": "Check 1",
          "value": "不要把试用当真实运行"
        },
        {
          "body": "mcp_host, claude",
          "label": "Check 2",
          "value": "确认宿主兼容"
        },
        {
          "body": "publish to Doramagic.ai project surfaces",
          "label": "Check 3",
          "value": "先隔离验证"
        }
      ],
      "mode": "mcp_config, recipe, host_instruction, eval, preflight",
      "pitfall_log": {
        "items": [
          {
            "body": "项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。",
            "category": "配置坑",
            "evidence": [
              "capability.host_targets | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | host_targets=mcp_host, claude"
            ],
            "severity": "medium",
            "suggested_check": "列出会写入的配置文件、目录和卸载/回滚步骤。",
            "title": "可能修改宿主 AI 配置",
            "user_impact": "安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。"
          },
          {
            "body": "README/documentation is current enough for a first validation pass.",
            "category": "能力坑",
            "evidence": [
              "capability.assumptions | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | README/documentation is current enough for a first validation pass."
            ],
            "severity": "medium",
            "suggested_check": "将假设转成下游验证清单。",
            "title": "能力判断依赖假设",
            "user_impact": "假设不成立时，用户拿不到承诺的能力。"
          },
          {
            "body": "未记录 last_activity_observed。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | last_activity_observed missing"
            ],
            "severity": "medium",
            "suggested_check": "补 GitHub 最近 commit、release、issue/PR 响应信号。",
            "title": "维护活跃度未知",
            "user_impact": "新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。"
          },
          {
            "body": "no_demo",
            "category": "安全/权限坑",
            "evidence": [
              "downstream_validation.risk_items | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium"
            ],
            "severity": "medium",
            "suggested_check": "进入安全/权限治理复核队列。",
            "title": "下游验证发现风险项",
            "user_impact": "下游已经要求复核，不能在页面中弱化。"
          },
          {
            "body": "no_demo",
            "category": "安全/权限坑",
            "evidence": [
              "risks.scoring_risks | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium"
            ],
            "severity": "medium",
            "suggested_check": "把风险写入边界卡，并确认是否需要人工复核。",
            "title": "存在评分风险",
            "user_impact": "风险会影响是否适合普通用户安装。"
          },
          {
            "body": "issue_or_pr_quality=unknown。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | issue_or_pr_quality=unknown"
            ],
            "severity": "low",
            "suggested_check": "抽样最近 issue/PR，判断是否长期无人处理。",
            "title": "issue/PR 响应质量未知",
            "user_impact": "用户无法判断遇到问题后是否有人维护。"
          },
          {
            "body": "release_recency=unknown。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | release_recency=unknown"
            ],
            "severity": "low",
            "suggested_check": "确认最近 release/tag 和 README 安装命令是否一致。",
            "title": "发布节奏不明确",
            "user_impact": "安装命令和文档可能落后于代码，用户踩坑概率升高。"
          }
        ],
        "source": "ProjectPitfallLog + ProjectHitPacket + validation + community signals",
        "summary": "发现 7 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：配置坑 - 可能修改宿主 AI 配置。",
        "title": "踩坑日志"
      },
      "snapshot": {
        "contributors": 1,
        "forks": 0,
        "license": "unknown",
        "note": "站点快照，非实时质量证明；用于开工前背景判断。",
        "stars": 0
      },
      "source_url": "https://github.com/dmang-dev/mcp-retroarch",
      "steps": [
        {
          "body": "不安装项目，先体验能力节奏。",
          "code": "preview",
          "title": "先试 Prompt"
        },
        {
          "body": "理解输入、输出、失败模式和边界。",
          "code": "manual",
          "title": "读说明书"
        },
        {
          "body": "把上下文交给宿主 AI 继续工作。",
          "code": "context",
          "title": "带给 AI"
        },
        {
          "body": "进入主力环境前先完成安装入口与风险边界验证。",
          "code": "verify",
          "title": "沙箱验证"
        }
      ],
      "subtitle": "MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface",
      "title": "mcp-retroarch 能力包",
      "trial_prompt": "# mcp-retroarch - Prompt Preview\n\n> Copy the prompt below into your AI host before installing anything.\n> Its purpose is to let you safely feel the project's workflow, not to claim the project has already run.\n\n## Copy this prompt\n\n```text\nYou are using an independent Doramagic capability pack for dmang-dev/mcp-retroarch.\n\nProject:\n- Name: mcp-retroarch\n- Repository: https://github.com/dmang-dev/mcp-retroarch\n- Summary: MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface\n- Host target: mcp_host, claude\n\nGoal:\nHelp me evaluate this project for the following task without installing it yet: MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface\n\nBefore taking action:\n1. Restate my task, success standard, and boundary.\n2. Identify whether the next step requires tools, browser access, network access, filesystem access, credentials, package installation, or host configuration.\n3. Use only the Doramagic Project Pack, the upstream repository, and the source-linked evidence listed below.\n4. If a real command, install step, API call, file write, or host integration is required, mark it as \"requires post-install verification\" and ask for approval first.\n5. If evidence is missing, say \"evidence is missing\" instead of filling the gap.\n\nPreviewable capabilities:\n- Capability 1: MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface\n\nCapabilities that require post-install verification:\n- Capability 1: Use the source-backed project context to guide one small, checkable workflow step.\n\nCore service flow:\n1. page-introduction: Introduction. Produce one small intermediate artifact and wait for confirmation.\n2. page-quick-start: Quick Start Guide. Produce one small intermediate artifact and wait for confirmation.\n3. page-architecture: System Architecture. Produce one small intermediate artifact and wait for confirmation.\n4. page-memory-operations: Memory Read/Write Operations. Produce one small intermediate artifact and wait for confirmation.\n5. page-savestate-management: Savestate Management. Produce one small intermediate artifact and wait for confirmation.\n\nSource-backed evidence to keep in mind:\n- https://github.com/dmang-dev/mcp-retroarch\n- https://github.com/dmang-dev/mcp-retroarch#readme\n- README.md\n- package.json\n- src/index.ts\n- src/retroarch.ts\n- src/tools.ts\n\nFirst response rules:\n1. Start Step 1 only.\n2. Explain the one service action you will perform first.\n3. Ask exactly three questions about my target workflow, success standard, and sandbox boundary.\n4. Stop and wait for my answers.\n\nStep 1 follow-up protocol:\n- After I answer the first three questions, stay in Step 1.\n- Produce six parts only: clarified task, success standard, boundary conditions, two or three options, tradeoffs for each option, and one recommendation.\n- End by asking whether I confirm the recommendation.\n- Do not move to Step 2 until I explicitly confirm.\n\nConversation rules:\n- Advance one step at a time and wait for confirmation after each small artifact.\n- Write outputs as recommendations or planned checks, not as completed execution.\n- Do not claim tests passed, files changed, commands ran, APIs were called, or the project was installed.\n- If the user asks for execution, first provide the sandbox setup, expected output, rollback, and approval checkpoint.\n```\n",
      "voices": [
        {
          "body": "当前没有项目级社区来源；不会把未抓取讨论包装成社会证明。",
          "items": [],
          "status": "待发现 Agent 补证",
          "title": "社区讨论"
        }
      ]
    },
    "homepage_card": {
      "category": "工具连接与集成",
      "desc": "MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface",
      "effort": "安装已验证",
      "forks": 0,
      "icon": "link",
      "name": "mcp-retroarch 能力包",
      "risk": "需复核",
      "slug": "mcp-retroarch",
      "stars": 0,
      "tags": [
        "MCP 工具",
        "知识库问答",
        "流程自动化",
        "节点式流程编排",
        "本地优先"
      ],
      "thumb": "gray",
      "type": "MCP 配置"
    },
    "manual": {
      "markdown": "# https://github.com/dmang-dev/mcp-retroarch 项目说明书\n\n生成时间：2026-05-16 06:53:34 UTC\n\n## 目录\n\n- [Introduction](#page-introduction)\n- [Quick Start Guide](#page-quick-start)\n- [System Architecture](#page-architecture)\n- [Data Flow](#page-data-flow)\n- [Memory Read/Write Operations](#page-memory-operations)\n- [Savestate Management](#page-savestate-management)\n- [Emulation Control](#page-emulation-control)\n- [MCP Tools Reference](#page-tools-reference)\n- [Core Compatibility](#page-core-compatibility)\n- [Configuration](#page-configuration)\n\n<a id='page-introduction'></a>\n\n## Introduction\n\n### 相关页面\n\n相关主题：[System Architecture](#page-architecture), [Quick Start Guide](#page-quick-start)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Introduction\n\nmcp-retroarch is a Model Context Protocol (MCP) server that bridges AI assistants (such as Claude) with the RetroArch emulator through its Network Control Interface (NCI). This enables AI-driven automation of retro gaming tasks including memory inspection, save state management, screenshot capture, and frame-by-frame execution control.\n\n## Project Overview\n\nmcp-retroarch exposes RetroArch's NCI functionality as MCP tools, allowing AI agents to:\n\n- Read and write emulated system memory\n- Manage save states across slots\n- Capture screenshots\n- Control emulation execution (pause, frame advance, reset)\n- Display notifications within the emulator\n\n**Key characteristics:**\n\n| Attribute | Value |\n|-----------|-------|\n| Protocol | MCP over stdio |\n| Transport to RetroArch | UDP (IPv4) |\n| Default UDP port | 55355 |\n| Language | TypeScript |\n| MCP SDK version | ^1.12.0 |\n| License | MIT |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Architecture\n\nThe system consists of three primary components communicating across two protocols:\n\n```mermaid\ngraph TD\n    subgraph \"MCP Client Layer\"\n        A[Claude / AI Assistant]\n    end\n    \n    subgraph \"mcp-retroarch Process\"\n        B[MCP SDK<br/>stdio JSON-RPC]\n        C[RetroArch Client<br/>src/retroarch.ts]\n    end\n    \n    subgraph \"RetroArch\"\n        D[Network Control<br/>Interface]\n    end\n    \n    A -->|\"MCP JSON-RPC\"| B\n    B -->|Tool calls| C\n    C -->|\"UDP Datagrams\"| D\n    D -->|\"UDP Response\"| C\n    C -->|\"MCP Response\"| B\n    B -->|\"JSON-RPC\"| A\n```\n\n### Component Responsibilities\n\n| Component | Role |\n|-----------|------|\n| MCP Client | Sends JSON-RPC requests via stdio |\n| mcp-retroarch | Translates MCP tools to NCI UDP commands |\n| RetroArch NCI | Executes commands on the running emulator |\n\n资料来源：[src/index.ts:1-20](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n## How It Works\n\n### Connection Flow\n\n1. **Startup**: The MCP server initializes and creates a UDP socket for RetroArch communication\n2. **Background probe**: An asynchronous connection attempt retrieves RetroArch version\n3. **Ready signal**: Server signals readiness via stderr and stdout\n\n```mermaid\nsequenceDiagram\n    participant RA as RetroArch\n    participant MCP as mcp-retroarch\n    participant Client as MCP Client\n    \n    MCP->>MCP: Create UDP socket\n    Note over MCP: Background probe<br/>(fire-and-forget)\n    MCP->>RA: VERSION command\n    RA-->>MCP: RetroArch version\n    MCP->>Client: Ready notification (stdout)\n    Client->>MCP: Tool call (e.g., read_memory)\n    MCP->>RA: READ_CORE_MEMORY\n    RA-->>MCP: Memory bytes\n    MCP-->>Client: Hex dump response\n```\n\n资料来源：[src/index.ts:8-17](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n### UDP Communication Model\n\nThe RetroArch client implements two communication patterns:\n\n| Pattern | Method | Use Case |\n|---------|--------|----------|\n| Fire-and-forget | `send(command)` | Pause toggle, reset, screenshot |\n| Query/Response | `query(command)` | Memory reads, status queries |\n\n```typescript\n// Fire-and-forget: no response expected\nasync send(command: string): Promise<void>\n\n// Query with timeout: awaits UDP response\nasync query(command: string): Promise<Buffer>\n```\n\n**Timeout behavior**: Queries default to a configurable timeout. If no response arrives, the promise rejects with a timeout error. The client maintains serial request semantics—one query must complete before the next begins.\n\n资料来源：[src/retroarch.ts:43-64](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n### Serial Request Constraint\n\nThe implementation enforces serial requests at the protocol level:\n\n```typescript\nif (this.pending) {\n  throw new Error(\"retroarch query already in flight (client is serial)\");\n}\n```\n\nThis means concurrent tool calls from the MCP client will queue or fail if queries overlap.\n\n资料来源：[src/retroarch.ts:56-59](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n## Prerequisites\n\nBefore using mcp-retroarch, ensure:\n\n1. **RetroArch is installed** with Network Commands enabled\n2. **A libretro core and game are loaded**\n3. **Network Command Interface is active**\n\n### Enabling Network Commands in RetroArch\n\n**GUI Method**:\n- Navigate to Settings → Network → Network Commands → ON\n- Confirm Network Cmd Port is `55355` (default)\n\n**Configuration File Method** (retroarch.cfg):\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Configuration\n\nmcp-retroarch is configured via environment variables:\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in retroarch.cfg) |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Available Tools\n\nThe following MCP tools are exposed by mcp-retroarch:\n\n### Memory Operations\n\n| Tool | Purpose | Address Space |\n|------|---------|---------------|\n| `retroarch_read_memory` | Read bytes from system memory map | libretro memory map |\n| `retroarch_write_memory` | Write bytes to system memory | libretro memory map |\n| `retroarch_read_ram` | Read bytes via CHEEVOS address space | Achievement space |\n| `retroarch_write_ram` | Write bytes via CHEEVOS space | Achievement space |\n\n**Memory read/write limitations**:\n- Maximum 4096 bytes per call (NCI single-datagram limit)\n- `write_memory` returns byte count; `write_ram` does not acknowledge\n\n### Emulation Control\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_pause_toggle` | Toggle pause state |\n| `retroarch_frame_advance` | Step exactly one frame |\n| `retroarch_reset` | Hard reset the game |\n\n### State Management\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_save_state_current` | Save to current slot |\n| `retroarch_load_state_current` | Load from current slot |\n| `retroarch_load_state_slot` | Load from explicit slot number |\n| `retroarch_state_slot_plus` | Increment slot pointer |\n| `retroarch_state_slot_minus` | Decrement slot pointer |\n\n### Utility\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_screenshot` | Save screenshot to RetroArch's configured directory |\n| `retroarch_show_message` | Display notification overlay |\n| `retroarch_get_status` | Query current emulation state |\n| `retroarch_get_config` | Read a config parameter value |\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Address Space Differences\n\nUnderstanding the distinction between address spaces is critical:\n\n| Address Space | Used By | Notes |\n|---------------|---------|-------|\n| libretro memory map | `read_memory` / `write_memory` | System-specific layout (e.g., GBA EWRAM at 0x02000000) |\n| CHEEVOS space | `read_ram` / `write_ram` | RetroAchievements address conventions |\n\n**Example address mappings**:\n- GBA ROM: `0x08000000` (memory map) vs `0x000000` (CHEEVOS)\n- SNES WRAM: `0x7E0000-0x7FFFFF` (memory map) vs `0x000000` (CHEEVOS)\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Verified Core Support\n\nThe following cores have been tested with mcp-retroarch:\n\n| System | Core | read_memory | read_ram | Notes |\n|--------|------|-------------|----------|-------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA interrupt vector at 0x0000 visible |\n| NES | `mesen_libretro` | ✅ | ✅ | Full 16-bit address space; WRAM at 0x0000-0x07FF |\n| NES | `nestopia_libretro` | ❌ | ✅ | No memory map; use read_ram |\n| SNES | `snes9x_libretro` | ❌ | — | Memory map not exposed |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Fire-and-Forget Semantics\n\nMost NCI commands do not receive acknowledgments from RetroArch. The response message from mcp-retroarch indicates only that the UDP datagram was sent, not that RetroArch received or acted on it.\n\n**Exceptions**:\n- `retroarch_write_memory` — returns byte count (NCI acknowledges this command)\n- `retroarch_read_memory` / `retroarch_read_ram` — returns actual data read\n\n**Verification strategy**: For fire-and-forget commands, verify success by:\n1. Reading memory back with `read_ram`\n2. Checking state with `retroarch_get_status`\n\n资料来源：[CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n\n## Error Handling\n\n### Common Errors\n\n| Error | Cause | Resolution |\n|-------|-------|------------|\n| `RetroArch query timed out` | Network Commands disabled or port mismatch | Verify `network_cmd_enable = \"true\"` and matching ports |\n| `READ_CORE_MEMORY failed: no memory map defined` | Core doesn't expose memory map | Use `retroarch_read_ram` instead |\n| `READ_CORE_MEMORY failed: no descriptor for address` | Address outside core's memory regions | Try different core or address |\n\n**UDP reliability note**: UDP datagrams may be dropped under load even on loopback. If a single call times out, retry the operation.\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Development\n\n### Project Structure\n\n```\nmcp-retroarch/\n├── src/\n│   ├── index.ts        # MCP server entry point\n│   ├── retroarch.ts    # UDP client for NCI protocol\n│   └── tools.ts        # Tool definitions and handlers\n├── package.json\n├── tsconfig.json\n└── .scratch/\n    └── smoke.cjs       # Manual smoke test\n```\n\n### Running Locally\n\n```bash\nnpm install\nnpm run dev      # tsc --watch (development mode)\nnode .scratch/smoke.cjs  # Smoke test against running RetroArch\n```\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md), [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n## Limitations\n\n| Feature | Status | Notes |\n|---------|--------|-------|\n| Game-pad input | ❌ Not available | NCI doesn't expose input; see [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) for GBA input |\n| Save to specific slot | Limited | Only current slot save; must walk to target slot |\n| Screenshot directory | Not configurable via NCI | Check RetroArch GUI for configured path |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Related Projects\n\n| Project | Purpose |\n|---------|---------|\n| [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | GBA via mGBA's Lua bridge (includes input + screenshot) |\n| [mcp-pine](https://github.com/dmang-dev/mcp-pine) | PCSX2 and PINE-speaking emulators |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n<a id='page-quick-start'></a>\n\n## Quick Start Guide\n\n### 相关页面\n\n相关主题：[Introduction](#page-introduction), [Configuration](#page-configuration)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Quick Start Guide\n\nThis guide walks you through setting up **mcp-retroarch**, a Model Context Protocol (MCP) server that enables AI assistants to interact with RetroArch through its Network Command Interface (NCI). The integration provides memory inspection, savestate management, screenshot capture, and emulator control via JSON-RPC over stdio.\n\n## Overview\n\nmcp-retroarch bridges AI coding assistants (like Claude Code or Claude Desktop) with RetroArch by:\n\n- Exposing RetroArch NCI commands as MCP tools\n- Communicating over stdio (JSON-RPC) with the MCP client\n- Sending UDP datagrams to RetroArch's Network Command Interface on port 55355\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## System Architecture\n\n```mermaid\ngraph TD\n    A[\"MCP Client<br/>(Claude Code/Desktop)\"] -->|stdio JSON-RPC| B[\"mcp-retroarch<br/>MCP Server\"]\n    B -->|UDP :55355| C[\"RetroArch<br/>Network Commands\"]\n    C -->|Emulator Control| D[\"Libretro Core<br/>+ Game ROM\"]\n    \n    B -->|Background Probe| C\n    \n    style A fill:#e1f5fe\n    style B fill:#fff3e0\n    style C fill:#e8f5e9\n```\n\n资料来源：[src/index.ts:8-14](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts), [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n## Prerequisites\n\n| Requirement | Details |\n|-------------|---------|\n| Node.js | Version compatible with `@modelcontextprotocol/sdk` ^1.12.0 |\n| RetroArch | Version with Network Command Interface enabled |\n| MCP Client | Claude Code or Claude Desktop |\n| Network Commands | Must be enabled in RetroArch |\n\n资料来源：[package.json:20-26](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json), [README.md:40-50](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Step 1: Install mcp-retroarch\n\n### From npm (Recommended)\n\n```bash\nnpm install -g mcp-retroarch\n```\n\nThis makes the `mcp-retroarch` command globally available.\n\n资料来源：[package.json:1-10](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n### From Source\n\n```bash\ngit clone https://github.com/dmang-dev/mcp-retroarch.git\ncd mcp-retroarch\nnpm install\nnpm run build   # or use npm run dev for watch mode\n```\n\n资料来源：[README.md:100-105](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Step 2: Enable Network Commands in RetroArch\n\nRetroArch's NCI must be enabled before mcp-retroarch can communicate with it.\n\n### Via GUI\n\n1. Open RetroArch\n2. Navigate to **Settings → Network → Network Commands**\n3. Set **Network Commands** to **ON**\n4. Confirm **Network Cmd Port** is `55355` (default)\n\n### Via Configuration File\n\nEdit `retroarch.cfg` (located in RetroArch's config directory):\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n资料来源：[README.md:40-50](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Verify Setup\n\nLaunch RetroArch and load any libretro core with a game. The Network Command Interface is always-on once enabled—no additional scripts required.\n\n## Step 3: Register with Your MCP Client\n\n### Claude Code\n\nRegister retroarch as a user-level MCP server:\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\nVerify registration:\n\n```bash\nclaude mcp list\n# retroarch: mcp-retroarch - ✓ Connected\n```\n\n资料来源：[README.md:52-60](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Claude Desktop\n\nEdit the platform-specific configuration file:\n\n| Platform | Config Path |\n|----------|-------------|\n| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |\n| Windows | `%APPDATA%\\Claude\\claude_desktop_config.json` |\n| Linux | `~/.config/Claude/claude_desktop_config.json` |\n\nAdd the `mcpServers` section:\n\n```json\n{\n  \"mcpServers\": {\n    \"retroarch\": {\n      \"command\": \"mcp-retroarch\"\n    }\n  }\n}\n```\n\nRestart Claude Desktop after editing.\n\n资料来源：[README.md:62-78](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Step 4: Configure Environment Variables\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in retroarch.cfg) |\n\nSet these before running Claude Code or Claude Desktop if your RetroArch runs on a different host or port:\n\n```bash\nexport RETROARCH_HOST=192.168.1.100\nexport RETROARCH_PORT=55355\n```\n\n资料来源：[README.md:80-85](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Available Tools\n\nOnce connected, the following MCP tools become available:\n\n### Emulator Control\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_get_status` | Query running state, system, game, CRC32 |\n| `retroarch_pause_toggle` | Toggle pause on/off |\n| `retroarch_frame_advance` | Advance exactly one frame |\n| `retroarch_reset` | Hard reset the running game |\n| `retroarch_show_message` | Display notification on RetroArch window |\n\n### Memory Operations\n\n| Tool | Description |\n|------|-------------|\n| `retroarch_read_memory` | Read from libretro system memory map |\n| `retroarch_write_memory` | Write to libretro system memory map |\n| `retroarch_read_ram` | Read from CHEEVOS (achievements) address space |\n| `retroarch_write_ram` | Write to CHEEVOS address space |\n\n### Savestate Management\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_save_state_current` | Save to currently-selected slot |\n| `retroarch_load_state_current` | Load from currently-selected slot |\n| `retroarch_load_state_slot` | Load from explicit slot number |\n| `retroarch_state_slot_plus` | Increment slot pointer |\n| `retroarch_state_slot_minus` | Decrement slot pointer |\n\n### Media & Config\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_screenshot` | Save screenshot to RetroArch's screenshot directory |\n| `retroarch_get_config` | Read a RetroArch configuration parameter |\n\n资料来源：[README.md:1-30](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md), [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Step 5: Smoke Test\n\nVerify connectivity by running the smoke test script against a running RetroArch:\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n资料来源：[README.md:107-110](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## First Commands to Try\n\n### Check Emulator Status\n\n```\nretroarch_get_status\n```\n\nExpected output:\n```\nState:  playing\nSystem: snes9x_libretro\nGame:   Super Metroid (USA).sfc\nCRC32:  12345678\n```\n\n### Pause and Read Memory\n\n```\nretroarch_pause_toggle\nretroarch_read_memory(address=0x7E0000, length=16)\n```\n\n### Take a Screenshot\n\n```\nretroarch_screenshot\n```\n\n资料来源：[src/tools.ts:1-50](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Verified Core Compatibility\n\n| System | Core | `read_memory` | `read_ram` | Notes |\n|--------|------|---------------|------------|-------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA interrupt vector at `0x0000` |\n| NES | `mesen_libretro` | ✅ | ✅ | Full 16-bit NES address space |\n| NES | `nestopia_libretro` | ❌ | ✅ | CHEEVOS only |\n| SNES | `snes9x_libretro` | ❌ | — | Memory map not exposed |\n\n资料来源：[README.md:30-45](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Troubleshooting\n\n| Symptom | Cause / Fix |\n|---------|-------------|\n| `RetroArch query timed out` | Network Commands not enabled, or port mismatch. Confirm `network_cmd_enable = \"true\"` in retroarch.cfg |\n| `READ_CORE_MEMORY failed: no memory map defined` | Core doesn't advertise memory map. Try `retroarch_read_ram` as fallback |\n| `READ_CORE_MEMORY failed: no descriptor for address` | Address outside core's memory regions |\n| Screenshots don't appear | Check RetroArch's screenshot directory via Settings → Directory → Screenshot |\n| Can't save to specific slot | NCI limitation—use `state_slot_plus`/`state_slot_minus` to walk to target slot |\n\n资料来源：[README.md:115-130](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Next Steps\n\n- Review [docs/RECIPES.md](docs/RECIPES.md) for end-to-end examples\n- Explore related MCP servers: [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) for GBA input + screenshots\n- Consult [RetroArch NCI documentation](https://docs.libretro.com/development/retroarch/network-control-interface/) for protocol details\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n<a id='page-architecture'></a>\n\n## System Architecture\n\n### 相关页面\n\n相关主题：[Introduction](#page-introduction), [Data Flow](#page-data-flow)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n</details>\n\n# System Architecture\n\n## Overview\n\nmcp-retroarch is a Model Context Protocol (MCP) server that bridges MCP clients (such as Claude Code or Claude Desktop) with RetroArch's Network Control Interface (NCI). It enables AI assistants to interact with running emulated games through memory inspection, state manipulation, and emulator control.\n\n**资料来源：** [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## High-Level Architecture\n\nThe system follows a three-layer architecture:\n\n```mermaid\ngraph TD\n    subgraph \"Client Layer\"\n        MCP[MCP Client<br/>Claude Code / Claude Desktop]\n    end\n\n    subgraph \"Bridge Layer\"\n        MCP_Server[MCP Server<br/>mcp-retroarch]\n        Tools[MCP Tools<br/>tools.ts]\n        Transport[UDP Transport<br/>retroarch.ts]\n    end\n\n    subgraph \"Target Layer\"\n        RA[RetroArch<br/>Running Emulator]\n        NCI[Network Control<br/>Interface]\n    end\n\n    MCP -->|\"stdio JSON-RPC\"| MCP_Server\n    MCP_Server --> Tools\n    Tools --> Transport\n    Transport -->|\"UDP :55355\"| NCI\n    NCI --> RA\n```\n\n**资料来源：** [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Component Architecture\n\n### Layer 1: MCP Server Entry Point\n\n**File:** `src/index.ts`\n\nThe main entry point initializes the MCP server using the `@modelcontextprotocol/sdk` package and establishes a background connectivity probe to RetroArch.\n\n```typescript\n// Simplified initialization flow\nconst server = new Server(\n  { name: \"mcp-retroarch\", version: \"0.1.2\" },\n  { capabilities: { tools: {} } }\n);\n\nra.connect()\n  .then(() => ra.getVersion())\n  .then((v) => process.stderr.write(`[mcp-retroarch] connected to ${ra.describeTarget()} — RetroArch ${v}\\n`))\n  .catch((err) => process.stderr.write(`[mcp-retroarch] note: RetroArch not reachable yet...\\n`));\n```\n\n**Key responsibilities:**\n- Initialize MCP server with stdio transport\n- Register all tool handlers\n- Perform fire-and-forget connectivity probe on startup\n- Handle fatal errors gracefully\n\n**资料来源：** [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n### Layer 2: UDP Transport Module\n\n**File:** `src/retroarch.ts`\n\nThe transport layer manages UDP socket communication with RetroArch's NCI. It implements a serial query pattern where only one request can be in-flight at a time.\n\n```mermaid\nsequenceDiagram\n    participant Client as MCP Client\n    participant Server as MCP Server\n    participant Transport as UDP Transport\n    participant RA as RetroArch NCI\n\n    Client->>Server: tool_call\n    Server->>Transport: send(query)\n    Transport->>RA: UDP datagram\n    RA-->>Transport: UDP response\n    Transport-->>Server: Buffer\n    Server-->>Client: JSON response\n```\n\n**Connection Management:**\n\n| Method | Purpose |\n|--------|---------|\n| `connect()` | Initialize UDP socket, bind to random port |\n| `disconnect()` | Close socket and cleanup |\n| `send(command)` | Fire-and-forget send (for hotkey commands) |\n| `query(command)` | Send and await response with timeout |\n\n**Configuration parameters:**\n\n| Parameter | Default | Description |\n|-----------|---------|-------------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in `retroarch.cfg`) |\n\n**资料来源：** [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts), [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Layer 3: MCP Tools Definition\n\n**File:** `src/tools.ts`\n\nAll available MCP tools are defined with JSON Schema input validation and descriptive documentation following a PURPOSE / USAGE / BEHAVIOR / RETURNS template.\n\n**Tool Categories:**\n\n| Category | Tools |\n|----------|-------|\n| **Memory** | `retroarch_read_memory`, `retroarch_write_memory`, `retroarch_read_ram`, `retroarch_write_ram` |\n| **State** | `retroarch_save_state_current`, `retroarch_load_state_current`, `retroarch_load_state_slot`, `retroarch_state_slot_plus`, `retroarch_state_slot_minus` |\n| **Control** | `retroarch_pause_toggle`, `retroarch_frame_advance`, `retroarch_reset` |\n| **Media** | `retroarch_screenshot`, `retroarch_show_message` |\n| **Info** | `retroarch_get_status`, `retroarch_get_config`, `retroarch_get_version` |\n\n**资料来源：** [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Data Flow\n\n### Memory Read Flow\n\n```mermaid\ngraph LR\n    A[Client:<br/>retroarch_read_memory] --> B[Validate:<br/>address, length]\n    B --> C[Send:<br/>READ_CORE_MEMORY]\n    C --> D{RetroArch<br/>Memory Map<br/>Available?}\n    D -->|Yes| E[Return bytes<br/>via UDP]\n    D -->|No| F[Error:<br/>no memory map defined]\n    E --> G[Format hex dump<br/>ADDR [N bytes]: XX XX...]\n```\n\n### Memory Write Flow\n\n```mermaid\ngraph LR\n    A[Client:<br/>retroarch_write_memory] --> B[Validate:<br/>address, bytes array]\n    B --> C[Send:<br/>WRITE_CORE_MEMORY]\n    C --> D[RetroArch<br/>Acknowledges<br/>byte count]\n    D --> E[Return count<br/>to client]\n```\n\n**资料来源：** [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts), [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Command Mapping\n\nThe following table shows how MCP tools map to RetroArch NCI commands:\n\n| MCP Tool | NCI Command | Response Pattern |\n|----------|-------------|-------------------|\n| `retroarch_get_version` | `VERSION` | String version |\n| `retroarch_get_status` | `GET_STATUS` | `GET_STATUS {state} {system},{game},crc32={crc}` |\n| `retroarch_read_memory` | `READ_CORE_MEMORY {addr} {len}` | Binary bytes |\n| `retroarch_write_memory` | `WRITE_CORE_MEMORY {addr} {bytes}` | `{count} bytes written` |\n| `retroarch_read_ram` | `READ_CORE_RAM {addr} {len}` | Binary bytes (CHEEVOS) |\n| `retroarch_write_ram` | `WRITE_CORE_RAM {addr} {bytes}` | Fire-and-forget |\n| `retroarch_pause_toggle` | `PAUSE_TOGGLE` | Fire-and-forget |\n| `retroarch_frame_advance` | `FRAMEADVANCE` | Fire-and-forget |\n| `retroarch_reset` | `RESET` | Fire-and-forget |\n| `retroarch_save_state_current` | `SAVE_STATE` | Fire-and-forget |\n| `retroarch_load_state_current` | `LOAD_STATE` | Fire-and-forget |\n| `retroarch_load_state_slot` | `LOAD_STATE {slot}` | Fire-and-forget |\n| `retroarch_screenshot` | `SCREENSHOT` | Fire-and-forget |\n| `retroarch_show_message` | `SET_MESSAGE \"{msg}\"` | Fire-and-forget |\n\n**资料来源：** [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n## Transport Characteristics\n\n### Serial Query Pattern\n\nThe transport layer enforces serial query execution:\n\n```typescript\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  // ... timeout handling\n}\n```\n\n**Key behaviors:**\n- Only one UDP query can be in-flight at a time\n- Queries timeout after configurable `timeoutMs` (default: 5000ms)\n- Fire-and-forget commands (`send()`) bypass the serial queue\n\n### Error Handling\n\n| Error Condition | Cause | Resolution |\n|-----------------|-------|------------|\n| `RetroArch query timed out` | Network Commands not enabled or port mismatch | Verify `network_cmd_enable = \"true\"` in `retroarch.cfg` |\n| `no memory map defined` | Core doesn't advertise system memory map | Use `retroarch_read_ram` as fallback |\n| `no descriptor for address` | Address outside core's memory regions | Use different core or address |\n| `query already in flight` | Multiple concurrent queries attempted | Wait for previous query to complete |\n\n**资料来源：** [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md), [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n## Memory Address Spaces\n\nmcp-retroarch exposes two distinct memory address spaces:\n\n### System Memory Map (`read_memory` / `write_memory`)\n\nUses `READ_CORE_MEMORY` / `WRITE_CORE_MEMORY` via the libretro core's system memory map.\n\n| System | Typical Address Range |\n|--------|------------------------|\n| GBA EWRAM | `0x02000000` - `0x0203FFFF` |\n| SNES WRAM | `0x7E0000` - `0x7FFFFF` |\n| Genesis 68K RAM | `0xFF0000` - `0xFFFFFF` |\n\n### CHEEVOS Address Space (`read_ram` / `write_ram`)\n\nUses `READ_CORE_RAM` / `WRITE_CORE_RAM` via the RetroAchievements address space. Uses different conventions per system (e.g., SNES WRAM starts at `0x000000` in CHEEVOS space).\n\n**资料来源：** [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Dependencies\n\n**File:** `package.json`\n\n| Dependency | Version | Purpose |\n|------------|---------|---------|\n| `@modelcontextprotocol/sdk` | `^1.12.0` | MCP server implementation |\n| `@types/node` | `^22.0.0` | TypeScript definitions |\n| `typescript` | `^5.5.0` | Build tooling |\n\n**资料来源：** [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n## Tested Cores Compatibility\n\n| System | Core | `read_memory` | `read_ram` | Notes |\n|--------|------|:------------:|:----------:|-------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA interrupt vector at `0x0000` |\n| NES | `mesen_libretro` | ✅ | ✅ | Full 16-bit address space |\n| NES | `nestopia_libretro` | ❌ | ✅ | CHEEVOS only |\n| SNES | `snes9x_libretro` | ❌ | N/A | Memory map not exposed |\n| PSX | `swanstation_libretro` | ❌ | ✅ | Use `read_ram` |\n\n**资料来源：** [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Project Structure\n\n```\nmcp-retroarch/\n├── src/\n│   ├── index.ts       # MCP server entry point\n│   ├── retroarch.ts  # UDP transport & NCI protocol\n│   └── tools.ts      # Tool definitions & handlers\n├── docs/\n│   └── RECIPES.md     # End-to-end usage examples\n├── package.json\n├── tsconfig.json\n└── README.md\n```\n\n**资料来源：** [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n<a id='page-data-flow'></a>\n\n## Data Flow\n\n### 相关页面\n\n相关主题：[System Architecture](#page-architecture), [Memory Read/Write Operations](#page-memory-operations)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Data Flow\n\nThis page documents the complete data flow through the mcp-retroarch system, from MCP client requests through UDP communication with RetroArch's Network Control Interface (NCI).\n\n## Architecture Overview\n\nmcp-retroarch bridges two distinct communication protocols:\n\n| Layer | Transport | Protocol |\n|-------|-----------|----------|\n| MCP Client ↔ mcp-retroarch | stdio | JSON-RPC 2.0 |\n| mcp-retroarch ↔ RetroArch | UDP (port 55355) | NCI text commands |\n\n资料来源：[README.md:1-50]()\n\n```mermaid\ngraph TB\n    subgraph \"MCP Layer (stdio)\"\n        A[\"MCP Client<br/>(Claude Code, Claude Desktop)\"]\n    end\n    \n    subgraph \"mcp-retroarch Process\"\n        B[\"src/index.ts<br/>MCP Server Entry\"]\n        C[\"src/tools.ts<br/>Tool Handlers\"]\n        D[\"src/retroarch.ts<br/>RetroArch Client\"]\n    end\n    \n    subgraph \"RetroArch\"\n        E[\"Network Control Interface<br/>(UDP :55355)\"]\n    end\n    \n    A -->|\"JSON-RPC 2.0<br/>stdio\"| B\n    B -->|routes| C\n    C -->|invokes methods| D\n    D -->|\"NCI commands<br/>UDP\"| E\n    E -->|\"UDP response\"| D\n```\n\n## Request-Response Flow\n\n### 1. MCP Request Ingress\n\nWhen an MCP client invokes a tool (e.g., `retroarch_read_memory`), the following occurs:\n\n1. The client sends a JSON-RPC 2.0 request via stdio\n2. `src/index.ts` receives the request and routes it to the appropriate tool handler in `src/tools.ts`\n3. The tool handler validates parameters against the input schema\n\n资料来源：[src/tools.ts:1-100]()\n\n### 2. Tool Handler Processing\n\nEach tool maps to a specific case in the tool handler switch statement:\n\n```typescript\ncase \"retroarch_read_memory\": {\n  const bytes = await ra.readMemory(p.address as number, p.length as number);\n  const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, \"0\").toUpperCase()).join(\" \");\n  return ok(`${addrHex(p.address as number)} [${bytes.length} bytes]:\\n${hex}`);\n}\n```\n\n资料来源：[src/tools.ts:20-30]()\n\n### 3. UDP Query Execution\n\nThe `RetroArch` class in `src/retroarch.ts` handles all network communication:\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP Client\n    participant Server as mcp-retroarch\n    participant Socket as UDP Socket\n    participant RA as RetroArch NCI\n    \n    MCP->>Server: retroarch_read_memory(0x02000000, 256)\n    Server->>Socket: send(\"READ_CORE_MEMORY 02000000 0100\")\n    Socket->>RA: UDP datagram to 127.0.0.1:55355\n    RA-->>Socket: \"READ_CORE_MEMORY OK [256 bytes]\"\n    Socket-->>Server: Buffer response\n    Server-->>MCP: JSON-RPC response with hex dump\n```\n\n资料来源：[src/retroarch.ts:1-50]()\n\n## Socket Communication Model\n\n### Connection Lifecycle\n\n```mermaid\ngraph LR\n    A[Lazy Connect] -->|on first query| B[Socket Created]\n    B --> C[bind to random port]\n    C --> D[ready for send/receive]\n    D --> E[on tool call]\n    E --> F[send UDP datagram]\n    F --> G[wait for response]\n    G -->|timeout| H[Error: query timed out]\n    G -->|response| I[resolve promise]\n```\n\n资料来源：[src/retroarch.ts:20-45]()\n\n### Query Serialization\n\nThe `query()` method enforces serial execution:\n\n```typescript\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  return new Promise<Buffer>((resolve, reject) => {\n    let timer: NodeJS.Timeout | null = setTimeout(() => {\n      this.pending = null;\n      reject(new Error(\n        `RetroArch query \"${command.split(\" \")[0]}\" timed out after ${this.timeoutMs}ms ` +\n        `— is RetroArch running with Network Commands enabled?`,\n      ));\n    }, this.timeoutMs);\n\n    this.pending = (data) => {\n      if (timer) { clearTimeout(timer); timer = null; }\n      resolve(data);\n    };\n    // ...\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:70-95]()\n\n**Key characteristics:**\n- **Lazy connection**: Socket is created on first query, not at startup\n- **Serial queries**: Only one pending query at a time (prevents response ambiguity)\n- **Timeout handling**: Configurable timeout with cleanup on resolution or expiry\n\n### Fire-and-Forget Commands\n\nSome commands use `send()` instead of `query()` for hotkey-style operations:\n\n```typescript\nasync send(command: string): Promise<void> {\n  if (!this.socket) await this.connect();\n  return new Promise((resolve, reject) => {\n    this.socket!.send(command, this.port, this.host, (err) =>\n      err ? reject(err) : resolve(),\n    );\n  });\n}\n```\n\nThese commands do not wait for or expect a response from RetroArch:\n- `retroarch_pause_toggle`\n- `retroarch_reset`\n- `retroarch_screenshot`\n\n资料来源：[src/retroarch.ts:55-68]()\n\n## Memory Read/Write Data Paths\n\n### Two Memory APIs\n\nmcp-retroarch exposes two distinct memory access paths:\n\n```mermaid\ngraph TD\n    A[Memory Request] --> B{Which API?}\n    B -->|System Memory Map| C[READ_CORE_MEMORY<br/>WRITE_CORE_MEMORY]\n    B -->|CHEEVOS Space| D[READ_CORE_RAM<br/>WRITE_CORE_RAM]\n    \n    C --> E[Full system bus access]\n    C --> F[Precise memory regions]\n    C --> G[Returns byte count on write]\n    \n    D --> H[Achievement address space]\n    D --> I[Limited to 64KB on some cores]\n    D --> J[No acknowledgment on write<br/>\"fire-and-forget\"]\n```\n\n资料来源：[src/tools.ts:100-200]()\n\n### Memory Read Flow\n\n1. **Tool handler** receives `address` and `length` parameters\n2. **RetroArch client** calls `readMemory()` or `readRam()`\n3. **UDP query** sent with address and byte count\n4. **Response parsing** extracts bytes from NCI response\n5. **Hex encoding** converts bytes to space-separated hex string\n\n```typescript\ncase \"retroarch_read_memory\": {\n  const bytes = await ra.readMemory(p.address as number, p.length as number);\n  const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, \"0\").toUpperCase()).join(\" \");\n  return ok(`${addrHex(p.address as number)} [${bytes.length} bytes]:\\n${hex}`);\n}\n```\n\n### Memory Write Flow\n\n| API | Acknowledgment | Use Case |\n|-----|----------------|----------|\n| `write_memory` | Yes (returns byte count) | Precise writes, cheats |\n| `write_ram` | No (fire-and-forget) | Fallback when memory map unavailable |\n\n资料来源：[src/tools.ts:30-50]()\n\n## Error Flow\n\n```mermaid\ngraph TD\n    A[Tool Call] --> B{UDP Send Success?}\n    B -->|No| C[Reject with send error]\n    B -->|Yes| D{Ack received?}\n    D -->|No| E[Timeout after 5000ms]\n    E --> F[\"Error: RetroArch query timed out\"]\n    D -->|Yes| G{NCI Response OK?}\n    G -->|No| H[Parse error or invalid response]\n    G -->|Yes| I[Return success data]\n    \n    C --> J[Error logged to stderr]\n    F --> J\n    H --> J\n    I --> K[JSON-RPC response to MCP client]\n```\n\n资料来源：[src/retroarch.ts:80-90]()\n\n### Error Scenarios\n\n| Error | Cause | User Message |\n|-------|-------|--------------|\n| `RetroArch query timed out` | Network Commands disabled or wrong port | Check `network_cmd_enable` in retroarch.cfg |\n| `no memory map defined` | Core doesn't expose system memory map | Use `read_ram` / `write_ram` instead |\n| `no descriptor for address` | Address outside core's memory regions | Use different address or core |\n| `retroarch query already in flight` | Concurrent query attempted | Tool calls are serialized |\n\n资料来源：[README.md:troubleshooting]()\n\n## Response Data Format\n\n### Memory Read Response\n\n```\nADDR_HEX [N bytes]:\nAB CD EF 12 34 56 78 9A ...\n```\n\nExample:\n```\n0x02000000 [16 bytes]:\n03 D0 00 EA 03 D1 00 EA 03 D2 00 EA 03 D3 00 EA\n```\n\n### Status Response\n\n```\nState:  playing\nSystem: snes\nGame:   Super Mario World (USA).sfc\nCRC32:  1A9FBD77\n```\n\n### Config Response\n\n```\nKEY = VALUE\n```\n\n## Configuration and Environment\n\n```mermaid\ngraph LR\n    subgraph \"Environment Variables\"\n        RA_HOST[\"RETROARCH_HOST<br/>default: 127.0.0.1\"]\n        RA_PORT[\"RETROARCH_PORT<br/>default: 55355\"]\n    end\n    \n    subgraph \"Runtime Config\"\n        SOCKET[\"UDP Socket\"]\n        TIMEOUT[\"timeoutMs<br/>default: 5000\"]\n    end\n    \n    RA_HOST -->|target IP| SOCKET\n    RA_PORT -->|target port| SOCKET\n```\n\n| Variable | Default | Purpose |\n|----------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in retroarch.cfg) |\n\n资料来源：[README.md:configuration]()\n\n## Startup Connectivity Probe\n\nThe server performs a non-blocking connectivity check on startup:\n\n```typescript\nra.connect()\n  .then(() => ra.getVersion())\n  .then((v) => process.stderr.write(`[mcp-retroarch] connected to ${ra.describeTarget()} — RetroArch ${v}\\n`))\n  .catch((err) => process.stderr.write(\n    `[mcp-retroarch] note: RetroArch not reachable yet (${ra.describeTarget()}): ${err}\\n` +\n    `             Enable Network Commands in retroarch.cfg...\\n`,\n  ));\n```\n\nThis probe is **fire-and-forget** and never blocks MCP server readiness.\n\n资料来源：[src/index.ts:1-20]()\n\n## Tool-to-Command Mapping\n\n| MCP Tool | NCI Command | Transport | Expects Response |\n|----------|-------------|-----------|------------------|\n| `retroarch_get_status` | `GET_STATUS` | query | Yes |\n| `retroarch_get_config` | `GET_CONFIG_PARAM` | query | Yes |\n| `retroarch_read_memory` | `READ_CORE_MEMORY` | query | Yes |\n| `retroarch_read_ram` | `READ_CORE_RAM` | query | Yes |\n| `retroarch_write_memory` | `WRITE_CORE_MEMORY` | query | Yes |\n| `retroarch_write_ram` | `WRITE_CORE_RAM` | send | No |\n| `retroarch_save_state_current` | `SAVE_STATE` | send | No |\n| `retroarch_load_state_current` | `LOAD_STATE` | send | No |\n| `retroarch_load_state_slot` | `LOAD_STATE` | send | No |\n| `retroarch_pause_toggle` | `PAUSE_TOGGLE` | send | No |\n| `retroarch_frame_advance` | `FRAMEADVANCE` | send | No |\n| `retroarch_reset` | `RESET` | send | No |\n| `retroarch_screenshot` | `SCREENSHOT` | send | No |\n| `retroarch_show_message` | `SHOW_MSG` | send | No |\n\n资料来源：[src/tools.ts:1-300]()\n资料来源：[src/retroarch.ts:100-200]()\n\n## Non-Blocking Architecture\n\nUnlike earlier versions, the MCP server does not wait for RetroArch connectivity on startup:\n\n| Version | Behavior |\n|---------|----------|\n| ≤ 0.1.0 | Blocked ~5s on VERSION query timeout |\n| ≥ 0.1.1 | Non-blocking, probe runs in background |\n\nThis change eliminated startup delay when RetroArch is not running.\n\n资料来源：[CHANGELOG.md:0.1.1]()\n\n## Summary\n\nThe data flow through mcp-retroarch follows a clear layered architecture:\n\n1. **MCP Layer**: JSON-RPC over stdio for client-server communication\n2. **Tool Layer**: Parameter validation and response formatting in `src/tools.ts`\n3. **Transport Layer**: UDP socket management in `src/retroarch.ts`\n4. **NCI Layer**: RetroArch Network Control Interface commands\n\nThe design prioritizes:\n- **Serial query execution** to prevent response ambiguity\n- **Lazy connection** to avoid startup blocking\n- **Fire-and-forget** for hotkey commands to reduce latency\n- **Explicit acknowledgment** for writes that support it\n\n---\n\n<a id='page-memory-operations'></a>\n\n## Memory Read/Write Operations\n\n### 相关页面\n\n相关主题：[Core Compatibility](#page-core-compatibility), [MCP Tools Reference](#page-tools-reference)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n</details>\n\n# Memory Read/Write Operations\n\n## Overview\n\nThe mcp-retroarch project exposes memory read/write functionality through RetroArch's Network Control Interface (NCI), enabling MCP clients to inspect and mutate the emulated system's memory in real-time. This capability is fundamental for debugging, cheat implementation, game state inspection, and scripted automation.\n\nMemory operations target the emulated system—not the host machine—and support two distinct address space APIs depending on the loaded libretro core's capabilities.\n\n## Architecture\n\nMemory operations flow through a serial UDP transport layer to RetroArch's NCI endpoint:\n\n```mermaid\ngraph TD\n    A[\"MCP Client<br/>retroarch_read_memory<br/>retroarch_write_ram\"] --> B[\"mcp-retroarch<br/>src/tools.ts\"]\n    B --> C[\"RetroArchClient<br/>src/retroarch.ts\"]\n    C -->|UDP :55355| D[\"RetroArch NCI\"]\n    D -->|Memory Map API<br/>or CHEEVOS API| E[\"libretro Core<br/>Emulated System Memory\"]\n    \n    F[\"READ_CORE_MEMORY<br/>WRITE_CORE_MEMORY\"] -.->|system bus| E\n    G[\"READ_CORE_RAM<br/>WRITE_CORE_RAM\"] -.->|CHEEVOS space| E\n```\n\n### Transport Layer\n\nThe UDP socket is initialized in `src/retroarch.ts` with the following behavior:\n\n- **Query mode** (`query()`): Sends a command and awaits exactly one UDP response, throwing on timeout (~5 seconds)\n- **Fire-and-forget mode** (`send()`): Sends a command without waiting for acknowledgment\n\n```typescript\n// Serial query with timeout: src/retroarch.ts:60-85\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  return new Promise<Buffer>((resolve, reject) => {\n    let timer: NodeJS.Timeout | null = setTimeout(() => {\n      this.pending = null;\n      reject(new Error(\n        `RetroArch query \"${command.split(\" \")[0]}\" timed out after ${this.timeoutMs}ms ` +\n        `— is RetroArch running with Network Commands enabled?`,\n      ));\n    }, this.timeoutMs);\n    // ...\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:60-75]()\n\n## Two Memory APIs\n\nmcp-retroarch exposes two independent memory interfaces, each mapping to a different RetroArch NCI command family:\n\n| Aspect | `_memory` API | `_ram` API |\n|--------|--------------|------------|\n| NCI Command | `READ_CORE_MEMORY` / `WRITE_CORE_MEMORY` | `READ_CORE_RAM` / `WRITE_CORE_RAM` |\n| Address Space | System memory bus | CHEEVOS (achievement) space |\n| Core Requirement | Core must expose memory map | Works via CHEEVOS interface |\n| Fallback | Falls back to `_ram` if \"no memory map defined\" | N/A (always available on supported cores) |\n| Write Acknowledgment | ✅ Returns byte count | ❌ Fire-and-forget |\n\n资料来源：[src/tools.ts:1-150]()\n\n### System Memory Map (`_memory`)\n\nThe `_memory` tools use the libretro core's exposed system memory descriptors. This is the **preferred** approach when available because:\n\n- Addresses follow the native system bus layout (e.g., SNES WRAM at `0x7E0000-0x7FFFFF`)\n- `WRITE_CORE_MEMORY` returns acknowledgment with actual byte count written\n- Read-only descriptors are honored (write stops at boundary)\n\n### CHEEVOS Address Space (`_ram`)\n\nThe `_ram` tools use RetroAchievements' address space conventions, which differ from the native system bus:\n\n| System | CHEEVOS WRAM Start | System Bus WRAM Start |\n|--------|-------------------|----------------------|\n| SNES | `0x000000` | `0x7E0000` |\n| GBA | `0x03000000` | `0x02000000` (EWRAM) |\n\n资料来源：[src/tools.ts:95-120]()\n\n## Tool Reference\n\n### `retroarch_read_memory`\n\nRead bytes via the libretro core's system memory map.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `address` | integer | ✅ | Starting address in system memory map |\n| `length` | integer | ✅ | Bytes to read (1-4096) |\n\n**Returns:** Header line `ADDR_HEX [N bytes]:` followed by space-separated uppercase hex bytes.\n\n**Error Conditions:**\n- `\"no memory map defined\"` — Core doesn't expose system memory map\n- `\"no descriptor for address\"` — Address outside core's memory regions\n- Timeout after ~5 seconds\n\n资料来源：[src/tools.ts:70-100]()\n\n### `retroarch_write_memory`\n\nWrite bytes via the libretro core's system memory map. **This is the only write tool that returns acknowledgment.**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `address` | integer | ✅ | Starting address in system memory map |\n| `bytes` | integer[] | ✅ | Byte values 0-255 (max 4096) |\n\n**Returns:** `Wrote N bytes → ADDR_HEX` where N is confirmed written count.\n\n**Side Effects:**\n- Disables RetroArch's hardcore mode for the session\n- Destructive (no undo; use `retroarch_save_state_current` first)\n\n资料来源：[src/tools.ts:100-140]()\n\n### `retroarch_read_ram`\n\nRead bytes via the CHEEVOS (achievement) address space.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `address` | integer | ✅ | Starting address in CHEEVOS space |\n| `length` | integer | ✅ | Bytes to read (1-4096) |\n\n**Returns:** Header line `ADDR_HEX [N bytes, CHEEVOS]:` followed by hex dump.\n\n**Note:** RetroArch may return fewer bytes than requested at memory-region boundaries.\n\n资料来源：[src/tools.ts:120-150]()\n\n### `retroarch_write_ram`\n\nWrite bytes via the CHEEVOS address space. **Fire-and-forget—no acknowledgment.**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `address` | integer | ✅ | Starting address in CHEEVOS space |\n| `bytes` | integer[] | ✅ | Byte values 0-255 (max 4096) |\n\n**Returns:** `Wrote N bytes → ADDR_HEX (CHEEVOS, no ack)`\n\n**Verification:** Follow up with `retroarch_read_ram` at the same address to confirm the write landed.\n\n资料来源：[src/tools.ts:150-180]()\n\n## Usage Workflow\n\n### Read Memory (System Bus)\n\n```typescript\n// Read 16 bytes from SNES WRAM at 0x7E0000\nconst result = await tools.retroarch_read_memory({\n  address: 0x7E0000,\n  length: 16\n});\n// Returns: \"7E0000 [16 bytes]:\n//          00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\"\n```\n\n### Write Memory with Verification\n\n```mermaid\ngraph LR\n    A[\"Save State<br/>retroarch_save_state_current\"] --> B[\"Write Memory<br/>retroarch_write_memory\"]\n    B --> C{\"Response received?\"}\n    C -->|Yes| D[\"Read Back<br/>retroarch_read_memory\"]\n    D --> E[\"Verify bytes match\"]\n    C -->|No/Timeout| F[\"Load State<br/>retroarch_load_state_current\"]\n    E -->|Mismatch| F\n```\n\n### Write RAM (CHEEVOS) with Verification\n\n```mermaid\ngraph LR\n    A[\"Save State\"] --> B[\"Write RAM<br/>retroarch_write_ram\"]\n    B --> C[\"Read Back<br/>retroarch_read_ram\"]\n    C --> D{\"Bytes match?\"}\n    D -->|Yes| E[\"Continue\"]\n    D -->|No| F[\"Load State<br/>retroarch_load_state_current\"]\n```\n\n## Common Address Ranges\n\n| System | Region | System Bus | CHEEVOS Space |\n|--------|--------|------------|---------------|\n| GBA | EWRAM | `0x02000000-0x0203FFFF` | `0x03000000` offset |\n| GBA | IWRAM | `0x03000000-0x03007FFF` | Direct |\n| SNES | WRAM | `0x7E0000-0x7FFFFF` | `0x000000` |\n| Genesis | 68K RAM | `0xFF0000-0xFFFFFF` | N/A |\n\n资料来源：[src/tools.ts:85-95]()\n\n## Limitations\n\n| Limitation | Cause | Workaround |\n|------------|-------|------------|\n| Max 4096 bytes/call | NCI single-datagram size | Batch larger reads in 4 KiB chunks |\n| No \"save to slot N\" | NCI protocol limitation | Walk slot pointer with `state_slot_plus`/`state_slot_minus` |\n| `write_ram` has no ack | RetroArch doesn't respond to `WRITE_CORE_RAM` | Follow up with `retroarch_read_ram` |\n| Address spaces differ | CHEEVOS vs system bus | Use `_memory` tools when possible |\n| Memory regions bounded | Core exposes specific regions | Some addresses (VRAM, etc.) may be inaccessible |\n\n资料来源：[src/tools.ts:145-155]()\n\n## Configuration\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in retroarch.cfg) |\n\n资料来源：[README.md:configuration]()\n\n---\n\n<a id='page-savestate-management'></a>\n\n## Savestate Management\n\n### 相关页面\n\n相关主题：[MCP Tools Reference](#page-tools-reference)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Savestate Management\n\n## Overview\n\nSavestate Management in mcp-retroarch enables programmatic save and load operations for game sessions running under RetroArch's Network Command Interface (NCI). The system provides five MCP tools that wrap RetroArch's savestate NCI commands, allowing MCP clients to snapshot emulator state, restore from previous snapshots, and navigate between save slots.\n\nThe savestate system operates over UDP to RetroArch's NCI on port 55355, with mcp-retroarch acting as a bridge between the MCP JSON-RPC protocol and RetroArch's line-based command protocol.\n\n## Architecture\n\n```\n┌─────────────────┐    stdio JSON-RPC    ┌──────────────────────┐   UDP :55355   ┌─────────────────┐\n│   MCP Client    │◄───────────────────►│    mcp-retroarch     │◄──────────────►│   RetroArch     │\n│ (Claude Code,   │                      │  (src/retroarch.ts)  │                │   (NCI Server)  │\n│  Claude Desktop)│                      └──────────────────────┘                └─────────────────┘\n└─────────────────┘\n```\n\nThe savestate subsystem relies on:\n\n| Layer | Technology | Role |\n|-------|------------|------|\n| MCP Protocol | stdio + JSON-RPC | Client-facing tool interface |\n| Bridge | TypeScript (src/retroarch.ts) | Protocol translation and UDP communication |\n| Transport | UDP datagrams | Direct communication with RetroArch NCI |\n| Target | RetroArch NCI | Savestate command execution |\n\n## Savestate Tools\n\n| Tool | NCI Command | Purpose |\n|------|-------------|---------|\n| `retroarch_save_state_current` | `SAVE_STATE` | Save to currently-selected slot |\n| `retroarch_load_state_current` | `LOAD_STATE` | Load from currently-selected slot |\n| `retroarch_load_state_slot` | `LOAD_STATE_SLOT N` | Load from explicit slot N (1-9) |\n| `retroarch_state_slot_plus` | `STATE_SLOT_PLUS` | Increment slot pointer |\n| `retroarch_state_slot_minus` | `STATE_SLOT_MINUS` | Decrement slot pointer |\n\n### Tool Parameters\n\n#### retroarch_load_state_slot\n\n```json\n{\n  \"name\": \"retroarch_load_state_slot\",\n  \"arguments\": {\n    \"slot\": {\n      \"type\": \"integer\",\n      \"minimum\": 1,\n      \"maximum\": 9,\n      \"description\": \"Savestate slot number (1-9). RetroArch uses 1-based slot indexing.\"\n    }\n  }\n}\n```\n\n### Return Values\n\nAll savestate tools return single-line confirmation messages:\n\n| Tool | Return Message |\n|------|----------------|\n| `retroarch_save_state_current` | `\"Saved to current slot\"` |\n| `retroarch_load_state_current` | `\"Loaded from current slot\"` |\n| `retroarch_load_state_slot` | `\"Loaded from slot N\"` |\n| `retroarch_state_slot_plus` | `\"Slot: N\"` |\n| `retroarch_state_slot_minus` | `\"Slot: N\"` |\n\n> **Note**: These return messages are UDP-send confirmations only. The NCI does not acknowledge command receipt. If a savestate operation fails silently, the tool will still return a success-like message.\n\n资料来源：[src/tools.ts:77-79]()\n\n## Slot-Based Savestate Model\n\n### How Slots Work\n\nRetroArch's savestate system uses a **slot-based model** with 10 slots (0-9 by default, though some builds use 1-9). Each slot holds one savestate file. When you save to an occupied slot, the existing savestate is overwritten.\n\n### The Slot Pointer\n\nRetroArch maintains an internal **current slot pointer** that determines which slot `SAVE_STATE` and `LOAD_STATE` (without a slot argument) target. The slot pointer can be changed using:\n\n```mermaid\ngraph LR\n    A[\"Current Slot = N\"] --> B[\"state_slot_plus\"]\n    B --> C[\"Current Slot = N+1\"]\n    C --> D[\"state_slot_plus\"]\n    D --> E[\"Current Slot = N+2\"]\n    \n    A --> F[\"state_slot_minus\"]\n    F --> G[\"Current Slot = N-1\"]\n    G --> H[\"state_slot_minus\"]\n    H --> I[\"Current Slot = N-2\"]\n```\n\n### Slot Navigation Workflow\n\nTo save to slot 5 when currently at slot 1:\n\n```mermaid\ngraph TD\n    A[\"Start: Slot = 1\"] --> B[\"retroarch_state_slot_plus\"]\n    B --> C[\"Slot = 2\"]\n    C --> D[\"retroarch_state_slot_plus\"]\n    D --> E[\"Slot = 3\"]\n    E --> F[\"retroarch_state_slot_plus\"]\n    F --> G[\"Slot = 4\"]\n    G --> H[\"retroarch_state_slot_plus\"]\n    H --> I[\"Slot = 5\"]\n    I --> J[\"retroarch_save_state_current\"]\n    J --> K[\"Saved to slot 5\"]\n```\n\n## Critical Limitations\n\n### No Direct Save-to-Slot\n\nThe NCI protocol does not expose a `SAVE_STATE_SLOT N` command. This is a protocol limitation, not a bug in mcp-retroarch.\n\n| Operation | Available? | Workaround |\n|-----------|------------|------------|\n| Save to current slot | ✅ Yes | `retroarch_save_state_current` |\n| Save to specific slot | ❌ No | Walk slot pointer with plus/minus, then save |\n| Load from current slot | ✅ Yes | `retroarch_load_state_current` |\n| Load from specific slot | ✅ Yes | `retroarch_load_state_slot` |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Current Slot Not Queryable\n\nThe NCI does not expose a command to query the current slot pointer. Clients must track slot position client-side or use `retroarch_show_message` to echo the slot number.\n\n```mermaid\ngraph TD\n    A[\"Track slot client-side\"] --> B[\"State variable: currentSlot\"]\n    A --> C[\"Use show_message for confirmation\"]\n    C --> D[\"retroarch_show_message with 'Slot: N'\"]\n```\n\n## UDP Communication Details\n\n### Query/Response Pattern\n\nThe savestate bridge uses serial UDP communication with timeout handling:\n\n```typescript\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  return new Promise<Buffer>((resolve, reject) => {\n    let timer: NodeJS.Timeout | null = setTimeout(() => {\n      this.pending = null;\n      reject(new Error(\n        `RetroArch query \"${command.split(\" \")[0]}\" timed out after ${this.timeoutMs}ms`,\n      ));\n    }, this.timeoutMs);\n    // ...\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:72-89]()\n\n### Fire-and-Forget Commands\n\n`retroarch_save_state_current`, `retroarch_state_slot_plus`, and `retroarch_state_slot_minus` use fire-and-forget semantics:\n\n```typescript\nasync send(command: string): Promise<void> {\n  if (!this.socket) await this.connect();\n  return new Promise((resolve, reject) => {\n    this.socket!.send(command, this.port, this.host, (err) =>\n      err ? reject(err) : resolve(),\n    );\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:63-69]()\n\n## Best Practices\n\n### Establish Rollback Points\n\nBefore memory writes or destructive operations, always save the current state:\n\n```typescript\n// 1. Save rollback point\nretroarch_save_state_current();\n\n// 2. Perform memory operations\nretroarch_write_memory(address, bytes);\n\n// 3. If something goes wrong, restore\nretroarch_load_state_current();\n```\n\n### Pre-Check Before Toggle Operations\n\nSince the NCI only exposes toggle commands, verify state before operations that depend on pause state:\n\n```mermaid\ngraph TD\n    A[\"retroarch_get_status\"] --> B{\"state: playing?\"}\n    B -->|Yes, want to pause| C[\"retroarch_pause_toggle\"]\n    B -->|No, want to unpause| C\n    C --> D[\"retroarch_save_state_current\"]\n    D --> E[\"Continue workflow\"]\n```\n\n### Slot Tracking Pattern\n\n```typescript\nlet currentSlot = 1; // Track client-side\n\nasync function saveToSlot(targetSlot) {\n  while (currentSlot < targetSlot) {\n    await retroarch_state_slot_plus();\n    currentSlot++;\n  }\n  while (currentSlot > targetSlot) {\n    await retroarch_state_slot_minus();\n    currentSlot--;\n  }\n  await retroarch_save_state_current();\n}\n```\n\n## Error Handling\n\n### Timeout Errors\n\nIf RetroArch doesn't respond within the timeout period (default: 5000ms), the tool returns an error:\n\n```\nRetroArch query \"SAVE_STATE\" timed out after 5000ms — is RetroArch running with Network Commands enabled?\n```\n\n**Troubleshooting**:\n1. Confirm `network_cmd_enable = \"true\"` in retroarch.cfg\n2. Verify `network_cmd_port = \"55355\"` matches `RETROARCH_PORT` environment variable\n3. Check that a game/ROM is currently loaded (NCI requires active content)\n\n### UDP Drop Handling\n\nUDP datagrams can be dropped under load even on loopback. If a call times out but a retry succeeds, that's normal UDP behavior—the bridge does not auto-retry.\n\n## Configuration\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in retroarch.cfg) |\n\n## Related Tools\n\n| Tool | Relationship |\n|------|--------------|\n| `retroarch_get_status` | Use to verify game state before loading states |\n| `retroarch_frame_advance` | Step frames after loading state to verify restore |\n| `retroarch_show_message` | Echo current slot number for tracking |\n\n## Changelog\n\n### v0.1.2 (2026-05-15)\n\nDocumentation improvements:\n- Slot-based savestate model now explicitly documented\n- Fire-and-forget UDP semantics surfaced in tool descriptions\n- NCI limitation (\"no save to slot N\") clearly documented with workaround\n\n资料来源：[CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n\n---\n\n<a id='page-emulation-control'></a>\n\n## Emulation Control\n\n### 相关页面\n\n相关主题：[MCP Tools Reference](#page-tools-reference)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n</details>\n\n# Emulation Control\n\n## Overview\n\nEmulation Control in mcp-retroarch encompasses the set of tools and mechanisms that allow MCP clients to interact with a running RetroArch emulator. This includes pausing/resuming execution, advancing frames one at a time, resetting games, capturing screenshots, displaying on-screen notifications, and managing save states.\n\nThe control layer operates exclusively through RetroArch's Network Control Interface (NCI), a UDP-based command protocol that listens on port 55355 by default. All control commands are sent as plain-text line-terminated strings over UDP, and the majority are fire-and-forget — RetroArch does not acknowledge receipt or execution status.\n\n## Architecture\n\n### Transport Layer\n\nThe UDP transport is implemented in `src/retroarch.ts`. The communication model uses a single persistent UDP socket with promise-based request/response handling.\n\n```mermaid\ngraph TD\n    A[\"MCP Client<br/>stdio JSON-RPC\"] --> B[\"mcp-retroarch<br/>src/index.ts\"]\n    B --> C[\"RetroArchClient<br/>src/retroarch.ts\"]\n    C --> D[\"UDP Socket<br/>127.0.0.1:55355\"]\n    D --> E[\"RetroArch NCI\"]\n    \n    F[\"NCI Response\"] --> D\n    D --> G[\"Pending Promise<br/>resolve/reject\"]\n    G --> B\n```\n\n**Key transport behaviors:**\n\n| Method | Behavior | Use Case |\n|--------|----------|----------|\n| `send(command)` | Fire-and-forget, no response expected | Pause, reset, frame advance |\n| `query(command)` | Sends command, awaits one UDP response | Memory reads, status queries |\n| `connect()` | Binds UDP socket to ephemeral port | Transport initialization |\n| `disconnect()` | Closes socket | Cleanup |\n\n资料来源：[src/retroarch.ts:1-50]()\n\n### Serialization Constraint\n\nUDP datagrams are line-terminated. This has a critical implication for the `retroarch_show_message` tool: any message containing `\\n` or `\\r` will be truncated at the first newline, with the remainder silently dropped on the wire.\n\n## Core Control Tools\n\n### Pause Toggle\n\n**Tool:** `retroarch_pause_toggle`\n\nToggles RetroArch's pause state between paused and running.\n\n```mermaid\ngraph LR\n    A[\"Call retroarch_get_status\"] --> B{\"state?\"}\n    B -->|\"playing\"| C[\"retroarch_pause_toggle<br/>→ paused\"]\n    B -->|\"paused\"| D[\"retroarch_pause_toggle<br/>→ playing\"]\n    C --> E[\"Verify with retroarch_get_status\"]\n    D --> E\n```\n\n**Important:** The NCI exposes only a toggle, not separate pause and unpause commands. Without first checking the current state via `retroarch_get_status`, the result is indeterminate.\n\n| Property | Value |\n|----------|-------|\n| Input Schema | `{}` (no parameters) |\n| Return | `\"Pause toggled\"` (UDP-send confirmation only) |\n| Fire-and-forget | Yes — no verification of actual pause state |\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### Frame Advance\n\n**Tool:** `retroarch_frame_advance`\n\nAdvances the emulation by exactly one frame. This is only effective while emulation is paused — calling FRAMEADVANCE while running is a no-op.\n\n| Property | Value |\n|----------|-------|\n| Input Schema | `{}` (no parameters) |\n| Prerequisite | Emulation must be paused |\n| Use Case | Frame-precise input automation, animation inspection |\n| Alternative | For large frame jumps, use `retroarch_save_state_current` / `retroarch_load_state_current` |\n\n资料来源：[src/tools.ts]()\n\n### Reset\n\n**Tool:** `retroarch_reset`\n\nPerforms a hard reset of the currently loaded game. The core is reloaded and execution begins from the game's reset vector.\n\n| Property | Value |\n|----------|-------|\n| Input Schema | `{}` (no parameters) |\n| Return | `\"Game reset\"` (UDP-send confirmation only) |\n| Behavior | Immediately interrupts current execution |\n\n资料来源：[src/tools.ts]()\n\n## Save State Management\n\n### State Slots\n\nRetroArch maintains a current state slot pointer (0-9 typically). The save state tools operate on this pointer.\n\n```mermaid\ngraph TD\n    A[\"Current Slot = N\"] --> B[\"retroarch_save_state_current\"]\n    B --> C[\"Save → Slot N\"]\n    \n    A --> D[\"retroarch_load_state_slot<br/>slot: M\"]\n    D --> E{\"M == N?\"}\n    E -->|Yes| F[\"Load from Slot N\"]\n    E -->|No| G[\"retroarch_state_slot_plus/minus<br/>to walk to M\"]\n    G --> H[\"Load from Slot M\"]\n```\n\n### Available Tools\n\n| Tool | Purpose | Input | Return |\n|------|---------|-------|--------|\n| `retroarch_save_state_current` | Save to current slot | None | `\"Saved to current slot\"` |\n| `retroarch_load_state_current` | Load from current slot | None | `\"Loaded from current slot\"` |\n| `retroarch_load_state_slot` | Load from explicit slot | `{ slot: number }` | `\"Loaded from slot N\"` |\n| `retroarch_state_slot_plus` | Increment slot pointer | None | Slot number confirmation |\n| `retroarch_state_slot_minus` | Decrement slot pointer | None | Slot number confirmation |\n\n### Known Limitation\n\nThe NCI protocol does not expose a command to save directly to a specific slot. To save to slot 5 when the pointer is on slot 0:\n\n1. Call `retroarch_state_slot_plus` five times\n2. Call `retroarch_save_state_current`\n\nThis is an NCI limitation, not a bug in mcp-retroarch.\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Visual Feedback Tools\n\n### Screenshot\n\n**Tool:** `retroarch_screenshot`\n\nCaptures the current frame and saves it to RetroArch's configured screenshot directory.\n\n| Property | Value |\n|----------|-------|\n| Input Schema | `{}` (no parameters) |\n| Return | `\"Screenshot saved to RetroArch's configured screenshot directory\"` |\n| Directory | Must be verified in RetroArch GUI: Settings → Directory → Screenshot |\n| NCI Limitation | The `screenshot_directory` param is NOT exposed via `GET_CONFIG_PARAM` |\n\n资料来源：[src/tools.ts](), [README.md]()\n\n### On-Screen Message\n\n**Tool:** `retroarch_show_message`\n\nDisplays a single-line notification overlay on the RetroArch window for approximately 3 seconds (RetroArch's default notification timeout).\n\n| Property | Value |\n|----------|-------|\n| Input Schema | `{ message: string }` | Required, minLength: 1 |\n| Message Limits | ≤80 characters recommended; newlines (`\\n`, `\\r`) truncate |\n| Duration | ~3 seconds (configurable via `input_overlay_show_inputs_port` settings) |\n| Queueing | Messages are NOT queued — rapid calls replace the previous message |\n| Use Case | Debug output, progress markers, \"look here\" cues |\n\n```mermaid\ngraph LR\n    A[\"Message: 'Frame 1234'\"] --> B[\"NCI OSD Overlay\"]\n    C[\"Rapid Second Call\"] --> D[\"Message: 'Frame 1235'\"]\n    D -->|Before A renders| B\n```\n\n**Important:** Because messages replace each other, do not issue multiple `show_message` calls in rapid succession without verification that the previous message was read.\n\n资料来源：[src/tools.ts]()\n\n## UDP Transport Deep Dive\n\n### Socket Lifecycle\n\nFrom `src/retroarch.ts`:\n\n```typescript\nasync connect(): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const sock = dgram.createSocket(\"udp4\");\n    sock.once(\"error\", (err) => reject(err));\n    sock.bind(0, () => {\n      sock.on(\"message\", (msg) => {\n        const cb = this.pending;\n        if (!cb) return;  // unsolicited or late reply — drop\n        this.pending = null;\n        cb(msg);\n      });\n      // ...\n    });\n  });\n}\n```\n\n### Query Timeout\n\nThe `query()` method enforces a configurable timeout (default ~5 seconds):\n\n```typescript\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  return new Promise<Buffer>((resolve, reject) => {\n    let timer: NodeJS.Timeout | null = setTimeout(() => {\n      this.pending = null;\n      reject(new Error(\"RetroArch query timed out\"));\n    }, this.timeoutMs);\n    // ...\n  });\n}\n```\n\n**Serial constraint:** Only one query can be in-flight at a time. The client enforces this with a `pending` callback reference.\n\n资料来源：[src/retroarch.ts]()\n\n## Error Handling\n\n### Common Errors\n\n| Symptom | Cause | Fix |\n|---------|-------|-----|\n| `RetroArch query timed out` | Network Commands disabled or port mismatch | Verify `network_cmd_enable = \"true\"` in `retroarch.cfg` |\n| `retroarch query already in flight` | Code bug or concurrent tool calls | Ensure serial tool execution |\n| Screenshot not where expected | Screenshot saved to RetroArch's configured directory | Check Settings → Directory → Screenshot |\n\n### Background Connectivity\n\nThe MCP server performs a fire-and-find connectivity probe on startup in `src/index.ts`:\n\n```typescript\nra.connect()\n  .then(() => ra.getVersion())\n  .then((v) => process.stderr.write(`[mcp-retroarch] connected to ${ra.describeTarget()} — RetroArch ${v}\\n`))\n  .catch((err) => process.stderr.write(\n    `[mcp-retroarch] note: RetroArch not reachable yet (${ra.describeTarget()}): ${err}\\n` +\n    `             Enable Network Commands in retroarch.cfg (network_cmd_enable / network_cmd_port)\\n`\n  ));\n```\n\nThis does not block server startup — tool calls will connect on demand.\n\n资料来源：[src/index.ts]()\n\n## Configuration\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in `retroarch.cfg`) |\n\nRetroArch-side configuration (via GUI or `retroarch.cfg`):\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\nOr via RetroArch GUI: **Settings → Network → Network Commands → ON**\n\n资料来源：[README.md]()\n\n## Tool Summary Table\n\n| Tool | Type | Input | Fire-and-Forget | Verified Return |\n|------|------|-------|-----------------|-----------------|\n| `retroarch_pause_toggle` | Control | None | Yes | Confirmation only |\n| `retroarch_frame_advance` | Control | None | Yes | Confirmation only |\n| `retroarch_reset` | Control | None | Yes | Confirmation only |\n| `retroarch_save_state_current` | State | None | Yes | Confirmation only |\n| `retroarch_load_state_current` | State | None | Yes | Confirmation only |\n| `retroarch_load_state_slot` | State | `{ slot }` | Yes | Confirmation only |\n| `retroarch_state_slot_plus` | State | None | Yes | Confirmation only |\n| `retroarch_state_slot_minus` | State | None | Yes | Confirmation only |\n| `retroarch_screenshot` | Visual | None | Yes | Confirmation only |\n| `retroarch_show_message` | Visual | `{ message }` | Yes | Confirmation only |\n\n## Dependencies\n\nThe emulation control functionality depends on:\n\n```json\n{\n  \"@modelcontextprotocol/sdk\": \"^1.12.0\"\n}\n```\n\nThe `@modelcontextprotocol/sdk` provides the MCP server framework that exposes these tools via stdio JSON-RPC to compatible MCP clients (Claude Code, Claude Desktop, etc.).\n\n资料来源：[package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n---\n\n<a id='page-tools-reference'></a>\n\n## MCP Tools Reference\n\n### 相关页面\n\n相关主题：[Memory Read/Write Operations](#page-memory-operations), [Savestate Management](#page-savestate-management), [Emulation Control](#page-emulation-control)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# MCP Tools Reference\n\nThe mcp-retroarch project exposes a collection of Model Context Protocol (MCP) tools that enable programmatic control of RetroArch through its Network Control Interface (NCI). These tools provide capabilities ranging from memory inspection and modification to savestate management and emulator control.\n\n## Overview\n\nmcp-retroarch acts as a bridge between MCP clients and RetroArch's UDP-based NCI protocol. The MCP server communicates with RetroArch over UDP port 55355 (default), translating JSON-RPC requests from MCP clients into NCI commands. 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n```\n+----------------+    stdio     +-----------------+   UDP :55355  +-----------------+\n|   MCP client   |   JSON-RPC   |  mcp-retroarch  |   NCI commands |  RetroArch      |\n+----------------+              +-----------------+                +-----------------+\n```\n\n## Tool Categories\n\nThe tools are organized into five functional categories:\n\n| Category | Tools | Purpose |\n|----------|-------|---------|\n| **Status & Config** | `retroarch_get_status`, `retroarch_get_config` | Query emulator state and configuration |\n| **Memory Access** | `retroarch_read_memory`, `retroarch_write_memory`, `retroarch_read_ram`, `retroarch_write_ram` | Read/write emulated system memory |\n| **Savestate** | `retroarch_save_state_current`, `retroarch_load_state_current`, `retroarch_load_state_slot`, `retroarch_state_slot_plus`, `retroarch_state_slot_minus` | Manage game save states |\n| **Emulator Control** | `retroarch_pause_toggle`, `retroarch_frame_advance`, `retroarch_reset` | Control emulation execution |\n| **Media & UI** | `retroarch_screenshot`, `retroarch_show_message` | Capture screenshots and display notifications |\n\n## Memory Architecture\n\nmcp-retroarch provides two distinct memory access APIs, each using different address spaces and underlying NCI commands. 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### System Memory Map (`_memory` tools)\n\nThe `_memory` tools use `READ_CORE_MEMORY` and `WRITE_CORE_MEMORY` commands, accessing the libretro core's system memory map. This is the preferred method when the loaded core advertises a memory map. 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n**Address conventions vary by system:**\n\n| System | Memory Region | Address Range |\n|--------|---------------|---------------|\n| GBA EWRAM | External Work RAM | `0x02000000-0x0203FFFF` |\n| SNES WRAM | Work RAM | `0x7E0000-0x7FFFFF` |\n| Genesis 68K RAM | Main RAM | `0xFF0000-0xFFFFFF` |\n\n### CHEEVOS Address Space (`_ram` tools)\n\nThe `_ram` tools use `READ_CORE_RAM` and `WRITE_CORE_RAM` commands (the older CHEEVOS/achievements API). These tools access the RetroAchievements address space, which follows per-system conventions distinct from the system memory map. 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n**When to use which:**\n\n- Use `_memory` tools as the starting point for memory access\n- Fall back to `_ram` tools when `_memory` returns `'no memory map defined'` (older cores)\n- `read_ram` confirmed working for SwanStation (PSX), Mesen (NES) 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Memory Tool Comparison\n\n| Feature | `_memory` tools | `_ram` tools |\n|---------|-----------------|--------------|\n| NCI Command | `READ_CORE_MEMORY` / `WRITE_CORE_MEMORY` | `READ_CORE_RAM` / `WRITE_CORE_RAM` |\n| Address Space | System memory map | CHEEVOS (achievements) |\n| Write Acknowledgment | Returns byte count | No acknowledgment (fire-and-forget) |\n| Core Support | Requires memory map | Broader (achievements-compatible cores) |\n| Max Bytes/Call | 4096 | 4096 |\n\n## Status & Configuration Tools\n\n### retroarch_get_status\n\nQueries the current emulator state including run-state, loaded ROM, and CRC32.\n\n**Input:** No parameters\n\n**Returns:**\n- `State: playing|paused`\n- `System: SYSTEM_ID`\n- `Game: BASENAME`\n- `CRC32: HEX or (none reported)`\n\nReturns `'No content loaded'` when RetroArch is at the menu with no ROM. 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### retroarch_get_config\n\nReads a single RetroArch configuration parameter by name.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `name` | string | Yes | Configuration parameter name |\n\n**Notes:**\n- Uses `GET_CONFIG_PARAM` command\n- RetroArch whitelists exposed parameters; non-whitelisted names error\n- `screenshot_directory` is NOT exposed via this API 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Memory Access Tools\n\n### retroarch_read_memory\n\nReads bytes from the system memory map via `READ_CORE_MEMORY`.\n\n**Parameters:**\n\n| Parameter | Type | Required | Constraints | Description |\n|-----------|------|----------|-------------|-------------|\n| `address` | integer | Yes | ≥ 0 | Starting address in system memory map |\n| `length` | integer | Yes | 1-4096 | Number of bytes to read |\n\n**Returns:** `ADDR_HEX [N bytes]:` followed by space-separated uppercase hex bytes\n\n**Notes:**\n- Returns fewer bytes if read crosses a memory-region boundary\n- Works whether emulation is paused or running\n- Throws error if core doesn't expose a memory map 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### retroarch_write_memory\n\nWrites bytes to the system memory map via `WRITE_CORE_MEMORY`.\n\n**Parameters:**\n\n| Parameter | Type | Required | Constraints | Description |\n|-----------|------|----------|-------------|-------------|\n| `address` | integer | Yes | ≥ 0 | Starting address in system memory map |\n| `bytes` | array | Yes | 1-4096 elements, each 0-255 | Byte values to write |\n\n**Returns:** `Wrote N bytes → ADDR_HEX`\n\n**Notes:**\n- **DESTRUCTIVE** - overwrites existing data with no undo\n- Disables RetroArch's hardcore mode for the session\n- Returns byte count (the only NCI write command that acknowledges) 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### retroarch_read_ram\n\nReads bytes from the CHEEVOS address space via `READ_CORE_RAM`.\n\n**Parameters:**\n\n| Parameter | Type | Required | Constraints | Description |\n|-----------|------|----------|-------------|-------------|\n| `address` | integer | Yes | ≥ 0 | Starting address in CHEEVOS space |\n| `length` | integer | Yes | 1-4096 | Number of bytes to read |\n\n**Returns:** `ADDR_HEX [N bytes, CHEEVOS]:` followed by space-separated uppercase hex bytes\n\n**Notes:**\n- Fallback when `_memory` returns `'no memory map defined'`\n- CHEEVOS addresses follow RetroAchievements conventions (e.g., SNES WRAM starts at `0x000000`, not `0x7E0000`) 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### retroarch_write_ram\n\nWrites bytes to the CHEEVOS address space via `WRITE_CORE_RAM`.\n\n**Parameters:**\n\n| Parameter | Type | Required | Constraints | Description |\n|-----------|------|----------|-------------|-------------|\n| `address` | integer | Yes | ≥ 0 | Starting address in CHEEVOS space |\n| `bytes` | array | Yes | 1-4096 elements, each 0-255 | Byte values to write |\n\n**Returns:** `Wrote N bytes → ADDR_HEX (CHEEVOS, no ack)`\n\n**Notes:**\n- **DESTRUCTIVE** and **fire-and-forget** - no verification\n- Disables RetroArch's hardcore mode\n- RetroArch does not acknowledge this command\n- Verify writes with `retroarch_read_ram` after writing 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Savestate Management\n\nThe NCI protocol has limitations for savestate operations:\n\n1. **No direct \"save to slot N\"** - only save to the currently-selected slot\n2. **No query for current slot** - client must track the slot pointer\n3. **Load** supports both current slot and explicit slot numbers 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### retroarch_save_state_current\n\nSaves the current game state to the currently-selected slot.\n\n**Input:** No parameters\n\n**Returns:** `Saved to current slot`\n\n### retroarch_load_state_current\n\nLoads game state from the currently-selected slot.\n\n**Input:** No parameters\n\n**Returns:** `Loaded from current slot`\n\n### retroarch_load_state_slot\n\nLoads game state from an explicit slot number.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `slot` | integer | Yes | Savestate slot number (0-9 typically) |\n\n**Returns:** `Loaded from slot N`\n\n### retroarch_state_slot_plus / retroarch_state_slot_minus\n\nMoves the current slot pointer up or down. Used to navigate to a target slot before saving.\n\n**Input:** No parameters\n\n**Returns:** Slot navigation confirmation\n\n**Workflow for saving to a specific slot:**\n\n```mermaid\ngraph TD\n    A[Start] --> B{Current slot = target?}\n    B -->|Yes| E[retroarch_save_state_current]\n    B -->|No| C{Increment or decrement?}\n    C -->|Plus| D[retroarch_state_slot_plus]\n    C -->|Minus| F[retroarch_state_slot_minus]\n    D --> B\n    F --> B\n    E --> G[Done]\n```\n\n## Emulator Control Tools\n\n### retroarch_pause_toggle\n\nToggles RetroArch's pause state.\n\n**Input:** No parameters\n\n**Returns:** `Pause toggled`\n\n**Notes:**\n- NCI exposes only a toggle, not separate pause/unpause\n- Call `retroarch_get_status` first to check current state if needed 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### retroarch_frame_advance\n\nAdvances emulation by exactly one frame.\n\n**Input:** No parameters\n\n**Returns:** `Advanced one frame`\n\n### retroarch_reset\n\nHard-resets the running game.\n\n**Input:** No parameters\n\n**Returns:** `Game reset`\n\n## Media & UI Tools\n\n### retroarch_screenshot\n\nCaptures a screenshot and saves it to RetroArch's configured screenshot directory.\n\n**Input:** No parameters\n\n**Returns:** `Screenshot saved to RetroArch's configured screenshot directory`\n\n**Notes:**\n- The NCI doesn't expose `screenshot_directory` via `GET_CONFIG_PARAM`\n- Check the configured path via RetroArch GUI: Settings → Directory → Screenshot 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### retroarch_show_message\n\nDisplays a notification on the RetroArch window.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `message` | string | Yes | Message text to display |\n\n**Returns:** `Showed: {message}`\n\n## Transport Semantics\n\nAll tools communicate with RetroArch via UDP datagrams. This has important implications:\n\n### Fire-and-Forget Commands\n\nMost NCI commands (write_ram, pause_toggle, frame_advance, reset, save_state, etc.) do **not** receive acknowledgment from RetroArch. The success message returned by the tool confirms only that the UDP packet was sent, not that RetroArch received or acted on it. 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### Query Commands with Acknowledgment\n\nThe `retroarch_write_memory` command is the **only** write command that returns a byte count from RetroArch, providing limited verification of the write operation.\n\n### Timeout Handling\n\nUDP queries timeout after a configurable interval (default: 5000ms). Common timeout causes:\n\n1. Network Commands not enabled in RetroArch\n2. Port mismatch between `RETROARCH_PORT` and RetroArch's `network_cmd_port`\n3. UDP datagrams dropped under load (even on loopback) 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\nThe bridge does **not** auto-retry on timeout; retry the call if needed. 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Configuration\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in `retroarch.cfg`) |\n\n## Error Handling\n\n| Error Message | Cause / Fix |\n|---------------|-------------|\n| `RetroArch query timed out` | Network Commands not enabled; port mismatch; UDP dropped |\n| `READ_CORE_MEMORY failed: no memory map defined` | Core doesn't advertise memory map; use `read_ram` instead |\n| `READ_CORE_MEMORY failed: no descriptor for address` | Address outside core's memory regions |\n| Screenshots don't appear | Check RetroArch's screenshot directory setting via GUI |\n| Can't save to specific slot directly | NCI limitation; walk slot pointer with `state_slot_plus/minus` first |\n\n## Tool Summary Table\n\n| Tool | Input Parameters | Returns | Side Effects |\n|------|------------------|---------|--------------|\n| `retroarch_get_status` | — | Emulator state info | None |\n| `retroarch_get_config` | `name` | Config value | None |\n| `retroarch_read_memory` | `address`, `length` | Hex dump | None |\n| `retroarch_write_memory` | `address`, `bytes` | Byte count | Disables hardcore mode |\n| `retroarch_read_ram` | `address`, `length` | Hex dump (CHEEVOS) | None |\n| `retroarch_write_ram` | `address`, `bytes` | Confirmation | Disables hardcore mode |\n| `retroarch_pause_toggle` | — | Pause toggled | Changes run-state |\n| `retroarch_frame_advance` | — | Frame advanced | Advances emulation |\n| `retroarch_reset` | — | Game reset | Hard-resets game |\n| `retroarch_screenshot` | — | Screenshot path | Creates file |\n| `retroarch_show_message` | `message` | Message displayed | Shows notification |\n| `retroarch_save_state_current` | — | Save confirmed | Overwrites current slot |\n| `retroarch_load_state_current` | — | Load confirmed | Loads current slot |\n| `retroarch_load_state_slot` | `slot` | Load confirmed | Loads specified slot |\n| `retroarch_state_slot_plus` | — | Slot moved | Increments slot pointer |\n| `retroarch_state_slot_minus` | — | Slot moved | Decrements slot pointer |\n\n---\n\n<a id='page-core-compatibility'></a>\n\n## Core Compatibility\n\n### 相关页面\n\n相关主题：[Memory Read/Write Operations](#page-memory-operations)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Core Compatibility\n\n## Overview\n\nCore Compatibility refers to the ability of mcp-retroarch to interact with different libretro cores running inside RetroArch. Since each emulator core implements the libretro API differently—and exposes different memory maps and features—mcp-retroarch provides multiple memory access pathways and behavioral workarounds to maximize cross-core support.\n\nThe MCP server communicates with RetroArch via the Network Control Interface (NCI), a UDP-based command protocol. The level of functionality available depends on:\n\n1. Whether the loaded core exposes a system memory map via libretro\n2. Whether the core responds to the CHEEVOS (RetroAchievements) read API\n3. Which specific NCI commands the core supports\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Memory Access Architecture\n\nmcp-retroarch provides two distinct memory reading pathways, each targeting a different address space:\n\n### Memory Access Methods Comparison\n\n| Aspect | `retroarch_read_memory` | `retroarch_read_ram` |\n|--------|------------------------|---------------------|\n| **NCI Command** | `READ_CORE_MEMORY` | `READ_CORE_RAM` |\n| **Address Space** | Libretro system memory map | CHEEVOS achievement address space |\n| **Core Requirement** | Core must expose memory map descriptors | Works if core exposes CHEEVOS |\n| **Fallback** | Auto-fall back to `read_ram` on \"no memory map\" | No further fallback |\n| **Use Case** | Primary tool for memory inspection | Fallback / older cores |\n\n资料来源：[src/tools.ts:1-200](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### Address Space Differences\n\nThe two memory paths use fundamentally different addressing schemes:\n\n```mermaid\ngraph TB\n    subgraph \"Libretro Memory Map read_memory\"\n        A[\"SNES WRAM: 0x7E0000-0x7FFFFF\"] \n        B[\"GBA EWRAM: 0x02000000-0x0203FFFF\"]\n        C[\"Genesis 68K RAM: 0xFF0000-0xFFFFFF\"]\n    end\n    \n    subgraph \"CHEEVOS Address Space read_ram\"\n        D[\"SNES WRAM: 0x000000\"]\n        E[\"GBA WRAM: 0x02000000\"]\n        F[\"NES WRAM: 0x0000\"]\n    end\n```\n\nFor example, SNES WRAM appears at:\n- **System memory map**: `0x7E0000`\n- **CHEEVOS space**: `0x000000`\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Tested Cores Matrix\n\nThe following cores have been verified end-to-end with mcp-retroarch:\n\n| System | Core | `read_memory` | `read_ram` | Notes |\n|--------|------|---------------|------------|-------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA interrupt vector table visible at `0x0000` (`d3 00 00 ea ...`) |\n| NES | `mesen_libretro` | ✅ (only NES core tested that does) | ✅ | Full 16-bit NES address space exposed. WRAM at `0x0000-0x07FF`, mirrored to `0x1FFF`. CHEEVOS bounded to first 64 KB. |\n| NES | `nestopia_libretro` | ❌ (no memory map) | ✅ | CHEEVOS only. 64 KB bound. **For NES + memory map, prefer Mesen.** |\n| SNES | `snes9x_libretro` | ❌ | — | Status not fully documented in current release |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Feature Support by Core\n\n### Memory Read/Write\n\n| Capability | Supported | Details |\n|------------|-----------|---------|\n| System memory map | Core-dependent | Only cores that expose descriptors via `READ_CORE_MEMORY` |\n| CHEEVOS RAM read | Most cores | Achievement API is widely supported |\n| Memory write | Same pathways as reads | `WRITE_CORE_MEMORY` or `WRITE_CORE_RAM` |\n\n**Important limitation**: Memory writes via NCI automatically disable RetroArch's hardcore mode for the rest of the session.\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### Savestate Operations\n\nSavestate functionality is supported universally across cores since it uses RetroArch's internal state management:\n\n| Operation | Support | Notes |\n|-----------|---------|-------|\n| Save to current slot | ✅ | Uses `SAVE_STATE_CURRENT` |\n| Load from current slot | ✅ | Uses `LOAD_STATE_CURRENT` |\n| Load from explicit slot | ✅ | Uses `LOAD_STATE` with slot number |\n| Save to explicit slot | ❌ | NCI limitation—must walk slot pointer |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Game-Pad Input\n\n**Not supported** via mcp-retroarch. The NCI protocol does not expose game-pad input. RetroArch has a separate \"Remote RetroPad\" mechanism on UDP port 55400, but it requires loading a specific core and cannot drive an existing emulation session.\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Choosing the Right Memory Tool\n\n```mermaid\ngraph TD\n    A[\"Need to read/write memory?\"] --> B{\"Does read_memory return<br/>'no memory map defined'?\"}\n    B -->|Yes| C[\"Use retroarch_read_ram\"]\n    B -->|No| D[\"Use retroarch_read_memory\"]\n    C --> E[\"Address in CHEEVOS space\"]\n    D --> F[\"Address in libretro memory map\"]\n    \n    style B fill:#ffcccc\n    style C fill:#ccffcc\n    style D fill:#ccffcc\n```\n\n### Decision Criteria\n\n1. **Start with `retroarch_read_memory`** — It provides access to the native system memory map and is the preferred pathway.\n\n2. **Fall back to `retroarch_read_ram`** when:\n   - The core returns \"no memory map defined\"\n   - You need CHEEVOS achievement-style addresses\n   - Working with cores like `nestopia_libretro` that don't expose system memory maps\n\n3. **Write operations follow the same path** as your read operations.\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Core-Specific Behaviors\n\n### NES Cores Comparison\n\n| Feature | Mesen | Nestopia |\n|---------|-------|----------|\n| System memory map | ✅ Exposed | ❌ Not exposed |\n| CHEEVOS RAM | ✅ 64 KB bound | ✅ 64 KB bound |\n| Full address space | ✅ 0x0000-0xFFFF | Limited to first 64 KB |\n| **Recommendation** | **Preferred for memory work** | Use for achievements only |\n\n### GBA with mgba_libretro\n\nThe `mgba_libretro` core provides full memory map access:\n- Interrupt vector table at `0x0000` is readable via `read_memory`\n- Example data visible: `d3 00 00 ea ...`\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## UDP Communication Model\n\nmcp-retroarch uses a serial query model with timeout handling:\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP Client\n    participant Bridge as mcp-retroarch\n    participant RA as RetroArch NCI\n    \n    MCP->>Bridge: Tool call (e.g., retroarch_read_memory)\n    Bridge->>Bridge: Check if socket connected\n    Bridge->>RA: UDP query (e.g., READ_CORE_MEMORY ...)\n    Note over Bridge: Set timeout timer\n    RA-->>Bridge: UDP response\n    Bridge->>Bridge: Clear timeout, resolve promise\n    Bridge-->>MCP: JSON-RPC response\n    \n    Note over Bridge,RA: Timeout → Error \"RetroArch query timed out\"\n```\n\nKey behaviors:\n- Only one query can be in flight at a time\n- Default timeout: configurable, typically 5000ms\n- UDP is unreliable—retries may be needed under load\n\n资料来源：[src/retroarch.ts:1-100](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n## Troubleshooting Core Compatibility\n\n| Symptom | Cause | Solution |\n|---------|-------|----------|\n| `READ_CORE_MEMORY failed: no memory map defined` | Core doesn't expose system memory map | Use `retroarch_read_ram` instead |\n| `READ_CORE_MEMORY failed: no descriptor for address` | Address outside core's memory regions | Use a different core or check valid address range |\n| `RetroArch query timed out` | Network Commands not enabled or port mismatch | Enable in RetroArch GUI or set `network_cmd_enable = \"true\"` |\n| Inconsistent responses | UDP datagram drops under load | Retry the query—mcp-retroarch doesn't auto-retry |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Configuration for Core Support\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in RetroArch config) |\n\nRetroArch must have Network Commands enabled:\n- **GUI**: Settings → Network → Network Commands → ON\n- **Config file**: `network_cmd_enable = \"true\"`\n\n资料来源：[README.md](https://github://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Architecture Summary\n\n```\n+----------------+    stdio     +-----------------+   UDP :55355  +-----------------+\n|   MCP client   |   JSON-RPC   |  mcp-retroarch  |   commands   |   RetroArch     |\n|                |◄────────────►|                 |◄────────────►|   (any core)    |\n+----------------+              +-----------------+              +-----------------+\n```\n\nThe bridge translates MCP tool calls into NCI UDP commands. Core compatibility depends entirely on what the underlying libretro core exposes via the NCI protocol.\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Related Tools for Other Platforms\n\n| Platform | Tool | Features |\n|----------|------|----------|\n| Game Boy Advance | [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | Memory + button input + screenshot via mGBA Lua bridge |\n| PCSX2, etc. | [mcp-pine](https://github.com/dmang-dev/mcp-pine) | Memory + savestate only via PINE protocol |\n\nThese alternatives may provide better compatibility for their respective platforms when NCI-based cores lack features.\n\n---\n\n<a id='page-configuration'></a>\n\n## Configuration\n\n### 相关页面\n\n相关主题：[Quick Start Guide](#page-quick-start)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Configuration\n\nThe Configuration system in mcp-retroarch encompasses two distinct layers: the MCP server's runtime settings (controlled via environment variables) and RetroArch's Network Control Interface (NCI) parameters (queried at runtime). Together, they establish the communication bridge between an MCP client and a running RetroArch instance.\n\n## Overview\n\nmcp-retroarch acts as a bridge server that translates MCP tool calls into UDP datagrams sent to RetroArch's Network Command Interface. Configuration determines:\n\n1. **Network transport** — where to send UDP commands (host and port)\n2. **RetroArch NCI readiness** — ensuring RetroArch has Network Commands enabled\n3. **Runtime parameter discovery** — querying RetroArch's internal configuration state\n\n资料来源：[README.md:30-35]()\n\n```mermaid\ngraph TD\n    A[MCP Client] -->|JSON-RPC over stdio| B[mcp-retroarch Server]\n    B -->|UDP datagrams| C{RetroArch Network Commands}\n    C -->|Enabled?| D[Commands processed]\n    C -->|Disabled| E[Timeout / Error]\n    \n    F[Environment Variables] --> B\n    G[retroarch.cfg] --> C\n```\n\n## Environment Variables\n\nThe MCP server reads the following environment variables at startup to configure its UDP transport layer.\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host — the machine running RetroArch |\n| `RETROARCH_PORT` | `55355` | UDP port — must match `network_cmd_port` in RetroArch's config |\n\n资料来源：[README.md:52-54]()\n\n### Configuration Precedence\n\nEnvironment variables are read directly without any configuration file parsing. If not set, the defaults apply. The server does not support configuration via `~/.retroarch.cfg` or similar — only environment variables control mcp-retroarch itself.\n\n### Non-blocking Startup\n\nThe MCP server starts immediately without blocking on RetroArch connectivity. A background probe attempts to connect and log the RetroArch version, but tool calls connect on demand if RetroArch is unreachable at startup.\n\n资料来源：[src/index.ts:20-27]()\n\n```typescript\n// Background connectivity probe — fire-and-forget, never blocks the server.\nra.connect()\n  .then(() => ra.getVersion())\n  .then((v) => process.stderr.write(`[mcp-retroarch] connected to ${ra.describeTarget()} — RetroArch ${v}\\n`))\n  .catch((err) => process.stderr.write(\n    `[mcp-retroarch] note: RetroArch not reachable yet (${ra.describeTarget()}): ${err}\\n` +\n    `             Enable Network Commands in retroarch.cfg (network_cmd_enable / network_cmd_port)\\n` +\n    `             or Settings > Network > Network Commands. Tool calls will connect on demand.\\n`,\n  ));\n```\n\n资料来源：[src/index.ts:20-27]()\n\n## RetroArch Network Commands Setup\n\nFor mcp-retroarch to communicate with RetroArch, Network Commands must be enabled in RetroArch itself. This is a one-time setup per RetroArch installation.\n\n### Method 1: GUI Configuration\n\n1. Navigate to **Settings → Network → Network Commands**\n2. Set **Network Commands** to **ON**\n3. Confirm **Network Cmd Port** is `55355` (the default)\n\n资料来源：[README.md:25-28]()\n\n### Method 2: Configuration File\n\nAdd or edit the following in `retroarch.cfg`:\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n资料来源：[README.md:30-35]()\n\n### Port Matching Requirement\n\nThe port configured in RetroArch (`network_cmd_port`) **must match** the `RETROARCH_PORT` environment variable used by mcp-retroarch. Mismatches result in `RetroArch query timed out` errors.\n\n资料来源：[README.md:52-54]()\n\n```mermaid\ngraph LR\n    A[mcp-retroarch<br/>RETROARCH_PORT] -->|55355| B{Port Match?}\n    C[RetroArch<br/>network_cmd_port] -->|55355| B\n    B -->|Yes| D[Communication OK]\n    B -->|No| E[Timeout Error]\n```\n\n## Reading RetroArch Configuration\n\nThe `retroarch_get_config` tool queries RetroArch's internal configuration state via the NCI `GET_CONFIG_PARAM` command. This reads **runtime values** from RetroArch, not the static config file.\n\n资料来源：[src/tools.ts:80-96]()\n\n### Available Configuration Parameters\n\nRetroArch's NCI exposes a **whitelist** of configuration keys. The following parameters are confirmed available:\n\n| Category | Parameter | Returns | Notes |\n|----------|-----------|---------|-------|\n| Directories | `savefile_directory` | Absolute path | User's save file directory |\n| Directories | `savestate_directory` | Absolute path | Savestate directory |\n| Directories | `system_directory` | Absolute path | System/BIOS directory |\n| Directories | `cache_directory` | Absolute path | Cache location |\n| Directories | `log_dir` | Absolute path | Log file directory |\n| Directories | `runtime_log_directory` | Absolute path | Runtime log directory |\n| Directories | `core_assets_directory` | Absolute path | Downloaded core assets |\n| User Data | `netplay_nickname` | String | Netplay display name |\n| Video | `video_fullscreen` | `true` / `false` | Fullscreen toggle |\n| Video | `video_vsync` | `true` / `false` | Vertical sync toggle |\n| Audio | `audio_mute_enable` | `true` / `false` | Audio mute toggle |\n\n资料来源：[src/tools.ts:80-96]()\n\n### Notable Exclusions\n\nThe `screenshot_directory` parameter is **intentionally NOT exposed** by RetroArch's NCI whitelist. Screenshots are saved to RetroArch's configured screenshot directory, but this cannot be queried programmatically. Check the value manually via **Settings → Directory → Screenshot**.\n\n资料来源：[src/tools.ts:80-96]()\n\n### Current Savestate Slot\n\nThere is **no NCI key** for querying the currently-selected savestate slot. Track the slot number client-side by using `retroarch_state_slot_plus` and `retroarch_state_slot_minus`, or start from slot 1 (NCI default).\n\n资料来源：[src/tools.ts:80-96]()\n\n### Tool Definition\n\n```json\n{\n  \"name\": \"retroarch_get_config\",\n  \"description\": \"PURPOSE: Read a single RetroArch configuration parameter by name via the NCI GET_CONFIG_PARAM command.\",\n  \"inputSchema\": {\n    \"type\": \"object\",\n    \"required\": [\"name\"],\n    \"properties\": {\n      \"name\": {\n        \"type\": \"string\",\n        \"minLength\": 1,\n        \"description\": \"Config key — same snake_case ASCII identifier RetroArch uses in retroarch.cfg\"\n      }\n    }\n  }\n}\n```\n\n资料来源：[src/tools.ts:80-96]()\n\n### Return Format\n\n```\nNAME = VALUE\n```\n\nWhere `VALUE` is the raw string as stored in `retroarch.cfg`:\n- Paths are **unquoted**\n- Booleans are `'true'` / `'false'`\n- Integers are **decimal**\n\n资料来源：[src/tools.ts:80-96]()\n\n### Error Conditions\n\nThe tool returns an error if:\n1. The parameter name is not in RetroArch's NCI whitelist\n2. The value contains characters that break the line-based reply parser (rare — embedded newlines or null bytes)\n3. The UDP query times out (RetroArch not reachable)\n\n资料来源：[src/tools.ts:80-96]()\n\n## UDP Transport Layer\n\nThe communication between mcp-retroarch and RetroArch uses UDP datagrams on a serial-by-default basis.\n\n### Connection Behavior\n\n```typescript\nasync connect(): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const sock = dgram.createSocket(\"udp4\");\n    sock.once(\"error\", (err) => reject(err));\n    sock.bind(0, () => {\n      sock.on(\"message\", (msg) => {\n        const cb = this.pending;\n        if (!cb) return;       // unsolicited or late reply — drop\n        this.pending = null;\n        cb(msg);\n      });\n      sock.on(\"error\", () => { /* swallow late errors */ });\n      this.socket = sock;\n      resolve();\n    });\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:10-27]()\n\n### Serial Query Model\n\nThe NCI protocol carries no request IDs, so matching responses by command-name echo is fragile. mcp-retroarch uses a **serial-by-default** approach: only one query can be in flight at a time.\n\n```typescript\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  // ... send and wait for response\n}\n```\n\n资料来源：[src/retroarch.ts:50-58]()\n\n### Fire-and-Forget Commands\n\nHotkey-style commands (pause toggle, frame advance, etc.) use fire-and-forget semantics since the NCI doesn't acknowledge them:\n\n```typescript\nasync send(command: string): Promise<void> {\n  if (!this.socket) await this.connect();\n  return new Promise((resolve, reject) => {\n    this.socket!.send(command, this.port, this.host, (err) =>\n      err ? reject(err) : resolve(),\n    );\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:35-43]()\n\n## MCP Client Registration\n\nAfter configuring mcp-retroarch, register it with your MCP client.\n\n### Claude Code\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\nVerify registration:\n\n```bash\nclaude mcp list\n# retroarch: mcp-retroarch - ✓ Connected\n```\n\n资料来源：[README.md:38-43]()\n\n### Claude Desktop\n\nEdit `claude_desktop_config.json`:\n\n| Platform | Path |\n|----------|------|\n| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |\n| Windows | `%APPDATA%\\Claude\\claude_desktop_config.json` |\n| Linux | `~/.config/Claude/claude_desktop_config.json` |\n\n```json\n{\n  \"mcpServers\": {\n    \"retroarch\": {\n      \"command\": \"mcp-retroarch\"\n    }\n  }\n}\n```\n\n资料来源：[README.md:45-57]()\n\nAfter editing, **restart Claude Desktop** for changes to take effect.\n\n## Troubleshooting\n\n| Symptom | Cause / Fix |\n|---------|-------------|\n| `RetroArch query timed out` | Network Commands aren't enabled in RetroArch, or the port doesn't match `RETROARCH_PORT`. Confirm `network_cmd_enable = \"true\"` in `retroarch.cfg`. UDP datagrams can be dropped under load even on loopback — if a single call times out but a retry succeeds, that's the cause. |\n| `READ_CORE_MEMORY failed: no memory map defined` | The loaded libretro core doesn't advertise a system memory map. Try `retroarch_read_ram` (CHEEVOS path). |\n| `READ_CORE_MEMORY failed: no descriptor for address` | The address isn't covered by the core's memory map. Either a different core would expose it, or the address is outside the system bus. |\n| Screenshots don't appear where I expect | RetroArch saves to its configured screenshot directory. This cannot be queried via NCI — check via **Settings → Directory → Screenshot**. |\n\n资料来源：[README.md:85-98]()\n\n## Development Configuration\n\nFor local development:\n\n```bash\nnpm install\nnpm run dev      # tsc --watch\n```\n\n资料来源：[README.md:75-79]()\n\nSmoke test against a running RetroArch:\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n资料来源：[README.md:80-82]()\n\n## Configuration Summary\n\n| Layer | Setting | Default | Source |\n|-------|---------|---------|--------|\n| MCP Server | `RETROARCH_HOST` | `127.0.0.1` | Environment variable |\n| MCP Server | `RETROARCH_PORT` | `55355` | Environment variable |\n| RetroArch | `network_cmd_enable` | `\"true\"` | `retroarch.cfg` or GUI |\n| RetroArch | `network_cmd_port` | `55355` | `retroarch.cfg` or GUI |\n\n资料来源：[README.md:30-35, 52-54]()\n\n## Version History\n\n| Version | Date | Configuration Changes |\n|---------|------|----------------------|\n| 0.1.2 | 2026-05-15 | Tool description quality pass — improved configuration parameter documentation |\n| 0.1.1 | 2026-05-11 | Non-blocking startup — server no longer waits for RetroArch connectivity |\n| 0.1.0 | 2026-05-10 | Initial release with UDP client and MCP server |\n\n资料来源：[CHANGELOG.md:1-30]()\n\n---\n\n---\n\n## Doramagic Pitfall Log\n\nProject: dmang-dev/mcp-retroarch\n\nSummary: Found 7 potential pitfall items; 0 are high/blocking. Highest priority: configuration - 可能修改宿主 AI 配置.\n\n## 1. configuration · 可能修改宿主 AI 配置\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: 项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。\n- User impact: 安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。\n- Suggested check: 列出会写入的配置文件、目录和卸载/回滚步骤。\n- Guardrail action: 涉及宿主配置目录时必须给回滚路径，不能只给安装命令。\n- Evidence: capability.host_targets | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | host_targets=mcp_host, claude\n\n## 2. capability · 能力判断依赖假设\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: README/documentation is current enough for a first validation pass.\n- User impact: 假设不成立时，用户拿不到承诺的能力。\n- Suggested check: 将假设转成下游验证清单。\n- Guardrail action: 假设必须转成验证项；没有验证结果前不能写成事实。\n- Evidence: capability.assumptions | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | README/documentation is current enough for a first validation pass.\n\n## 3. maintenance · 维护活跃度未知\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: 未记录 last_activity_observed。\n- User impact: 新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- Suggested check: 补 GitHub 最近 commit、release、issue/PR 响应信号。\n- Guardrail action: 维护活跃度未知时，推荐强度不能标为高信任。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | last_activity_observed missing\n\n## 4. security_permissions · 下游验证发现风险项\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: 下游已经要求复核，不能在页面中弱化。\n- Suggested check: 进入安全/权限治理复核队列。\n- Guardrail action: 下游风险存在时必须保持 review/recommendation 降级。\n- Evidence: downstream_validation.risk_items | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 5. security_permissions · 存在评分风险\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: 风险会影响是否适合普通用户安装。\n- Suggested check: 把风险写入边界卡，并确认是否需要人工复核。\n- Guardrail action: 评分风险必须进入边界卡，不能只作为内部分数。\n- Evidence: risks.scoring_risks | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 6. maintenance · issue/PR 响应质量未知\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: issue_or_pr_quality=unknown。\n- User impact: 用户无法判断遇到问题后是否有人维护。\n- Suggested check: 抽样最近 issue/PR，判断是否长期无人处理。\n- Guardrail action: issue/PR 响应未知时，必须提示维护风险。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | issue_or_pr_quality=unknown\n\n## 7. maintenance · 发布节奏不明确\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: release_recency=unknown。\n- User impact: 安装命令和文档可能落后于代码，用户踩坑概率升高。\n- Suggested check: 确认最近 release/tag 和 README 安装命令是否一致。\n- Guardrail action: 发布节奏未知或过期时，安装说明必须标注可能漂移。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | release_recency=unknown\n\n<!-- canonical_name: dmang-dev/mcp-retroarch; human_manual_source: deepwiki_human_wiki -->\n",
      "markdown_key": "mcp-retroarch",
      "pages": "draft",
      "source_refs": [
        {
          "evidence_id": "github_repo:1234498337",
          "kind": "repo",
          "supports_claim_ids": [
            "claim_identity",
            "claim_distribution",
            "claim_capability"
          ],
          "url": "https://github.com/dmang-dev/mcp-retroarch"
        },
        {
          "evidence_id": "art_c635769d3e3c4887a891040dc3b6d43e",
          "kind": "docs",
          "supports_claim_ids": [
            "claim_identity",
            "claim_distribution",
            "claim_capability"
          ],
          "url": "https://github.com/dmang-dev/mcp-retroarch#readme"
        }
      ],
      "summary": "DeepWiki/Human Wiki output with a Doramagic pitfall appendix.",
      "title": "mcp-retroarch 说明书",
      "toc": [
        "https://github.com/dmang-dev/mcp-retroarch 项目说明书",
        "目录",
        "Introduction",
        "Project Overview",
        "Architecture",
        "How It Works",
        "Prerequisites",
        "Configuration",
        "Doramagic 踩坑日志"
      ]
    }
  },
  "quality_gate": {
    "blocking_gaps": [],
    "category_confidence": "medium",
    "compile_status": "ready_for_review",
    "five_assets_present": true,
    "install_sandbox_verified": true,
    "missing_evidence": [],
    "next_action": "publish to Doramagic.ai project surfaces",
    "prompt_preview_boundary_ok": true,
    "publish_status": "publishable",
    "quick_start_verified": true,
    "repo_clone_verified": true,
    "repo_commit": "2e08b44b3fd2f9ff83a07b42306322b38dea934f",
    "repo_inspection_error": null,
    "repo_inspection_files": [
      "Dockerfile",
      "package.json",
      "README.md",
      "docs/RECIPES.md",
      "docs/REMOTE-RETROPAD-INVESTIGATION.md",
      "src/tools.ts",
      "src/retroarch.ts",
      "src/index.ts"
    ],
    "repo_inspection_verified": true,
    "review_reasons": [
      "community_discussion_evidence_below_public_threshold"
    ],
    "tag_count_ok": true,
    "unsupported_claims": []
  },
  "schema_version": "0.1",
  "user_assets": {
    "ai_context_pack": {
      "asset_id": "ai_context_pack",
      "filename": "AI_CONTEXT_PACK.md",
      "markdown": "# mcp-retroarch - Doramagic AI Context Pack\n\n> 定位：安装前体验与判断资产。它帮助宿主 AI 有一个好的开始，但不代表已经安装、执行或验证目标项目。\n\n## 充分原则\n\n- **充分原则，不是压缩原则**：AI Context Pack 应该充分到让宿主 AI 在开工前理解项目价值、能力边界、使用入口、风险和证据来源；它可以分层组织，但不以最短摘要为目标。\n- **压缩策略**：只压缩噪声和重复内容，不压缩会影响判断和开工质量的上下文。\n\n## 给宿主 AI 的使用方式\n\n你正在读取 Doramagic 为 mcp-retroarch 编译的 AI Context Pack。请把它当作开工前上下文：帮助用户理解适合谁、能做什么、如何开始、哪些必须安装后验证、风险在哪里。不要声称你已经安装、运行或执行了目标项目。\n\n## Claim 消费规则\n\n- **事实来源**：Repo Evidence + Claim/Evidence Graph；Human Wiki 只提供显著性、术语和叙事结构。\n- **事实最低状态**：`supported`\n- `supported`：可以作为项目事实使用，但回答中必须引用 claim_id 和证据路径。\n- `weak`：只能作为低置信度线索，必须要求用户继续核实。\n- `inferred`：只能用于风险提示或待确认问题，不能包装成项目事实。\n- `unverified`：不得作为事实使用，应明确说证据不足。\n- `contradicted`：必须展示冲突来源，不得替用户强行选择一个版本。\n\n## 它最适合谁\n\n- **正在使用 Claude/Codex/Cursor/Gemini 等宿主 AI 的开发者**：README 或插件配置提到多个宿主 AI。 证据：`README.md` Claim：`clm_0002` supported 0.86\n\n## 它能做什么\n\n- **命令行启动或安装流程**（需要安装后验证）：项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 证据：`README.md` Claim：`clm_0001` supported 0.86\n\n## 怎么开始\n\n- `npm install -g mcp-retroarch` 证据：`README.md` Claim：`clm_0003` supported 0.86\n- `npx -y mcp-retroarch` 证据：`README.md` Claim：`clm_0004` supported 0.86\n- `git clone https://github.com/dmang-dev/mcp-retroarch` 证据：`README.md` Claim：`clm_0005` supported 0.86\n- `claude mcp add retroarch --scope user mcp-retroarch` 证据：`README.md` Claim：`clm_0006` supported 0.86\n\n## 继续前判断卡\n\n- **当前建议**：先做权限沙盒试用\n- **为什么**：项目存在安装命令、宿主配置或本地写入线索，不建议直接进入主力环境，应先在隔离环境试装。\n\n### 30 秒判断\n\n- **现在怎么做**：先做权限沙盒试用\n- **最小安全下一步**：先跑 Prompt Preview；若仍要安装，只在隔离环境试装\n- **先别相信**：工具权限边界不能在安装前相信。\n- **继续会触碰**：命令执行、本地环境或项目文件、宿主 AI 上下文\n\n### 现在可以相信\n\n- **适合人群线索：正在使用 Claude/Codex/Cursor/Gemini 等宿主 AI 的开发者**（supported）：有 supported claim 或项目证据支撑，但仍不等于真实安装效果。 证据：`README.md` Claim：`clm_0002` supported 0.86\n- **能力存在：命令行启动或安装流程**（supported）：可以相信项目包含这类能力线索；是否适合你的具体任务仍要试用或安装后验证。 证据：`README.md` Claim：`clm_0001` supported 0.86\n- **存在 Quick Start / 安装命令线索**（supported）：可以相信项目文档出现过启动或安装入口；不要因此直接在主力环境运行。 证据：`README.md` Claim：`clm_0003` supported 0.86\n\n### 现在还不能相信\n\n- **工具权限边界不能在安装前相信。**（unverified）：MCP/tool 类项目通常会触碰文件、网络、浏览器或外部 API，必须真实检查权限和日志。\n- **真实输出质量不能在安装前相信。**（unverified）：Prompt Preview 只能展示引导方式，不能证明真实项目中的结果质量。\n- **宿主 AI 版本兼容性不能在安装前相信。**（unverified）：Claude、Cursor、Codex、Gemini 等宿主加载规则和版本差异必须在真实环境验证。\n- **不会污染现有宿主 AI 行为，不能直接相信。**（inferred）：Skill、plugin、AGENTS/CLAUDE/GEMINI 指令可能改变宿主 AI 的默认行为。\n- **可安全回滚不能默认相信。**（unverified）：除非项目明确提供卸载和恢复说明，否则必须先在隔离环境验证。\n- **真实安装后是否与用户当前宿主 AI 版本兼容？**（unverified）：兼容性只能通过实际宿主环境验证。\n- **项目输出质量是否满足用户具体任务？**（unverified）：安装前预览只能展示流程和边界，不能替代真实评测。\n- **安装命令是否需要网络、权限或全局写入？**（unverified）：这影响企业环境和个人环境的安装风险。 证据：`README.md`\n\n### 继续会触碰什么\n\n- **命令执行**：包管理器、网络下载、本地插件目录、项目配置或用户主目录。 原因：运行第一条命令就可能产生环境改动；必须先判断是否值得跑。 证据：`README.md`\n- **本地环境或项目文件**：安装结果、插件缓存、项目配置或本地依赖目录。 原因：安装前无法证明写入范围和回滚方式，需要隔离验证。 证据：`README.md`\n- **宿主 AI 上下文**：AI Context Pack、Prompt Preview、Skill 路由、风险规则和项目事实。 原因：导入上下文会影响宿主 AI 后续判断，必须避免把未验证项包装成事实。\n\n### 最小安全下一步\n\n- **先跑 Prompt Preview**：用安装前交互式试用判断工作方式是否匹配，不需要授权或改环境。（适用：任何项目都适用，尤其是输出质量未知时。）\n- **只在隔离目录或测试账号试装**：避免安装命令污染主力宿主 AI、真实项目或用户主目录。（适用：存在命令执行、插件配置或本地写入线索时。）\n- **安装后只验证一个最小任务**：先验证加载、兼容、输出质量和回滚，再决定是否深用。（适用：准备从试用进入真实工作流时。）\n\n### 退出方式\n\n- **保留安装前状态**：记录原始宿主配置和项目状态，后续才能判断是否可恢复。\n- **记录安装命令和写入路径**：没有明确卸载说明时，至少要知道哪些目录或配置需要手动清理。\n- **如果没有回滚路径，不进入主力环境**：不可回滚是继续前阻断项，不应靠信任或运气继续。\n\n## 哪些只能预览\n\n- 解释项目适合谁和能做什么\n- 基于项目文档演示典型对话流程\n- 帮助用户判断是否值得安装或继续研究\n\n## 哪些必须安装后验证\n\n- 真实安装 Skill、插件或 CLI\n- 执行脚本、修改本地文件或访问外部服务\n- 验证真实输出质量、性能和兼容性\n\n## 边界与风险判断卡\n\n- **把安装前预览误认为真实运行**：用户可能高估项目已经完成的配置、权限和兼容性验证。 处理方式：明确区分 prompt_preview_can_do 与 runtime_required。 Claim：`clm_0007` inferred 0.45\n- **命令执行会修改本地环境**：安装命令可能写入用户主目录、宿主插件目录或项目配置。 处理方式：先在隔离环境或测试账号中运行。 证据：`README.md` Claim：`clm_0008` supported 0.86\n- **待确认**：真实安装后是否与用户当前宿主 AI 版本兼容？。原因：兼容性只能通过实际宿主环境验证。\n- **待确认**：项目输出质量是否满足用户具体任务？。原因：安装前预览只能展示流程和边界，不能替代真实评测。\n- **待确认**：安装命令是否需要网络、权限或全局写入？。原因：这影响企业环境和个人环境的安装风险。\n\n## 开工前工作上下文\n\n### 加载顺序\n\n- 先读取 how_to_use.host_ai_instruction，建立安装前判断资产的边界。\n- 读取 claim_graph_summary，确认事实来自 Claim/Evidence Graph，而不是 Human Wiki 叙事。\n- 再读取 intended_users、capabilities 和 quick_start_candidates，判断用户是否匹配。\n- 需要执行具体任务时，优先查 role_skill_index，再查 evidence_index。\n- 遇到真实安装、文件修改、网络访问、性能或兼容性问题时，转入 risk_card 和 boundaries.runtime_required。\n\n### 任务路由\n\n- **命令行启动或安装流程**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`README.md` Claim：`clm_0001` supported 0.86\n\n### 上下文规模\n\n- 文件总数：14\n- 重要文件覆盖：13/14\n- 证据索引条目：13\n- 角色 / Skill 条目：4\n\n### 证据不足时的处理\n\n- **missing_evidence**：说明证据不足，要求用户提供目标文件、README 段落或安装后验证记录；不要补全事实。\n- **out_of_scope_request**：说明该任务超出当前 AI Context Pack 证据范围，并建议用户先查看 Human Manual 或真实安装后验证。\n- **runtime_request**：给出安装前检查清单和命令来源，但不要替用户执行命令或声称已执行。\n- **source_conflict**：同时展示冲突来源，标记为待核实，不要强行选择一个版本。\n\n## Prompt Recipes\n\n### 适配判断\n\n- 目标：判断这个项目是否适合用户当前任务。\n- 预期输出：适配结论、关键理由、证据引用、安装前可预览内容、必须安装后验证内容、下一步建议。\n\n```text\n请基于 mcp-retroarch 的 AI Context Pack，先问我 3 个必要问题，然后判断它是否适合我的任务。回答必须包含：适合谁、能做什么、不能做什么、是否值得安装、证据来自哪里。所有项目事实必须引用 evidence_refs、source_paths 或 claim_id。\n```\n\n### 安装前体验\n\n- 目标：让用户在安装前感受核心工作流，同时避免把预览包装成真实能力或营销承诺。\n- 预期输出：一段带边界标签的体验剧本、安装后验证清单和谨慎建议；不含真实运行承诺或强营销表述。\n\n```text\n请把 mcp-retroarch 当作安装前体验资产，而不是已安装工具或真实运行环境。\n\n请严格输出四段：\n1. 先问我 3 个必要问题。\n2. 给出一段“体验剧本”：用 [安装前可预览]、[必须安装后验证]、[证据不足] 三种标签展示它可能如何引导工作流。\n3. 给出安装后验证清单：列出哪些能力只有真实安装、真实宿主加载、真实项目运行后才能确认。\n4. 给出谨慎建议：只能说“值得继续研究/试装”“先补充信息后再判断”或“不建议继续”，不得替项目背书。\n\n硬性边界：\n- 不要声称已经安装、运行、执行测试、修改文件或产生真实结果。\n- 不要写“自动适配”“确保通过”“完美适配”“强烈建议安装”等承诺性表达。\n- 如果描述安装后的工作方式，必须使用“如果安装成功且宿主正确加载 Skill，它可能会……”这种条件句。\n- 体验剧本只能写成“示例台词/假设流程”：使用“可能会询问/可能会建议/可能会展示”，不要写“已写入、已生成、已通过、正在运行、正在生成”。\n- Prompt Preview 不负责给安装命令；如用户准备试装，只能提示先阅读 Quick Start 和 Risk Card，并在隔离环境验证。\n- 所有项目事实必须来自 supported claim、evidence_refs 或 source_paths；inferred/unverified 只能作风险或待确认项。\n\n```\n\n### 角色 / Skill 选择\n\n- 目标：从项目里的角色或 Skill 中挑选最匹配的资产。\n- 预期输出：候选角色或 Skill 列表，每项包含适用场景、证据路径、风险边界和是否需要安装后验证。\n\n```text\n请读取 role_skill_index，根据我的目标任务推荐 3-5 个最相关的角色或 Skill。每个推荐都要说明适用场景、可能输出、风险边界和 evidence_refs。\n```\n\n### 风险预检\n\n- 目标：安装或引入前识别环境、权限、规则冲突和质量风险。\n- 预期输出：环境、权限、依赖、许可、宿主冲突、质量风险和未知项的检查清单。\n\n```text\n请基于 risk_card、boundaries 和 quick_start_candidates，给我一份安装前风险预检清单。不要替我执行命令，只说明我应该检查什么、为什么检查、失败会有什么影响。\n```\n\n### 宿主 AI 开工指令\n\n- 目标：把项目上下文转成一次对话开始前的宿主 AI 指令。\n- 预期输出：一段边界明确、证据引用明确、适合复制给宿主 AI 的开工前指令。\n\n```text\n请基于 mcp-retroarch 的 AI Context Pack，生成一段我可以粘贴给宿主 AI 的开工前指令。这段指令必须遵守 not_runtime=true，不能声称项目已经安装、运行或产生真实结果。\n```\n\n\n## 角色 / Skill 索引\n\n- 共索引 4 个角色 / Skill / 项目文档条目。\n\n- **mcp-retroarch**（project_doc）：! npm version https://img.shields.io/npm/v/mcp-retroarch.svg https://www.npmjs.com/package/mcp-retroarch ! npm downloads https://img.shields.io/npm/dm/mcp-retroarch.svg https://www.npmjs.com/package/mcp-retroarch ! CI https://github.com/dmang-dev/mcp-retroarch/actions/workflows/ci.yml/badge.svg https://github.com/dmang-dev/mcp-retroarch/actions/workflows/ci.yml ! License: MIT https://img.shields.io/npm/l/mcp-retroar… 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`README.md`\n- **mcp-retroarch recipes**（project_doc）：Practical examples of driving RetroArch from Claude or any MCP client. Each recipe is self-contained. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/RECIPES.md`\n- **Adding game-pad input to mcp-retroarch — investigation notes**（project_doc）：Adding game-pad input to mcp-retroarch — investigation notes 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/REMOTE-RETROPAD-INVESTIGATION.md`\n- **Changelog**（project_doc）：All notable changes to this project will be documented in this file. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`CHANGELOG.md`\n\n## 证据索引\n\n- 共索引 13 条证据。\n\n- **mcp-retroarch**（documentation）：! npm version https://img.shields.io/npm/v/mcp-retroarch.svg https://www.npmjs.com/package/mcp-retroarch ! npm downloads https://img.shields.io/npm/dm/mcp-retroarch.svg https://www.npmjs.com/package/mcp-retroarch ! CI https://github.com/dmang-dev/mcp-retroarch/actions/workflows/ci.yml/badge.svg https://github.com/dmang-dev/mcp-retroarch/actions/workflows/ci.yml ! License: MIT https://img.shields.io/npm/l/mcp-retroarch.svg LICENSE 证据：`README.md`\n- **Package**（package_manifest）：{ \"name\": \"mcp-retroarch\", \"version\": \"0.1.2\", \"description\": \"MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface UDP \", \"license\": \"MIT\", \"type\": \"module\", \"bin\": { \"mcp-retroarch\": \"dist/index.js\" }, \"files\": \"dist/\", \"docs/\", \"README.md\", \"LICENSE\" , \"scripts\": { \"build\": \"tsc && node -e \\\"import 'node:fs' .then fs = fs.chmodSync 'dist/index.js', 0o755 \\\"\", \"dev\": \"tsc --watch\", \"start\": \"node dist/index.js\", \"prepare\": \"npm run build\", \"inspector\": \"npx @modelcontextprotocol/inspector node dist/index.js\" }, \"engines\": { \"node\": \" =18\" }, \"repository\": { \"type\": \"git\", \"url\": \"git+https://github.com/dmang-dev/… 证据：`package.json`\n- **License**（source_file）：Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files the \"Software\" , to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 证据：`LICENSE`\n- **mcp-retroarch recipes**（documentation）：Practical examples of driving RetroArch from Claude or any MCP client. Each recipe is self-contained. 证据：`docs/RECIPES.md`\n- **Adding game-pad input to mcp-retroarch — investigation notes**（documentation）：Adding game-pad input to mcp-retroarch — investigation notes 证据：`docs/REMOTE-RETROPAD-INVESTIGATION.md`\n- **Changelog**（documentation）：All notable changes to this project will be documented in this file. 证据：`CHANGELOG.md`\n- **Glama**（structured_config）：{ \"$schema\": \"https://glama.ai/mcp/schemas/server.json\", \"maintainers\": \"dmang-dev\" } 证据：`glama.json`\n- **Tsconfig**（structured_config）：{ \"compilerOptions\": { \"target\": \"ES2022\", \"module\": \"NodeNext\", \"moduleResolution\": \"NodeNext\", \"outDir\": \"./dist\", \"rootDir\": \"./src\", \"strict\": true, \"esModuleInterop\": true, \"skipLibCheck\": true, \"declaration\": true, \"declarationMap\": true, \"sourceMap\": true }, \"include\": \"src/ / \" , \"exclude\": \"node modules\", \"dist\" } 证据：`tsconfig.json`\n- **.gitignore**（source_file）：node modules/ dist/ .js.map .claude/ .rstk/ .scratch/ .png 证据：`.gitignore`\n- **Dockerfile — primarily for the Glama MCP registry https://glama.ai/mcp/servers .**（source_file）：Dockerfile — primarily for the Glama MCP registry https://glama.ai/mcp/servers . Builds the MCP server and runs it over stdio. The server starts cleanly WITHOUT RetroArch present: the connectivity probe runs in the background and the MCP transport comes up immediately, so tools/list responds fast. That's exactly what Glama's \"start + respond to introspection\" check needs. For actual use you don't need Docker — npm install -g mcp-retroarch and point it at a running RetroArch with Network Commands enabled. See README.md. 证据：`Dockerfile`\n- **!/usr/bin/env node**（source_file）：!/usr/bin/env node import { Server } from \"@modelcontextprotocol/sdk/server/index.js\"; import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\"; import { RetroArchClient } from \"./retroarch.js\"; import { registerTools } from \"./tools.js\"; 证据：`src/index.ts`\n- **Retroarch**（source_file）：// RetroArch Network Control Interface NCI client // ───────────────────────────────────────────────── // Wire format text-based UDP : // Send: \"COMMAND arg1 arg2 ...\\n\" as a single UDP datagram // Receive: One UDP datagram per response, plain text. Most responses echo // the command name as a prefix e.g. \"READ CORE MEMORY 0x1000 ab cd ef\" . // VERSION is the only one with no echo — the response is just the // version string itself. // // Default port: 55355 UDP . Enable in retroarch.cfg with: // network cmd enable = \"true\" // network cmd port = \"55355\" // Or via Settings Network Network Commands. // // Concurrency model: this client serializes — exactly one query in flight at // a time. UD… 证据：`src/retroarch.ts`\n- **Tools**（source_file）：import { CallToolRequestSchema, ListToolsRequestSchema, Tool, } from \"@modelcontextprotocol/sdk/types.js\"; import type { Server } from \"@modelcontextprotocol/sdk/server/index.js\"; import { RetroArchClient } from \"./retroarch.js\"; 证据：`src/tools.ts`\n\n## 宿主 AI 必须遵守的规则\n\n- **把本资产当作开工前上下文，而不是运行环境。**：AI Context Pack 只包含证据化项目理解，不包含目标项目的可执行状态。 证据：`README.md`, `package.json`, `LICENSE`\n- **回答用户时区分可预览内容与必须安装后才能验证的内容。**：安装前体验的消费者价值来自降低误装和误判，而不是伪装成真实运行。 证据：`README.md`, `package.json`, `LICENSE`\n\n## 用户开工前应该回答的问题\n\n- 你准备在哪个宿主 AI 或本地环境中使用它？\n- 你只是想先体验工作流，还是准备真实安装？\n- 你最在意的是安装成本、输出质量、还是和现有规则的冲突？\n\n## 验收标准\n\n- 所有能力声明都能回指到 evidence_refs 中的文件路径。\n- AI_CONTEXT_PACK.md 没有把预览包装成真实运行。\n- 用户能在 3 分钟内看懂适合谁、能做什么、如何开始和风险边界。\n\n---\n\n## Doramagic Context Augmentation\n\nThe following material strengthens the Repomix/AI Context Pack body. Human Manual is only a reading skeleton; pitfall logs become hard operating constraints for the host AI.\n\n## Human Manual Skeleton\n\nUsage rule: this is only a reading path and salience signal, not factual authority. Concrete facts must still come from repo evidence / Claim Graph.\n\nHard rules for the host AI:\n- Do not treat page titles, order, summaries, or importance as project facts.\n- When explaining the Human Manual skeleton, state that it is only a reading path / salience signal.\n- Capability, installation, compatibility, runtime status, and risk judgments must cite repo evidence, source paths, or Claim Graph.\n\n- **Introduction**：importance `high`\n  - source_paths: README.md\n- **Quick Start Guide**：importance `high`\n  - source_paths: README.md, package.json\n- **System Architecture**：importance `high`\n  - source_paths: src/index.ts, src/retroarch.ts, README.md\n- **Data Flow**：importance `medium`\n  - source_paths: src/retroarch.ts, src/tools.ts\n- **Memory Read/Write Operations**：importance `high`\n  - source_paths: src/tools.ts, src/retroarch.ts\n- **Savestate Management**：importance `high`\n  - source_paths: src/tools.ts, src/retroarch.ts\n- **Emulation Control**：importance `medium`\n  - source_paths: src/tools.ts\n- **MCP Tools Reference**：importance `high`\n  - source_paths: src/tools.ts, README.md\n\n## Repo Inspection Evidence\n\n- repo_clone_verified: true\n- repo_inspection_verified: true\n- repo_commit: `2e08b44b3fd2f9ff83a07b42306322b38dea934f`\n- inspected_files: `Dockerfile`, `package.json`, `README.md`, `docs/RECIPES.md`, `docs/REMOTE-RETROPAD-INVESTIGATION.md`, `src/tools.ts`, `src/retroarch.ts`, `src/index.ts`\n\nHard rules for the host AI:\n- Without repo_clone_verified=true, do not claim the source code has been read.\n- Without repo_inspection_verified=true, do not turn README/docs/package observations into facts.\n- Without quick_start_verified=true, do not claim the Quick Start has been successfully run.\n\n## Doramagic Pitfall Constraints\n\nThese rules come from Doramagic discovery, validation, or compilation pitfalls. The host AI must treat them as operating constraints, not general background notes.\n\n### Constraint 1: 可能修改宿主 AI 配置\n\n- Trigger: 项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。\n- Host AI rule: 列出会写入的配置文件、目录和卸载/回滚步骤。\n- Why it matters: 安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。\n- Evidence: capability.host_targets | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | host_targets=mcp_host, claude\n- Hard boundary: do not present this pitfall as solved, verified, or safe to ignore unless later validation evidence explicitly closes it.\n\n### Constraint 2: 能力判断依赖假设\n\n- Trigger: README/documentation is current enough for a first validation pass.\n- Host AI rule: 将假设转成下游验证清单。\n- Why it matters: 假设不成立时，用户拿不到承诺的能力。\n- Evidence: capability.assumptions | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | README/documentation is current enough for a first validation pass.\n- Hard boundary: do not present this pitfall as solved, verified, or safe to ignore unless later validation evidence explicitly closes it.\n\n### Constraint 3: 维护活跃度未知\n\n- Trigger: 未记录 last_activity_observed。\n- Host AI rule: 补 GitHub 最近 commit、release、issue/PR 响应信号。\n- Why it matters: 新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | last_activity_observed missing\n- Hard boundary: do not present this pitfall as solved, verified, or safe to ignore unless later validation evidence explicitly closes it.\n\n### Constraint 4: 下游验证发现风险项\n\n- Trigger: no_demo\n- Host AI rule: 进入安全/权限治理复核队列。\n- Why it matters: 下游已经要求复核，不能在页面中弱化。\n- Evidence: downstream_validation.risk_items | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n- Hard boundary: do not present this pitfall as solved, verified, or safe to ignore unless later validation evidence explicitly closes it.\n\n### Constraint 5: 存在评分风险\n\n- Trigger: no_demo\n- Host AI rule: 把风险写入边界卡，并确认是否需要人工复核。\n- Why it matters: 风险会影响是否适合普通用户安装。\n- Evidence: risks.scoring_risks | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n- Hard boundary: do not present this pitfall as solved, verified, or safe to ignore unless later validation evidence explicitly closes it.\n\n### Constraint 6: issue/PR 响应质量未知\n\n- Trigger: issue_or_pr_quality=unknown。\n- Host AI rule: 抽样最近 issue/PR，判断是否长期无人处理。\n- Why it matters: 用户无法判断遇到问题后是否有人维护。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | issue_or_pr_quality=unknown\n- Hard boundary: do not present this pitfall as solved, verified, or safe to ignore unless later validation evidence explicitly closes it.\n\n### Constraint 7: 发布节奏不明确\n\n- Trigger: release_recency=unknown。\n- Host AI rule: 确认最近 release/tag 和 README 安装命令是否一致。\n- Why it matters: 安装命令和文档可能落后于代码，用户踩坑概率升高。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | release_recency=unknown\n- Hard boundary: do not present this pitfall as solved, verified, or safe to ignore unless later validation evidence explicitly closes it.\n",
      "summary": "Context and operating boundaries for host AI agents.",
      "title": "AI Context Pack"
    },
    "boundary_risk_card": {
      "asset_id": "boundary_risk_card",
      "filename": "BOUNDARY_RISK_CARD.md",
      "markdown": "# Boundary & Risk Card\n\nProject: dmang-dev/mcp-retroarch\n\n## Doramagic Trial Decision\n\nCurrent decision: it can enter pre-publication recommendation checks. First use should still start with least privilege, a temporary directory, and reversible configuration.\n\n## What The User Can Do Now\n\n- Read the Human Manual first to understand the project purpose and main workflows.\n- Use Prompt Preview for pre-install exploration; it validates interaction shape, not real execution.\n- Run official Quick Start commands only inside an isolated environment, not a primary setup.\n\n## Do Not Do Yet\n\n- Do not treat Prompt Preview as a real project execution result.\n- Do not treat metadata-only validation as sandbox installation validation.\n- Do not describe unverified capabilities as supported, working, or safe to install.\n- Do not provide production data, private files, real secrets, or primary host configuration on first trial.\n\n## Pre-Install Checklist\n\n- Host AI match: mcp_host, claude\n- Official installation entry status: official entry point found\n- Isolated temporary directory, temporary host, or container validation: required\n- Configuration rollback path: required\n- API keys, network access, file access, or host configuration changes: treat as high risk until confirmed\n- Installation command, actual output, and failure logs: must be recorded\n\n## Current Blockers\n\n- review_required: community_discussion_evidence_below_public_threshold\n\n## Project-Specific Pitfalls\n\n- 可能修改宿主 AI 配置 (medium): 安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。 Suggested check: 列出会写入的配置文件、目录和卸载/回滚步骤。\n- 能力判断依赖假设 (medium): 假设不成立时，用户拿不到承诺的能力。 Suggested check: 将假设转成下游验证清单。\n- 维护活跃度未知 (medium): 新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。 Suggested check: 补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 下游验证发现风险项 (medium): 下游已经要求复核，不能在页面中弱化。 Suggested check: 进入安全/权限治理复核队列。\n- 存在评分风险 (medium): 风险会影响是否适合普通用户安装。 Suggested check: 把风险写入边界卡，并确认是否需要人工复核。\n\n## Risk And Permission Notes\n\n- no_demo: medium\n\n## Evidence Gaps\n\n- No structured evidence gaps are currently visible.\n",
      "summary": "Installation, permission, validation, and pre-recommendation risks.",
      "title": "Boundary & Risk Card"
    },
    "human_manual": {
      "asset_id": "human_manual",
      "filename": "HUMAN_MANUAL.md",
      "markdown": "# https://github.com/dmang-dev/mcp-retroarch 项目说明书\n\n生成时间：2026-05-16 06:53:34 UTC\n\n## 目录\n\n- [Introduction](#page-introduction)\n- [Quick Start Guide](#page-quick-start)\n- [System Architecture](#page-architecture)\n- [Data Flow](#page-data-flow)\n- [Memory Read/Write Operations](#page-memory-operations)\n- [Savestate Management](#page-savestate-management)\n- [Emulation Control](#page-emulation-control)\n- [MCP Tools Reference](#page-tools-reference)\n- [Core Compatibility](#page-core-compatibility)\n- [Configuration](#page-configuration)\n\n<a id='page-introduction'></a>\n\n## Introduction\n\n### 相关页面\n\n相关主题：[System Architecture](#page-architecture), [Quick Start Guide](#page-quick-start)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Introduction\n\nmcp-retroarch is a Model Context Protocol (MCP) server that bridges AI assistants (such as Claude) with the RetroArch emulator through its Network Control Interface (NCI). This enables AI-driven automation of retro gaming tasks including memory inspection, save state management, screenshot capture, and frame-by-frame execution control.\n\n## Project Overview\n\nmcp-retroarch exposes RetroArch's NCI functionality as MCP tools, allowing AI agents to:\n\n- Read and write emulated system memory\n- Manage save states across slots\n- Capture screenshots\n- Control emulation execution (pause, frame advance, reset)\n- Display notifications within the emulator\n\n**Key characteristics:**\n\n| Attribute | Value |\n|-----------|-------|\n| Protocol | MCP over stdio |\n| Transport to RetroArch | UDP (IPv4) |\n| Default UDP port | 55355 |\n| Language | TypeScript |\n| MCP SDK version | ^1.12.0 |\n| License | MIT |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Architecture\n\nThe system consists of three primary components communicating across two protocols:\n\n```mermaid\ngraph TD\n    subgraph \"MCP Client Layer\"\n        A[Claude / AI Assistant]\n    end\n    \n    subgraph \"mcp-retroarch Process\"\n        B[MCP SDK<br/>stdio JSON-RPC]\n        C[RetroArch Client<br/>src/retroarch.ts]\n    end\n    \n    subgraph \"RetroArch\"\n        D[Network Control<br/>Interface]\n    end\n    \n    A -->|\"MCP JSON-RPC\"| B\n    B -->|Tool calls| C\n    C -->|\"UDP Datagrams\"| D\n    D -->|\"UDP Response\"| C\n    C -->|\"MCP Response\"| B\n    B -->|\"JSON-RPC\"| A\n```\n\n### Component Responsibilities\n\n| Component | Role |\n|-----------|------|\n| MCP Client | Sends JSON-RPC requests via stdio |\n| mcp-retroarch | Translates MCP tools to NCI UDP commands |\n| RetroArch NCI | Executes commands on the running emulator |\n\n资料来源：[src/index.ts:1-20](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n## How It Works\n\n### Connection Flow\n\n1. **Startup**: The MCP server initializes and creates a UDP socket for RetroArch communication\n2. **Background probe**: An asynchronous connection attempt retrieves RetroArch version\n3. **Ready signal**: Server signals readiness via stderr and stdout\n\n```mermaid\nsequenceDiagram\n    participant RA as RetroArch\n    participant MCP as mcp-retroarch\n    participant Client as MCP Client\n    \n    MCP->>MCP: Create UDP socket\n    Note over MCP: Background probe<br/>(fire-and-forget)\n    MCP->>RA: VERSION command\n    RA-->>MCP: RetroArch version\n    MCP->>Client: Ready notification (stdout)\n    Client->>MCP: Tool call (e.g., read_memory)\n    MCP->>RA: READ_CORE_MEMORY\n    RA-->>MCP: Memory bytes\n    MCP-->>Client: Hex dump response\n```\n\n资料来源：[src/index.ts:8-17](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n### UDP Communication Model\n\nThe RetroArch client implements two communication patterns:\n\n| Pattern | Method | Use Case |\n|---------|--------|----------|\n| Fire-and-forget | `send(command)` | Pause toggle, reset, screenshot |\n| Query/Response | `query(command)` | Memory reads, status queries |\n\n```typescript\n// Fire-and-forget: no response expected\nasync send(command: string): Promise<void>\n\n// Query with timeout: awaits UDP response\nasync query(command: string): Promise<Buffer>\n```\n\n**Timeout behavior**: Queries default to a configurable timeout. If no response arrives, the promise rejects with a timeout error. The client maintains serial request semantics—one query must complete before the next begins.\n\n资料来源：[src/retroarch.ts:43-64](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n### Serial Request Constraint\n\nThe implementation enforces serial requests at the protocol level:\n\n```typescript\nif (this.pending) {\n  throw new Error(\"retroarch query already in flight (client is serial)\");\n}\n```\n\nThis means concurrent tool calls from the MCP client will queue or fail if queries overlap.\n\n资料来源：[src/retroarch.ts:56-59](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n## Prerequisites\n\nBefore using mcp-retroarch, ensure:\n\n1. **RetroArch is installed** with Network Commands enabled\n2. **A libretro core and game are loaded**\n3. **Network Command Interface is active**\n\n### Enabling Network Commands in RetroArch\n\n**GUI Method**:\n- Navigate to Settings → Network → Network Commands → ON\n- Confirm Network Cmd Port is `55355` (default)\n\n**Configuration File Method** (retroarch.cfg):\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Configuration\n\nmcp-retroarch is configured via environment variables:\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in retroarch.cfg) |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Available Tools\n\nThe following MCP tools are exposed by mcp-retroarch:\n\n### Memory Operations\n\n| Tool | Purpose | Address Space |\n|------|---------|---------------|\n| `retroarch_read_memory` | Read bytes from system memory map | libretro memory map |\n| `retroarch_write_memory` | Write bytes to system memory | libretro memory map |\n| `retroarch_read_ram` | Read bytes via CHEEVOS address space | Achievement space |\n| `retroarch_write_ram` | Write bytes via CHEEVOS space | Achievement space |\n\n**Memory read/write limitations**:\n- Maximum 4096 bytes per call (NCI single-datagram limit)\n- `write_memory` returns byte count; `write_ram` does not acknowledge\n\n### Emulation Control\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_pause_toggle` | Toggle pause state |\n| `retroarch_frame_advance` | Step exactly one frame |\n| `retroarch_reset` | Hard reset the game |\n\n### State Management\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_save_state_current` | Save to current slot |\n| `retroarch_load_state_current` | Load from current slot |\n| `retroarch_load_state_slot` | Load from explicit slot number |\n| `retroarch_state_slot_plus` | Increment slot pointer |\n| `retroarch_state_slot_minus` | Decrement slot pointer |\n\n### Utility\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_screenshot` | Save screenshot to RetroArch's configured directory |\n| `retroarch_show_message` | Display notification overlay |\n| `retroarch_get_status` | Query current emulation state |\n| `retroarch_get_config` | Read a config parameter value |\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Address Space Differences\n\nUnderstanding the distinction between address spaces is critical:\n\n| Address Space | Used By | Notes |\n|---------------|---------|-------|\n| libretro memory map | `read_memory` / `write_memory` | System-specific layout (e.g., GBA EWRAM at 0x02000000) |\n| CHEEVOS space | `read_ram` / `write_ram` | RetroAchievements address conventions |\n\n**Example address mappings**:\n- GBA ROM: `0x08000000` (memory map) vs `0x000000` (CHEEVOS)\n- SNES WRAM: `0x7E0000-0x7FFFFF` (memory map) vs `0x000000` (CHEEVOS)\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Verified Core Support\n\nThe following cores have been tested with mcp-retroarch:\n\n| System | Core | read_memory | read_ram | Notes |\n|--------|------|-------------|----------|-------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA interrupt vector at 0x0000 visible |\n| NES | `mesen_libretro` | ✅ | ✅ | Full 16-bit address space; WRAM at 0x0000-0x07FF |\n| NES | `nestopia_libretro` | ❌ | ✅ | No memory map; use read_ram |\n| SNES | `snes9x_libretro` | ❌ | — | Memory map not exposed |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Fire-and-Forget Semantics\n\nMost NCI commands do not receive acknowledgments from RetroArch. The response message from mcp-retroarch indicates only that the UDP datagram was sent, not that RetroArch received or acted on it.\n\n**Exceptions**:\n- `retroarch_write_memory` — returns byte count (NCI acknowledges this command)\n- `retroarch_read_memory` / `retroarch_read_ram` — returns actual data read\n\n**Verification strategy**: For fire-and-forget commands, verify success by:\n1. Reading memory back with `read_ram`\n2. Checking state with `retroarch_get_status`\n\n资料来源：[CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n\n## Error Handling\n\n### Common Errors\n\n| Error | Cause | Resolution |\n|-------|-------|------------|\n| `RetroArch query timed out` | Network Commands disabled or port mismatch | Verify `network_cmd_enable = \"true\"` and matching ports |\n| `READ_CORE_MEMORY failed: no memory map defined` | Core doesn't expose memory map | Use `retroarch_read_ram` instead |\n| `READ_CORE_MEMORY failed: no descriptor for address` | Address outside core's memory regions | Try different core or address |\n\n**UDP reliability note**: UDP datagrams may be dropped under load even on loopback. If a single call times out, retry the operation.\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Development\n\n### Project Structure\n\n```\nmcp-retroarch/\n├── src/\n│   ├── index.ts        # MCP server entry point\n│   ├── retroarch.ts    # UDP client for NCI protocol\n│   └── tools.ts        # Tool definitions and handlers\n├── package.json\n├── tsconfig.json\n└── .scratch/\n    └── smoke.cjs       # Manual smoke test\n```\n\n### Running Locally\n\n```bash\nnpm install\nnpm run dev      # tsc --watch (development mode)\nnode .scratch/smoke.cjs  # Smoke test against running RetroArch\n```\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md), [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n## Limitations\n\n| Feature | Status | Notes |\n|---------|--------|-------|\n| Game-pad input | ❌ Not available | NCI doesn't expose input; see [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) for GBA input |\n| Save to specific slot | Limited | Only current slot save; must walk to target slot |\n| Screenshot directory | Not configurable via NCI | Check RetroArch GUI for configured path |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Related Projects\n\n| Project | Purpose |\n|---------|---------|\n| [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | GBA via mGBA's Lua bridge (includes input + screenshot) |\n| [mcp-pine](https://github.com/dmang-dev/mcp-pine) | PCSX2 and PINE-speaking emulators |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n<a id='page-quick-start'></a>\n\n## Quick Start Guide\n\n### 相关页面\n\n相关主题：[Introduction](#page-introduction), [Configuration](#page-configuration)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Quick Start Guide\n\nThis guide walks you through setting up **mcp-retroarch**, a Model Context Protocol (MCP) server that enables AI assistants to interact with RetroArch through its Network Command Interface (NCI). The integration provides memory inspection, savestate management, screenshot capture, and emulator control via JSON-RPC over stdio.\n\n## Overview\n\nmcp-retroarch bridges AI coding assistants (like Claude Code or Claude Desktop) with RetroArch by:\n\n- Exposing RetroArch NCI commands as MCP tools\n- Communicating over stdio (JSON-RPC) with the MCP client\n- Sending UDP datagrams to RetroArch's Network Command Interface on port 55355\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## System Architecture\n\n```mermaid\ngraph TD\n    A[\"MCP Client<br/>(Claude Code/Desktop)\"] -->|stdio JSON-RPC| B[\"mcp-retroarch<br/>MCP Server\"]\n    B -->|UDP :55355| C[\"RetroArch<br/>Network Commands\"]\n    C -->|Emulator Control| D[\"Libretro Core<br/>+ Game ROM\"]\n    \n    B -->|Background Probe| C\n    \n    style A fill:#e1f5fe\n    style B fill:#fff3e0\n    style C fill:#e8f5e9\n```\n\n资料来源：[src/index.ts:8-14](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts), [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n## Prerequisites\n\n| Requirement | Details |\n|-------------|---------|\n| Node.js | Version compatible with `@modelcontextprotocol/sdk` ^1.12.0 |\n| RetroArch | Version with Network Command Interface enabled |\n| MCP Client | Claude Code or Claude Desktop |\n| Network Commands | Must be enabled in RetroArch |\n\n资料来源：[package.json:20-26](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json), [README.md:40-50](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Step 1: Install mcp-retroarch\n\n### From npm (Recommended)\n\n```bash\nnpm install -g mcp-retroarch\n```\n\nThis makes the `mcp-retroarch` command globally available.\n\n资料来源：[package.json:1-10](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n### From Source\n\n```bash\ngit clone https://github.com/dmang-dev/mcp-retroarch.git\ncd mcp-retroarch\nnpm install\nnpm run build   # or use npm run dev for watch mode\n```\n\n资料来源：[README.md:100-105](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Step 2: Enable Network Commands in RetroArch\n\nRetroArch's NCI must be enabled before mcp-retroarch can communicate with it.\n\n### Via GUI\n\n1. Open RetroArch\n2. Navigate to **Settings → Network → Network Commands**\n3. Set **Network Commands** to **ON**\n4. Confirm **Network Cmd Port** is `55355` (default)\n\n### Via Configuration File\n\nEdit `retroarch.cfg` (located in RetroArch's config directory):\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n资料来源：[README.md:40-50](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Verify Setup\n\nLaunch RetroArch and load any libretro core with a game. The Network Command Interface is always-on once enabled—no additional scripts required.\n\n## Step 3: Register with Your MCP Client\n\n### Claude Code\n\nRegister retroarch as a user-level MCP server:\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\nVerify registration:\n\n```bash\nclaude mcp list\n# retroarch: mcp-retroarch - ✓ Connected\n```\n\n资料来源：[README.md:52-60](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Claude Desktop\n\nEdit the platform-specific configuration file:\n\n| Platform | Config Path |\n|----------|-------------|\n| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |\n| Windows | `%APPDATA%\\Claude\\claude_desktop_config.json` |\n| Linux | `~/.config/Claude/claude_desktop_config.json` |\n\nAdd the `mcpServers` section:\n\n```json\n{\n  \"mcpServers\": {\n    \"retroarch\": {\n      \"command\": \"mcp-retroarch\"\n    }\n  }\n}\n```\n\nRestart Claude Desktop after editing.\n\n资料来源：[README.md:62-78](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Step 4: Configure Environment Variables\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in retroarch.cfg) |\n\nSet these before running Claude Code or Claude Desktop if your RetroArch runs on a different host or port:\n\n```bash\nexport RETROARCH_HOST=192.168.1.100\nexport RETROARCH_PORT=55355\n```\n\n资料来源：[README.md:80-85](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Available Tools\n\nOnce connected, the following MCP tools become available:\n\n### Emulator Control\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_get_status` | Query running state, system, game, CRC32 |\n| `retroarch_pause_toggle` | Toggle pause on/off |\n| `retroarch_frame_advance` | Advance exactly one frame |\n| `retroarch_reset` | Hard reset the running game |\n| `retroarch_show_message` | Display notification on RetroArch window |\n\n### Memory Operations\n\n| Tool | Description |\n|------|-------------|\n| `retroarch_read_memory` | Read from libretro system memory map |\n| `retroarch_write_memory` | Write to libretro system memory map |\n| `retroarch_read_ram` | Read from CHEEVOS (achievements) address space |\n| `retroarch_write_ram` | Write to CHEEVOS address space |\n\n### Savestate Management\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_save_state_current` | Save to currently-selected slot |\n| `retroarch_load_state_current` | Load from currently-selected slot |\n| `retroarch_load_state_slot` | Load from explicit slot number |\n| `retroarch_state_slot_plus` | Increment slot pointer |\n| `retroarch_state_slot_minus` | Decrement slot pointer |\n\n### Media & Config\n\n| Tool | Purpose |\n|------|---------|\n| `retroarch_screenshot` | Save screenshot to RetroArch's screenshot directory |\n| `retroarch_get_config` | Read a RetroArch configuration parameter |\n\n资料来源：[README.md:1-30](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md), [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Step 5: Smoke Test\n\nVerify connectivity by running the smoke test script against a running RetroArch:\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n资料来源：[README.md:107-110](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## First Commands to Try\n\n### Check Emulator Status\n\n```\nretroarch_get_status\n```\n\nExpected output:\n```\nState:  playing\nSystem: snes9x_libretro\nGame:   Super Metroid (USA).sfc\nCRC32:  12345678\n```\n\n### Pause and Read Memory\n\n```\nretroarch_pause_toggle\nretroarch_read_memory(address=0x7E0000, length=16)\n```\n\n### Take a Screenshot\n\n```\nretroarch_screenshot\n```\n\n资料来源：[src/tools.ts:1-50](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Verified Core Compatibility\n\n| System | Core | `read_memory` | `read_ram` | Notes |\n|--------|------|---------------|------------|-------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA interrupt vector at `0x0000` |\n| NES | `mesen_libretro` | ✅ | ✅ | Full 16-bit NES address space |\n| NES | `nestopia_libretro` | ❌ | ✅ | CHEEVOS only |\n| SNES | `snes9x_libretro` | ❌ | — | Memory map not exposed |\n\n资料来源：[README.md:30-45](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Troubleshooting\n\n| Symptom | Cause / Fix |\n|---------|-------------|\n| `RetroArch query timed out` | Network Commands not enabled, or port mismatch. Confirm `network_cmd_enable = \"true\"` in retroarch.cfg |\n| `READ_CORE_MEMORY failed: no memory map defined` | Core doesn't advertise memory map. Try `retroarch_read_ram` as fallback |\n| `READ_CORE_MEMORY failed: no descriptor for address` | Address outside core's memory regions |\n| Screenshots don't appear | Check RetroArch's screenshot directory via Settings → Directory → Screenshot |\n| Can't save to specific slot | NCI limitation—use `state_slot_plus`/`state_slot_minus` to walk to target slot |\n\n资料来源：[README.md:115-130](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Next Steps\n\n- Review [docs/RECIPES.md](docs/RECIPES.md) for end-to-end examples\n- Explore related MCP servers: [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) for GBA input + screenshots\n- Consult [RetroArch NCI documentation](https://docs.libretro.com/development/retroarch/network-control-interface/) for protocol details\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n<a id='page-architecture'></a>\n\n## System Architecture\n\n### 相关页面\n\n相关主题：[Introduction](#page-introduction), [Data Flow](#page-data-flow)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n</details>\n\n# System Architecture\n\n## Overview\n\nmcp-retroarch is a Model Context Protocol (MCP) server that bridges MCP clients (such as Claude Code or Claude Desktop) with RetroArch's Network Control Interface (NCI). It enables AI assistants to interact with running emulated games through memory inspection, state manipulation, and emulator control.\n\n**资料来源：** [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## High-Level Architecture\n\nThe system follows a three-layer architecture:\n\n```mermaid\ngraph TD\n    subgraph \"Client Layer\"\n        MCP[MCP Client<br/>Claude Code / Claude Desktop]\n    end\n\n    subgraph \"Bridge Layer\"\n        MCP_Server[MCP Server<br/>mcp-retroarch]\n        Tools[MCP Tools<br/>tools.ts]\n        Transport[UDP Transport<br/>retroarch.ts]\n    end\n\n    subgraph \"Target Layer\"\n        RA[RetroArch<br/>Running Emulator]\n        NCI[Network Control<br/>Interface]\n    end\n\n    MCP -->|\"stdio JSON-RPC\"| MCP_Server\n    MCP_Server --> Tools\n    Tools --> Transport\n    Transport -->|\"UDP :55355\"| NCI\n    NCI --> RA\n```\n\n**资料来源：** [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Component Architecture\n\n### Layer 1: MCP Server Entry Point\n\n**File:** `src/index.ts`\n\nThe main entry point initializes the MCP server using the `@modelcontextprotocol/sdk` package and establishes a background connectivity probe to RetroArch.\n\n```typescript\n// Simplified initialization flow\nconst server = new Server(\n  { name: \"mcp-retroarch\", version: \"0.1.2\" },\n  { capabilities: { tools: {} } }\n);\n\nra.connect()\n  .then(() => ra.getVersion())\n  .then((v) => process.stderr.write(`[mcp-retroarch] connected to ${ra.describeTarget()} — RetroArch ${v}\\n`))\n  .catch((err) => process.stderr.write(`[mcp-retroarch] note: RetroArch not reachable yet...\\n`));\n```\n\n**Key responsibilities:**\n- Initialize MCP server with stdio transport\n- Register all tool handlers\n- Perform fire-and-forget connectivity probe on startup\n- Handle fatal errors gracefully\n\n**资料来源：** [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n### Layer 2: UDP Transport Module\n\n**File:** `src/retroarch.ts`\n\nThe transport layer manages UDP socket communication with RetroArch's NCI. It implements a serial query pattern where only one request can be in-flight at a time.\n\n```mermaid\nsequenceDiagram\n    participant Client as MCP Client\n    participant Server as MCP Server\n    participant Transport as UDP Transport\n    participant RA as RetroArch NCI\n\n    Client->>Server: tool_call\n    Server->>Transport: send(query)\n    Transport->>RA: UDP datagram\n    RA-->>Transport: UDP response\n    Transport-->>Server: Buffer\n    Server-->>Client: JSON response\n```\n\n**Connection Management:**\n\n| Method | Purpose |\n|--------|---------|\n| `connect()` | Initialize UDP socket, bind to random port |\n| `disconnect()` | Close socket and cleanup |\n| `send(command)` | Fire-and-forget send (for hotkey commands) |\n| `query(command)` | Send and await response with timeout |\n\n**Configuration parameters:**\n\n| Parameter | Default | Description |\n|-----------|---------|-------------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in `retroarch.cfg`) |\n\n**资料来源：** [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts), [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Layer 3: MCP Tools Definition\n\n**File:** `src/tools.ts`\n\nAll available MCP tools are defined with JSON Schema input validation and descriptive documentation following a PURPOSE / USAGE / BEHAVIOR / RETURNS template.\n\n**Tool Categories:**\n\n| Category | Tools |\n|----------|-------|\n| **Memory** | `retroarch_read_memory`, `retroarch_write_memory`, `retroarch_read_ram`, `retroarch_write_ram` |\n| **State** | `retroarch_save_state_current`, `retroarch_load_state_current`, `retroarch_load_state_slot`, `retroarch_state_slot_plus`, `retroarch_state_slot_minus` |\n| **Control** | `retroarch_pause_toggle`, `retroarch_frame_advance`, `retroarch_reset` |\n| **Media** | `retroarch_screenshot`, `retroarch_show_message` |\n| **Info** | `retroarch_get_status`, `retroarch_get_config`, `retroarch_get_version` |\n\n**资料来源：** [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Data Flow\n\n### Memory Read Flow\n\n```mermaid\ngraph LR\n    A[Client:<br/>retroarch_read_memory] --> B[Validate:<br/>address, length]\n    B --> C[Send:<br/>READ_CORE_MEMORY]\n    C --> D{RetroArch<br/>Memory Map<br/>Available?}\n    D -->|Yes| E[Return bytes<br/>via UDP]\n    D -->|No| F[Error:<br/>no memory map defined]\n    E --> G[Format hex dump<br/>ADDR [N bytes]: XX XX...]\n```\n\n### Memory Write Flow\n\n```mermaid\ngraph LR\n    A[Client:<br/>retroarch_write_memory] --> B[Validate:<br/>address, bytes array]\n    B --> C[Send:<br/>WRITE_CORE_MEMORY]\n    C --> D[RetroArch<br/>Acknowledges<br/>byte count]\n    D --> E[Return count<br/>to client]\n```\n\n**资料来源：** [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts), [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Command Mapping\n\nThe following table shows how MCP tools map to RetroArch NCI commands:\n\n| MCP Tool | NCI Command | Response Pattern |\n|----------|-------------|-------------------|\n| `retroarch_get_version` | `VERSION` | String version |\n| `retroarch_get_status` | `GET_STATUS` | `GET_STATUS {state} {system},{game},crc32={crc}` |\n| `retroarch_read_memory` | `READ_CORE_MEMORY {addr} {len}` | Binary bytes |\n| `retroarch_write_memory` | `WRITE_CORE_MEMORY {addr} {bytes}` | `{count} bytes written` |\n| `retroarch_read_ram` | `READ_CORE_RAM {addr} {len}` | Binary bytes (CHEEVOS) |\n| `retroarch_write_ram` | `WRITE_CORE_RAM {addr} {bytes}` | Fire-and-forget |\n| `retroarch_pause_toggle` | `PAUSE_TOGGLE` | Fire-and-forget |\n| `retroarch_frame_advance` | `FRAMEADVANCE` | Fire-and-forget |\n| `retroarch_reset` | `RESET` | Fire-and-forget |\n| `retroarch_save_state_current` | `SAVE_STATE` | Fire-and-forget |\n| `retroarch_load_state_current` | `LOAD_STATE` | Fire-and-forget |\n| `retroarch_load_state_slot` | `LOAD_STATE {slot}` | Fire-and-forget |\n| `retroarch_screenshot` | `SCREENSHOT` | Fire-and-forget |\n| `retroarch_show_message` | `SET_MESSAGE \"{msg}\"` | Fire-and-forget |\n\n**资料来源：** [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n## Transport Characteristics\n\n### Serial Query Pattern\n\nThe transport layer enforces serial query execution:\n\n```typescript\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  // ... timeout handling\n}\n```\n\n**Key behaviors:**\n- Only one UDP query can be in-flight at a time\n- Queries timeout after configurable `timeoutMs` (default: 5000ms)\n- Fire-and-forget commands (`send()`) bypass the serial queue\n\n### Error Handling\n\n| Error Condition | Cause | Resolution |\n|-----------------|-------|------------|\n| `RetroArch query timed out` | Network Commands not enabled or port mismatch | Verify `network_cmd_enable = \"true\"` in `retroarch.cfg` |\n| `no memory map defined` | Core doesn't advertise system memory map | Use `retroarch_read_ram` as fallback |\n| `no descriptor for address` | Address outside core's memory regions | Use different core or address |\n| `query already in flight` | Multiple concurrent queries attempted | Wait for previous query to complete |\n\n**资料来源：** [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md), [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n## Memory Address Spaces\n\nmcp-retroarch exposes two distinct memory address spaces:\n\n### System Memory Map (`read_memory` / `write_memory`)\n\nUses `READ_CORE_MEMORY` / `WRITE_CORE_MEMORY` via the libretro core's system memory map.\n\n| System | Typical Address Range |\n|--------|------------------------|\n| GBA EWRAM | `0x02000000` - `0x0203FFFF` |\n| SNES WRAM | `0x7E0000` - `0x7FFFFF` |\n| Genesis 68K RAM | `0xFF0000` - `0xFFFFFF` |\n\n### CHEEVOS Address Space (`read_ram` / `write_ram`)\n\nUses `READ_CORE_RAM` / `WRITE_CORE_RAM` via the RetroAchievements address space. Uses different conventions per system (e.g., SNES WRAM starts at `0x000000` in CHEEVOS space).\n\n**资料来源：** [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Dependencies\n\n**File:** `package.json`\n\n| Dependency | Version | Purpose |\n|------------|---------|---------|\n| `@modelcontextprotocol/sdk` | `^1.12.0` | MCP server implementation |\n| `@types/node` | `^22.0.0` | TypeScript definitions |\n| `typescript` | `^5.5.0` | Build tooling |\n\n**资料来源：** [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n## Tested Cores Compatibility\n\n| System | Core | `read_memory` | `read_ram` | Notes |\n|--------|------|:------------:|:----------:|-------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA interrupt vector at `0x0000` |\n| NES | `mesen_libretro` | ✅ | ✅ | Full 16-bit address space |\n| NES | `nestopia_libretro` | ❌ | ✅ | CHEEVOS only |\n| SNES | `snes9x_libretro` | ❌ | N/A | Memory map not exposed |\n| PSX | `swanstation_libretro` | ❌ | ✅ | Use `read_ram` |\n\n**资料来源：** [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Project Structure\n\n```\nmcp-retroarch/\n├── src/\n│   ├── index.ts       # MCP server entry point\n│   ├── retroarch.ts  # UDP transport & NCI protocol\n│   └── tools.ts      # Tool definitions & handlers\n├── docs/\n│   └── RECIPES.md     # End-to-end usage examples\n├── package.json\n├── tsconfig.json\n└── README.md\n```\n\n**资料来源：** [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n<a id='page-data-flow'></a>\n\n## Data Flow\n\n### 相关页面\n\n相关主题：[System Architecture](#page-architecture), [Memory Read/Write Operations](#page-memory-operations)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Data Flow\n\nThis page documents the complete data flow through the mcp-retroarch system, from MCP client requests through UDP communication with RetroArch's Network Control Interface (NCI).\n\n## Architecture Overview\n\nmcp-retroarch bridges two distinct communication protocols:\n\n| Layer | Transport | Protocol |\n|-------|-----------|----------|\n| MCP Client ↔ mcp-retroarch | stdio | JSON-RPC 2.0 |\n| mcp-retroarch ↔ RetroArch | UDP (port 55355) | NCI text commands |\n\n资料来源：[README.md:1-50]()\n\n```mermaid\ngraph TB\n    subgraph \"MCP Layer (stdio)\"\n        A[\"MCP Client<br/>(Claude Code, Claude Desktop)\"]\n    end\n    \n    subgraph \"mcp-retroarch Process\"\n        B[\"src/index.ts<br/>MCP Server Entry\"]\n        C[\"src/tools.ts<br/>Tool Handlers\"]\n        D[\"src/retroarch.ts<br/>RetroArch Client\"]\n    end\n    \n    subgraph \"RetroArch\"\n        E[\"Network Control Interface<br/>(UDP :55355)\"]\n    end\n    \n    A -->|\"JSON-RPC 2.0<br/>stdio\"| B\n    B -->|routes| C\n    C -->|invokes methods| D\n    D -->|\"NCI commands<br/>UDP\"| E\n    E -->|\"UDP response\"| D\n```\n\n## Request-Response Flow\n\n### 1. MCP Request Ingress\n\nWhen an MCP client invokes a tool (e.g., `retroarch_read_memory`), the following occurs:\n\n1. The client sends a JSON-RPC 2.0 request via stdio\n2. `src/index.ts` receives the request and routes it to the appropriate tool handler in `src/tools.ts`\n3. The tool handler validates parameters against the input schema\n\n资料来源：[src/tools.ts:1-100]()\n\n### 2. Tool Handler Processing\n\nEach tool maps to a specific case in the tool handler switch statement:\n\n```typescript\ncase \"retroarch_read_memory\": {\n  const bytes = await ra.readMemory(p.address as number, p.length as number);\n  const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, \"0\").toUpperCase()).join(\" \");\n  return ok(`${addrHex(p.address as number)} [${bytes.length} bytes]:\\n${hex}`);\n}\n```\n\n资料来源：[src/tools.ts:20-30]()\n\n### 3. UDP Query Execution\n\nThe `RetroArch` class in `src/retroarch.ts` handles all network communication:\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP Client\n    participant Server as mcp-retroarch\n    participant Socket as UDP Socket\n    participant RA as RetroArch NCI\n    \n    MCP->>Server: retroarch_read_memory(0x02000000, 256)\n    Server->>Socket: send(\"READ_CORE_MEMORY 02000000 0100\")\n    Socket->>RA: UDP datagram to 127.0.0.1:55355\n    RA-->>Socket: \"READ_CORE_MEMORY OK [256 bytes]\"\n    Socket-->>Server: Buffer response\n    Server-->>MCP: JSON-RPC response with hex dump\n```\n\n资料来源：[src/retroarch.ts:1-50]()\n\n## Socket Communication Model\n\n### Connection Lifecycle\n\n```mermaid\ngraph LR\n    A[Lazy Connect] -->|on first query| B[Socket Created]\n    B --> C[bind to random port]\n    C --> D[ready for send/receive]\n    D --> E[on tool call]\n    E --> F[send UDP datagram]\n    F --> G[wait for response]\n    G -->|timeout| H[Error: query timed out]\n    G -->|response| I[resolve promise]\n```\n\n资料来源：[src/retroarch.ts:20-45]()\n\n### Query Serialization\n\nThe `query()` method enforces serial execution:\n\n```typescript\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  return new Promise<Buffer>((resolve, reject) => {\n    let timer: NodeJS.Timeout | null = setTimeout(() => {\n      this.pending = null;\n      reject(new Error(\n        `RetroArch query \"${command.split(\" \")[0]}\" timed out after ${this.timeoutMs}ms ` +\n        `— is RetroArch running with Network Commands enabled?`,\n      ));\n    }, this.timeoutMs);\n\n    this.pending = (data) => {\n      if (timer) { clearTimeout(timer); timer = null; }\n      resolve(data);\n    };\n    // ...\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:70-95]()\n\n**Key characteristics:**\n- **Lazy connection**: Socket is created on first query, not at startup\n- **Serial queries**: Only one pending query at a time (prevents response ambiguity)\n- **Timeout handling**: Configurable timeout with cleanup on resolution or expiry\n\n### Fire-and-Forget Commands\n\nSome commands use `send()` instead of `query()` for hotkey-style operations:\n\n```typescript\nasync send(command: string): Promise<void> {\n  if (!this.socket) await this.connect();\n  return new Promise((resolve, reject) => {\n    this.socket!.send(command, this.port, this.host, (err) =>\n      err ? reject(err) : resolve(),\n    );\n  });\n}\n```\n\nThese commands do not wait for or expect a response from RetroArch:\n- `retroarch_pause_toggle`\n- `retroarch_reset`\n- `retroarch_screenshot`\n\n资料来源：[src/retroarch.ts:55-68]()\n\n## Memory Read/Write Data Paths\n\n### Two Memory APIs\n\nmcp-retroarch exposes two distinct memory access paths:\n\n```mermaid\ngraph TD\n    A[Memory Request] --> B{Which API?}\n    B -->|System Memory Map| C[READ_CORE_MEMORY<br/>WRITE_CORE_MEMORY]\n    B -->|CHEEVOS Space| D[READ_CORE_RAM<br/>WRITE_CORE_RAM]\n    \n    C --> E[Full system bus access]\n    C --> F[Precise memory regions]\n    C --> G[Returns byte count on write]\n    \n    D --> H[Achievement address space]\n    D --> I[Limited to 64KB on some cores]\n    D --> J[No acknowledgment on write<br/>\"fire-and-forget\"]\n```\n\n资料来源：[src/tools.ts:100-200]()\n\n### Memory Read Flow\n\n1. **Tool handler** receives `address` and `length` parameters\n2. **RetroArch client** calls `readMemory()` or `readRam()`\n3. **UDP query** sent with address and byte count\n4. **Response parsing** extracts bytes from NCI response\n5. **Hex encoding** converts bytes to space-separated hex string\n\n```typescript\ncase \"retroarch_read_memory\": {\n  const bytes = await ra.readMemory(p.address as number, p.length as number);\n  const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, \"0\").toUpperCase()).join(\" \");\n  return ok(`${addrHex(p.address as number)} [${bytes.length} bytes]:\\n${hex}`);\n}\n```\n\n### Memory Write Flow\n\n| API | Acknowledgment | Use Case |\n|-----|----------------|----------|\n| `write_memory` | Yes (returns byte count) | Precise writes, cheats |\n| `write_ram` | No (fire-and-forget) | Fallback when memory map unavailable |\n\n资料来源：[src/tools.ts:30-50]()\n\n## Error Flow\n\n```mermaid\ngraph TD\n    A[Tool Call] --> B{UDP Send Success?}\n    B -->|No| C[Reject with send error]\n    B -->|Yes| D{Ack received?}\n    D -->|No| E[Timeout after 5000ms]\n    E --> F[\"Error: RetroArch query timed out\"]\n    D -->|Yes| G{NCI Response OK?}\n    G -->|No| H[Parse error or invalid response]\n    G -->|Yes| I[Return success data]\n    \n    C --> J[Error logged to stderr]\n    F --> J\n    H --> J\n    I --> K[JSON-RPC response to MCP client]\n```\n\n资料来源：[src/retroarch.ts:80-90]()\n\n### Error Scenarios\n\n| Error | Cause | User Message |\n|-------|-------|--------------|\n| `RetroArch query timed out` | Network Commands disabled or wrong port | Check `network_cmd_enable` in retroarch.cfg |\n| `no memory map defined` | Core doesn't expose system memory map | Use `read_ram` / `write_ram` instead |\n| `no descriptor for address` | Address outside core's memory regions | Use different address or core |\n| `retroarch query already in flight` | Concurrent query attempted | Tool calls are serialized |\n\n资料来源：[README.md:troubleshooting]()\n\n## Response Data Format\n\n### Memory Read Response\n\n```\nADDR_HEX [N bytes]:\nAB CD EF 12 34 56 78 9A ...\n```\n\nExample:\n```\n0x02000000 [16 bytes]:\n03 D0 00 EA 03 D1 00 EA 03 D2 00 EA 03 D3 00 EA\n```\n\n### Status Response\n\n```\nState:  playing\nSystem: snes\nGame:   Super Mario World (USA).sfc\nCRC32:  1A9FBD77\n```\n\n### Config Response\n\n```\nKEY = VALUE\n```\n\n## Configuration and Environment\n\n```mermaid\ngraph LR\n    subgraph \"Environment Variables\"\n        RA_HOST[\"RETROARCH_HOST<br/>default: 127.0.0.1\"]\n        RA_PORT[\"RETROARCH_PORT<br/>default: 55355\"]\n    end\n    \n    subgraph \"Runtime Config\"\n        SOCKET[\"UDP Socket\"]\n        TIMEOUT[\"timeoutMs<br/>default: 5000\"]\n    end\n    \n    RA_HOST -->|target IP| SOCKET\n    RA_PORT -->|target port| SOCKET\n```\n\n| Variable | Default | Purpose |\n|----------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in retroarch.cfg) |\n\n资料来源：[README.md:configuration]()\n\n## Startup Connectivity Probe\n\nThe server performs a non-blocking connectivity check on startup:\n\n```typescript\nra.connect()\n  .then(() => ra.getVersion())\n  .then((v) => process.stderr.write(`[mcp-retroarch] connected to ${ra.describeTarget()} — RetroArch ${v}\\n`))\n  .catch((err) => process.stderr.write(\n    `[mcp-retroarch] note: RetroArch not reachable yet (${ra.describeTarget()}): ${err}\\n` +\n    `             Enable Network Commands in retroarch.cfg...\\n`,\n  ));\n```\n\nThis probe is **fire-and-forget** and never blocks MCP server readiness.\n\n资料来源：[src/index.ts:1-20]()\n\n## Tool-to-Command Mapping\n\n| MCP Tool | NCI Command | Transport | Expects Response |\n|----------|-------------|-----------|------------------|\n| `retroarch_get_status` | `GET_STATUS` | query | Yes |\n| `retroarch_get_config` | `GET_CONFIG_PARAM` | query | Yes |\n| `retroarch_read_memory` | `READ_CORE_MEMORY` | query | Yes |\n| `retroarch_read_ram` | `READ_CORE_RAM` | query | Yes |\n| `retroarch_write_memory` | `WRITE_CORE_MEMORY` | query | Yes |\n| `retroarch_write_ram` | `WRITE_CORE_RAM` | send | No |\n| `retroarch_save_state_current` | `SAVE_STATE` | send | No |\n| `retroarch_load_state_current` | `LOAD_STATE` | send | No |\n| `retroarch_load_state_slot` | `LOAD_STATE` | send | No |\n| `retroarch_pause_toggle` | `PAUSE_TOGGLE` | send | No |\n| `retroarch_frame_advance` | `FRAMEADVANCE` | send | No |\n| `retroarch_reset` | `RESET` | send | No |\n| `retroarch_screenshot` | `SCREENSHOT` | send | No |\n| `retroarch_show_message` | `SHOW_MSG` | send | No |\n\n资料来源：[src/tools.ts:1-300]()\n资料来源：[src/retroarch.ts:100-200]()\n\n## Non-Blocking Architecture\n\nUnlike earlier versions, the MCP server does not wait for RetroArch connectivity on startup:\n\n| Version | Behavior |\n|---------|----------|\n| ≤ 0.1.0 | Blocked ~5s on VERSION query timeout |\n| ≥ 0.1.1 | Non-blocking, probe runs in background |\n\nThis change eliminated startup delay when RetroArch is not running.\n\n资料来源：[CHANGELOG.md:0.1.1]()\n\n## Summary\n\nThe data flow through mcp-retroarch follows a clear layered architecture:\n\n1. **MCP Layer**: JSON-RPC over stdio for client-server communication\n2. **Tool Layer**: Parameter validation and response formatting in `src/tools.ts`\n3. **Transport Layer**: UDP socket management in `src/retroarch.ts`\n4. **NCI Layer**: RetroArch Network Control Interface commands\n\nThe design prioritizes:\n- **Serial query execution** to prevent response ambiguity\n- **Lazy connection** to avoid startup blocking\n- **Fire-and-forget** for hotkey commands to reduce latency\n- **Explicit acknowledgment** for writes that support it\n\n---\n\n<a id='page-memory-operations'></a>\n\n## Memory Read/Write Operations\n\n### 相关页面\n\n相关主题：[Core Compatibility](#page-core-compatibility), [MCP Tools Reference](#page-tools-reference)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n</details>\n\n# Memory Read/Write Operations\n\n## Overview\n\nThe mcp-retroarch project exposes memory read/write functionality through RetroArch's Network Control Interface (NCI), enabling MCP clients to inspect and mutate the emulated system's memory in real-time. This capability is fundamental for debugging, cheat implementation, game state inspection, and scripted automation.\n\nMemory operations target the emulated system—not the host machine—and support two distinct address space APIs depending on the loaded libretro core's capabilities.\n\n## Architecture\n\nMemory operations flow through a serial UDP transport layer to RetroArch's NCI endpoint:\n\n```mermaid\ngraph TD\n    A[\"MCP Client<br/>retroarch_read_memory<br/>retroarch_write_ram\"] --> B[\"mcp-retroarch<br/>src/tools.ts\"]\n    B --> C[\"RetroArchClient<br/>src/retroarch.ts\"]\n    C -->|UDP :55355| D[\"RetroArch NCI\"]\n    D -->|Memory Map API<br/>or CHEEVOS API| E[\"libretro Core<br/>Emulated System Memory\"]\n    \n    F[\"READ_CORE_MEMORY<br/>WRITE_CORE_MEMORY\"] -.->|system bus| E\n    G[\"READ_CORE_RAM<br/>WRITE_CORE_RAM\"] -.->|CHEEVOS space| E\n```\n\n### Transport Layer\n\nThe UDP socket is initialized in `src/retroarch.ts` with the following behavior:\n\n- **Query mode** (`query()`): Sends a command and awaits exactly one UDP response, throwing on timeout (~5 seconds)\n- **Fire-and-forget mode** (`send()`): Sends a command without waiting for acknowledgment\n\n```typescript\n// Serial query with timeout: src/retroarch.ts:60-85\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  return new Promise<Buffer>((resolve, reject) => {\n    let timer: NodeJS.Timeout | null = setTimeout(() => {\n      this.pending = null;\n      reject(new Error(\n        `RetroArch query \"${command.split(\" \")[0]}\" timed out after ${this.timeoutMs}ms ` +\n        `— is RetroArch running with Network Commands enabled?`,\n      ));\n    }, this.timeoutMs);\n    // ...\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:60-75]()\n\n## Two Memory APIs\n\nmcp-retroarch exposes two independent memory interfaces, each mapping to a different RetroArch NCI command family:\n\n| Aspect | `_memory` API | `_ram` API |\n|--------|--------------|------------|\n| NCI Command | `READ_CORE_MEMORY` / `WRITE_CORE_MEMORY` | `READ_CORE_RAM` / `WRITE_CORE_RAM` |\n| Address Space | System memory bus | CHEEVOS (achievement) space |\n| Core Requirement | Core must expose memory map | Works via CHEEVOS interface |\n| Fallback | Falls back to `_ram` if \"no memory map defined\" | N/A (always available on supported cores) |\n| Write Acknowledgment | ✅ Returns byte count | ❌ Fire-and-forget |\n\n资料来源：[src/tools.ts:1-150]()\n\n### System Memory Map (`_memory`)\n\nThe `_memory` tools use the libretro core's exposed system memory descriptors. This is the **preferred** approach when available because:\n\n- Addresses follow the native system bus layout (e.g., SNES WRAM at `0x7E0000-0x7FFFFF`)\n- `WRITE_CORE_MEMORY` returns acknowledgment with actual byte count written\n- Read-only descriptors are honored (write stops at boundary)\n\n### CHEEVOS Address Space (`_ram`)\n\nThe `_ram` tools use RetroAchievements' address space conventions, which differ from the native system bus:\n\n| System | CHEEVOS WRAM Start | System Bus WRAM Start |\n|--------|-------------------|----------------------|\n| SNES | `0x000000` | `0x7E0000` |\n| GBA | `0x03000000` | `0x02000000` (EWRAM) |\n\n资料来源：[src/tools.ts:95-120]()\n\n## Tool Reference\n\n### `retroarch_read_memory`\n\nRead bytes via the libretro core's system memory map.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `address` | integer | ✅ | Starting address in system memory map |\n| `length` | integer | ✅ | Bytes to read (1-4096) |\n\n**Returns:** Header line `ADDR_HEX [N bytes]:` followed by space-separated uppercase hex bytes.\n\n**Error Conditions:**\n- `\"no memory map defined\"` — Core doesn't expose system memory map\n- `\"no descriptor for address\"` — Address outside core's memory regions\n- Timeout after ~5 seconds\n\n资料来源：[src/tools.ts:70-100]()\n\n### `retroarch_write_memory`\n\nWrite bytes via the libretro core's system memory map. **This is the only write tool that returns acknowledgment.**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `address` | integer | ✅ | Starting address in system memory map |\n| `bytes` | integer[] | ✅ | Byte values 0-255 (max 4096) |\n\n**Returns:** `Wrote N bytes → ADDR_HEX` where N is confirmed written count.\n\n**Side Effects:**\n- Disables RetroArch's hardcore mode for the session\n- Destructive (no undo; use `retroarch_save_state_current` first)\n\n资料来源：[src/tools.ts:100-140]()\n\n### `retroarch_read_ram`\n\nRead bytes via the CHEEVOS (achievement) address space.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `address` | integer | ✅ | Starting address in CHEEVOS space |\n| `length` | integer | ✅ | Bytes to read (1-4096) |\n\n**Returns:** Header line `ADDR_HEX [N bytes, CHEEVOS]:` followed by hex dump.\n\n**Note:** RetroArch may return fewer bytes than requested at memory-region boundaries.\n\n资料来源：[src/tools.ts:120-150]()\n\n### `retroarch_write_ram`\n\nWrite bytes via the CHEEVOS address space. **Fire-and-forget—no acknowledgment.**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `address` | integer | ✅ | Starting address in CHEEVOS space |\n| `bytes` | integer[] | ✅ | Byte values 0-255 (max 4096) |\n\n**Returns:** `Wrote N bytes → ADDR_HEX (CHEEVOS, no ack)`\n\n**Verification:** Follow up with `retroarch_read_ram` at the same address to confirm the write landed.\n\n资料来源：[src/tools.ts:150-180]()\n\n## Usage Workflow\n\n### Read Memory (System Bus)\n\n```typescript\n// Read 16 bytes from SNES WRAM at 0x7E0000\nconst result = await tools.retroarch_read_memory({\n  address: 0x7E0000,\n  length: 16\n});\n// Returns: \"7E0000 [16 bytes]:\n//          00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\"\n```\n\n### Write Memory with Verification\n\n```mermaid\ngraph LR\n    A[\"Save State<br/>retroarch_save_state_current\"] --> B[\"Write Memory<br/>retroarch_write_memory\"]\n    B --> C{\"Response received?\"}\n    C -->|Yes| D[\"Read Back<br/>retroarch_read_memory\"]\n    D --> E[\"Verify bytes match\"]\n    C -->|No/Timeout| F[\"Load State<br/>retroarch_load_state_current\"]\n    E -->|Mismatch| F\n```\n\n### Write RAM (CHEEVOS) with Verification\n\n```mermaid\ngraph LR\n    A[\"Save State\"] --> B[\"Write RAM<br/>retroarch_write_ram\"]\n    B --> C[\"Read Back<br/>retroarch_read_ram\"]\n    C --> D{\"Bytes match?\"}\n    D -->|Yes| E[\"Continue\"]\n    D -->|No| F[\"Load State<br/>retroarch_load_state_current\"]\n```\n\n## Common Address Ranges\n\n| System | Region | System Bus | CHEEVOS Space |\n|--------|--------|------------|---------------|\n| GBA | EWRAM | `0x02000000-0x0203FFFF` | `0x03000000` offset |\n| GBA | IWRAM | `0x03000000-0x03007FFF` | Direct |\n| SNES | WRAM | `0x7E0000-0x7FFFFF` | `0x000000` |\n| Genesis | 68K RAM | `0xFF0000-0xFFFFFF` | N/A |\n\n资料来源：[src/tools.ts:85-95]()\n\n## Limitations\n\n| Limitation | Cause | Workaround |\n|------------|-------|------------|\n| Max 4096 bytes/call | NCI single-datagram size | Batch larger reads in 4 KiB chunks |\n| No \"save to slot N\" | NCI protocol limitation | Walk slot pointer with `state_slot_plus`/`state_slot_minus` |\n| `write_ram` has no ack | RetroArch doesn't respond to `WRITE_CORE_RAM` | Follow up with `retroarch_read_ram` |\n| Address spaces differ | CHEEVOS vs system bus | Use `_memory` tools when possible |\n| Memory regions bounded | Core exposes specific regions | Some addresses (VRAM, etc.) may be inaccessible |\n\n资料来源：[src/tools.ts:145-155]()\n\n## Configuration\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in retroarch.cfg) |\n\n资料来源：[README.md:configuration]()\n\n---\n\n<a id='page-savestate-management'></a>\n\n## Savestate Management\n\n### 相关页面\n\n相关主题：[MCP Tools Reference](#page-tools-reference)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Savestate Management\n\n## Overview\n\nSavestate Management in mcp-retroarch enables programmatic save and load operations for game sessions running under RetroArch's Network Command Interface (NCI). The system provides five MCP tools that wrap RetroArch's savestate NCI commands, allowing MCP clients to snapshot emulator state, restore from previous snapshots, and navigate between save slots.\n\nThe savestate system operates over UDP to RetroArch's NCI on port 55355, with mcp-retroarch acting as a bridge between the MCP JSON-RPC protocol and RetroArch's line-based command protocol.\n\n## Architecture\n\n```\n┌─────────────────┐    stdio JSON-RPC    ┌──────────────────────┐   UDP :55355   ┌─────────────────┐\n│   MCP Client    │◄───────────────────►│    mcp-retroarch     │◄──────────────►│   RetroArch     │\n│ (Claude Code,   │                      │  (src/retroarch.ts)  │                │   (NCI Server)  │\n│  Claude Desktop)│                      └──────────────────────┘                └─────────────────┘\n└─────────────────┘\n```\n\nThe savestate subsystem relies on:\n\n| Layer | Technology | Role |\n|-------|------------|------|\n| MCP Protocol | stdio + JSON-RPC | Client-facing tool interface |\n| Bridge | TypeScript (src/retroarch.ts) | Protocol translation and UDP communication |\n| Transport | UDP datagrams | Direct communication with RetroArch NCI |\n| Target | RetroArch NCI | Savestate command execution |\n\n## Savestate Tools\n\n| Tool | NCI Command | Purpose |\n|------|-------------|---------|\n| `retroarch_save_state_current` | `SAVE_STATE` | Save to currently-selected slot |\n| `retroarch_load_state_current` | `LOAD_STATE` | Load from currently-selected slot |\n| `retroarch_load_state_slot` | `LOAD_STATE_SLOT N` | Load from explicit slot N (1-9) |\n| `retroarch_state_slot_plus` | `STATE_SLOT_PLUS` | Increment slot pointer |\n| `retroarch_state_slot_minus` | `STATE_SLOT_MINUS` | Decrement slot pointer |\n\n### Tool Parameters\n\n#### retroarch_load_state_slot\n\n```json\n{\n  \"name\": \"retroarch_load_state_slot\",\n  \"arguments\": {\n    \"slot\": {\n      \"type\": \"integer\",\n      \"minimum\": 1,\n      \"maximum\": 9,\n      \"description\": \"Savestate slot number (1-9). RetroArch uses 1-based slot indexing.\"\n    }\n  }\n}\n```\n\n### Return Values\n\nAll savestate tools return single-line confirmation messages:\n\n| Tool | Return Message |\n|------|----------------|\n| `retroarch_save_state_current` | `\"Saved to current slot\"` |\n| `retroarch_load_state_current` | `\"Loaded from current slot\"` |\n| `retroarch_load_state_slot` | `\"Loaded from slot N\"` |\n| `retroarch_state_slot_plus` | `\"Slot: N\"` |\n| `retroarch_state_slot_minus` | `\"Slot: N\"` |\n\n> **Note**: These return messages are UDP-send confirmations only. The NCI does not acknowledge command receipt. If a savestate operation fails silently, the tool will still return a success-like message.\n\n资料来源：[src/tools.ts:77-79]()\n\n## Slot-Based Savestate Model\n\n### How Slots Work\n\nRetroArch's savestate system uses a **slot-based model** with 10 slots (0-9 by default, though some builds use 1-9). Each slot holds one savestate file. When you save to an occupied slot, the existing savestate is overwritten.\n\n### The Slot Pointer\n\nRetroArch maintains an internal **current slot pointer** that determines which slot `SAVE_STATE` and `LOAD_STATE` (without a slot argument) target. The slot pointer can be changed using:\n\n```mermaid\ngraph LR\n    A[\"Current Slot = N\"] --> B[\"state_slot_plus\"]\n    B --> C[\"Current Slot = N+1\"]\n    C --> D[\"state_slot_plus\"]\n    D --> E[\"Current Slot = N+2\"]\n    \n    A --> F[\"state_slot_minus\"]\n    F --> G[\"Current Slot = N-1\"]\n    G --> H[\"state_slot_minus\"]\n    H --> I[\"Current Slot = N-2\"]\n```\n\n### Slot Navigation Workflow\n\nTo save to slot 5 when currently at slot 1:\n\n```mermaid\ngraph TD\n    A[\"Start: Slot = 1\"] --> B[\"retroarch_state_slot_plus\"]\n    B --> C[\"Slot = 2\"]\n    C --> D[\"retroarch_state_slot_plus\"]\n    D --> E[\"Slot = 3\"]\n    E --> F[\"retroarch_state_slot_plus\"]\n    F --> G[\"Slot = 4\"]\n    G --> H[\"retroarch_state_slot_plus\"]\n    H --> I[\"Slot = 5\"]\n    I --> J[\"retroarch_save_state_current\"]\n    J --> K[\"Saved to slot 5\"]\n```\n\n## Critical Limitations\n\n### No Direct Save-to-Slot\n\nThe NCI protocol does not expose a `SAVE_STATE_SLOT N` command. This is a protocol limitation, not a bug in mcp-retroarch.\n\n| Operation | Available? | Workaround |\n|-----------|------------|------------|\n| Save to current slot | ✅ Yes | `retroarch_save_state_current` |\n| Save to specific slot | ❌ No | Walk slot pointer with plus/minus, then save |\n| Load from current slot | ✅ Yes | `retroarch_load_state_current` |\n| Load from specific slot | ✅ Yes | `retroarch_load_state_slot` |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Current Slot Not Queryable\n\nThe NCI does not expose a command to query the current slot pointer. Clients must track slot position client-side or use `retroarch_show_message` to echo the slot number.\n\n```mermaid\ngraph TD\n    A[\"Track slot client-side\"] --> B[\"State variable: currentSlot\"]\n    A --> C[\"Use show_message for confirmation\"]\n    C --> D[\"retroarch_show_message with 'Slot: N'\"]\n```\n\n## UDP Communication Details\n\n### Query/Response Pattern\n\nThe savestate bridge uses serial UDP communication with timeout handling:\n\n```typescript\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  return new Promise<Buffer>((resolve, reject) => {\n    let timer: NodeJS.Timeout | null = setTimeout(() => {\n      this.pending = null;\n      reject(new Error(\n        `RetroArch query \"${command.split(\" \")[0]}\" timed out after ${this.timeoutMs}ms`,\n      ));\n    }, this.timeoutMs);\n    // ...\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:72-89]()\n\n### Fire-and-Forget Commands\n\n`retroarch_save_state_current`, `retroarch_state_slot_plus`, and `retroarch_state_slot_minus` use fire-and-forget semantics:\n\n```typescript\nasync send(command: string): Promise<void> {\n  if (!this.socket) await this.connect();\n  return new Promise((resolve, reject) => {\n    this.socket!.send(command, this.port, this.host, (err) =>\n      err ? reject(err) : resolve(),\n    );\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:63-69]()\n\n## Best Practices\n\n### Establish Rollback Points\n\nBefore memory writes or destructive operations, always save the current state:\n\n```typescript\n// 1. Save rollback point\nretroarch_save_state_current();\n\n// 2. Perform memory operations\nretroarch_write_memory(address, bytes);\n\n// 3. If something goes wrong, restore\nretroarch_load_state_current();\n```\n\n### Pre-Check Before Toggle Operations\n\nSince the NCI only exposes toggle commands, verify state before operations that depend on pause state:\n\n```mermaid\ngraph TD\n    A[\"retroarch_get_status\"] --> B{\"state: playing?\"}\n    B -->|Yes, want to pause| C[\"retroarch_pause_toggle\"]\n    B -->|No, want to unpause| C\n    C --> D[\"retroarch_save_state_current\"]\n    D --> E[\"Continue workflow\"]\n```\n\n### Slot Tracking Pattern\n\n```typescript\nlet currentSlot = 1; // Track client-side\n\nasync function saveToSlot(targetSlot) {\n  while (currentSlot < targetSlot) {\n    await retroarch_state_slot_plus();\n    currentSlot++;\n  }\n  while (currentSlot > targetSlot) {\n    await retroarch_state_slot_minus();\n    currentSlot--;\n  }\n  await retroarch_save_state_current();\n}\n```\n\n## Error Handling\n\n### Timeout Errors\n\nIf RetroArch doesn't respond within the timeout period (default: 5000ms), the tool returns an error:\n\n```\nRetroArch query \"SAVE_STATE\" timed out after 5000ms — is RetroArch running with Network Commands enabled?\n```\n\n**Troubleshooting**:\n1. Confirm `network_cmd_enable = \"true\"` in retroarch.cfg\n2. Verify `network_cmd_port = \"55355\"` matches `RETROARCH_PORT` environment variable\n3. Check that a game/ROM is currently loaded (NCI requires active content)\n\n### UDP Drop Handling\n\nUDP datagrams can be dropped under load even on loopback. If a call times out but a retry succeeds, that's normal UDP behavior—the bridge does not auto-retry.\n\n## Configuration\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in retroarch.cfg) |\n\n## Related Tools\n\n| Tool | Relationship |\n|------|--------------|\n| `retroarch_get_status` | Use to verify game state before loading states |\n| `retroarch_frame_advance` | Step frames after loading state to verify restore |\n| `retroarch_show_message` | Echo current slot number for tracking |\n\n## Changelog\n\n### v0.1.2 (2026-05-15)\n\nDocumentation improvements:\n- Slot-based savestate model now explicitly documented\n- Fire-and-forget UDP semantics surfaced in tool descriptions\n- NCI limitation (\"no save to slot N\") clearly documented with workaround\n\n资料来源：[CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n\n---\n\n<a id='page-emulation-control'></a>\n\n## Emulation Control\n\n### 相关页面\n\n相关主题：[MCP Tools Reference](#page-tools-reference)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n</details>\n\n# Emulation Control\n\n## Overview\n\nEmulation Control in mcp-retroarch encompasses the set of tools and mechanisms that allow MCP clients to interact with a running RetroArch emulator. This includes pausing/resuming execution, advancing frames one at a time, resetting games, capturing screenshots, displaying on-screen notifications, and managing save states.\n\nThe control layer operates exclusively through RetroArch's Network Control Interface (NCI), a UDP-based command protocol that listens on port 55355 by default. All control commands are sent as plain-text line-terminated strings over UDP, and the majority are fire-and-forget — RetroArch does not acknowledge receipt or execution status.\n\n## Architecture\n\n### Transport Layer\n\nThe UDP transport is implemented in `src/retroarch.ts`. The communication model uses a single persistent UDP socket with promise-based request/response handling.\n\n```mermaid\ngraph TD\n    A[\"MCP Client<br/>stdio JSON-RPC\"] --> B[\"mcp-retroarch<br/>src/index.ts\"]\n    B --> C[\"RetroArchClient<br/>src/retroarch.ts\"]\n    C --> D[\"UDP Socket<br/>127.0.0.1:55355\"]\n    D --> E[\"RetroArch NCI\"]\n    \n    F[\"NCI Response\"] --> D\n    D --> G[\"Pending Promise<br/>resolve/reject\"]\n    G --> B\n```\n\n**Key transport behaviors:**\n\n| Method | Behavior | Use Case |\n|--------|----------|----------|\n| `send(command)` | Fire-and-forget, no response expected | Pause, reset, frame advance |\n| `query(command)` | Sends command, awaits one UDP response | Memory reads, status queries |\n| `connect()` | Binds UDP socket to ephemeral port | Transport initialization |\n| `disconnect()` | Closes socket | Cleanup |\n\n资料来源：[src/retroarch.ts:1-50]()\n\n### Serialization Constraint\n\nUDP datagrams are line-terminated. This has a critical implication for the `retroarch_show_message` tool: any message containing `\\n` or `\\r` will be truncated at the first newline, with the remainder silently dropped on the wire.\n\n## Core Control Tools\n\n### Pause Toggle\n\n**Tool:** `retroarch_pause_toggle`\n\nToggles RetroArch's pause state between paused and running.\n\n```mermaid\ngraph LR\n    A[\"Call retroarch_get_status\"] --> B{\"state?\"}\n    B -->|\"playing\"| C[\"retroarch_pause_toggle<br/>→ paused\"]\n    B -->|\"paused\"| D[\"retroarch_pause_toggle<br/>→ playing\"]\n    C --> E[\"Verify with retroarch_get_status\"]\n    D --> E\n```\n\n**Important:** The NCI exposes only a toggle, not separate pause and unpause commands. Without first checking the current state via `retroarch_get_status`, the result is indeterminate.\n\n| Property | Value |\n|----------|-------|\n| Input Schema | `{}` (no parameters) |\n| Return | `\"Pause toggled\"` (UDP-send confirmation only) |\n| Fire-and-forget | Yes — no verification of actual pause state |\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### Frame Advance\n\n**Tool:** `retroarch_frame_advance`\n\nAdvances the emulation by exactly one frame. This is only effective while emulation is paused — calling FRAMEADVANCE while running is a no-op.\n\n| Property | Value |\n|----------|-------|\n| Input Schema | `{}` (no parameters) |\n| Prerequisite | Emulation must be paused |\n| Use Case | Frame-precise input automation, animation inspection |\n| Alternative | For large frame jumps, use `retroarch_save_state_current` / `retroarch_load_state_current` |\n\n资料来源：[src/tools.ts]()\n\n### Reset\n\n**Tool:** `retroarch_reset`\n\nPerforms a hard reset of the currently loaded game. The core is reloaded and execution begins from the game's reset vector.\n\n| Property | Value |\n|----------|-------|\n| Input Schema | `{}` (no parameters) |\n| Return | `\"Game reset\"` (UDP-send confirmation only) |\n| Behavior | Immediately interrupts current execution |\n\n资料来源：[src/tools.ts]()\n\n## Save State Management\n\n### State Slots\n\nRetroArch maintains a current state slot pointer (0-9 typically). The save state tools operate on this pointer.\n\n```mermaid\ngraph TD\n    A[\"Current Slot = N\"] --> B[\"retroarch_save_state_current\"]\n    B --> C[\"Save → Slot N\"]\n    \n    A --> D[\"retroarch_load_state_slot<br/>slot: M\"]\n    D --> E{\"M == N?\"}\n    E -->|Yes| F[\"Load from Slot N\"]\n    E -->|No| G[\"retroarch_state_slot_plus/minus<br/>to walk to M\"]\n    G --> H[\"Load from Slot M\"]\n```\n\n### Available Tools\n\n| Tool | Purpose | Input | Return |\n|------|---------|-------|--------|\n| `retroarch_save_state_current` | Save to current slot | None | `\"Saved to current slot\"` |\n| `retroarch_load_state_current` | Load from current slot | None | `\"Loaded from current slot\"` |\n| `retroarch_load_state_slot` | Load from explicit slot | `{ slot: number }` | `\"Loaded from slot N\"` |\n| `retroarch_state_slot_plus` | Increment slot pointer | None | Slot number confirmation |\n| `retroarch_state_slot_minus` | Decrement slot pointer | None | Slot number confirmation |\n\n### Known Limitation\n\nThe NCI protocol does not expose a command to save directly to a specific slot. To save to slot 5 when the pointer is on slot 0:\n\n1. Call `retroarch_state_slot_plus` five times\n2. Call `retroarch_save_state_current`\n\nThis is an NCI limitation, not a bug in mcp-retroarch.\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Visual Feedback Tools\n\n### Screenshot\n\n**Tool:** `retroarch_screenshot`\n\nCaptures the current frame and saves it to RetroArch's configured screenshot directory.\n\n| Property | Value |\n|----------|-------|\n| Input Schema | `{}` (no parameters) |\n| Return | `\"Screenshot saved to RetroArch's configured screenshot directory\"` |\n| Directory | Must be verified in RetroArch GUI: Settings → Directory → Screenshot |\n| NCI Limitation | The `screenshot_directory` param is NOT exposed via `GET_CONFIG_PARAM` |\n\n资料来源：[src/tools.ts](), [README.md]()\n\n### On-Screen Message\n\n**Tool:** `retroarch_show_message`\n\nDisplays a single-line notification overlay on the RetroArch window for approximately 3 seconds (RetroArch's default notification timeout).\n\n| Property | Value |\n|----------|-------|\n| Input Schema | `{ message: string }` | Required, minLength: 1 |\n| Message Limits | ≤80 characters recommended; newlines (`\\n`, `\\r`) truncate |\n| Duration | ~3 seconds (configurable via `input_overlay_show_inputs_port` settings) |\n| Queueing | Messages are NOT queued — rapid calls replace the previous message |\n| Use Case | Debug output, progress markers, \"look here\" cues |\n\n```mermaid\ngraph LR\n    A[\"Message: 'Frame 1234'\"] --> B[\"NCI OSD Overlay\"]\n    C[\"Rapid Second Call\"] --> D[\"Message: 'Frame 1235'\"]\n    D -->|Before A renders| B\n```\n\n**Important:** Because messages replace each other, do not issue multiple `show_message` calls in rapid succession without verification that the previous message was read.\n\n资料来源：[src/tools.ts]()\n\n## UDP Transport Deep Dive\n\n### Socket Lifecycle\n\nFrom `src/retroarch.ts`:\n\n```typescript\nasync connect(): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const sock = dgram.createSocket(\"udp4\");\n    sock.once(\"error\", (err) => reject(err));\n    sock.bind(0, () => {\n      sock.on(\"message\", (msg) => {\n        const cb = this.pending;\n        if (!cb) return;  // unsolicited or late reply — drop\n        this.pending = null;\n        cb(msg);\n      });\n      // ...\n    });\n  });\n}\n```\n\n### Query Timeout\n\nThe `query()` method enforces a configurable timeout (default ~5 seconds):\n\n```typescript\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  return new Promise<Buffer>((resolve, reject) => {\n    let timer: NodeJS.Timeout | null = setTimeout(() => {\n      this.pending = null;\n      reject(new Error(\"RetroArch query timed out\"));\n    }, this.timeoutMs);\n    // ...\n  });\n}\n```\n\n**Serial constraint:** Only one query can be in-flight at a time. The client enforces this with a `pending` callback reference.\n\n资料来源：[src/retroarch.ts]()\n\n## Error Handling\n\n### Common Errors\n\n| Symptom | Cause | Fix |\n|---------|-------|-----|\n| `RetroArch query timed out` | Network Commands disabled or port mismatch | Verify `network_cmd_enable = \"true\"` in `retroarch.cfg` |\n| `retroarch query already in flight` | Code bug or concurrent tool calls | Ensure serial tool execution |\n| Screenshot not where expected | Screenshot saved to RetroArch's configured directory | Check Settings → Directory → Screenshot |\n\n### Background Connectivity\n\nThe MCP server performs a fire-and-find connectivity probe on startup in `src/index.ts`:\n\n```typescript\nra.connect()\n  .then(() => ra.getVersion())\n  .then((v) => process.stderr.write(`[mcp-retroarch] connected to ${ra.describeTarget()} — RetroArch ${v}\\n`))\n  .catch((err) => process.stderr.write(\n    `[mcp-retroarch] note: RetroArch not reachable yet (${ra.describeTarget()}): ${err}\\n` +\n    `             Enable Network Commands in retroarch.cfg (network_cmd_enable / network_cmd_port)\\n`\n  ));\n```\n\nThis does not block server startup — tool calls will connect on demand.\n\n资料来源：[src/index.ts]()\n\n## Configuration\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in `retroarch.cfg`) |\n\nRetroArch-side configuration (via GUI or `retroarch.cfg`):\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\nOr via RetroArch GUI: **Settings → Network → Network Commands → ON**\n\n资料来源：[README.md]()\n\n## Tool Summary Table\n\n| Tool | Type | Input | Fire-and-Forget | Verified Return |\n|------|------|-------|-----------------|-----------------|\n| `retroarch_pause_toggle` | Control | None | Yes | Confirmation only |\n| `retroarch_frame_advance` | Control | None | Yes | Confirmation only |\n| `retroarch_reset` | Control | None | Yes | Confirmation only |\n| `retroarch_save_state_current` | State | None | Yes | Confirmation only |\n| `retroarch_load_state_current` | State | None | Yes | Confirmation only |\n| `retroarch_load_state_slot` | State | `{ slot }` | Yes | Confirmation only |\n| `retroarch_state_slot_plus` | State | None | Yes | Confirmation only |\n| `retroarch_state_slot_minus` | State | None | Yes | Confirmation only |\n| `retroarch_screenshot` | Visual | None | Yes | Confirmation only |\n| `retroarch_show_message` | Visual | `{ message }` | Yes | Confirmation only |\n\n## Dependencies\n\nThe emulation control functionality depends on:\n\n```json\n{\n  \"@modelcontextprotocol/sdk\": \"^1.12.0\"\n}\n```\n\nThe `@modelcontextprotocol/sdk` provides the MCP server framework that exposes these tools via stdio JSON-RPC to compatible MCP clients (Claude Code, Claude Desktop, etc.).\n\n资料来源：[package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n---\n\n<a id='page-tools-reference'></a>\n\n## MCP Tools Reference\n\n### 相关页面\n\n相关主题：[Memory Read/Write Operations](#page-memory-operations), [Savestate Management](#page-savestate-management), [Emulation Control](#page-emulation-control)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# MCP Tools Reference\n\nThe mcp-retroarch project exposes a collection of Model Context Protocol (MCP) tools that enable programmatic control of RetroArch through its Network Control Interface (NCI). These tools provide capabilities ranging from memory inspection and modification to savestate management and emulator control.\n\n## Overview\n\nmcp-retroarch acts as a bridge between MCP clients and RetroArch's UDP-based NCI protocol. The MCP server communicates with RetroArch over UDP port 55355 (default), translating JSON-RPC requests from MCP clients into NCI commands. 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n```\n+----------------+    stdio     +-----------------+   UDP :55355  +-----------------+\n|   MCP client   |   JSON-RPC   |  mcp-retroarch  |   NCI commands |  RetroArch      |\n+----------------+              +-----------------+                +-----------------+\n```\n\n## Tool Categories\n\nThe tools are organized into five functional categories:\n\n| Category | Tools | Purpose |\n|----------|-------|---------|\n| **Status & Config** | `retroarch_get_status`, `retroarch_get_config` | Query emulator state and configuration |\n| **Memory Access** | `retroarch_read_memory`, `retroarch_write_memory`, `retroarch_read_ram`, `retroarch_write_ram` | Read/write emulated system memory |\n| **Savestate** | `retroarch_save_state_current`, `retroarch_load_state_current`, `retroarch_load_state_slot`, `retroarch_state_slot_plus`, `retroarch_state_slot_minus` | Manage game save states |\n| **Emulator Control** | `retroarch_pause_toggle`, `retroarch_frame_advance`, `retroarch_reset` | Control emulation execution |\n| **Media & UI** | `retroarch_screenshot`, `retroarch_show_message` | Capture screenshots and display notifications |\n\n## Memory Architecture\n\nmcp-retroarch provides two distinct memory access APIs, each using different address spaces and underlying NCI commands. 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### System Memory Map (`_memory` tools)\n\nThe `_memory` tools use `READ_CORE_MEMORY` and `WRITE_CORE_MEMORY` commands, accessing the libretro core's system memory map. This is the preferred method when the loaded core advertises a memory map. 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n**Address conventions vary by system:**\n\n| System | Memory Region | Address Range |\n|--------|---------------|---------------|\n| GBA EWRAM | External Work RAM | `0x02000000-0x0203FFFF` |\n| SNES WRAM | Work RAM | `0x7E0000-0x7FFFFF` |\n| Genesis 68K RAM | Main RAM | `0xFF0000-0xFFFFFF` |\n\n### CHEEVOS Address Space (`_ram` tools)\n\nThe `_ram` tools use `READ_CORE_RAM` and `WRITE_CORE_RAM` commands (the older CHEEVOS/achievements API). These tools access the RetroAchievements address space, which follows per-system conventions distinct from the system memory map. 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n**When to use which:**\n\n- Use `_memory` tools as the starting point for memory access\n- Fall back to `_ram` tools when `_memory` returns `'no memory map defined'` (older cores)\n- `read_ram` confirmed working for SwanStation (PSX), Mesen (NES) 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Memory Tool Comparison\n\n| Feature | `_memory` tools | `_ram` tools |\n|---------|-----------------|--------------|\n| NCI Command | `READ_CORE_MEMORY` / `WRITE_CORE_MEMORY` | `READ_CORE_RAM` / `WRITE_CORE_RAM` |\n| Address Space | System memory map | CHEEVOS (achievements) |\n| Write Acknowledgment | Returns byte count | No acknowledgment (fire-and-forget) |\n| Core Support | Requires memory map | Broader (achievements-compatible cores) |\n| Max Bytes/Call | 4096 | 4096 |\n\n## Status & Configuration Tools\n\n### retroarch_get_status\n\nQueries the current emulator state including run-state, loaded ROM, and CRC32.\n\n**Input:** No parameters\n\n**Returns:**\n- `State: playing|paused`\n- `System: SYSTEM_ID`\n- `Game: BASENAME`\n- `CRC32: HEX or (none reported)`\n\nReturns `'No content loaded'` when RetroArch is at the menu with no ROM. 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### retroarch_get_config\n\nReads a single RetroArch configuration parameter by name.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `name` | string | Yes | Configuration parameter name |\n\n**Notes:**\n- Uses `GET_CONFIG_PARAM` command\n- RetroArch whitelists exposed parameters; non-whitelisted names error\n- `screenshot_directory` is NOT exposed via this API 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Memory Access Tools\n\n### retroarch_read_memory\n\nReads bytes from the system memory map via `READ_CORE_MEMORY`.\n\n**Parameters:**\n\n| Parameter | Type | Required | Constraints | Description |\n|-----------|------|----------|-------------|-------------|\n| `address` | integer | Yes | ≥ 0 | Starting address in system memory map |\n| `length` | integer | Yes | 1-4096 | Number of bytes to read |\n\n**Returns:** `ADDR_HEX [N bytes]:` followed by space-separated uppercase hex bytes\n\n**Notes:**\n- Returns fewer bytes if read crosses a memory-region boundary\n- Works whether emulation is paused or running\n- Throws error if core doesn't expose a memory map 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### retroarch_write_memory\n\nWrites bytes to the system memory map via `WRITE_CORE_MEMORY`.\n\n**Parameters:**\n\n| Parameter | Type | Required | Constraints | Description |\n|-----------|------|----------|-------------|-------------|\n| `address` | integer | Yes | ≥ 0 | Starting address in system memory map |\n| `bytes` | array | Yes | 1-4096 elements, each 0-255 | Byte values to write |\n\n**Returns:** `Wrote N bytes → ADDR_HEX`\n\n**Notes:**\n- **DESTRUCTIVE** - overwrites existing data with no undo\n- Disables RetroArch's hardcore mode for the session\n- Returns byte count (the only NCI write command that acknowledges) 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### retroarch_read_ram\n\nReads bytes from the CHEEVOS address space via `READ_CORE_RAM`.\n\n**Parameters:**\n\n| Parameter | Type | Required | Constraints | Description |\n|-----------|------|----------|-------------|-------------|\n| `address` | integer | Yes | ≥ 0 | Starting address in CHEEVOS space |\n| `length` | integer | Yes | 1-4096 | Number of bytes to read |\n\n**Returns:** `ADDR_HEX [N bytes, CHEEVOS]:` followed by space-separated uppercase hex bytes\n\n**Notes:**\n- Fallback when `_memory` returns `'no memory map defined'`\n- CHEEVOS addresses follow RetroAchievements conventions (e.g., SNES WRAM starts at `0x000000`, not `0x7E0000`) 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### retroarch_write_ram\n\nWrites bytes to the CHEEVOS address space via `WRITE_CORE_RAM`.\n\n**Parameters:**\n\n| Parameter | Type | Required | Constraints | Description |\n|-----------|------|----------|-------------|-------------|\n| `address` | integer | Yes | ≥ 0 | Starting address in CHEEVOS space |\n| `bytes` | array | Yes | 1-4096 elements, each 0-255 | Byte values to write |\n\n**Returns:** `Wrote N bytes → ADDR_HEX (CHEEVOS, no ack)`\n\n**Notes:**\n- **DESTRUCTIVE** and **fire-and-forget** - no verification\n- Disables RetroArch's hardcore mode\n- RetroArch does not acknowledge this command\n- Verify writes with `retroarch_read_ram` after writing 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Savestate Management\n\nThe NCI protocol has limitations for savestate operations:\n\n1. **No direct \"save to slot N\"** - only save to the currently-selected slot\n2. **No query for current slot** - client must track the slot pointer\n3. **Load** supports both current slot and explicit slot numbers 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### retroarch_save_state_current\n\nSaves the current game state to the currently-selected slot.\n\n**Input:** No parameters\n\n**Returns:** `Saved to current slot`\n\n### retroarch_load_state_current\n\nLoads game state from the currently-selected slot.\n\n**Input:** No parameters\n\n**Returns:** `Loaded from current slot`\n\n### retroarch_load_state_slot\n\nLoads game state from an explicit slot number.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `slot` | integer | Yes | Savestate slot number (0-9 typically) |\n\n**Returns:** `Loaded from slot N`\n\n### retroarch_state_slot_plus / retroarch_state_slot_minus\n\nMoves the current slot pointer up or down. Used to navigate to a target slot before saving.\n\n**Input:** No parameters\n\n**Returns:** Slot navigation confirmation\n\n**Workflow for saving to a specific slot:**\n\n```mermaid\ngraph TD\n    A[Start] --> B{Current slot = target?}\n    B -->|Yes| E[retroarch_save_state_current]\n    B -->|No| C{Increment or decrement?}\n    C -->|Plus| D[retroarch_state_slot_plus]\n    C -->|Minus| F[retroarch_state_slot_minus]\n    D --> B\n    F --> B\n    E --> G[Done]\n```\n\n## Emulator Control Tools\n\n### retroarch_pause_toggle\n\nToggles RetroArch's pause state.\n\n**Input:** No parameters\n\n**Returns:** `Pause toggled`\n\n**Notes:**\n- NCI exposes only a toggle, not separate pause/unpause\n- Call `retroarch_get_status` first to check current state if needed 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### retroarch_frame_advance\n\nAdvances emulation by exactly one frame.\n\n**Input:** No parameters\n\n**Returns:** `Advanced one frame`\n\n### retroarch_reset\n\nHard-resets the running game.\n\n**Input:** No parameters\n\n**Returns:** `Game reset`\n\n## Media & UI Tools\n\n### retroarch_screenshot\n\nCaptures a screenshot and saves it to RetroArch's configured screenshot directory.\n\n**Input:** No parameters\n\n**Returns:** `Screenshot saved to RetroArch's configured screenshot directory`\n\n**Notes:**\n- The NCI doesn't expose `screenshot_directory` via `GET_CONFIG_PARAM`\n- Check the configured path via RetroArch GUI: Settings → Directory → Screenshot 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### retroarch_show_message\n\nDisplays a notification on the RetroArch window.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `message` | string | Yes | Message text to display |\n\n**Returns:** `Showed: {message}`\n\n## Transport Semantics\n\nAll tools communicate with RetroArch via UDP datagrams. This has important implications:\n\n### Fire-and-Forget Commands\n\nMost NCI commands (write_ram, pause_toggle, frame_advance, reset, save_state, etc.) do **not** receive acknowledgment from RetroArch. The success message returned by the tool confirms only that the UDP packet was sent, not that RetroArch received or acted on it. 资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### Query Commands with Acknowledgment\n\nThe `retroarch_write_memory` command is the **only** write command that returns a byte count from RetroArch, providing limited verification of the write operation.\n\n### Timeout Handling\n\nUDP queries timeout after a configurable interval (default: 5000ms). Common timeout causes:\n\n1. Network Commands not enabled in RetroArch\n2. Port mismatch between `RETROARCH_PORT` and RetroArch's `network_cmd_port`\n3. UDP datagrams dropped under load (even on loopback) 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\nThe bridge does **not** auto-retry on timeout; retry the call if needed. 资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Configuration\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in `retroarch.cfg`) |\n\n## Error Handling\n\n| Error Message | Cause / Fix |\n|---------------|-------------|\n| `RetroArch query timed out` | Network Commands not enabled; port mismatch; UDP dropped |\n| `READ_CORE_MEMORY failed: no memory map defined` | Core doesn't advertise memory map; use `read_ram` instead |\n| `READ_CORE_MEMORY failed: no descriptor for address` | Address outside core's memory regions |\n| Screenshots don't appear | Check RetroArch's screenshot directory setting via GUI |\n| Can't save to specific slot directly | NCI limitation; walk slot pointer with `state_slot_plus/minus` first |\n\n## Tool Summary Table\n\n| Tool | Input Parameters | Returns | Side Effects |\n|------|------------------|---------|--------------|\n| `retroarch_get_status` | — | Emulator state info | None |\n| `retroarch_get_config` | `name` | Config value | None |\n| `retroarch_read_memory` | `address`, `length` | Hex dump | None |\n| `retroarch_write_memory` | `address`, `bytes` | Byte count | Disables hardcore mode |\n| `retroarch_read_ram` | `address`, `length` | Hex dump (CHEEVOS) | None |\n| `retroarch_write_ram` | `address`, `bytes` | Confirmation | Disables hardcore mode |\n| `retroarch_pause_toggle` | — | Pause toggled | Changes run-state |\n| `retroarch_frame_advance` | — | Frame advanced | Advances emulation |\n| `retroarch_reset` | — | Game reset | Hard-resets game |\n| `retroarch_screenshot` | — | Screenshot path | Creates file |\n| `retroarch_show_message` | `message` | Message displayed | Shows notification |\n| `retroarch_save_state_current` | — | Save confirmed | Overwrites current slot |\n| `retroarch_load_state_current` | — | Load confirmed | Loads current slot |\n| `retroarch_load_state_slot` | `slot` | Load confirmed | Loads specified slot |\n| `retroarch_state_slot_plus` | — | Slot moved | Increments slot pointer |\n| `retroarch_state_slot_minus` | — | Slot moved | Decrements slot pointer |\n\n---\n\n<a id='page-core-compatibility'></a>\n\n## Core Compatibility\n\n### 相关页面\n\n相关主题：[Memory Read/Write Operations](#page-memory-operations)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Core Compatibility\n\n## Overview\n\nCore Compatibility refers to the ability of mcp-retroarch to interact with different libretro cores running inside RetroArch. Since each emulator core implements the libretro API differently—and exposes different memory maps and features—mcp-retroarch provides multiple memory access pathways and behavioral workarounds to maximize cross-core support.\n\nThe MCP server communicates with RetroArch via the Network Control Interface (NCI), a UDP-based command protocol. The level of functionality available depends on:\n\n1. Whether the loaded core exposes a system memory map via libretro\n2. Whether the core responds to the CHEEVOS (RetroAchievements) read API\n3. Which specific NCI commands the core supports\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Memory Access Architecture\n\nmcp-retroarch provides two distinct memory reading pathways, each targeting a different address space:\n\n### Memory Access Methods Comparison\n\n| Aspect | `retroarch_read_memory` | `retroarch_read_ram` |\n|--------|------------------------|---------------------|\n| **NCI Command** | `READ_CORE_MEMORY` | `READ_CORE_RAM` |\n| **Address Space** | Libretro system memory map | CHEEVOS achievement address space |\n| **Core Requirement** | Core must expose memory map descriptors | Works if core exposes CHEEVOS |\n| **Fallback** | Auto-fall back to `read_ram` on \"no memory map\" | No further fallback |\n| **Use Case** | Primary tool for memory inspection | Fallback / older cores |\n\n资料来源：[src/tools.ts:1-200](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### Address Space Differences\n\nThe two memory paths use fundamentally different addressing schemes:\n\n```mermaid\ngraph TB\n    subgraph \"Libretro Memory Map read_memory\"\n        A[\"SNES WRAM: 0x7E0000-0x7FFFFF\"] \n        B[\"GBA EWRAM: 0x02000000-0x0203FFFF\"]\n        C[\"Genesis 68K RAM: 0xFF0000-0xFFFFFF\"]\n    end\n    \n    subgraph \"CHEEVOS Address Space read_ram\"\n        D[\"SNES WRAM: 0x000000\"]\n        E[\"GBA WRAM: 0x02000000\"]\n        F[\"NES WRAM: 0x0000\"]\n    end\n```\n\nFor example, SNES WRAM appears at:\n- **System memory map**: `0x7E0000`\n- **CHEEVOS space**: `0x000000`\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Tested Cores Matrix\n\nThe following cores have been verified end-to-end with mcp-retroarch:\n\n| System | Core | `read_memory` | `read_ram` | Notes |\n|--------|------|---------------|------------|-------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA interrupt vector table visible at `0x0000` (`d3 00 00 ea ...`) |\n| NES | `mesen_libretro` | ✅ (only NES core tested that does) | ✅ | Full 16-bit NES address space exposed. WRAM at `0x0000-0x07FF`, mirrored to `0x1FFF`. CHEEVOS bounded to first 64 KB. |\n| NES | `nestopia_libretro` | ❌ (no memory map) | ✅ | CHEEVOS only. 64 KB bound. **For NES + memory map, prefer Mesen.** |\n| SNES | `snes9x_libretro` | ❌ | — | Status not fully documented in current release |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Feature Support by Core\n\n### Memory Read/Write\n\n| Capability | Supported | Details |\n|------------|-----------|---------|\n| System memory map | Core-dependent | Only cores that expose descriptors via `READ_CORE_MEMORY` |\n| CHEEVOS RAM read | Most cores | Achievement API is widely supported |\n| Memory write | Same pathways as reads | `WRITE_CORE_MEMORY` or `WRITE_CORE_RAM` |\n\n**Important limitation**: Memory writes via NCI automatically disable RetroArch's hardcore mode for the rest of the session.\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### Savestate Operations\n\nSavestate functionality is supported universally across cores since it uses RetroArch's internal state management:\n\n| Operation | Support | Notes |\n|-----------|---------|-------|\n| Save to current slot | ✅ | Uses `SAVE_STATE_CURRENT` |\n| Load from current slot | ✅ | Uses `LOAD_STATE_CURRENT` |\n| Load from explicit slot | ✅ | Uses `LOAD_STATE` with slot number |\n| Save to explicit slot | ❌ | NCI limitation—must walk slot pointer |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Game-Pad Input\n\n**Not supported** via mcp-retroarch. The NCI protocol does not expose game-pad input. RetroArch has a separate \"Remote RetroPad\" mechanism on UDP port 55400, but it requires loading a specific core and cannot drive an existing emulation session.\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Choosing the Right Memory Tool\n\n```mermaid\ngraph TD\n    A[\"Need to read/write memory?\"] --> B{\"Does read_memory return<br/>'no memory map defined'?\"}\n    B -->|Yes| C[\"Use retroarch_read_ram\"]\n    B -->|No| D[\"Use retroarch_read_memory\"]\n    C --> E[\"Address in CHEEVOS space\"]\n    D --> F[\"Address in libretro memory map\"]\n    \n    style B fill:#ffcccc\n    style C fill:#ccffcc\n    style D fill:#ccffcc\n```\n\n### Decision Criteria\n\n1. **Start with `retroarch_read_memory`** — It provides access to the native system memory map and is the preferred pathway.\n\n2. **Fall back to `retroarch_read_ram`** when:\n   - The core returns \"no memory map defined\"\n   - You need CHEEVOS achievement-style addresses\n   - Working with cores like `nestopia_libretro` that don't expose system memory maps\n\n3. **Write operations follow the same path** as your read operations.\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## Core-Specific Behaviors\n\n### NES Cores Comparison\n\n| Feature | Mesen | Nestopia |\n|---------|-------|----------|\n| System memory map | ✅ Exposed | ❌ Not exposed |\n| CHEEVOS RAM | ✅ 64 KB bound | ✅ 64 KB bound |\n| Full address space | ✅ 0x0000-0xFFFF | Limited to first 64 KB |\n| **Recommendation** | **Preferred for memory work** | Use for achievements only |\n\n### GBA with mgba_libretro\n\nThe `mgba_libretro` core provides full memory map access:\n- Interrupt vector table at `0x0000` is readable via `read_memory`\n- Example data visible: `d3 00 00 ea ...`\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## UDP Communication Model\n\nmcp-retroarch uses a serial query model with timeout handling:\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP Client\n    participant Bridge as mcp-retroarch\n    participant RA as RetroArch NCI\n    \n    MCP->>Bridge: Tool call (e.g., retroarch_read_memory)\n    Bridge->>Bridge: Check if socket connected\n    Bridge->>RA: UDP query (e.g., READ_CORE_MEMORY ...)\n    Note over Bridge: Set timeout timer\n    RA-->>Bridge: UDP response\n    Bridge->>Bridge: Clear timeout, resolve promise\n    Bridge-->>MCP: JSON-RPC response\n    \n    Note over Bridge,RA: Timeout → Error \"RetroArch query timed out\"\n```\n\nKey behaviors:\n- Only one query can be in flight at a time\n- Default timeout: configurable, typically 5000ms\n- UDP is unreliable—retries may be needed under load\n\n资料来源：[src/retroarch.ts:1-100](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n## Troubleshooting Core Compatibility\n\n| Symptom | Cause | Solution |\n|---------|-------|----------|\n| `READ_CORE_MEMORY failed: no memory map defined` | Core doesn't expose system memory map | Use `retroarch_read_ram` instead |\n| `READ_CORE_MEMORY failed: no descriptor for address` | Address outside core's memory regions | Use a different core or check valid address range |\n| `RetroArch query timed out` | Network Commands not enabled or port mismatch | Enable in RetroArch GUI or set `network_cmd_enable = \"true\"` |\n| Inconsistent responses | UDP datagram drops under load | Retry the query—mcp-retroarch doesn't auto-retry |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Configuration for Core Support\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host |\n| `RETROARCH_PORT` | `55355` | UDP port (must match `network_cmd_port` in RetroArch config) |\n\nRetroArch must have Network Commands enabled:\n- **GUI**: Settings → Network → Network Commands → ON\n- **Config file**: `network_cmd_enable = \"true\"`\n\n资料来源：[README.md](https://github://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Architecture Summary\n\n```\n+----------------+    stdio     +-----------------+   UDP :55355  +-----------------+\n|   MCP client   |   JSON-RPC   |  mcp-retroarch  |   commands   |   RetroArch     |\n|                |◄────────────►|                 |◄────────────►|   (any core)    |\n+----------------+              +-----------------+              +-----------------+\n```\n\nThe bridge translates MCP tool calls into NCI UDP commands. Core compatibility depends entirely on what the underlying libretro core exposes via the NCI protocol.\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## Related Tools for Other Platforms\n\n| Platform | Tool | Features |\n|----------|------|----------|\n| Game Boy Advance | [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | Memory + button input + screenshot via mGBA Lua bridge |\n| PCSX2, etc. | [mcp-pine](https://github.com/dmang-dev/mcp-pine) | Memory + savestate only via PINE protocol |\n\nThese alternatives may provide better compatibility for their respective platforms when NCI-based cores lack features.\n\n---\n\n<a id='page-configuration'></a>\n\n## Configuration\n\n### 相关页面\n\n相关主题：[Quick Start Guide](#page-quick-start)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n- [src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n- [src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# Configuration\n\nThe Configuration system in mcp-retroarch encompasses two distinct layers: the MCP server's runtime settings (controlled via environment variables) and RetroArch's Network Control Interface (NCI) parameters (queried at runtime). Together, they establish the communication bridge between an MCP client and a running RetroArch instance.\n\n## Overview\n\nmcp-retroarch acts as a bridge server that translates MCP tool calls into UDP datagrams sent to RetroArch's Network Command Interface. Configuration determines:\n\n1. **Network transport** — where to send UDP commands (host and port)\n2. **RetroArch NCI readiness** — ensuring RetroArch has Network Commands enabled\n3. **Runtime parameter discovery** — querying RetroArch's internal configuration state\n\n资料来源：[README.md:30-35]()\n\n```mermaid\ngraph TD\n    A[MCP Client] -->|JSON-RPC over stdio| B[mcp-retroarch Server]\n    B -->|UDP datagrams| C{RetroArch Network Commands}\n    C -->|Enabled?| D[Commands processed]\n    C -->|Disabled| E[Timeout / Error]\n    \n    F[Environment Variables] --> B\n    G[retroarch.cfg] --> C\n```\n\n## Environment Variables\n\nThe MCP server reads the following environment variables at startup to configure its UDP transport layer.\n\n| Environment Variable | Default | Purpose |\n|---------------------|---------|---------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP destination host — the machine running RetroArch |\n| `RETROARCH_PORT` | `55355` | UDP port — must match `network_cmd_port` in RetroArch's config |\n\n资料来源：[README.md:52-54]()\n\n### Configuration Precedence\n\nEnvironment variables are read directly without any configuration file parsing. If not set, the defaults apply. The server does not support configuration via `~/.retroarch.cfg` or similar — only environment variables control mcp-retroarch itself.\n\n### Non-blocking Startup\n\nThe MCP server starts immediately without blocking on RetroArch connectivity. A background probe attempts to connect and log the RetroArch version, but tool calls connect on demand if RetroArch is unreachable at startup.\n\n资料来源：[src/index.ts:20-27]()\n\n```typescript\n// Background connectivity probe — fire-and-forget, never blocks the server.\nra.connect()\n  .then(() => ra.getVersion())\n  .then((v) => process.stderr.write(`[mcp-retroarch] connected to ${ra.describeTarget()} — RetroArch ${v}\\n`))\n  .catch((err) => process.stderr.write(\n    `[mcp-retroarch] note: RetroArch not reachable yet (${ra.describeTarget()}): ${err}\\n` +\n    `             Enable Network Commands in retroarch.cfg (network_cmd_enable / network_cmd_port)\\n` +\n    `             or Settings > Network > Network Commands. Tool calls will connect on demand.\\n`,\n  ));\n```\n\n资料来源：[src/index.ts:20-27]()\n\n## RetroArch Network Commands Setup\n\nFor mcp-retroarch to communicate with RetroArch, Network Commands must be enabled in RetroArch itself. This is a one-time setup per RetroArch installation.\n\n### Method 1: GUI Configuration\n\n1. Navigate to **Settings → Network → Network Commands**\n2. Set **Network Commands** to **ON**\n3. Confirm **Network Cmd Port** is `55355` (the default)\n\n资料来源：[README.md:25-28]()\n\n### Method 2: Configuration File\n\nAdd or edit the following in `retroarch.cfg`:\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n资料来源：[README.md:30-35]()\n\n### Port Matching Requirement\n\nThe port configured in RetroArch (`network_cmd_port`) **must match** the `RETROARCH_PORT` environment variable used by mcp-retroarch. Mismatches result in `RetroArch query timed out` errors.\n\n资料来源：[README.md:52-54]()\n\n```mermaid\ngraph LR\n    A[mcp-retroarch<br/>RETROARCH_PORT] -->|55355| B{Port Match?}\n    C[RetroArch<br/>network_cmd_port] -->|55355| B\n    B -->|Yes| D[Communication OK]\n    B -->|No| E[Timeout Error]\n```\n\n## Reading RetroArch Configuration\n\nThe `retroarch_get_config` tool queries RetroArch's internal configuration state via the NCI `GET_CONFIG_PARAM` command. This reads **runtime values** from RetroArch, not the static config file.\n\n资料来源：[src/tools.ts:80-96]()\n\n### Available Configuration Parameters\n\nRetroArch's NCI exposes a **whitelist** of configuration keys. The following parameters are confirmed available:\n\n| Category | Parameter | Returns | Notes |\n|----------|-----------|---------|-------|\n| Directories | `savefile_directory` | Absolute path | User's save file directory |\n| Directories | `savestate_directory` | Absolute path | Savestate directory |\n| Directories | `system_directory` | Absolute path | System/BIOS directory |\n| Directories | `cache_directory` | Absolute path | Cache location |\n| Directories | `log_dir` | Absolute path | Log file directory |\n| Directories | `runtime_log_directory` | Absolute path | Runtime log directory |\n| Directories | `core_assets_directory` | Absolute path | Downloaded core assets |\n| User Data | `netplay_nickname` | String | Netplay display name |\n| Video | `video_fullscreen` | `true` / `false` | Fullscreen toggle |\n| Video | `video_vsync` | `true` / `false` | Vertical sync toggle |\n| Audio | `audio_mute_enable` | `true` / `false` | Audio mute toggle |\n\n资料来源：[src/tools.ts:80-96]()\n\n### Notable Exclusions\n\nThe `screenshot_directory` parameter is **intentionally NOT exposed** by RetroArch's NCI whitelist. Screenshots are saved to RetroArch's configured screenshot directory, but this cannot be queried programmatically. Check the value manually via **Settings → Directory → Screenshot**.\n\n资料来源：[src/tools.ts:80-96]()\n\n### Current Savestate Slot\n\nThere is **no NCI key** for querying the currently-selected savestate slot. Track the slot number client-side by using `retroarch_state_slot_plus` and `retroarch_state_slot_minus`, or start from slot 1 (NCI default).\n\n资料来源：[src/tools.ts:80-96]()\n\n### Tool Definition\n\n```json\n{\n  \"name\": \"retroarch_get_config\",\n  \"description\": \"PURPOSE: Read a single RetroArch configuration parameter by name via the NCI GET_CONFIG_PARAM command.\",\n  \"inputSchema\": {\n    \"type\": \"object\",\n    \"required\": [\"name\"],\n    \"properties\": {\n      \"name\": {\n        \"type\": \"string\",\n        \"minLength\": 1,\n        \"description\": \"Config key — same snake_case ASCII identifier RetroArch uses in retroarch.cfg\"\n      }\n    }\n  }\n}\n```\n\n资料来源：[src/tools.ts:80-96]()\n\n### Return Format\n\n```\nNAME = VALUE\n```\n\nWhere `VALUE` is the raw string as stored in `retroarch.cfg`:\n- Paths are **unquoted**\n- Booleans are `'true'` / `'false'`\n- Integers are **decimal**\n\n资料来源：[src/tools.ts:80-96]()\n\n### Error Conditions\n\nThe tool returns an error if:\n1. The parameter name is not in RetroArch's NCI whitelist\n2. The value contains characters that break the line-based reply parser (rare — embedded newlines or null bytes)\n3. The UDP query times out (RetroArch not reachable)\n\n资料来源：[src/tools.ts:80-96]()\n\n## UDP Transport Layer\n\nThe communication between mcp-retroarch and RetroArch uses UDP datagrams on a serial-by-default basis.\n\n### Connection Behavior\n\n```typescript\nasync connect(): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const sock = dgram.createSocket(\"udp4\");\n    sock.once(\"error\", (err) => reject(err));\n    sock.bind(0, () => {\n      sock.on(\"message\", (msg) => {\n        const cb = this.pending;\n        if (!cb) return;       // unsolicited or late reply — drop\n        this.pending = null;\n        cb(msg);\n      });\n      sock.on(\"error\", () => { /* swallow late errors */ });\n      this.socket = sock;\n      resolve();\n    });\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:10-27]()\n\n### Serial Query Model\n\nThe NCI protocol carries no request IDs, so matching responses by command-name echo is fragile. mcp-retroarch uses a **serial-by-default** approach: only one query can be in flight at a time.\n\n```typescript\nasync query(command: string): Promise<Buffer> {\n  if (!this.socket) await this.connect();\n  if (this.pending) {\n    throw new Error(\"retroarch query already in flight (client is serial)\");\n  }\n  // ... send and wait for response\n}\n```\n\n资料来源：[src/retroarch.ts:50-58]()\n\n### Fire-and-Forget Commands\n\nHotkey-style commands (pause toggle, frame advance, etc.) use fire-and-forget semantics since the NCI doesn't acknowledge them:\n\n```typescript\nasync send(command: string): Promise<void> {\n  if (!this.socket) await this.connect();\n  return new Promise((resolve, reject) => {\n    this.socket!.send(command, this.port, this.host, (err) =>\n      err ? reject(err) : resolve(),\n    );\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:35-43]()\n\n## MCP Client Registration\n\nAfter configuring mcp-retroarch, register it with your MCP client.\n\n### Claude Code\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\nVerify registration:\n\n```bash\nclaude mcp list\n# retroarch: mcp-retroarch - ✓ Connected\n```\n\n资料来源：[README.md:38-43]()\n\n### Claude Desktop\n\nEdit `claude_desktop_config.json`:\n\n| Platform | Path |\n|----------|------|\n| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |\n| Windows | `%APPDATA%\\Claude\\claude_desktop_config.json` |\n| Linux | `~/.config/Claude/claude_desktop_config.json` |\n\n```json\n{\n  \"mcpServers\": {\n    \"retroarch\": {\n      \"command\": \"mcp-retroarch\"\n    }\n  }\n}\n```\n\n资料来源：[README.md:45-57]()\n\nAfter editing, **restart Claude Desktop** for changes to take effect.\n\n## Troubleshooting\n\n| Symptom | Cause / Fix |\n|---------|-------------|\n| `RetroArch query timed out` | Network Commands aren't enabled in RetroArch, or the port doesn't match `RETROARCH_PORT`. Confirm `network_cmd_enable = \"true\"` in `retroarch.cfg`. UDP datagrams can be dropped under load even on loopback — if a single call times out but a retry succeeds, that's the cause. |\n| `READ_CORE_MEMORY failed: no memory map defined` | The loaded libretro core doesn't advertise a system memory map. Try `retroarch_read_ram` (CHEEVOS path). |\n| `READ_CORE_MEMORY failed: no descriptor for address` | The address isn't covered by the core's memory map. Either a different core would expose it, or the address is outside the system bus. |\n| Screenshots don't appear where I expect | RetroArch saves to its configured screenshot directory. This cannot be queried via NCI — check via **Settings → Directory → Screenshot**. |\n\n资料来源：[README.md:85-98]()\n\n## Development Configuration\n\nFor local development:\n\n```bash\nnpm install\nnpm run dev      # tsc --watch\n```\n\n资料来源：[README.md:75-79]()\n\nSmoke test against a running RetroArch:\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n资料来源：[README.md:80-82]()\n\n## Configuration Summary\n\n| Layer | Setting | Default | Source |\n|-------|---------|---------|--------|\n| MCP Server | `RETROARCH_HOST` | `127.0.0.1` | Environment variable |\n| MCP Server | `RETROARCH_PORT` | `55355` | Environment variable |\n| RetroArch | `network_cmd_enable` | `\"true\"` | `retroarch.cfg` or GUI |\n| RetroArch | `network_cmd_port` | `55355` | `retroarch.cfg` or GUI |\n\n资料来源：[README.md:30-35, 52-54]()\n\n## Version History\n\n| Version | Date | Configuration Changes |\n|---------|------|----------------------|\n| 0.1.2 | 2026-05-15 | Tool description quality pass — improved configuration parameter documentation |\n| 0.1.1 | 2026-05-11 | Non-blocking startup — server no longer waits for RetroArch connectivity |\n| 0.1.0 | 2026-05-10 | Initial release with UDP client and MCP server |\n\n资料来源：[CHANGELOG.md:1-30]()\n\n---\n\n---\n\n## Doramagic Pitfall Log\n\nProject: dmang-dev/mcp-retroarch\n\nSummary: Found 7 potential pitfall items; 0 are high/blocking. Highest priority: configuration - 可能修改宿主 AI 配置.\n\n## 1. configuration · 可能修改宿主 AI 配置\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: 项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。\n- User impact: 安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。\n- Suggested check: 列出会写入的配置文件、目录和卸载/回滚步骤。\n- Guardrail action: 涉及宿主配置目录时必须给回滚路径，不能只给安装命令。\n- Evidence: capability.host_targets | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | host_targets=mcp_host, claude\n\n## 2. capability · 能力判断依赖假设\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: README/documentation is current enough for a first validation pass.\n- User impact: 假设不成立时，用户拿不到承诺的能力。\n- Suggested check: 将假设转成下游验证清单。\n- Guardrail action: 假设必须转成验证项；没有验证结果前不能写成事实。\n- Evidence: capability.assumptions | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | README/documentation is current enough for a first validation pass.\n\n## 3. maintenance · 维护活跃度未知\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: 未记录 last_activity_observed。\n- User impact: 新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- Suggested check: 补 GitHub 最近 commit、release、issue/PR 响应信号。\n- Guardrail action: 维护活跃度未知时，推荐强度不能标为高信任。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | last_activity_observed missing\n\n## 4. security_permissions · 下游验证发现风险项\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: 下游已经要求复核，不能在页面中弱化。\n- Suggested check: 进入安全/权限治理复核队列。\n- Guardrail action: 下游风险存在时必须保持 review/recommendation 降级。\n- Evidence: downstream_validation.risk_items | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 5. security_permissions · 存在评分风险\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: 风险会影响是否适合普通用户安装。\n- Suggested check: 把风险写入边界卡，并确认是否需要人工复核。\n- Guardrail action: 评分风险必须进入边界卡，不能只作为内部分数。\n- Evidence: risks.scoring_risks | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 6. maintenance · issue/PR 响应质量未知\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: issue_or_pr_quality=unknown。\n- User impact: 用户无法判断遇到问题后是否有人维护。\n- Suggested check: 抽样最近 issue/PR，判断是否长期无人处理。\n- Guardrail action: issue/PR 响应未知时，必须提示维护风险。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | issue_or_pr_quality=unknown\n\n## 7. maintenance · 发布节奏不明确\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: release_recency=unknown。\n- User impact: 安装命令和文档可能落后于代码，用户踩坑概率升高。\n- Suggested check: 确认最近 release/tag 和 README 安装命令是否一致。\n- Guardrail action: 发布节奏未知或过期时，安装说明必须标注可能漂移。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | release_recency=unknown\n\n<!-- canonical_name: dmang-dev/mcp-retroarch; human_manual_source: deepwiki_human_wiki -->\n",
      "summary": "DeepWiki/Human Wiki output with a Doramagic pitfall appendix.",
      "title": "Human Manual"
    },
    "pitfall_log": {
      "asset_id": "pitfall_log",
      "filename": "PITFALL_LOG.md",
      "markdown": "# Pitfall Log\n\nProject: dmang-dev/mcp-retroarch\n\nSummary: Found 7 potential pitfall items; 0 are high/blocking. Highest priority: configuration - 可能修改宿主 AI 配置.\n\n## 1. configuration · 可能修改宿主 AI 配置\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: 项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。\n- User impact: 安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。\n- Suggested check: 列出会写入的配置文件、目录和卸载/回滚步骤。\n- Guardrail action: 涉及宿主配置目录时必须给回滚路径，不能只给安装命令。\n- Evidence: capability.host_targets | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | host_targets=mcp_host, claude\n\n## 2. capability · 能力判断依赖假设\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: README/documentation is current enough for a first validation pass.\n- User impact: 假设不成立时，用户拿不到承诺的能力。\n- Suggested check: 将假设转成下游验证清单。\n- Guardrail action: 假设必须转成验证项；没有验证结果前不能写成事实。\n- Evidence: capability.assumptions | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | README/documentation is current enough for a first validation pass.\n\n## 3. maintenance · 维护活跃度未知\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: 未记录 last_activity_observed。\n- User impact: 新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- Suggested check: 补 GitHub 最近 commit、release、issue/PR 响应信号。\n- Guardrail action: 维护活跃度未知时，推荐强度不能标为高信任。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | last_activity_observed missing\n\n## 4. security_permissions · 下游验证发现风险项\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: 下游已经要求复核，不能在页面中弱化。\n- Suggested check: 进入安全/权限治理复核队列。\n- Guardrail action: 下游风险存在时必须保持 review/recommendation 降级。\n- Evidence: downstream_validation.risk_items | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 5. security_permissions · 存在评分风险\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: 风险会影响是否适合普通用户安装。\n- Suggested check: 把风险写入边界卡，并确认是否需要人工复核。\n- Guardrail action: 评分风险必须进入边界卡，不能只作为内部分数。\n- Evidence: risks.scoring_risks | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 6. maintenance · issue/PR 响应质量未知\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: issue_or_pr_quality=unknown。\n- User impact: 用户无法判断遇到问题后是否有人维护。\n- Suggested check: 抽样最近 issue/PR，判断是否长期无人处理。\n- Guardrail action: issue/PR 响应未知时，必须提示维护风险。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | issue_or_pr_quality=unknown\n\n## 7. maintenance · 发布节奏不明确\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: release_recency=unknown。\n- User impact: 安装命令和文档可能落后于代码，用户踩坑概率升高。\n- Suggested check: 确认最近 release/tag 和 README 安装命令是否一致。\n- Guardrail action: 发布节奏未知或过期时，安装说明必须标注可能漂移。\n- Evidence: evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | release_recency=unknown\n",
      "summary": "Identity, installation, configuration, runtime, and safety pitfalls before user trial.",
      "title": "Pitfall Log"
    },
    "prompt_preview": {
      "asset_id": "prompt_preview",
      "filename": "PROMPT_PREVIEW.md",
      "markdown": "# mcp-retroarch - Prompt Preview\n\n> Copy the prompt below into your AI host before installing anything.\n> Its purpose is to let you safely feel the project's workflow, not to claim the project has already run.\n\n## Copy this prompt\n\n```text\nYou are using an independent Doramagic capability pack for dmang-dev/mcp-retroarch.\n\nProject:\n- Name: mcp-retroarch\n- Repository: https://github.com/dmang-dev/mcp-retroarch\n- Summary: MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface\n- Host target: mcp_host, claude\n\nGoal:\nHelp me evaluate this project for the following task without installing it yet: MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface\n\nBefore taking action:\n1. Restate my task, success standard, and boundary.\n2. Identify whether the next step requires tools, browser access, network access, filesystem access, credentials, package installation, or host configuration.\n3. Use only the Doramagic Project Pack, the upstream repository, and the source-linked evidence listed below.\n4. If a real command, install step, API call, file write, or host integration is required, mark it as \"requires post-install verification\" and ask for approval first.\n5. If evidence is missing, say \"evidence is missing\" instead of filling the gap.\n\nPreviewable capabilities:\n- Capability 1: MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface\n\nCapabilities that require post-install verification:\n- Capability 1: Use the source-backed project context to guide one small, checkable workflow step.\n\nCore service flow:\n1. page-introduction: Introduction. Produce one small intermediate artifact and wait for confirmation.\n2. page-quick-start: Quick Start Guide. Produce one small intermediate artifact and wait for confirmation.\n3. page-architecture: System Architecture. Produce one small intermediate artifact and wait for confirmation.\n4. page-memory-operations: Memory Read/Write Operations. Produce one small intermediate artifact and wait for confirmation.\n5. page-savestate-management: Savestate Management. Produce one small intermediate artifact and wait for confirmation.\n\nSource-backed evidence to keep in mind:\n- https://github.com/dmang-dev/mcp-retroarch\n- https://github.com/dmang-dev/mcp-retroarch#readme\n- README.md\n- package.json\n- src/index.ts\n- src/retroarch.ts\n- src/tools.ts\n\nFirst response rules:\n1. Start Step 1 only.\n2. Explain the one service action you will perform first.\n3. Ask exactly three questions about my target workflow, success standard, and sandbox boundary.\n4. Stop and wait for my answers.\n\nStep 1 follow-up protocol:\n- After I answer the first three questions, stay in Step 1.\n- Produce six parts only: clarified task, success standard, boundary conditions, two or three options, tradeoffs for each option, and one recommendation.\n- End by asking whether I confirm the recommendation.\n- Do not move to Step 2 until I explicitly confirm.\n\nConversation rules:\n- Advance one step at a time and wait for confirmation after each small artifact.\n- Write outputs as recommendations or planned checks, not as completed execution.\n- Do not claim tests passed, files changed, commands ran, APIs were called, or the project was installed.\n- If the user asks for execution, first provide the sandbox setup, expected output, rollback, and approval checkpoint.\n```\n",
      "summary": "不安装项目也能感受能力节奏的安全试用 Prompt。",
      "title": "Prompt Preview / 安装前试用 Prompt"
    },
    "quick_start": {
      "asset_id": "quick_start",
      "filename": "QUICK_START.md",
      "markdown": "# Quick Start\n\nProject: dmang-dev/mcp-retroarch\n\n## Official Entry Points\n\n### Node.js / npm · 官方安装入口\n\n```bash\nnpm install -g mcp-retroarch\n```\n\nSource：https://github.com/dmang-dev/mcp-retroarch#readme\n\n## Sources\n\n- repo: https://github.com/dmang-dev/mcp-retroarch\n- docs: https://github.com/dmang-dev/mcp-retroarch#readme\n",
      "summary": "Entry points extracted from official README or installation documentation.",
      "title": "Quick Start"
    }
  },
  "validation_id": "dval_b7fb1b1c9baf4a869e745a8f04409775"
}
