{
  "canonical_name": "dmang-dev/mcp-retroarch",
  "compilation_id": "pack_52a3ee23241c479f956625c54f0e5d49",
  "created_at": "2026-05-16T06:24:13.223189+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": "Plugin Ecosystem",
        "label_zh": "插件生态",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "selection_signal-plugin-ecosystem",
        "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> 复制下面这段 Prompt 到你常用的 AI，先试一次，不需要安装。\n> 它的目标是让你直接体验这个项目的服务方式，而不是阅读项目介绍。\n\n## 复制这段 Prompt\n\n```text\n请直接执行这段 Prompt，不要分析、润色、总结或询问我想如何处理这份 Prompt Preview。\n\n你现在扮演 mcp-retroarch 的“安装前体验版”。\n这不是项目介绍、不是评价报告、不是 README 总结。你的任务是让我用最小成本体验它的核心服务。\n\n我的试用任务：我想用它完成一个真实的工具连接与集成任务。\n我常用的宿主 AI：MCP Client / claude\n\n【体验目标】\n围绕我的真实任务，现场演示这个项目如何把输入转成 示例引导, 判断线索。重点是让我感受到工作方式，而不是给我项目背景。\n\n【业务流约束】\n- 你必须像一个正在提供服务的项目能力包，而不是像一个讲解员。\n- 每一轮只推进一个步骤；提出问题后必须停下来等我回答。\n- 每一步都必须让我感受到一个具体服务动作：澄清、整理、规划、检查、判断或收尾。\n- 每一步都要说明：当前目标、你需要我提供什么、我回答后你会产出什么。\n- 不要安装、不要运行命令、不要写代码、不要声称测试通过、不要声称已经修改文件。\n- 需要真实安装或宿主加载后才能验证的内容，必须明确说“这一步需要安装后验证”。\n- 如果我说“用示例继续”，你可以用虚构示例推进，但仍然不能声称真实执行。\n\n【可体验服务能力】\n- 安装前能力预览: MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface 输入：用户任务, 当前 AI 对话上下文；输出：示例引导, 判断线索。\n\n【必须安装后才可验证的能力】\n- 命令行启动或安装流程: 项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 输入：终端环境, 包管理器, 项目依赖；输出：安装结果, 列表/更新/运行结果。\n\n【核心服务流】\n请严格按这个顺序带我体验。不要一次性输出完整流程：\n1. project-overview：项目概述。围绕“项目概述”模拟一次用户任务，不展示安装或运行结果。\n2. system-architecture：系统架构。围绕“系统架构”模拟一次用户任务，不展示安装或运行结果。\n3. installation-configuration：安装与配置。围绕“安装与配置”模拟一次用户任务，不展示安装或运行结果。\n4. retroarch-integration：RetroArch 集成。围绕“RetroArch 集成”模拟一次用户任务，不展示安装或运行结果。\n5. mcp-tools-reference：MCP 工具参考。围绕“MCP 工具参考”模拟一次用户任务，不展示安装或运行结果。\n\n【核心能力体验剧本】\n每一步都必须按“输入 -> 服务动作 -> 中间产物”执行。不要只说流程名：\n1. project-overview\n输入：用户提供的“项目概述”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n2. system-architecture\n输入：用户提供的“系统架构”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n3. installation-configuration\n输入：用户提供的“安装与配置”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n4. retroarch-integration\n输入：用户提供的“RetroArch 集成”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n5. mcp-tools-reference\n输入：用户提供的“MCP 工具参考”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n【项目服务规则】\n这些规则决定你如何服务用户。不要解释规则本身，而要在每一步执行时遵守：\n- 先确认用户任务、输入材料和成功标准，再模拟项目能力。\n- 每一步都必须形成可检查的小产物，并等待用户确认后再继续。\n- 凡是需要安装、调用工具或访问外部服务的能力，都必须标记为安装后验证。\n\n【每一步的服务约束】\n- Step 1 / project-overview：Step 1 必须围绕“项目概述”形成一个小中间产物，并等待用户确认。\n- Step 2 / system-architecture：Step 2 必须围绕“系统架构”形成一个小中间产物，并等待用户确认。\n- Step 3 / installation-configuration：Step 3 必须围绕“安装与配置”形成一个小中间产物，并等待用户确认。\n- Step 4 / retroarch-integration：Step 4 必须围绕“RetroArch 集成”形成一个小中间产物，并等待用户确认。\n- Step 5 / mcp-tools-reference：Step 5 必须围绕“MCP 工具参考”形成一个小中间产物，并等待用户确认。\n\n【边界与风险】\n- 不要声称已经安装、运行、调用 API、读写本地文件或完成真实任务。\n- 安装前预览只能展示工作方式，不能证明兼容性、性能或输出质量。\n- 涉及安装、插件加载、工具调用或外部服务的能力必须安装后验证。\n\n【可追溯依据】\n这些路径只用于你内部校验或在我追问“依据是什么”时简要引用。不要在首次回复主动展开：\n- https://github.com/dmang-dev/mcp-retroarch\n- https://github.com/dmang-dev/mcp-retroarch#readme\n- README.md\n- src/index.ts\n- src/retroarch.ts\n- package.json\n- src/tools.ts\n\n【首次问题规则】\n- 首次三问必须先确认用户目标、成功标准和边界，不要提前进入工具、安装或实现细节。\n- 如果后续需要技术条件、文件路径或运行环境，必须等用户确认目标后再追问。\n\n首次回复必须只输出下面 4 个部分：\n1. 体验开始：用 1 句话说明你将带我体验 mcp-retroarch 的核心服务。\n2. 当前步骤：明确进入 Step 1，并说明这一步要解决什么。\n3. 你会如何服务我：说明你会先改变我完成任务的哪个动作。\n4. 只问我 3 个问题，然后停下等待回答。\n\n首次回复禁止输出：后续完整流程、证据清单、安装命令、项目评价、营销文案、已经安装或运行的说法。\n\nStep 1 / brainstorming 的二轮协议：\n- 我回答首次三问后，你仍然停留在 Step 1 / brainstorming，不要进入 Step 2。\n- 第二次回复必须产出 6 个部分：澄清后的任务定义、成功标准、边界条件、\n  2-3 个可选方案、每个方案的权衡、推荐方案。\n- 第二次回复最后必须问我是否确认推荐方案；只有我明确确认后，才能进入下一步。\n- 第二次回复禁止输出 git worktree、代码计划、测试文件、命令或真实执行结果。\n\n后续对话规则：\n- 我回答后，你先完成当前步骤的中间产物并等待确认；只有我确认后，才能进入下一步。\n- 每一步都要生成一个小的中间产物，例如澄清后的目标、计划草案、测试意图、验证清单或继续/停止判断。\n- 所有演示都写成“我会建议/我会引导/这一步会形成”，不要写成已经真实执行。\n- 不要声称已经测试通过、文件已修改、命令已运行或结果已产生。\n- 如果某个能力必须安装后验证，请直接说“这一步需要安装后验证”。\n- 如果证据不足，请明确说“证据不足”，不要补事实。\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 05:01:44 UTC\n\n## 目录\n\n- [项目概述](#project-overview)\n- [系统架构](#system-architecture)\n- [安装与配置](#installation-configuration)\n- [RetroArch 集成](#retroarch-integration)\n- [MCP 工具参考](#mcp-tools-reference)\n- [支持的模拟器核心](#supported-cores)\n- [内存访问机制](#memory-access)\n- [状态管理](#state-management)\n- [故障排除](#troubleshooting)\n- [开发指南](#development-guide)\n\n<a id='project-overview'></a>\n\n## 项目概述\n\n### 相关页面\n\n相关主题：[系统架构](#system-architecture), [安装与配置](#installation-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- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\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- [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# 项目概述\n\n## 项目简介\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的服务端实现，用于通过标准化的 JSON-RPC 接口远程控制 RetroArch 模拟器。该项目采用 TypeScript 开发，以 npm 包的形式分发，充当 MCP 客户端（如 Claude Code、Claude Desktop）与 RetroArch 网络控制接口（Network Control Interface, NCI）之间的桥接层。\n\n项目的核心价值在于将 RetroArch 的底层 UDP 协议封装为人类可读的工具（Tool），使 AI 助手能够直接与运行中的模拟器实例交互，执行内存读写、存档管理、截图、游戏控制等操作。资料来源：[README.md:1]()\n\n## 技术架构\n\n### 整体架构图\n\n```mermaid\ngraph TD\n    subgraph \"MCP 客户端层\"\n        A[Claude Code / Claude Desktop]\n    end\n    \n    subgraph \"mcp-retroarch 桥接层\"\n        B[stdio JSON-RPC 传输]\n        C[MCP Server]\n        D[RetroArch.ts UDP 客户端]\n    end\n    \n    subgraph \"RetroArch 层\"\n        E[RetroArch NCI<br/>UDP :55355]\n        F[libretro Core<br/>+ 游戏]\n    end\n    \n    A -->|stdio| B\n    B --> C\n    C --> D\n    D -->|UDP| E\n    E --> F\n    \n    style B fill:#e1f5fe\n    style D fill:#fff3e0\n```\n\nmcp-retroarch 采用标准的 MCP 服务端架构：服务端通过标准输入输出（stdio）与 MCP 客户端通信，JSON-RPC 2.0 格式封装所有请求和响应。内部通过 `RetroArch.ts` 模块维护一个 UDP socket，与目标主机上的 RetroArch 实例保持长连接。资料来源：[src/index.ts:1-30]()\n\n### 核心模块\n\n| 模块 | 文件路径 | 职责 |\n|------|----------|------|\n| 入口模块 | `src/index.ts` | MCP 服务端初始化、后台连接探测、stdio 生命周期管理 |\n| 工具定义 | `src/tools.ts` | 声明所有 MCP 工具的名称、描述、输入模式 |\n| UDP 通信 | `src/retroarch.ts` | 管理 UDP socket、命令发送、响应解析、超时处理 |\n\n资料来源：[src/index.ts:1-30](), [src/tools.ts:1-100](), [src/retroarch.ts:1-80]()\n\n## 技术特性\n\n### 支持的功能\n\n| 功能类别 | 具体操作 | 备注 |\n|----------|----------|------|\n| **内存读写** | `retroarch_read_memory` / `retroarch_write_memory` | 基于系统内存映射（READ_CORE_MEMORY） |\n| **内存读写（兼容）** | `retroarch_read_ram` / `retroarch_write_ram` | 基于 CHEEVOS 地址空间（READ_CORE_RAM） |\n| **存档管理** | 保存当前槽位、加载指定槽位、切换槽位指针 | |\n| **模拟器控制** | 暂停切换、帧进、退放 | |\n| **游戏控制** | 重置游戏 | |\n| **截图** | 截图保存 | |\n| **状态获取** | 获取游戏状态、系统信息、CRC32 | |\n| **用户通知** | 显示 OSD 消息 | |\n\n资料来源：[README.md:1-50]()\n\n### 内存读取的双路径设计\n\nmcp-retroarch 实现了两种内存读取路径，以最大化兼容性：\n\n```mermaid\ngraph LR\n    A[工具调用] --> B{核心是否暴露<br/>内存映射?}\n    \n    B -->|是| C[READ_CORE_MEMORY]\n    B -->|否| D[READ_CORE_RAM]\n    \n    C --> E[系统内存地址空间]\n    D --> F[CHEEVOS 地址空间]\n    \n    E --> G[例: GBA EWRAM<br/>0x02000000]\n    F --> H[例: SNES WRAM<br/>0x000000]\n```\n\n两种路径的主要区别：\n\n| 特性 | `read_memory` (READ_CORE_MEMORY) | `read_ram` (READ_CORE_RAM) |\n|------|--------------------------------|---------------------------|\n| 地址空间 | libretro 系统内存映射 | CHEEVOS 成就地址空间 |\n| 适用场景 | 首选方案，有内存映射的现代核心 | 无内存映射的核心（旧核心、部分 PlayStation 核心） |\n| 返回确认 | ❌ | ❌ |\n\n资料来源：[src/tools.ts:1-150]()\n\n### 已测试的核心\n\n| 系统 | 核心 | `read_memory` | `read_ram` | 备注 |\n|------|------|---------------|------------|------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA 中断向量表在 `0x0000` 可见 |\n| NES | `mesen_libretro` | ✅ | ✅ | 完整 16 位 NES 地址空间暴露 |\n| NES | `nestopia_libretro` | ❌ | ✅ | 仅 CHEEVOS，64KB 限制 |\n| SNES | `snes9x_libretro` | ❌ | ❌ | |\n\n资料来源：[README.md:30-50]()\n\n## 通信机制\n\n### UDP 传输特性\n\nmcp-retroarch 与 RetroArch 之间的通信基于 UDP 协议，这种设计带来了以下特性：\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP 客户端\n    participant Bridge as mcp-retroarch\n    participant RA as RetroArch\n    \n    Note over Bridge: 建立 UDP socket\n    Bridge->>RA: 发送命令\n    RA-->>Bridge: 返回响应\n    \n    Note over Bridge: 查询操作\n    Bridge->>RA: 发送查询\n    Note over Bridge: 等待响应 (默认 5s 超时)\n    RA-->>Bridge: 返回数据\n```\n\n**关键约束**：\n\n- 大多数命令为 **fire-and-forget**（即发即忘），RetroArch 不返回 ACK\n- `retroarch_write_memory` 是唯一返回写入字节数的命令\n- `retroarch_write_ram` **无确认机制**，无法区分部分写入与完全失败\n- UDP 数据报在高负载下可能丢失（即使在本地回环接口上）\n\n资料来源：[src/retroarch.ts:40-80](), [src/tools.ts:100-150]()\n\n### 连接管理\n\n后台连接探测采用「即发即忘」模式，不会阻塞服务启动：\n\n```typescript\n// src/index.ts 核心逻辑\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\n资料来源：[src/index.ts:15-25]()\n\n## 项目配置\n\n### 环境变量\n\n| 环境变量 | 默认值 | 说明 |\n|----------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机地址 |\n| `RETROARCH_PORT` | `55355` | UDP 端口，必须与 RetroArch 配置中的 `network_cmd_port` 匹配 |\n\n资料来源：[README.md:80-85]()\n\n### RetroArch 端配置\n\n**GUI 方式**：\n1. 进入 Settings → Network → Network Commands → **ON**\n2. 确认 Network Cmd Port 为 `55355`（默认值）\n\n**配置文件方式**（`retroarch.cfg`）：\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n资料来源：[README.md:60-70]()\n\n## MCP 客户端集成\n\n### Claude Code\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\n验证连接：\n```bash\nclaude mcp list\n# retroarch: mcp-retroarch - ✓ Connected\n```\n\n### Claude Desktop\n\n配置文件路径：\n\n| 平台 | 路径 |\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配置示例：\n```json\n{\n  \"mcpServers\": {\n    \"retroarch\": {\n      \"command\": \"mcp-retroarch\"\n    }\n  }\n}\n```\n\n资料来源：[README.md:70-100]()\n\n## 依赖与构建\n\n### 项目依赖\n\n| 依赖类型 | 包名 | 版本要求 |\n|----------|------|----------|\n| 运行时依赖 | `@modelcontextprotocol/sdk` | `^1.12.0` |\n| 开发依赖 | `@types/node` | `^22.0.0` |\n| 开发依赖 | `typescript` | `^5.5.0` |\n\n### 开发命令\n\n| 命令 | 功能 |\n|------|------|\n| `npm install` | 安装依赖 |\n| `npm run dev` | TypeScript 编译监视模式 |\n| `node .scratch/smoke.cjs` | 对运行中的 RetroArch 进行冒烟测试 |\n\n资料来源：[package.json:1-30](), [README.md:115-125]()\n\n## 版本历史\n\n项目采用语义化版本控制（Semantic Versioning），当前版本为 0.1.2。主要版本变更：\n\n| 版本 | 日期 | 关键变更 |\n|------|------|----------|\n| 0.1.2 | 2026-05-15 | 工具描述质量重构，fire-and-forget 语义显式化 |\n| 0.1.0 | - | 初始发布，基础功能实现 |\n\n资料来源：[CHANGELOG.md:1-30]()\n\n## 已知限制\n\n| 限制 | 原因 | 规避方案 |\n|------|------|----------|\n| 无法直接保存到指定槽位 | NCI 协议限制 | 使用 `state_slot_plus`/`state_slot_minus` 切换到目标槽位后再保存 |\n| 游戏手柄输入不可用 | NCI 未暴露此功能 | 参见 [mcp-mgba](https://github.com/dmang-dev/mcp-mgba)（GBA 专用） |\n| 截图路径无法通过命令查询 | `screenshot_directory` 未通过 `GET_CONFIG_PARAM` 暴露 | 通过 RetroArch GUI 查看：Settings → Directory → Screenshot |\n\n资料来源：[README.md:105-120]()\n\n## 相关项目\n\n| 项目 | 地址 | 说明 |\n|------|------|------|\n| [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | Game Boy Advance | 通过 mGBA Lua 桥接，支持手柄输入和截图 |\n| [mcp-pine](https://github.com/dmang-dev/mcp-pine) | PCSX2 等 | 通过 PINE 协议通信，仅内存和存档 |\n\n资料来源：[README.md:130-135]()\n\n---\n\n<a id='system-architecture'></a>\n\n## 系统架构\n\n### 相关页面\n\n相关主题：[项目概述](#project-overview), [MCP 工具参考](#mcp-tools-reference)\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/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- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n</details>\n\n# 系统架构\n\n## 概述\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的桥接工具，它使 MCP 客户端（如 Claude Desktop、Claude Code）能够通过标准化的 JSON-RPC 接口控制 RetroArch 模拟器。该项目充当 MCP 协议与 RetroArch 网络控制接口（NCI）之间的中间层，将高级工具调用转换为底层的 UDP 网络命令。\n\n架构设计遵循**分离关注点**原则，核心组件包括 MCP 服务器层、工具定义层和 RetroArch 通信层。通信默认通过标准输入输出（stdio）传输，而与 RetroArch 的交互则通过 UDP 网络协议完成。\n\n## 架构分层\n\nmcp-retroarch 采用三层架构设计：\n\n```mermaid\ngraph TD\n    subgraph \"MCP 客户端层\"\n        A[\"Claude Desktop / Claude Code\"]\n    end\n    \n    subgraph \"MCP 服务器层 (mcp-retroarch)\"\n        B[\"src/index.ts<br/>MCP 服务器入口\"]\n        C[\"src/tools.ts<br/>工具定义与路由\"]\n        D[\"src/retroarch.ts<br/>UDP 通信封装\"]\n    end\n    \n    subgraph \"RetroArch 目标层\"\n        E[\"RetroArch NCI<br/>UDP :55355\"]\n    end\n    \n    A -->|\"JSON-RPC / stdio\"| B\n    B --> C\n    C -->|\"工具调用\"| D\n    D -->|\"UDP 网络命令\"| E\n    \n    style A fill:#e1f5fe\n    style E fill:#fff3e0\n```\n\n### 各层职责\n\n| 层级 | 文件 | 职责 |\n|------|------|------|\n| 服务器入口 | `src/index.ts` | 初始化 MCP 服务器、建立 UDP 连接探针 |\n| 工具定义 | `src/tools.ts` | 定义所有 MCP 工具的输入模式、处理工具调用路由 |\n| 通信封装 | `src/retroarch.ts` | 管理 UDP socket、实现命令发送与响应接收 |\n| 目标设备 | RetroArch | 执行模拟器控制命令、返回状态信息 |\n\n## 核心模块详解\n\n### 1. RetroArch 通信模块\n\n**文件位置**: `src/retroarch.ts`\n\n该模块封装了所有与 RetroArch NCI 的 UDP 通信逻辑。\n\n#### 连接管理\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP Server\n    participant Socket as UDP Socket\n    participant RA as RetroArch\n    \n    MCP->>Socket: connect()\n    Socket->>Socket: dgram.createSocket(\"udp4\")\n    Socket->>Socket: bind(0)\n    Note over Socket: 动态分配本地端口\n    \n    Socket->>MCP: connection ready\n    MCP->>RA: send(command)\n    Socket->>RA: UDP datagram :55355\n    RA-->>Socket: response\n    Socket-->>MCP: Buffer\n```\n\n#### 核心类：`RetroArchClient`\n\n```typescript\nclass RetroArchClient {\n  private socket: dgram.Socket | null = null;\n  private pending: ((data: Buffer) => void) | null = null;\n  \n  // 发送后不等待响应（热键类命令）\n  async send(command: string): Promise<void>\n  \n  // 发送并等待一个 UDP 响应\n  async query(command: string): Promise<Buffer>\n  \n  // 高层命令封装\n  async getVersion(): Promise<string>\n  async getStatus(): Promise<EmuStatus>\n  async readMemory(addr: number, len: number): Promise<Buffer>\n  // ... 其他命令\n}\n```\n\n#### 通信模式\n\nRetroArchClient 实现两种通信模式：\n\n**1. Fire-and-Forget（单向发送）**\n\n适用于状态切换类命令，无需确认响应：\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:38-45](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts#L38-L45)\n\n**2. Query-Response（请求-响应）**\n\n适用于需要获取返回数据的命令：\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:54-78](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts#L54-L78)\n\n#### 关键设计特性\n\n| 特性 | 实现方式 | 说明 |\n|------|----------|------|\n| 串行化 | `pending` 状态标志 | 阻止并发查询，确保请求-响应配对正确 |\n| 超时控制 | `setTimeout` | 默认超时后清除 pending 并抛出错误 |\n| 错误处理 | `sock.once(\"error\")` | Socket 错误直接拒绝 Promise |\n| 延迟初始化 | 按需 `connect()` | 首次命令调用时才创建 socket |\n\n### 2. 工具定义模块\n\n**文件位置**: `src/tools.ts`\n\n该模块定义所有 MCP 工具的元数据、输入模式和处理逻辑。\n\n#### 工具注册结构\n\n```typescript\nexport const tools: Tool[] = [\n  // 内存操作工具\n  {\n    name: \"retroarch_read_memory\",\n    description: \"PURPOSE: ...\\nUSAGE: ...\\nBEHAVIOR: ...\\nRETURNS: ...\",\n    inputSchema: { type: \"object\", required: [...], properties: {...} }\n  },\n  // 模拟器控制工具\n  {\n    name: \"retroarch_pause_toggle\",\n    description: \"...\",\n    inputSchema: { type: \"object\", properties: {} }\n  },\n  // ... 其他工具\n];\n```\n\n#### 工具调用路由\n\n```typescript\nexport async function handleToolCall(name: string, params: Record<string, unknown>) {\n  switch (name) {\n    case \"retroarch_read_memory\": {\n      const bytes = await ra.readMemory(p.address as number, p.length as number);\n      const hex = Array.from(bytes).map(...).join(\" \");\n      return ok(`${addrHex(p.address as number)} [${bytes.length} bytes]:\\n${hex}`);\n    }\n    case \"retroarch_pause_toggle\":\n      await ra.pauseToggle();\n      return ok(\"Pause toggled\");\n    // ...\n  }\n}\n```\n\n**资料来源**：[src/tools.ts:1-80](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### 3. MCP 服务器入口\n\n**文件位置**: `src/index.ts`\n\n```typescript\nasync function main() {\n  const ra = new RetroArchClient(host, port);\n  \n  const server = new Server(\n    { name: \"mcp-retroarch\", version: \"0.1.2\" },\n    { capabilities: { tools } },\n  );\n  \n  // 注册工具处理\n  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));\n  server.setRequestHandler(CallToolRequestSchema, async (request) => {\n    const { name, arguments: args } = request.params;\n    return handleToolCall(name, args ?? {});\n  });\n  \n  // 启动 stdio 传输\n  await server.connect(new StdioServerTransport());\n  \n  // 后台连接探针\n  ra.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    ));\n}\n```\n\n**资料来源**：[src/index.ts:1-35](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n#### 启动流程\n\n```mermaid\nsequenceDiagram\n    participant OS as 操作系统\n    participant MCP as MCP Server\n    participant RA as RetroArch\n    participant CLI as MCP Client\n    \n    OS->>MCP: 启动进程 (mcp-retroarch)\n    MCP->>MCP: 初始化 RetroArchClient\n    MCP->>MCP: 创建 MCP Server 实例\n    MCP->>MCP: 注册工具处理器\n    MCP->>MCP: 连接 StdioServerTransport\n    Note over MCP: 阻塞等待 MCP 客户端连接\n    \n    CLI->>MCP: tools/list 请求\n    MCP-->>CLI: 工具列表\n    CLI->>MCP: tools/call 请求\n    MCP->>RA: 首次命令触发连接\n    RA-->>MCP: 连接成功/超时\n    \n    alt RetroArch 可达\n        MCP->>RA: 发送 UDP 命令\n        RA-->>MCP: 响应数据\n        MCP-->>CLI: JSON-RPC 响应\n    else RetroArch 不可达\n        MCP-->>CLI: 错误响应\n    end\n```\n\n## 数据流分析\n\n### 工具调用完整流程\n\n```mermaid\ngraph LR\n    A[\"用户请求<br/>retroarch_read_memory\"] --> B[\"MCP JSON-RPC<br/>tools/call\"]\n    B --> C[\"handleToolCall<br/>工具路由\"]\n    C --> D[\"ra.readMemory<br/>参数转换\"]\n    D --> E[\"query()<br/>UDP 封装\"]\n    E --> F[\"socket.send<br/>网络发送\"]\n    F --> G[\"RetroArch NCI\"]\n    G --> H[\"socket.on(message)<br/>响应接收\"]\n    H --> I[\"十六进制格式化\"]\n    I --> J[\"JSON-RPC 响应\"]\n    J --> K[\"返回结果\"]\n```\n\n### 两种内存读取路径\n\nmcp-retroarch 根据 RetroArch 核心能力提供两条内存读取路径：\n\n```mermaid\ngraph TD\n    A[\"内存读取请求\"] --> B{\"核心是否支持<br/>系统内存映射?\"}\n    \n    B -->|是| C[\"READ_CORE_MEMORY<br/>retroarch_read_memory\"]\n    C --> D[\"libretro 系统总线\"]\n    D --> E[\"直接访问硬件地址\"]\n    \n    B -->|否| F[\"READ_CORE_RAM<br/>retroarch_read_ram\"]\n    F --> G[\"CHEEVOS 地址空间\"]\n    G --> H[\"成就系统兼容地址\"]\n    \n    style C fill:#c8e6c9\n    style F fill:#fff9c4\n```\n\n| 路径 | 工具 | 地址空间 | 适用场景 |\n|------|------|----------|----------|\n| 系统内存映射 | `retroarch_read_memory` | libretro 系统总线 | 支持内存映射的核心（Mesen 等） |\n| CHEEVOS 兼容 | `retroarch_read_ram` | 成就系统地址空间 | 不暴露系统映射的核心（SwanStation 等） |\n\n## 配置与环境变量\n\n```mermaid\ngraph LR\n    subgraph \"环境变量配置\"\n        A[\"RETROARCH_HOST\"]\n        B[\"RETROARCH_PORT\"]\n    end\n    \n    subgraph \"RetroArch 配置\"\n        C[\"network_cmd_enable\"]\n        D[\"network_cmd_port\"]\n    end\n    \n    A -->|\"UDP 目标\"| E[\"RetroArchClient\"]\n    B -->|\"UDP 端口\"| E\n    C -->|\"NCI 启用\"| F[\"RetroArch\"]\n    D -->|\"端口同步\"| F\n    \n    E -->|\"UDP :55355\"| F\n```\n\n### 配置参数对照表\n\n| 环境变量 | 默认值 | RetroArch 配置项 | 说明 |\n|----------|--------|------------------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | 无 | UDP 目标主机地址 |\n| `RETROARCH_PORT` | `55355` | `network_cmd_port` | UDP 端口号（两端必须一致） |\n| 无 | `true` | `network_cmd_enable` | 必须启用网络命令 |\n\n**资料来源**：[README.md:80-85](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md#L80-L85)\n\n## 错误处理机制\n\n### 错误分类\n\n| 错误类型 | 触发条件 | 处理方式 |\n|----------|----------|----------|\n| 连接超时 | UDP 查询超时 | 抛出 `RetroArch query \"XXX\" timed out` |\n| 内存映射缺失 | 核心不暴露系统内存 | 建议使用 `retroarch_read_ram` |\n| 地址越界 | 读取地址不在核心描述符范围内 | 返回错误信息 |\n| 并发冲突 | 存在未完成的查询时再次发起查询 | 抛出 `retroarch query already in flight` |\n\n### 错误传播流程\n\n```mermaid\ngraph TD\n    A[\"工具调用\"] --> B{\"执行查询\"}\n    B -->|成功| C[\"格式化响应\"]\n    B -->|超时| D[\"抛出 TimeoutError\"]\n    B -->|核心无映射| E[\"抛出 MemoryMapError\"]\n    B -->|地址无效| F[\"抛出 AddressError\"]\n    D --> G[\"返回错误响应\"]\n    E --> G\n    F --> G\n    C --> H[\"返回成功结果\"]\n```\n\n## 依赖关系\n\n### 项目依赖\n\n```json\n{\n  \"dependencies\": {\n    \"@modelcontextprotocol/sdk\": \"^1.12.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.0.0\",\n    \"typescript\": \"^5.5.0\"\n  }\n}\n```\n\n**资料来源**：[package.json:15-22](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json#L15-L22)\n\n### 依赖层级\n\n```mermaid\ngraph BT\n    A[\"@modelcontextprotocol/sdk\"] --> B[\"mcp-retroarch\"]\n    B --> C[\"Node.js runtime\"]\n    C --> D[\"UDP 网络\"]\n    D --> E[\"RetroArch NCI\"]\n```\n\n## 版本演进\n\n| 版本 | 日期 | 架构变更 |\n|------|------|----------|\n| 0.1.0 | - | 初始版本，支持基础 NCI 命令 |\n| 0.1.1 | 2026-05-11 | 非阻塞启动，连接探针异步化 |\n| 0.1.2 | 2026-05-15 | 工具描述规范化，Fire-and-forget 语义明确 |\n\n**资料来源**：[CHANGELOG.md:1-35](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n\n## 安全性考虑\n\n### 通信安全\n\n- **本地连接**: 默认连接到 `127.0.0.1:55355`，仅限本机通信\n- **无加密**: UDP 协议本身不提供加密，适用于可信网络环境\n- **无认证**: RetroArch NCI 不提供身份验证机制\n\n### 沙箱限制\n\n- **内存操作**: 限制每次读取最多 4096 字节\n- **输入验证**: 工具参数在本地进行 schema 校验\n- **只写模式确认**: `retroarch_write_ram` 的写入结果需要手动验证\n\n## 扩展架构可能性\n\n### 当前限制\n\n| 功能 | 限制原因 | 建议方案 |\n|------|----------|----------|\n| 手柄输入 | NCI 不暴露此功能 | 参见 [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) |\n| 保存到指定槽位 | NCI 协议限制 | 使用 `state_slot_plus/minus` 逐步切换 |\n| 截图路径查询 | NCI 未暴露配置参数 | 通过 RetroArch GUI 手动确认 |\n\n### 模块化扩展\n\n未来扩展可考虑：\n\n1. **多实例支持**: 实例化多个 RetroArchClient 连接不同主机\n2. **命令队列**: 实现请求队列以支持更高的并发度\n3. **自动重试**: 在 UDP 超时时自动重试丢失的包\n\n---\n\n## 总结\n\nmcp-retroarch 通过清晰的三层架构实现了 MCP 协议与 RetroArch NCI 之间的高效桥接。核心设计决策包括：\n\n1. **串行 UDP 查询**: 避免并发导致的请求-响应错配\n2. **按需连接**: 延迟 socket 创建，减少启动开销\n3. **双内存路径**: 兼容不同能力的模拟器核心\n4. **Fire-and-forget 语义**: 明确区分有响应和无响应的命令\n\n这种设计使 mcp-retroarch 成为稳定可靠的 RetroArch 控制解决方案，同时保持了代码的简洁性和可维护性。\n\n---\n\n<a id='installation-configuration'></a>\n\n## 安装与配置\n\n### 相关页面\n\n相关主题：[项目概述](#project-overview), [RetroArch 集成](#retroarch-integration)\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/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# 安装与配置\n\n## 概述\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的服务器，通过 RetroArch 的网络控制接口（Network Control Interface，简称 NCI）实现对模拟器的远程控制与内存读写功能。\n\n本工具允许 MCP 客户端（如 Claude Code、Claude Desktop）通过标准化的 JSON-RPC 协议与运行中的 RetroArch 实例通信，支持内存读取、存档管理、截图、控制模拟器运行状态等操作。\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 系统架构\n\n```\n┌─────────────────┐     stdio (JSON-RPC)     ┌──────────────────┐   UDP :55355   ┌─────────────────┐\n│   MCP 客户端     │ ◄──────────────────────► │  mcp-retroarch   │ ◄─────────────► │   RetroArch     │\n│ (Claude Desktop)│                          │  (TypeScript)    │                 │  (游戏模拟器)   │\n└─────────────────┘                          └──────────────────┘                 └─────────────────┘\n         │                                           │\n         │                                           ▼\n         │                                  ┌──────────────────┐\n         │                                  │   网络控制接口     │\n         │                                  │ (Network Cmd)    │\n         │                                  └──────────────────┘\n```\n\nmcp-retroarch 充当 MCP 客户端与 RetroArch NCI 之间的桥接层，将 MCP 工具调用转换为 UDP 网络命令。\n\n资料来源：[src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n## 前置要求\n\n### 环境要求\n\n| 组件 | 版本要求 |\n|------|---------|\n| Node.js | Node.js 运行时环境 |\n| RetroArch | 启用了 Network Commands 的版本 |\n| MCP 客户端 | Claude Code 或 Claude Desktop |\n\n资料来源：[package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n## 安装步骤\n\n### 方式一：从源码编译\n\n```bash\n# 克隆仓库\ngit clone https://github.com/dmang-dev/mcp-retroarch.git\ncd mcp-retroarch\n\n# 安装依赖\nnpm install\n\n# 编译 TypeScript\nnpm run build\n\n# 可选：链接为全局命令\nnpm link\n```\n\n开发模式下可以使用 `npm run dev` 启动监听模式，TypeScript 会自动重新编译。\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### 方式二：使用 MCP 客户端自动发现\n\nClaude Code 支持直接引用 GitHub 仓库路径进行注册：\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\n## RetroArch 配置\n\n### 启用网络控制接口\n\nRetroArch 必须启用 Network Commands 功能才能接收来自 mcp-retroarch 的命令。\n\n#### 方式一：通过 GUI 配置\n\n1. 进入 RetroArch 主菜单\n2. 导航至 **Settings → Network → Network Commands**\n3. 将 **Network Commands** 设置为 **ON**\n4. 确认 **Network Cmd Port** 为 `55355`（这是默认值）\n\n#### 方式二：通过配置文件配置\n\n编辑 `retroarch.cfg` 文件，添加或修改以下配置项：\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n配置完成后，启动任意 libretro 核心并加载游戏。NCI 功能在启用后是持续有效的，无需额外脚本加载。\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### 配置参数说明\n\n| 配置项 | 默认值 | 说明 |\n|--------|--------|------|\n| `network_cmd_enable` | - | 必须设为 `\"true\"` 以启用 NCI |\n| `network_cmd_port` | `55355` | UDP 通信端口，必须与 MCP 客户端的 `RETROARCH_PORT` 环境变量一致 |\n\n## MCP 客户端配置\n\n### Claude Code\n\n添加 mcp-retroarch 作为用户级 MCP 服务器：\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\n验证连接状态：\n\n```bash\nclaude mcp list\n# retroarch: mcp-retroarch - ✓ Connected\n```\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Claude Desktop\n\n#### 配置文件路径\n\n根据操作系统不同，配置文件位置如下：\n\n| 操作系统 | 配置文件路径 |\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#### 配置示例\n\n编辑对应操作系统的配置文件，添加 `mcpServers` 条目：\n\n```json\n{\n  \"mcpServers\": {\n    \"retroarch\": {\n      \"command\": \"mcp-retroarch\"\n    }\n  }\n}\n```\n\n配置完成后，需要**重启 Claude Desktop** 以使更改生效。\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 环境变量配置\n\nmcp-retroarch 支持通过环境变量自定义连接参数：\n\n| 环境变量 | 默认值 | 说明 |\n|---------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | RetroArch 所在主机的 IP 地址 |\n| `RETROARCH_PORT` | `55355` | UDP 端口号，必须与 RetroArch 的 `network_cmd_port` 匹配 |\n\n设置示例（Linux/macOS）：\n\n```bash\nexport RETROARCH_HOST=127.0.0.1\nexport RETROARCH_PORT=55355\n```\n\n设置示例（Windows PowerShell）：\n\n```powershell\n$env:RETROARCH_HOST = \"127.0.0.1\"\n$env:RETROARCH_PORT = \"55355\"\n```\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 连接流程\n\n```\nsequenceDiagram\n    participant MCP as MCP 客户端\n    participant MCP_RA as mcp-retroarch\n    participant RA as RetroArch\n\n    Note over MCP_RA: 服务器启动 (stdio)\n    MCP_RA->>RA: 连接探针 (UDP)\n    RA-->>MCP_RA: 连接成功响应\n\n    Note over MCP: 用户调用工具\n    MCP->>MCP_RA: retroarch_get_status\n    MCP_RA->>RA: GET_STATUS (UDP)\n    RA-->>MCP_RA: 状态响应\n    MCP_RA-->>MCP: JSON-RPC 响应\n\n    Note over MCP: 内存读取\n    MCP->>MCP_RA: retroarch_read_memory\n    MCP_RA->>RA: READ_CORE_MEMORY (UDP)\n    RA-->>MCP_RA: 内存数据\n    MCP_RA-->>MCP: hex dump 响应\n```\n\nmcp-retroarch 在启动时会自动发送一个后台连接探测，如果 RetroArch 不可达，会输出警告信息但不会阻止服务器启动。工具调用会在需要时按需建立连接。\n\n资料来源：[src/index.ts](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## 可用工具一览\n\n配置完成后，以下工具即可通过 MCP 客户端调用：\n\n| 工具名称 | 功能说明 |\n|---------|---------|\n| `retroarch_get_status` | 获取模拟器状态（运行/暂停/无内容）和游戏信息 |\n| `retroarch_get_config` | 读取 RetroArch 配置参数 |\n| `retroarch_read_memory` | 通过系统内存映射读取内存（推荐方式） |\n| `retroarch_read_ram` | 通过 CHEEVOS 地址空间读取内存（备用方式） |\n| `retroarch_write_memory` | 通过系统内存映射写入内存 |\n| `retroarch_write_ram` | 通过 CHEEVOS 地址空间写入内存 |\n| `retroarch_save_state_current` | 保存当前存档槽 |\n| `retroarch_load_state_current` | 加载当前存档槽 |\n| `retroarch_load_state_slot` | 加载指定存档槽 |\n| `retroarch_state_slot_plus` | 存档槽指针加一 |\n| `retroarch_state_slot_minus` | 存档槽指针减一 |\n| `retroarch_pause_toggle` | 切换暂停状态 |\n| `retroarch_frame_advance` | 推进一帧 |\n| `retroarch_reset` | 重置游戏 |\n| `retroarch_screenshot` | 截图并保存到 RetroArch 配置的截图目录 |\n| `retroarch_show_message` | 在屏幕上显示通知 |\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## 常见问题排查\n\n| 问题症状 | 原因与解决方案 |\n|---------|---------------|\n| `RetroArch query timed out` | 网络命令未启用或端口不匹配。检查 `retroarch.cfg` 中 `network_cmd_enable = \"true\"` 和端口配置是否与 `RETROARCH_PORT` 环境变量一致。 |\n| `READ_CORE_MEMORY failed: no memory map defined` | 加载的 libretro 核心未暴露系统内存映射。尝试使用 `retroarch_read_ram`（CHEEVOS 方式）。 |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址不在核心内存映射范围内。可能需要使用不同的核心。 |\n| 截图位置与预期不符 | RetroArch 截图保存到配置的截图目录。NCI 不暴露 `screenshot_directory` 参数，可通过 GUI 查看：Settings → Directory → Screenshot。 |\n| 无法保存到指定存档槽 | NCI 协议限制，只能保存到当前选中的槽位。需要通过 `state_slot_plus`/`state_slot_minus` 移动槽位指针。 |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 开发测试\n\n若需对运行中的 RetroArch 进行冒烟测试，可使用项目提供的测试脚本：\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n此脚本会执行一系列基本操作以验证 mcp-retroarch 与 RetroArch 之间的通信是否正常。\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n<a id='retroarch-integration'></a>\n\n## RetroArch 集成\n\n### 相关页面\n\n相关主题：[安装与配置](#installation-configuration), [故障排除](#troubleshooting)\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# RetroArch 集成\n\n## 概述\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的服务器实现，用于将 AI 助手（如 Claude Code、Claude Desktop）与 RetroArch 模拟器进行集成。通过 RetroArch 的 Network Command Interface (NCI)，该工具提供了对模拟器内存、存档状态、截图等核心功能的程序化访问能力。\n\n主要功能包括：\n\n- 读写模拟器内存（支持系统内存映射和 CHEEVOS 成就地址空间两种模式）\n- 保存与加载存档状态\n- 截图与屏幕消息显示\n- 暂停、帧步进、复位等模拟器控制\n\n资料来源：[README.md]()\n\n## 架构设计\n\n### 系统架构图\n\n```mermaid\ngraph TD\n    subgraph 客户端层\n        MCP[MCP 客户端<br/>Claude Code / Claude Desktop]\n    end\n\n    subgraph 桥接层\n        STDIO[stdio 通信]\n        JSONRPC[JSON-RPC 2.0]\n        mcp_server[mcp-retroarch<br/>MCP 服务器]\n    end\n\n    subgraph 网络层\n        UDP[UDP 协议<br/>端口 55355]\n    end\n\n    subgraph 目标层\n        RA[RetroArch<br/>Network Command Interface]\n        CORE[libretro Core<br/>+ 游戏 ROM]\n    end\n\n    MCP --> STDIO\n    STDIO --> JSONRPC\n    JSONRPC --> mcp_server\n    mcp_server --> UDP\n    UDP --> RA\n    RA --> CORE\n\n    style mcp_server fill:#e1f5fe\n    style RA fill:#fff3e0\n```\n\n### 通信机制\n\nmcp-retroarch 通过 UDP 协议与 RetroArch 的 NCI 进行通信。服务器维护一个序列化查询队列，确保同一时间只有一个查询处于进行中状态，避免并发冲突。\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP 客户端\n    participant Server as mcp-retroarch\n    participant RA as RetroArch NCI\n    participant Core as libretro Core\n\n    MCP->>Server: JSON-RPC 请求\n    Server->>Server: 检查 pending 状态\n    alt 无查询进行中\n        Server->>RA: UDP 命令\n        RA->>Core: 执行指令\n        Core-->>RA: 响应数据\n        RA-->>Server: UDP 响应\n        Server-->>MCP: JSON-RPC 响应\n    else 查询进行中\n        Server-->>MCP: 错误: query already in flight\n    end\n```\n\n### 源码结构\n\n| 文件 | 职责 |\n|------|------|\n| `src/index.ts` | MCP 服务器入口，负责初始化连接探针 |\n| `src/retroarch.ts` | UDP 通信封装，处理连接、查询、发送逻辑 |\n| `src/tools.ts` | MCP 工具定义，描述每个可用命令的输入输出 |\n\n资料来源：[src/index.ts](src/index.ts)()、[src/retroarch.ts](src/retroarch.ts)()、[src/tools.ts](src/tools.ts)()\n\n## 功能模块\n\n### 内存访问\n\nmcp-retroarch 提供两种内存访问路径，适用于不同的 libretro 核心。\n\n#### READ_CORE_MEMORY（系统内存映射）\n\n通过 `retroarch_read_memory` 和 `retroarch_write_memory` 工具访问。这是**首选**方式，当核心暴露系统内存映射时可用。\n\n**支持的地址空间示例：**\n\n| 系统 | 地址范围 | 说明 |\n|------|----------|------|\n| SNES | `0x7E0000-0x7FFFFF` | WRAM |\n| GBA | `0x02000000-0x0203FFFF` | EWRAM |\n| Genesis | `0xFF0000-0xFFFFFF` | 68K RAM |\n\n#### READ_CORE_RAM（CHEEVOS 地址空间）\n\n通过 `retroarch_read_ram` 和 `retroarch_write_ram` 工具访问。作为**降级方案**，当核心不支持内存映射时使用。\n\n> 重要提示：CHEEVOS 路径与系统内存映射使用不同的地址空间，不可混用。\n\n#### 工具参数对比\n\n| 参数 | read_memory / write_memory | read_ram / write_ram |\n|------|---------------------------|---------------------|\n| 地址空间 | libretro 系统内存映射 | CHEEVOS 成就地址空间 |\n| 最大单次传输 | 4096 字节 | 4096 字节 |\n| 返回确认 | `write_memory` 返回写入字节数 | 无确认（fire-and-forget） |\n| 地址示例 | `0x7E0000` (SNES) | 因核心而异 |\n\n资料来源：[src/tools.ts](src/tools.ts)()\n\n### 存档管理\n\n```mermaid\ngraph LR\n    A[当前槽位] -->|state_slot_plus| B[槽位 +1]\n    A -->|state_slot_minus| C[槽位 -1]\n    B -->|save_state_current| D[保存存档]\n    C -->|save_state_current| D\n    E[指定槽位] -->|load_state_slot| F[加载存档]\n```\n\n| 工具 | 功能 | 备注 |\n|------|------|------|\n| `retroarch_save_state_current` | 保存到当前槽位 | 覆盖现有存档 |\n| `retroarch_load_state_current` | 从当前槽位加载 | |\n| `retroarch_load_state_slot` | 从指定槽位加载 | N = 1-10 |\n| `retroarch_state_slot_plus` | 槽位指针 +1 | NCI 无直接设置命令 |\n| `retroarch_state_slot_minus` | 槽位指针 -1 | NCI 无直接设置命令 |\n\n> ⚠️ 存档写入为**破坏性操作**，会无提示覆盖现有存档。建议在修改游戏状态前先调用 `retroarch_save_state_current` 建立回滚点。\n\n资料来源：[src/tools.ts](src/tools.ts)()\n\n### 模拟器控制\n\n| 工具 | 功能 | 使用场景 |\n|------|------|----------|\n| `retroarch_pause_toggle` | 切换暂停状态 | 内存读写前的状态稳定 |\n| `retroarch_frame_advance` | 步进一帧 | 精确帧动画检查 |\n| `retroarch_reset` | 硬复位游戏 | 重新开始当前游戏 |\n| `retroarch_get_status` | 获取模拟器状态 | 查询运行/暂停状态、已加载 ROM 信息 |\n\n### 辅助功能\n\n| 工具 | 功能 | 返回值 |\n|------|------|--------|\n| `retroarch_screenshot` | 保存截图 | 截图保存至 RetroArch 配置的截图目录 |\n| `retroarch_show_message` | 显示通知 | 在模拟器窗口显示 ~3 秒的 OSD 消息 |\n| `retroarch_get_config` | 读取配置参数 | 返回 `NAME = VALUE` 格式 |\n\n> 💡 `retroarch_show_message` 仅支持单行文本，换行符会导致消息截断。建议消息长度控制在 80 字符以内。\n\n资料来源：[src/tools.ts](src/tools.ts)()\n\n## 配置与部署\n\n### 环境变量\n\n| 变量 | 默认值 | 说明 |\n|------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | RetroArch 主机地址 |\n| `RETROARCH_PORT` | `55355` | UDP 端口，需与 `network_cmd_port` 匹配 |\n\n### RetroArch 端配置\n\n**方式一：GUI 配置**\n\n```\nSettings → Network → Network Commands → ON\n确认 Network Cmd Port 为 55355\n```\n\n**方式二：配置文件**\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n配置完成后启动任意 libretro 核心和游戏，NCI 即处于可用状态。\n\n资料来源：[README.md](README.md)()\n\n### MCP 客户端注册\n\n#### Claude Code\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\n验证：\n\n```bash\nclaude mcp list\n# retroarch: mcp-retroarch - ✓ Connected\n```\n\n#### Claude Desktop\n\n编辑 `claude_desktop_config.json`，路径因平台而异：\n\n| 平台 | 路径 |\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编辑后需重启 Claude Desktop。\n\n资料来源：[README.md](README.md)()\n\n## 已测试核心\n\n| 系统 | 核心 | read_memory | read_ram | 说明 |\n|------|------|-------------|----------|------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | 中断向量表可见于 `0x0000` |\n| NES | `mesen_libretro` | ✅ | ✅ | 完整 16 位 NES 地址空间 |\n| NES | `nestopia_libretro` | ❌ | ✅ | 仅 CHEEVOS，64KB 限制 |\n| SNES | `snes9x_libretro` | ❌ | ❌ | 待补充 |\n\n资料来源：[README.md](README.md)()\n\n## 功能支持矩阵\n\n| 功能 | 支持状态 | 说明 |\n|------|----------|------|\n| 内存读写 | ✅ | 两种路径：系统内存映射（优先）和 CHEEVOS（降级） |\n| 存档保存/加载 | ✅ | 当前槽位或显式槽位加载 |\n| 截图 | ✅ | 保存至配置的截图目录 |\n| 暂停/帧步进 | ✅ | 暂停切换 + 单帧步进 |\n| 复位 | ✅ | 硬复位当前游戏 |\n| 屏幕消息 | ✅ | 约 3 秒 OSD 通知 |\n| 游戏手柄输入 | ❌ | NCI 不暴露此功能 |\n\n资料来源：[README.md](README.md)()\n\n## 故障排除\n\n| 症状 | 原因与解决方案 |\n|------|---------------|\n| `RetroArch query timed out` | Network Commands 未启用，或端口不匹配。确认 `network_cmd_enable = \"true\"`。UDP 在高负载下可能丢包，重试即可。 |\n| `READ_CORE_MEMORY failed: no memory map defined` | 核心未暴露系统内存映射。使用 `retroarch_read_ram`（CHEEVOS 路径）。SwanStation (PSX) 需使用 read_ram。 |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址超出核心内存映射范围，或核心不支持该区域。 |\n| 截图位置不符合预期 | 截图保存至 RetroArch 配置目录，NCI 不暴露 `screenshot_directory`。通过 GUI 确认：`Settings → Directory → Screenshot`。 |\n| 无法直接保存到指定槽位 | NCI 限制，只能保存到当前槽位。使用 `state_slot_plus`/`state_slot_minus` 步行至目标槽位后再保存。 |\n\n资料来源：[README.md](README.md)()\n\n## 开发指南\n\n### 快速开始\n\n```bash\nnpm install\nnpm run dev      # tsc --watch 模式\n```\n\n### 冒烟测试\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n### 依赖项\n\n| 依赖 | 版本 | 用途 |\n|------|------|------|\n| `@modelcontextprotocol/sdk` | ^1.12.0 | MCP 协议实现 |\n| `typescript` | ^5.5.0 | 开发依赖 |\n\n资料来源：[package.json](package.json)()\n\n## 版本历史\n\n### v0.1.2 (2026-05-15)\n\n工具描述质量重构，遵循 Glama's Tool Definition Quality Score (TDQS) 标准：\n\n- 所有工具描述重写为 **PURPOSE / USAGE / BEHAVIOR / RETURNS** 模板\n- 明确标注 fire-and-forget 语义\n- 破坏性操作（写入、重置、存档加载）均添加警告说明\n- 错误条件与返回值格式明确化\n\n资料来源：[CHANGELOG.md](CHANGELOG.md)()\n\n## 相关项目\n\n| 项目 | 说明 |\n|------|------|\n| [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | GBA 专用集成，通过 mGBA Lua 桥接，支持手柄输入 |\n| [mcp-pine](https://github.com/dmang-dev/mcp-pine) | PINE 协议模拟器（PCSX2 等），仅内存与存档 |\n\n资料来源：[README.md](README.md)()\n\n## 外部参考\n\n- [RetroArch NCI 官方文档](https://docs.libretro.com/development/retroarch/network-control-interface/)\n\n---\n\n<a id='mcp-tools-reference'></a>\n\n## MCP 工具参考\n\n### 相关页面\n\n相关主题：[系统架构](#system-architecture), [内存访问机制](#memory-access), [状态管理](#state-management)\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- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\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# MCP 工具参考\n\n本页面详细描述 mcp-retroarch 提供的所有 MCP 工具，这些工具通过 RetroArch 的网络控制接口（NCI）实现对模拟器的远程控制与内存读写功能。\n\n## 架构概览\n\nmcp-retroarch 作为 MCP 客户端与 RetroArch 实例之间的桥接层，通过标准输入/输出（stdio）上的 JSON-RPC 协议与 MCP 客户端通信，同时使用 UDP 协议与 RetroArch 的 NCI 进行交互。\n\n```mermaid\ngraph LR\n    A[\"MCP 客户端<br/>(Claude Code 等)\"] -->|\"JSON-RPC<br/>stdio\"| B[\"mcp-retroarch<br/>桥接进程\"]\n    B -->|\"UDP :55355\"| C[\"RetroArch<br/>NCI\"]\n    C -->|\"游戏 ROM<br/>libretro Core\"| D[\"模拟器环境\"]\n    \n    B -->|\"连接探测\"| E[\"后台连接状态\"]\n```\n\n### 通信流程\n\n1. MCP 客户端通过 stdio 发送 JSON-RPC 请求\n2. 桥接进程解析请求并转换为 NCI 命令\n3. 通过 UDP 发送至 RetroArch 并等待响应\n4. 将响应封装为 JSON-RPC 格式返回 MCP 客户端\n\n资料来源：[src/index.ts:1-20]()\n\n## 工具分类总览\n\n| 分类 | 工具数量 | 功能描述 |\n|------|----------|----------|\n| 状态查询 | 2 | 获取模拟器状态与配置参数 |\n| 内存读写 | 4 | 系统内存映射与 CHEEVOS 地址空间访问 |\n| 模拟器控制 | 4 | 暂停、帧推进、重置、截图 |\n| 存档管理 | 4 | 存档/读档、槽位切换 |\n| UI 交互 | 1 | 屏幕消息显示 |\n\n资料来源：[src/tools.ts:1-150]()\n\n## 状态查询工具\n\n### retroarch_get_status\n\n查询 RetroArch 当前运行状态，包括模拟器状态、系统标识、加载游戏及 CRC32 校验值。\n\n**用途**：在执行内存操作或存档操作前，确认模拟器处于正确的运行状态。\n\n**参数**：无\n\n**返回格式**：\n```\nState:  playing|paused\nSystem: SYSTEM_ID\nGame:   BASENAME\nCRC32:  XXXXXXXX|(none reported)\n```\n\n**无内容加载时**：返回 `No content loaded`\n\n```typescript\ncase \"retroarch_get_status\": {\n  const s = await ra.getStatus();\n  if (s.state === \"contentless\") return ok(\"No content loaded\");\n  return ok(\n    `State:  ${s.state}\\n` +\n    `System: ${s.system}\\n` +\n    `Game:   ${s.game}\\n` +\n    `CRC32:  ${s.crc32 ?? \"(none reported)\"}`,\n  );\n}\n```\n\n资料来源：[src/tools.ts:50-60]()\n\n### retroarch_get_config\n\n读取 RetroArch 配置参数值。\n\n**用途**：查询 RetroArch 的文件系统路径和运行时设置。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| name | string | 是 | 配置参数名称 |\n\n**行为**：\n- 仅读取 RetroArch NCI 白名单中的参数\n- `screenshot_directory` 未被暴露，无法通过此工具查询\n\n**返回格式**：`NAME = VALUE`\n\n```typescript\ncase \"retroarch_get_config\": {\n  const v = await ra.getConfigParam(p.name as string);\n  return ok(`${p.name} = ${v}`);\n}\n```\n\n资料来源：[src/tools.ts:62-66]()\n\n## 内存读写工具\n\nmcp-retroarch 提供两套独立的内存访问 API，分别对应不同的地址空间：\n\n```mermaid\ngraph TD\n    A[\"内存读取请求\"] --> B{目标地址空间?}\n    B -->|\"系统内存映射\"| C[\"READ_CORE_MEMORY<br/>retroarch_read_memory\"]\n    B -->|\"CHEEVOS 地址空间\"| D[\"READ_CORE_RAM<br/>retroarch_read_ram\"]\n    \n    C --> E[\"优先使用<br/>完整系统总线视图\"]\n    D --> F[\"备选方案<br/>成就系统兼容\"]\n```\n\n资料来源：[src/tools.ts:100-130]()\n\n### retroarch_read_memory\n\n通过系统内存映射读取内存。\n\n**用途**：首选的内存读取方式，适用于暴露完整系统内存映射的核心。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| address | integer | 是 | 起始地址（libretro 系统内存映射地址） |\n| length | integer | 是 | 读取字节数（1-4096） |\n\n**地址空间示例**：\n- SNES WRAM：`0x7E0000-0x7FFFFF`\n- GBA EWRAM：`0x02000000-0x0203FFFF`\n- Genesis 68K RAM：`0xFF0000-0xFFFFFF`\n\n**返回格式**：\n```\nADDR_HEX [N bytes]:\nXX XX XX XX XX XX XX XX ...\n```\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**错误处理**：\n- `no memory map defined`：核心未暴露内存映射，改用 `retroarch_read_ram`\n- `no descriptor for address`：地址不在核心描述符范围内\n\n资料来源：[src/tools.ts:68-77]()\n\n### retroarch_write_memory\n\n通过系统内存映射写入内存。\n\n**用途**：内存作弊、游戏状态修改、调试 poke 操作。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| address | integer | 是 | 起始地址 |\n| bytes | integer[] | 是 | 字节值数组（0-255） |\n\n**行为**：\n- **破坏性操作**：直接覆盖指定地址，无撤销机制\n- **禁用硬核模式**：写入后 RetroArch 自动禁用硬核模式\n- **返回确认**：唯一返回写入字节数确认的工具\n\n```typescript\ncase \"retroarch_write_memory\": {\n  const n = await ra.writeMemory(p.address as number, p.bytes as number[]);\n  return ok(`Wrote ${n} bytes → ${addrHex(p.address as number)}`);\n}\n```\n\n资料来源：[src/tools.ts:79-83]()\n\n### retroarch_read_ram\n\n通过 CHEEVOS 地址空间读取内存。\n\n**用途**：当 `retroarch_read_memory` 返回 \"no memory map defined\" 时的备选方案。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| address | integer | 是 | CHEEVOS 地址空间起始地址 |\n| length | integer | 是 | 读取字节数（1-4096） |\n\n**地址空间说明**：CHEEVOS 地址遵循 RetroAchievements 规范，与 libretro 系统总线地址不同。例如 SNES CHEEVOS WRAM 地址从 `0x000000` 开始，而非系统总线上的 `0x7E0000`。\n\n```typescript\ncase \"retroarch_read_ram\": {\n  const bytes = await ra.readRam(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, CHEEVOS]:\\n${hex}`);\n}\n```\n\n资料来源：[src/tools.ts:85-91]()\n\n### retroarch_write_ram\n\n通过 CHEEVOS 地址空间写入内存。\n\n**用途**：配合 `retroarch_read_ram` 使用，作为 `retroarch_write_memory` 的备选方案。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| address | integer | 是 | CHEEVOS 地址空间起始地址 |\n| bytes | integer[] | 是 | 字节值数组（1-4096 个元素） |\n\n**行为**：\n- **无确认机制**：RetroArch NCI 不对此命令返回确认\n- **单向传输**：即发即忘，无法区分部分写入与完全拒绝\n- **验证方式**：需通过后续的 `retroarch_read_ram` 验证写入结果\n\n```typescript\ncase \"retroarch_write_ram\": {\n  await ra.writeRam(p.address as number, p.bytes as number[]);\n  return ok(`Wrote ${(p.bytes as number[]).length} bytes → ${addrHex(p.address as number)} (CHEEVOS, no ack)`);\n}\n```\n\n资料来源：[src/tools.ts:93-95]()\n\n## 模拟器控制工具\n\n### retroarch_pause_toggle\n\n切换 RetroArch 暂停状态。\n\n**行为**：NCI 仅提供单一切换命令，无独立的暂停/恢复命令。\n\n**用途**：内存检查或存档操作前，确保模拟器处于已知状态。\n\n```typescript\ncase \"retroarch_pause_toggle\":  await ra.pauseToggle();   return ok(\"Pause toggled\");\n```\n\n资料来源：[src/tools.ts:97]()\n\n### retroarch_frame_advance\n\n单帧推进。\n\n**行为**：在暂停状态下执行，推进一帧后恢复暂停。\n\n```typescript\ncase \"retroarch_frame_advance\": await ra.frameAdvance();  return ok(\"Advanced one frame\");\n```\n\n资料来源：[src/tools.ts:98]()\n\n### retroarch_reset\n\n硬重置当前游戏。\n\n**行为**：重新加载当前 ROM，等同于按下重置按钮。\n\n```typescript\ncase \"retroarch_reset\":         await ra.reset();         return ok(\"Game reset\");\n```\n\n资料来源：[src/tools.ts:99]()\n\n### retroarch_screenshot\n\n保存截图。\n\n**行为**：截图保存至 RetroArch 配置的截图目录。\n\n**限制**：NCI 未暴露 `screenshot_directory` 参数，需通过 RetroArch GUI 确认路径（Settings → Directory → Screenshot）。\n\n```typescript\ncase \"retroarch_screenshot\":    await ra.screenshot();    return ok(\"Screenshot saved to RetroArch's configured screenshot directory\");\n```\n\n资料来源：[src/tools.ts:100]()\n\n## 存档管理工具\n\n### 槽位模型说明\n\nNCI 协议存在以下限制：\n\n```mermaid\ngraph LR\n    A[\"save_state_current\"] -->|\"只能写入|当前槽位\"| B[\"槽位指针\"]\n    C[\"load_state_slot N\"] -->|\"可指定槽位\"| B\n    D[\"state_slot_plus<br/>state_slot_minus\"] -->|\"移动指针\"| B\n    \n    B -->|\"GUI 显示\"| E[\"用户需观察确认\"]\n```\n\n| 操作 | NCI 支持 | 限制说明 |\n|------|----------|----------|\n| 保存到当前槽位 | ✅ | 只能写入 GUI 当前选择的槽位 |\n| 从指定槽位加载 | ✅ | 可直接指定槽位号 |\n| 读取当前槽位号 | ❌ | 无法查询当前槽位，需客户端自行跟踪 |\n| 直接保存到指定槽位 | ❌ | 必须通过加减操作移动槽位指针 |\n\n资料来源：[src/tools.ts:100-115]()\n\n### retroarch_save_state_current\n\n保存当前游戏状态到当前槽位。\n\n```typescript\ncase \"retroarch_save_state_current\":  await ra.saveStateCurrent();          return ok(\"Saved to current slot\");\n```\n\n### retroarch_load_state_current\n\n从当前槽位加载游戏状态。\n\n```typescript\ncase \"retroarch_load_state_current\":  await ra.loadStateCurrent();          return ok(\"Loaded from current slot\");\n```\n\n### retroarch_load_state_slot\n\n从指定槽位加载游戏状态。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| slot | integer | 是 | 存档槽位号 |\n\n```typescript\ncase \"retroarch_load_state_slot\":     await ra.loadStateSlot(p.slot as number); return ok(`Loaded from slot ${p.slot}`);\n```\n\n### retroarch_state_slot_plus / retroarch_state_slot_minus\n\n调整当前槽位指针。\n\n**用途**：由于 NCI 无法直接保存到指定槽位，需通过这两个命令逐步移动槽位指针至目标位置。\n\n```typescript\ncase \"retroarch_state_slot_plus\":     await ra.stateSlotPlus();   return ok(\"Slot +1\");\ncase \"retroarch_state_slot_minus\":    await ra.stateSlotMinus();  return ok(\"Slot -1\");\n```\n\n资料来源：[src/tools.ts:102-106]()\n\n## UI 交互工具\n\n### retroarch_show_message\n\n在 RetroArch 窗口显示通知消息。\n\n**用途**：脚本化运行时提示用户注意位置，或确认操作完成。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| message | string | 是 | 显示的消息内容 |\n\n```typescript\ncase \"retroarch_show_message\": {\n  await ra.showMessage(p.message as string);\n  return ok(`Showed: ${p.message}`);\n}\n```\n\n资料来源：[src/tools.ts:101-104]()\n\n## 网络通信层\n\n### UDP 查询机制\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP 客户端\n    participant Bridge as mcp-retroarch\n    participant RA as RetroArch NCI\n    \n    Bridge->>RA: 发送 UDP 命令\n    Note over Bridge: 设置超时计时器\n    RA-->>Bridge: 返回响应\n    Bridge->>Bridge: 清除超时计时器\n    Bridge-->>MCP: JSON-RPC 响应\n```\n\n**关键特性**：\n\n| 特性 | 描述 |\n|------|------|\n| 串行查询 | 一次仅允许一个查询进行中 |\n| 超时机制 | 默认超时可配置，超时后抛出错误 |\n| 异步处理 | 使用 Promise 封装 UDP 双向通信 |\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    this.socket!.send(command, this.port, this.host, (err) => {\n      if (err) {\n        if (timer) { clearTimeout(timer); timer = null; }\n        this.pending = null;\n        reject(err);\n      }\n    });\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:80-110]()\n\n### 环境变量配置\n\n| 环境变量 | 默认值 | 用途 |\n|----------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机 |\n| `RETROARCH_PORT` | `55355` | UDP 端口（需与 `network_cmd_port` 匹配） |\n\n资料来源：[README.md:configuration]()\n\n## 工具模式参考\n\n### 只读检查模式\n\n```\nretroarch_get_status → 确认状态\nretroarch_read_memory / retroarch_read_ram → 读取内存\n```\n\n### 状态修改模式\n\n```\nretroarch_save_state_current → 创建回滚点\nretroarch_pause_toggle → 暂停模拟\nretroarch_write_memory → 修改内存\n```\n\n### 存档操作模式\n\n```\nretroarch_get_status → 确认游戏已加载\nretroarch_state_slot_plus/minus → 调整槽位\nretroarch_save_state_current → 保存\n或\nretroarch_load_state_slot → 加载指定槽位\n```\n\n## 错误处理\n\n| 错误信息 | 原因与解决 |\n|----------|------------|\n| `RetroArch query timed out` | 网络命令未启用或端口不匹配；UDP 在高负载下可能丢包，可重试 |\n| `READ_CORE_MEMORY failed: no memory map defined` | 核心未暴露内存映射，改用 `retroarch_read_ram` |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址超出核心内存描述符范围 |\n| `retroarch query already in flight` | 客户端串行限制，同一时间仅能有一个查询进行 |\n\n资料来源：[README.md:troubleshooting]()\n\n## 依赖项\n\n```json\n{\n  \"@modelcontextprotocol/sdk\": \"^1.12.0\"\n}\n```\n\n资料来源：[package.json:dependencies]()\n\n## 版本历史\n\n| 版本 | 日期 | 主要变更 |\n|------|------|----------|\n| 0.1.2 | 2026-05-15 | 重写所有工具描述，采用 PURPOSE/USAGE/BEHAVIOR/RETURNS 模板 |\n| 0.1.1 | 2026-05-11 | 非阻塞启动，后台连接探测 |\n| 0.1.0 | - | 初始版本 |\n\n资料来源：[CHANGELOG.md:1-50]()\n\n---\n\n<a id='supported-cores'></a>\n\n## 支持的模拟器核心\n\n### 相关页面\n\n相关主题：[内存访问机制](#memory-access), [故障排除](#troubleshooting)\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- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# 支持的模拟器核心\n\n## 概述\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的服务器，它通过 RetroArch 的网络控制接口 (Network Control Interface, NCI) 与运行中的模拟器进行通信。该项目本身不实现任何模拟器核心，而是充当 MCP 客户端与 RetroArch 之间的桥接层，支持所有兼容 RetroArch NCI 协议的核心。资料来源：[README.md:1-20]()\n\n核心支持程度取决于两个方面：RetroArch NCI 协议层面的通用支持，以及各 libretro 核心对内存映射的暴露程度。不同的模拟器核心在内存读取/写入功能上存在显著差异。\n\n## 架构通信流程\n\n```mermaid\ngraph TD\n    A[\"MCP 客户端<br/>(Claude Code 等)\"] -->|\"JSON-RPC/stdin\"| B[\"mcp-retroarch<br/>服务器进程\"]\n    B -->|\"UDP :55355<br/>NCI 命令\"| C[\"RetroArch<br/>网络控制接口\"]\n    C -->|\"LOADED CORE<br/>libretro 核心\"| D[\"GBA<br/>mgba_libretro\"]\n    C -->|\"LOADED CORE<br/>libretro 核心\"| E[\"NES<br/>mesen_libretro\"]\n    C -->|\"LOADED CORE<br/>libretro 核心\"| F[\"SNES<br/>snes9x_libretro\"]\n    C -->|\"LOADED CORE<br/>libretro 核心\"| G[\"PSX<br/>SwanStation\"]\n    \n    style B fill:#e1f5fe\n    style C fill:#fff3e0\n```\n\n## 已验证的核心\n\n### 核心兼容性总览\n\n| 系统 | 核心 | read_memory | read_ram | 备注 |\n|------|------|-------------|----------|------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA 中断向量表可见于 `0x0000` (显示 `d3 00 00 ea ...`) |\n| NES | `mesen_libretro` | ✅ | ✅ | 全 16 位 NES 地址空间暴露，WRAM 位于 `0x0000-0x07FF` 并镜像至 `0x1FFF`，CHEEVOS 限制在前 64 KB |\n| NES | `nestopia_libretro` | ❌ | ✅ | 无内存映射，仅支持 CHEEVOS，64 KB 限制 |\n| SNES | `snes9x_libretro` | ❌ | 待验证 | 需进一步测试 |\n| PlayStation | SwanStation | ❌ | ✅ | 需使用 `read_ram` |\n\n资料来源：[README.md:80-100]()\n\n### Game Boy Advance (mgba_libretro)\n\nGBA 核心是测试最充分的核心之一，其内存布局如下：\n\n| 内存区域 | 地址范围 | 大小 | 说明 |\n|----------|----------|------|------|\n| IWRAM | `0x03000000-0x03007FFF` | 32 KB | 内部工作 RAM |\n| EWRAM | `0x02000000-0x0203FFFF` | 256 KB | 外部工作 RAM |\n| ROM | 动态映射 | 可变 | 游戏卡带 ROM |\n| VRAM | `0x06000000-0x06017FFF` | 96 KB | 视频 RAM |\n\nGBA 核心通过 `READ_CORE_MEMORY` 命令完整暴露系统内存映射，中断向量表位于 `0x0000` 地址空间起始处，可通过 `retroarch_read_memory` 工具直接读取。资料来源：[README.md:84]()\n\n### NES (mesen_libretro)\n\nMesen 核心是 NES 平台的首选推荐，它提供完整的内存映射支持：\n\n| 地址范围 | 说明 |\n|----------|------|\n| `0x0000-0x07FF` | WRAM (2 KB，内部镜像至 `0x0800-0x1FFF`) |\n| `0x2000-0x3FFF` | PPU 寄存器 (I/O 寄存器) |\n| `0x4000-0x401F` | APU 和控制器寄存器 |\n\nNestopia 核心作为替代方案可用，但不支持 `READ_CORE_MEMORY`，只能通过 CHEEVOS 地址空间 (`read_ram`) 访问内存。资料来源：[README.md:88-92]()\n\n### PlayStation (SwanStation)\n\n对于 PlayStation 模拟，SwanStation 核心不支持 `READ_CORE_MEMORY`，需要使用 `retroarch_read_ram` 通过 CHEEVOS 地址空间读取内存。这种限制要求用户熟悉 PS1 的 CHEEVOS 地址规范。资料来源：[README.md:97]()\n\n## 内存访问 API 分层\n\nmcp-retroarch 提供两套内存访问接口，选择取决于目标核心的能力：\n\n```mermaid\ngraph LR\n    A[\"MCP 工具调用\"] --> B{核心是否支持<br/>系统内存映射?}\n    B -->|是| C[\"retroarch_read_memory<br/>retroarch_write_memory\"]\n    B -->|否| D[\"retroarch_read_ram<br/>retroarch_write_ram\"]\n    \n    C -->|\"READ_CORE_MEMORY<br/>WRITE_CORE_MEMORY\"| E[\"libretro 系统<br/>内存映射\"]\n    D -->|\"READ_CORE_RAM<br/>WRITE_CORE_RAM\"| F[\"CHEEVOS<br/>地址空间\"]\n```\n\n### READ_CORE_MEMORY / WRITE_CORE_MEMORY\n\n这是首选的内存访问方式，直接映射到 libretro 核心的原生系统内存布局：\n\n- **优势**：地址符合硬件实际架构（如 GBA EWRAM 位于 `0x02000000`）\n- **限制**：仅当核心广告内存映射时可用\n- **返回**：确认写入的字节数\n\n资料来源：[src/tools.ts:60-100]()\n\n### READ_CORE_RAM / WRITE_CORE_RAM\n\nCHEEVOS 地址空间，适用于不暴露系统内存映射的核心：\n\n- **优势**：即使核心无内存映射也能工作（RetroAchievements API 广泛支持）\n- **限制**：地址遵循 CHEEVOS 约定，非原生系统总线地址\n- **返回**：不确认写入成功（fire-and-forget 语义）\n\n资料来源：[src/tools.ts:130-170]()\n\n## 功能支持矩阵\n\n| 功能 | GBA (mgba) | NES (Mesen) | NES (Nestopia) | SNES | PSX |\n|------|------------|--------------|----------------|------|-----|\n| 内存读取 | ✅ 系统映射 | ✅ 系统映射 | ❌ 仅 CHEEVOS | ❌ | ❌ 仅 CHEEVOS |\n| 内存写入 | ✅ 系统映射 | ✅ 系统映射 | ❌ | ❌ | ❌ |\n| 存档状态 | ✅ | ✅ | ✅ | ✅ | ✅ |\n| 截图 | ✅ | ✅ | ✅ | ✅ | ✅ |\n| 暂停/帧推进 | ✅ | ✅ | ✅ | ✅ | ✅ |\n| 重置 | ✅ | ✅ | ✅ | ✅ | ✅ |\n| 屏幕消息 | ✅ | ✅ | ✅ | ✅ | ✅ |\n| 手柄输入 | ❌ | ❌ | ❌ | ❌ | ❌ |\n\n资料来源：[README.md:100-130]()\n\n## 核心选择建议\n\n### 内存操作场景\n\n```mermaid\ngraph TD\n    A[\"需要内存读写\"] --> B{\"哪个平台?\"}\n    B -->|GBA| C[\"使用 mgba_libretro<br/>首选 read_memory\"]\n    B -->|NES| D[\"使用 mesen_libretro<br/>首选 read_memory\"]\n    B -->|PSX| E[\"使用 SwanStation<br/>使用 read_ram\"]\n    B -->|其他| F[\"查阅核心文档<br/>尝试 read_memory 后 fallback\"]\n```\n\n对于 **GBA + 内存操作**：强烈推荐 `mgba_libretro`，它完整暴露内存映射且经过充分测试。\n\n对于 **NES + 内存操作**：推荐 `mesen_libretro` 而非 `nestopia_libretro`，前者支持系统内存映射，后者仅支持 CHEEVOS。\n\n对于 **PSX + 内存操作**：使用 `read_ram` (CHEEVOS 路径)，SwanStation 不暴露系统内存映射。\n\n资料来源：[README.md:90-92]()\n\n## 环境配置\n\n核心功能依赖于 RetroArch 网络控制接口的正确配置：\n\n```ini\n# retroarch.cfg 必要配置\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n| 环境变量 | 默认值 | 说明 |\n|----------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机 |\n| `RETROARCH_PORT` | `55355` | UDP 端口（必须与 retroarch.cfg 中的 `network_cmd_port` 匹配） |\n\n资料来源：[README.md:60-75]()\n\n## 已知限制\n\n### 核心无关限制\n\n- **游戏手柄输入**：NCI 协议不暴露手柄输入功能。RetroArch 有独立的 \"Remote RetroPad\" 核心（UDP 端口 55400），但需要加载特定核心，无法驱动现有模拟核心。GBA 平台的手柄输入可参考 [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) 项目。资料来源：[README.md:130-135]()\n\n- **存档槽位写入**：NCI 协议仅暴露\"保存到当前槽位\"命令，无法直接指定目标槽位。需使用 `state_slot_plus` / `state_slot_minus` 遍历到目标槽位后再保存。资料来源：[README.md:145-148]()\n\n- **截图目录查询**：NCI 不通过 `GET_CONFIG_PARAM` 暴露 `screenshot_directory`，需通过 RetroArch GUI (Settings → Directory → Screenshot) 确认。资料来源：[README.md:140-143]()\n\n### 特定核心限制\n\n| 限制 | 影响核心 | 原因 |\n|------|----------|------|\n| 无系统内存映射 | `nestopia_libretro` | 核心设计选择 |\n| 无系统内存映射 | SwanStation | 核心设计选择 |\n| 仅支持 CHEEVOS | 多个核心 | 兼容性和硬件限制 |\n\n## 相关项目\n\nmcp-retroarch 专注于通过 RetroArch NCI 控制模拟器。如需特定平台的高级功能，可参考相关项目：\n\n| 项目 | 平台 | 特性 |\n|------|------|------|\n| [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | Game Boy Advance | 通过 mGBA Lua 桥接，支持手柄输入和截图 |\n| [mcp-pine](https://github.com/dmang-dev/mcp-pine) | PCSX2 等 | 通过 PINE 协议，支持内存和存档状态 |\n\n资料来源：[README.md:150-155]()\n\n## 故障排除\n\n| 症状 | 原因/解决方案 |\n|------|---------------|\n| `RetroArch query timed out` | 网络命令未启用或端口不匹配，检查 `network_cmd_enable = \"true\"` |\n| `READ_CORE_MEMORY failed: no memory map defined` | 核心不支持系统内存映射，尝试 `retroarch_read_ram` |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址不在核心内存映射范围内，需更换核心或确认地址 |\n| Screenshots don't appear | 截图保存至 RetroArch 配置的截图目录，通过 GUI 确认路径 |\n\n资料来源：[README.md:110-145]()\n\n---\n\n<a id='memory-access'></a>\n\n## 内存访问机制\n\n### 相关页面\n\n相关主题：[MCP 工具参考](#mcp-tools-reference), [支持的模拟器核心](#supported-cores)\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- [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- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n</details>\n\n# 内存访问机制\n\n## 概述\n\nmcp-retroarch 通过 RetroArch 的网络控制接口（NCI）与模拟器进行通信，提供对模拟器内存的读写访问能力。该项目实现了两种独立的内存读取路径，分别对应不同的底层 API，适用于不同的应用场景和模拟器核心。\n\nmcp-retroarch 的内存访问机制是 MCP 工具服务器的核心功能之一，允许 AI 客户端直接读取和修改模拟器运行时的内存状态，从而实现游戏状态检查、作弊注入、调试辅助等高级功能。\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 架构概览\n\n```\n┌─────────────────┐     stdio/JSON-RPC     ┌──────────────────┐    UDP :55355    ┌─────────────────┐\n│    MCP 客户端    │ ◄────────────────────► │   mcp-retroarch  │ ◄──────────────► │   RetroArch     │\n│  (Claude Code)  │                        │   (Node.js)      │                   │   NCI 接口      │\n└─────────────────┘                        └──────────────────┘                   └─────────────────┘\n                                                    │\n                                          ┌─────────┴─────────┐\n                                          │                   │\n                                    ┌─────▼─────┐       ┌─────▼─────┐\n                                    │ READ_CORE │       │ READ_CORE │\n                                    │ _MEMORY   │       │ _RAM      │\n                                    │ (系统内存) │       │ (CHEEVOS) │\n                                    └───────────┘       └───────────┘\n```\n\n## 两种内存 API 的区分\n\nmcp-retroarch 实现了两套独立的内存访问 API，分别对应不同的底层协议和地址空间：\n\n| 特性 | `retroarch_read_memory` / `retroarch_write_memory` | `retroarch_read_ram` / `retroarch_write_ram` |\n|------|---------------------------------------------------|---------------------------------------------|\n| 底层协议 | `CMD_CORE_MEMORY`（READ_CORE_MEMORY / WRITE_CORE_MEMORY） | `READ_CORE_RAM`（CHEEVOS API） |\n| 地址空间 | libretro 核心声明的系统内存映射 | RetroAchievements 的 CHEEVOS 地址空间 |\n| 适用场景 | 需要精确系统总线地址时（如 GBA EWRAM、SNES WRAM） | 核心未暴露系统内存映射时的备用方案 |\n| 核心兼容性 | 仅部分核心支持（如 Mesen libretro） | 大多数核心均支持（即使没有内存映射） |\n| 写入确认 | **有**（返回写入字节数） | **无**（fire-and-forget，无确认） |\n\n资料来源：[README.md - Tested cores](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### READ_CORE_MEMORY（系统内存映射）\n\n该 API 通过 libretro 核心声明的系统内存描述符列表进行访问，返回的地址对应真实的系统总线地址。\n\n典型地址布局示例：\n\n| 系统 | 地址范围 | 说明 |\n|------|----------|------|\n| SNES | `0x7E0000-0x7FFFFF` | SNES 内部 WRAM |\n| GBA | `0x02000000-0x0203FFFF` | GBA 外部工作内存（EWRAM） |\n| Genesis | `0xFF0000-0xFFFFFF` | MC68000 主内存 |\n\n资料来源：[src/tools.ts:46-48](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### READ_CORE_RAM（CHEEVOS 地址空间）\n\n该 API 通过 RetroAchievements 的地址映射进行内存访问，适用于那些没有完整系统内存映射但启用了成就系统的模拟器核心。\n\nCHEEVOS 地址空间与系统总线地址使用不同的映射规则，例如 SNES CHEEVOS 地址空间中 WRAM 起始地址为 `0x000000`，而非系统总线的 `0x7E0000`。\n\n资料来源：[src/tools.ts:74-78](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## 核心实现\n\n### UDP 传输层\n\n内存访问通过 UDP 数据报实现，核心代码位于 `RetroArch` 类中：\n\n```typescript\n// 连接建立\nasync connect(): Promise<void> {\n  const sock = dgram.createSocket(\"udp4\");\n  // ... socket 初始化逻辑\n}\n\n// 查询并等待响应\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\");\n  }\n  // ... 超时处理和响应接收\n}\n```\n\n资料来源：[src/retroarch.ts:16-58](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n### 内存读取实现\n\n```typescript\nasync readMemory(address: number, length: number): Promise<Buffer> {\n  const cmd = `READ_CORE_MEMORY ${address} ${length}`;\n  return this.query(cmd);\n}\n\nasync readRam(address: number, length: number): Promise<Buffer> {\n  const cmd = `READ_CORE_RAM ${address} ${length}`;\n  return this.query(cmd);\n}\n```\n\n资料来源：[src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n### 内存写入实现\n\n两种写入 API 在确认机制上存在关键差异：\n\n| API | 返回值 | 说明 |\n|-----|--------|------|\n| `writeMemory` | 写入字节数 | RetroArch 协议会返回实际写入的字节数 |\n| `writeRam` | 无确认 | CHEEVOS API 不返回确认，属于 fire-and-forget 模式 |\n\n资料来源：[src/tools.ts:58-60](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## MCP 工具定义\n\n### retroarch_read_memory\n\n```json\n{\n  \"name\": \"retroarch_read_memory\",\n  \"description\": \"PURPOSE: 读取系统内存映射中的字节序列...\",\n  \"inputSchema\": {\n    \"type\": \"object\",\n    \"required\": [\"address\", \"length\"],\n    \"properties\": {\n      \"address\": {\n        \"type\": \"integer\",\n        \"minimum\": 0,\n        \"description\": \"libretro 核心系统内存映射中的起始地址...\"\n      },\n      \"length\": {\n        \"type\": \"integer\",\n        \"minimum\": 1,\n        \"maximum\": 4096,\n        \"description\": \"连续读取的字节数 (1-4096)\"\n      }\n    }\n  }\n}\n```\n\n### retroarch_read_ram\n\n```json\n{\n  \"name\": \"retroarch_read_ram\",\n  \"description\": \"PURPOSE: 通过 CHEEVOS 地址空间读取最多 4096 字节...\",\n  \"inputSchema\": {\n    \"type\": \"object\",\n    \"required\": [\"address\", \"length\"],\n    \"properties\": {\n      \"address\": {\n        \"type\": \"integer\",\n        \"minimum\": 0,\n        \"description\": \"CHEEVOS（成就）地址空间中的起始地址...\"\n      },\n      \"length\": {\n        \"type\": \"integer\",\n        \"minimum\": 1,\n        \"maximum\": 4096\n      }\n    }\n  }\n}\n```\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## 核心兼容性矩阵\n\n| 系统 | 核心 | `read_memory` | `read_ram` | 备注 |\n|------|------|-------------|-----------|------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA 中断向量表可见于 `0x0000` |\n| NES | `mesen_libretro` | ✅ | ✅ | 完整 16 位 NES 地址空间暴露 |\n| NES | `nestopia_libretro` | ❌ 无内存映射 | ✅ | 仅支持 CHEEVOS |\n| SNES | `snes9x_libretro` | ❌ | ❌ | 暂不支持 |\n\n资料来源：[README.md - Tested cores](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 行为特性与限制\n\n### 单次调用字节限制\n\n所有内存访问工具的单次调用最大字节数均为 **4096 字节**，这是 RetroArch NCI 单数据报大小的硬性限制。超出此限制的操作需要分块进行：\n\n```\n建议分块大小: 4 KiB (4096 bytes)\n对于大型写入操作，请按 4 KiB 分块批量处理\n```\n\n资料来源：[src/tools.ts:52](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### 内存区域边界\n\nRetroArch 可能在读取跨越内存区域边界时返回**少于请求的字节数**，响应中会报告实际返回的字节数。\n\n```typescript\n// 可能返回 fewer bytes than requested\nconst bytes = await ra.readMemory(address, length);\n// bytes.length <= length\n```\n\n### Fire-and-forget 语义\n\n除 `writeMemory` 外，大多数 NCI 命令不会返回确认。返回的成功消息仅表示 UDP 数据报已发送，**不表示** RetroArch 已接收或执行了该命令：\n\n> RetroArch's NCI doesn't acknowledge most state mutations. Every affected tool's BEHAVIOR section now warns that the success message is a UDP-send confirmation only, NOT verification that RetroArch received or acted on the command.\n\n资料来源：[CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n\n### 硬核模式副作用\n\n任何内存写入操作（`write_memory` 或 `write_ram`）都会自动禁用 RetroArch 的硬核模式（Hardcore Mode），这是 RetroArch 协议层面的安全机制。\n\n资料来源：[src/tools.ts:58-60](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### 状态修改警告\n\n内存写入是**破坏性操作**，会直接覆盖从 `address` 开始的 N 个字节，且无撤销功能。建议在执行写入前使用 `retroarch_save_state_current` 创建还原点：\n\n```typescript\n// 建议的工作流程\nawait ra.saveStateCurrent();           // 1. 保存还原点\nawait ra.writeMemory(address, bytes);   // 2. 执行写入\n// ... 验证操作 ...\nawait ra.loadStateCurrent();            // 3. 如需回滚\n```\n\n## 故障排查\n\n| 症状 | 原因 / 解决方案 |\n|------|----------------|\n| `READ_CORE_MEMORY failed: no memory map defined` | 加载的 libretro 核心未声明系统内存映射，尝试改用 `retroarch_read_ram` |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址不在核心内存描述符覆盖范围内 |\n| UDP 查询超时 | 确认 RetroArch 中 Network Commands 已启用，`network_cmd_enable = \"true\"` |\n| 返回字节数少于请求 | 读取跨越了内存区域边界，这是协议正常行为 |\n\n资料来源：[README.md - Troubleshooting](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 环境配置\n\n| 环境变量 | 默认值 | 说明 |\n|----------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机 |\n| `RETROARCH_PORT` | `55355` | UDP 端口（需与 `retroarch.cfg` 中的 `network_cmd_port` 匹配） |\n\n资料来源：[README.md - Configuration](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n<a id='state-management'></a>\n\n## 状态管理\n\n### 相关页面\n\n相关主题：[MCP 工具参考](#mcp-tools-reference)\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- [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# 状态管理\n\n## 概述\n\nmcp-retroarch 通过 UDP 网络协议与 RetroArch 的网络控制接口（NCI）通信，实现对模拟器的状态监控与控制。状态管理涵盖四个核心维度：**连接状态**、**查询状态机**、**模拟器运行状态**以及**存档槽位状态**。\n\n## 架构概览\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│                        mcp-retroarch                                 │\n│  ┌─────────────┐    ┌──────────────────┐    ┌────────────────────┐ │\n│  │ MCP Client  │───▶│  tools.ts        │───▶│  retroarch.ts      │ │\n│  │ (Claude等)  │◀───│  (工具定义)      │◀───│  (NCI通信层)       │ │\n│  └─────────────┘    └──────────────────┘    └─────────┬─────────┘ │\n│                                                       │           │\n│                                              ┌────────▼─────────┐  │\n│                                              │   UDP Socket     │  │\n│                                              │  (dgram模块)     │  │\n│                                              └────────┬─────────┘  │\n└───────────────────────────────────────────────────────┼─────────────┘\n                                                        │\n                                              UDP :55355│\n                                                        ▼\n                                              ┌─────────────────────┐\n                                              │  RetroArch NCI      │\n                                              │  (网络控制接口)      │\n                                              └─────────────────────┘\n```\n\n## 连接状态管理\n\n### 连接生命周期\n\n`RetroArch` 类通过 `connect()` 方法初始化 UDP socket，该方法返回一个 Promise，确保 socket 绑定完成后再进行后续操作。\n\n**关键状态字段：**\n\n| 字段 | 类型 | 说明 |\n|------|------|------|\n| `socket` | `dgram.Socket \\| null` | UDP socket 引用 |\n| `pending` | `((msg: Buffer) => void) \\| null` | 待处理的查询回调 |\n| `host` | `string` | 目标主机地址 |\n| `port` | `number` | 目标 UDP 端口 |\n| `timeoutMs` | `number` | 查询超时时间 |\n\n**初始化流程（源码第15-31行）：**\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;       // 无待处理回调时丢弃\n        this.pending = null;\n        cb(msg);\n      });\n      sock.on(\"error\", () => { /* 静默忽略后续错误 */ });\n      this.socket = sock;\n      resolve();\n    });\n  });\n}\n```\n\n### 连接配置\n\n通过环境变量控制连接目标：\n\n| 环境变量 | 默认值 | 说明 |\n|----------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机 |\n| `RETROARCH_PORT` | `55355` | UDP 端口（需与 RetroArch 配置匹配） |\n\n资料来源：[README.md:配置段落]() \n\n### 断开连接\n\n```typescript\ndisconnect(): void {\n  this.socket?.close();\n  this.socket = null;\n}\n```\n\n资料来源：[src/retroarch.ts:disconnect方法]() \n\n## 查询状态机\n\n### 请求-响应模型\n\nmcp-retroarch 实现了一个**串行查询状态机**：同一时间只允许一个查询在飞行中（in-flight）。这是 UDP 无连接特性的必然要求。\n\n**状态转换图：**\n\n```mermaid\ngraph TD\n    A[空闲] -->|query调用| B[查询中 pending]\n    B -->|收到响应| A\n    B -->|超时| C[错误: query timed out]\n    C -->|重试| A\n    A -->|query调用| B\n    B -->|send时socket未连接| D[自动connect]\n    D --> B\n```\n\n### query 方法实现\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    this.socket!.send(command, this.port, this.host, (err) => {\n      if (err) {\n        if (timer) { clearTimeout(timer); timer = null; }\n        this.pending = null;\n        reject(err);\n      }\n    });\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:query方法:73-99行]()\n\n### 两种发送模式\n\n| 模式 | 方法 | 用途 | 等待响应 |\n|------|------|------|----------|\n| **查询模式** | `query()` | 读取数据（状态、内存、配置） | ✅ 等待 UDP 响应 |\n| **发送模式** | `send()` | 发送命令（暂停、重置、截图） | ❌ 防火遗忘 |\n\n```typescript\n/** 防火遗忘发送，用于热键类命令 */\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:send方法:54-61行]()\n\n## 模拟器状态管理\n\n### 状态查询\n\n通过 `getStatus()` 方法获取 RetroArch 当前运行状态：\n\n```typescript\nasync getStatus(): Promise<EmuStatus> {\n  const r = (await this.query(\"GET_STATUS\")).toString().trim();\n  // 响应格式: \"GET_STATUS PAUSED system_id,game_basename,crc32=XXXXXXXX\"\n  const m = r.match(/^GET_STATUS\\s+(\\w+)(?:\\s+([^,]+),(.+?)(?:,crc32=([0-9A-Fa-f]+))?)?/);\n  // ...\n}\n```\n\n资料来源：[src/retroarch.ts:getStatus方法]() \n\n### 状态类型定义\n\n```typescript\ninterface EmuStatus {\n  state: \"playing\" | \"paused\" | \"contentless\";\n  system?: string;   // 系统标识符\n  game?: string;     // 游戏文件名\n  crc32?: string;    // CRC32 校验值\n}\n```\n\n### 状态值说明\n\n| 状态值 | 含义 | 触发条件 |\n|--------|------|----------|\n| `playing` | 模拟器正在运行游戏 | 加载 ROM 后未暂停 |\n| `paused` | 模拟器暂停 | 用户按暂停或调用 `pause_toggle` |\n| `contentless` | 无内容加载 | RetroArch 在主菜单未加载任何游戏 |\n\n## 存档槽位状态管理\n\n### 存档操作命令\n\n| 操作 | 命令 | 方法 | 槽位支持 |\n|------|------|------|----------|\n| 保存当前槽 | `SAVE_STATE` | `saveStateCurrent()` | 仅当前槽 |\n| 加载当前槽 | `LOAD_STATE` | `loadStateCurrent()` | 仅当前槽 |\n| 加载指定槽 | `LOAD_STATE N` | `loadStateSlot(n)` | 显式槽位号 |\n| 槽位+1 | `STATE_SLOT_PLUS` | `stateSlotPlus()` | 移动指针 |\n| 槽位-1 | `STATE_SLOT_MINUS` | `stateSlotMinus()` | 移动指针 |\n\n### 槽位指针机制\n\nNCI 协议仅暴露当前槽位指针的移动操作，不支持直接跳转到指定槽位：\n\n```mermaid\ngraph LR\n    A[槽位0] -->|STATE_SLOT_PLUS| B[槽位1]\n    B -->|STATE_SLOT_PLUS| C[槽位2]\n    C -->|STATE_SLOT_MINUS| B\n    B -->|SAVE_STATE| D[保存到槽位1]\n```\n\n### 工具层实现\n\n```typescript\ncase \"retroarch_save_state_current\":  \n  await ra.saveStateCurrent();          \n  return ok(\"Saved to current slot\");\ncase \"retroarch_load_state_current\":  \n  await ra.loadStateCurrent();          \n  return ok(\"Loaded from current slot\");\ncase \"retroarch_load_state_slot\":     \n  await ra.loadStateSlot(p.slot as number); \n  return ok(`Loaded from slot ${p.slot}`);\n```\n\n资料来源：[src/tools.ts:存档相关工具:130-136行]()\n\n## 内存访问状态\n\n### 双路径内存读取\n\n| 路径 | 命令 | 用途 | 适用场景 |\n|------|------|------|----------|\n| **READ_CORE_MEMORY** | `readMemory()` | 系统内存映射（优先） | 支持 memory map 的核心 |\n| **READ_CORE_RAM** | `readRam()` | CHEEVOS 地址空间（备用） | 无 memory map 的核心 |\n\n### 写入确认机制\n\n两种写入方法的确认行为不同：\n\n| 方法 | 返回确认 | 说明 |\n|------|----------|------|\n| `writeMemory()` | ✅ 返回写入字节数 | NCI 会响应写入计数 |\n| `writeRam()` | ❌ 无确认 | 纯防火遗忘 |\n\n```typescript\ncase \"retroarch_write_memory\": {\n  const n = await ra.writeMemory(p.address as number, p.bytes as number[]);\n  return ok(`Wrote ${n} bytes → ${addrHex(p.address as number)}`);\n}\n\ncase \"retroarch_write_ram\": {\n  await ra.writeRam(p.address as number, p.bytes as number[]);\n  return ok(`Wrote ${(p.bytes as number[]).length} bytes → ${addrHex(p.address as number)} (CHEEVOS, no ack)`);\n}\n```\n\n资料来源：[src/tools.ts:内存写入工具:45-55行]()\n\n## 错误处理与超时\n\n### 超时配置\n\n```typescript\nconst DEFAULT_TIMEOUT_MS = 5000;\n\nasync query(command: string): Promise<Buffer> {\n  // ... 5秒超时后 reject\n}\n```\n\n### 错误类型\n\n| 错误场景 | 错误信息 | 处理建议 |\n|----------|----------|----------|\n| 超时 | `RetroArch query \"XXX\" timed out after 5000ms` | 确认 RetroArch 运行且网络命令已启用 |\n| 并发冲突 | `retroarch query already in flight` | 等待前一个查询完成 |\n| 连接失败 | Socket error | 检查 `RETROARCH_HOST`/`RETROARCH_PORT` |\n\n### 后台连接探测\n\n`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\n资料来源：[src/index.ts:启动代码段]() \n\n## 状态管理最佳实践\n\n### 已知状态再操作\n\n由于大多数 NCI 命令为防火遗忘，操作前应先查询状态：\n\n```mermaid\ngraph TD\n    A[获取状态] --> B{状态是什么?}\n    B -->|playing| C[暂停]\n    B -->|paused| D[确认后再暂停]\n    C --> E[执行目标操作]\n    D --> E\n```\n\n### 破坏性操作前存档\n\n```typescript\n// 内存写入前保存当前状态\nawait ra.saveStateCurrent();           // 建立回滚点\nawait ra.writeMemory(addr, bytes);     // 执行写入\n// 出错时加载恢复\nawait ra.loadStateCurrent();\n```\n\n### 帧精确控制\n\n```typescript\n// 确保暂停状态\nconst status = await ra.getStatus();\nif (status.state === \"playing\") {\n  await ra.pauseToggle();\n}\n// 单帧步进\nawait ra.frameAdvance();\n```\n\n## 总结\n\nmcp-retroarch 的状态管理建立在三个核心机制之上：\n\n1. **串行查询状态机**：通过 `pending` 回调确保 UDP 响应的正确路由\n2. **双模式发送**：区分需要响应的 `query()` 和防火遗忘的 `send()`\n3. **状态同步**：工具层将 NCI 的文本响应解析为结构化状态对象供 MCP 客户端使用\n\n---\n\n<a id='troubleshooting'></a>\n\n## 故障排除\n\n### 相关页面\n\n相关主题：[RetroArch 集成](#retroarch-integration), [支持的模拟器核心](#supported-cores)\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</details>\n\n# 故障排除\n\n本文档整理了 `mcp-retroarch` 在实际使用过程中可能遇到的常见问题、错误信息及其解决方案。`mcp-retroarch` 通过 RetroArch 的网络控制接口（NCI）与模拟器通信，任何影响网络连接或 NCI 配置的问题都可能导致工具调用失败。\n\n---\n\n## 连接与通信问题\n\n### RetroArch 查询超时\n\n**症状：** 调用任意工具时返回 `RetroArch query timed out` 错误。\n\n**原因分析：**\n\n- RetroArch 端的网络命令（Network Commands）未启用\n- `mcp-retroarch` 的 `RETROARCH_PORT` 环境变量与 RetroArch 的 `network_cmd_port` 配置不匹配\n- UDP 数据报在高负载下可能被丢弃（即使是本地回环地址）\n\n**排查步骤：**\n\n1. 确认 RetroArch 已启用网络命令功能\n2. 验证端口配置一致性\n3. 考虑重试机制\n\n**解决方案：**\n\n1. 在 RetroArch GUI 中启用：**Settings → Network → Network Commands → ON**，确认 `Network Cmd Port` 为 `55355`（默认值）\n2. 或在 `retroarch.cfg` 中配置：\n   ```ini\n   network_cmd_enable = \"true\"\n   network_cmd_port   = \"55355\"\n   ```\n3. 启动任意 libretro 核心和游戏后，NCI 即处于可用状态，无需额外脚本加载\n\n环境变量配置对照表：\n\n| 环境变量 | 默认值 | 说明 |\n|---------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机 |\n| `RETROARCH_PORT` | `55355` | UDP 端口，需与 `retroarch.cfg` 中的 `network_cmd_port` 匹配 |\n\n资料来源：[README.md:40-47](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n### RetroArch 不可达时的启动行为\n\n**说明：** `mcp-retroarch` 服务器启动时不会因 RetroArch 不可达而失败，而是采用后台探测机制。\n\n**启动日志示例：**\n\n```\n[mcp-retroarch] MCP server ready (stdio)\n[mcp-retroarch] connected to 127.0.0.1:55355 — RetroArch <version>\n```\n\n如果 RetroArch 尚未就绪，服务器仍会启动并在标准错误输出中打印提示信息：\n\n```\n[mcp-retroarch] note: RetroArch not reachable yet (127.0.0.1:55355): <error>\n             Enable Network Commands in retroarch.cfg (network_cmd_enable / network_cmd_port)\n             or Settings > Network > Network Commands. Tool calls will connect on demand.\n```\n\n工具调用会在需要时按需连接，无需重启服务器。\n\n资料来源：[src/index.ts:10-19](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n---\n\n## 内存读取问题\n\n### 错误：no memory map defined\n\n**症状：** 调用 `retroarch_read_memory` 返回 `READ_CORE_MEMORY failed: no memory map defined`。\n\n**原因分析：** 当前加载的 libretro 核心未通过 `READ_CORE_MEMORY` 命令公开系统内存映射。这是核心级别的限制，并非 `mcp-retroarch` 的缺陷。\n\n**解决方案：**\n\n切换到 `retroarch_read_ram`（CHEEVOS 路径）。许多核心即使没有完整的内存映射，也会暴露 CHEEVOS 读写接口。\n\n| 已验证核心 | 推荐工具 | 备注 |\n|-----------|----------|------|\n| SwanStation (PSX) | `read_ram` | 使用 CHEEVOS 地址空间 |\n| Game Boy Advance (mgba_libretro) | `read_memory` | 支持完整内存映射 |\n| NES (Mesen) | `read_memory` 或 `read_ram` | 两者均支持 |\n| NES (Nestopia) | `read_ram` | 仅 CHEEVOS，无内存映射 |\n\n**核心选择建议：** 对于 NES + 内存映射需求，优先选择 Mesen 核心。\n\n资料来源：[README.md:80-93](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n### 错误：no descriptor for address\n\n**症状：** 调用 `retroarch_read_memory` 返回 `READ_CORE_MEMORY failed: no descriptor for address`。\n\n**原因分析：** 请求的地址不在核心内存映射的覆盖范围内。\n\n**可能原因：**\n\n- 该核心不支持访问目标地址区域\n- 目标地址属于系统总线之外的区域（如某些核心的视频内存）\n\n**解决方案：**\n\n- 尝试使用 `retroarch_read_ram` 作为替代方案\n- 检查目标地址是否在目标平台的已知内存范围内（如 GBA 的 EWRAM 位于 `0x02000000-0x0203FFFF`）\n- 考虑更换为支持该地址区域的核心\n\n资料来源：[README.md:94-98](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n### 内存读取返回值说明\n\n`retroarch_read_memory` 成功时返回格式如下：\n\n```\nADDR_HEX [N bytes]: <hex dump>\n```\n\n其中十六进制数据采用空格分隔的大写两字符格式。\n\n`retroarch_read_ram` 返回格式类似，但包含 `(CHEEVOS)` 标记以区分地址空间：\n\n```\nADDR_HEX [N bytes, CHEEVOS]: <hex dump>\n```\n\n**限制：** RetroArch 可能返回少于请求的字节数，特别是在读取跨越内存区域边界时。响应会报告实际返回的字节数。\n\n资料来源：[src/tools.ts:28-33](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n---\n\n## 存档与状态管理问题\n\n### 无法直接保存到指定存档槽\n\n**症状：** 需要将游戏状态保存到特定的存档槽（如槽位 5），但协议似乎不支持直接指定。\n\n**说明：** 这是 NCI 协议本身的限制，而非 `mcp-retroarch` 的 bug。NCI 仅提供\"保存到当前槽\"命令，不支持指定槽位号。\n\n**解决方案：**\n\n使用 `state_slot_plus` 和 `state_slot_minus` 逐步移动槽位指针到目标位置，然后调用 `retroarch_save_state_current` 保存。\n\n**操作序列示例：**\n\n1. `retroarch_state_slot_minus` — 减少槽位指针\n2. `retroarch_save_state_current` — 保存到当前槽位\n3. 重复上述步骤直到到达目标槽位\n\n**注意：** 由于 UDP 的\"即发即忘\"特性，大多数状态变更命令不会收到 RetroArch 的确认。调用成功仅表示 UDP 数据报已发送，不保证 RetroArch 已接收或执行。\n\n资料来源：[README.md:99-103](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n### 存档状态加载后状态不确定\n\n**症状：** 调用 `retroarch_load_state_current` 或 `retroarch_load_state_slot` 后，不确定当前状态是否已正确加载。\n\n**说明：** 这些命令执行的是破坏性操作，会覆盖当前游戏状态。NCI 不返回操作结果确认。\n\n**建议：** 在执行可能覆盖状态的操作前，先使用 `retroarch_save_state_current` 创建还原点。\n\n资料来源：[src/tools.ts:55-56](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n---\n\n## 截图与文件系统问题\n\n### 截图保存位置不符合预期\n\n**症状：** 调用 `retroarch_screenshot` 后，截图未出现在预期目录。\n\n**原因分析：** RetroArch 会将截图保存到其配置的截图目录，而非项目工作目录或固定路径。\n\n**重要限制：** NCI 协议不通过 `GET_CONFIG_PARAM` 暴露 `screenshot_directory` 参数，因此 `mcp-retroarch` 无法动态获取该路径。\n\n**解决方案：**\n\n1. 在 RetroArch GUI 中确认截图目录：**Settings → Directory → Screenshot**\n2. 或通过 `retroarch_get_config` 查看其他已暴露的目录配置（`savestate_directory`、`savefile_directory` 等）\n\n**可用配置查询示例：**\n\n| 配置项 | 返回类型 | 说明 |\n|--------|----------|------|\n| `screenshot_directory` | ❌ 不可用 | NCI 不暴露此项 |\n| `savefile_directory` | 路径 | 存档文件目录 |\n| `savestate_directory` | 路径 | 存档状态目录 |\n| `system_directory` | 路径 | 系统目录 |\n\n资料来源：[README.md:94-98](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n## 模拟器状态问题\n\n### 暂停与帧推进行为\n\n**说明：** RetroArch 的 NCI 仅提供 `PAUSE_TOGGLE` 命令，不提供独立的暂停/恢复命令。\n\n**影响：** 如果不确定当前状态，调用 `PAUSE_TOGGLE` 可能产生非预期结果。\n\n**正确使用方式：**\n\n```mermaid\ngraph TD\n    A[查询 retroarch_get_status] --> B{当前状态?}\n    B -->|playing| C[调用 pause_toggle 暂停]\n    B -->|paused| D[调用 pause_toggle 恢复]\n    C --> E[执行内存操作]\n    D --> E\n    E --> F[可选: frame_advance 单帧推进]\n    F --> G[使用 save_state_current 保存还原点]\n```\n\n**帧推进限制：** `FRAMEADVANCE` 命令仅在模拟器处于暂停状态时有效。如果模拟器正在运行，调用此命令不会有任何效果。\n\n资料来源：[src/tools.ts:53-54](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n---\n\n## 网络与协议层问题\n\n### UDP 通信的固有限制\n\n**特性说明：** RetroArch 的 NCI 基于 UDP 协议，UDP 具有以下固有特性：\n\n| 特性 | 影响 |\n|------|------|\n| 无连接 | 不建立握手，可能发送成功但对方未收到 |\n| 无确认机制 | 大多数命令不会收到 RetroArch 的回复 |\n| 可能丢包 | 高负载下数据报可能丢失 |\n\n**工具返回值的含义：**\n\n- `retroarch_write_memory`：唯一返回写入字节数的命令（`Wrote N bytes → ADDR_HEX`）\n- 其他状态变更命令：仅表示 UDP 数据报已发送，不代表 RetroArch 已处理\n\n资料来源：[CHANGELOG.md:17-27](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n\n---\n\n### 命令处理流程\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP 客户端\n    participant Bridge as mcp-retroarch\n    participant RA as RetroArch NCI\n\n    MCP->>Bridge: JSON-RPC 请求\n    Bridge->>Bridge: 参数验证\n    Bridge->>RA: UDP 命令\n    RA-->>Bridge: UDP 响应 (仅查询命令)\n    Bridge-->>MCP: JSON-RPC 响应\n\n    Note over Bridge: 即发即忘命令无响应\n    MCP->>Bridge: 状态变更命令\n    Bridge->>RA: UDP 命令\n    Bridge-->>MCP: 发送成功确认\n```\n\n资料来源：[src/retroarch.ts:48-57](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n---\n\n## 开发与调试\n\n### 本地开发环境\n\n**项目初始化：**\n\n```bash\nnpm install\nnpm run dev      # tsc --watch\n```\n\n**烟雾测试：** 可使用测试脚本验证与运行中的 RetroArch 的连接：\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n**依赖信息：**\n\n| 依赖 | 版本 | 用途 |\n|------|------|------|\n| `@modelcontextprotocol/sdk` | ^1.12.0 | MCP 协议实现 |\n| `@types/node` | ^22.0.0 | TypeScript 类型 |\n| `typescript` | ^5.5.0 | 编译工具 |\n\n资料来源：[package.json:18-25](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n---\n\n## 快速问题对照表\n\n| 症状 | 最可能的原因 | 首选解决方案 |\n|------|-------------|-------------|\n| 所有工具超时 | 网络命令未启用 | 启用 Network Commands |\n| `read_memory` 失败 | 核心无内存映射 | 改用 `read_ram` |\n| `read_memory` 报地址错误 | 地址超出映射范围 | 检查核心文档或换核心 |\n| 截图位置不对 | 默认截图目录配置 | 查看 RetroArch GUI 目录设置 |\n| 无法保存到指定槽 | NCI 协议限制 | 用 `state_slot_plus/minus` 移动指针 |\n| 暂停状态不确定 | 未先查询状态 | 调用 `get_status` 确认后再操作 |\n\n---\n\n## 相关文档\n\n- [RetroArch NCI 官方文档](https://docs.libretro.com/development/retroarch/network-control-interface/)\n- [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) — GBA 专用方案（含手柄输入）\n- [mcp-pine](https://github.com/dmang-dev/mcp-pine) — PCSX2 等 PINE 协议模拟器\n\n---\n\n<a id='development-guide'></a>\n\n## 开发指南\n\n### 相关页面\n\n相关主题：[项目概述](#project-overview)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\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/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# 开发指南\n\n本文档面向希望参与 mcp-retroarch 项目开发的工程师，介绍项目架构、本地开发环境配置、核心模块说明以及发布流程。\n\n## 项目概述\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的服务端实现，通过 RetroArch 的 Network Control Interface (NCI) 与模拟器通信。项目以 TypeScript 编写，通过 stdio 与 MCP 客户端交换 JSON-RPC 消息，实现对 RetroArch 的远程控制功能。\n\n核心能力包括：\n\n| 功能类别 | 支持情况 | 说明 |\n|---|---|---|\n| 内存读写 | ✅ | `READ_CORE_MEMORY`（系统内存映射）和 `READ_CORE_RAM`（CHEEVOS 地址空间）两种路径 |\n| 存档管理 | ✅ | 当前槽位或指定槽位加载；保存仅支持当前槽位 |\n| 截图 | ✅ | 保存至 RetroArch 配置的截图目录 |\n| 暂停/帧推进 | ✅ | `PAUSE_TOGGLE` 切换状态；`FRAMEADVANCE` 单步一帧 |\n| 重置 | ✅ | 硬重启当前运行游戏 |\n| 屏幕消息 | ✅ | 在 RetroArch 窗口显示通知 |\n| 游戏手柄输入 | ❌ | NCI 协议不暴露此功能 |\n\n资料来源：[README.md: Features]()\n\n## 项目结构\n\n```\nmcp-retroarch/\n├── src/\n│   ├── index.ts       # MCP 服务端入口，stdio 通信循环\n│   ├── tools.ts       # 工具定义和 JSON Schema\n│   └── retroarch.ts   # RetroArch NCI 通信层\n├── package.json\n├── tsconfig.json\n├── Dockerfile\n├── README.md\n├── CHANGELOG.md\n├── glama.json         # MCP 服务器元数据\n└── .scratch/\n    └── smoke.cjs      # 冒烟测试脚本\n```\n\n资料来源：[package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)()\n\n## 环境准备\n\n### 前提条件\n\n- **Node.js** >= 18.0.0\n- **npm** >= 9.0.0\n- **RetroArch** 已安装并启用 Network Commands 功能\n\n### RetroArch 配置\n\n**通过 GUI：**\n\nSettings → Network → Network Commands → **ON**，确认 `Network Cmd Port` 为 `55355`（默认值）。\n\n**通过 `retroarch.cfg`：**\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n资料来源：[README.md: Setup]()\n\n## 本地开发\n\n### 安装依赖\n\n```bash\nnpm install\n```\n\n### 编译与监听\n\n使用 TypeScript 编译器的 watch 模式进行持续编译：\n\n```bash\nnpm run dev\n```\n\n该命令等价于 `tsc --watch`，监听 `src/` 目录下所有 `.ts` 文件的变更并自动重新编译。\n\n资料来源：[README.md: Development]()\n\n### 编译检查\n\n单独运行一次 TypeScript 编译（不监听）：\n\n```bash\nnpx tsc\n```\n\n### 冒烟测试\n\n在 RetroArch 运行状态下，执行项目提供的冒烟测试脚本验证通信：\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n该脚本会尝试连接 RetroArch 并执行基础查询（如 `VERSION`、`GET_STATUS`）。\n\n资料来源：[README.md: Development]()\n\n## 架构设计\n\n### 系统架构图\n\n```mermaid\ngraph TD\n    subgraph \"MCP 客户端\"\n        A[Claude Code / Claude Desktop]\n    end\n\n    subgraph \"mcp-retroarch\"\n        B[src/index.ts<br/>MCP Server]\n        C[src/tools.ts<br/>Tool Definitions]\n        D[src/retroarch.ts<br/>NCI Client]\n    end\n\n    subgraph \"RetroArch\"\n        E[Network Commands<br/>UDP :55355]\n    end\n\n    A -->|\"stdio JSON-RPC\"| B\n    B -->|\"查询工具定义\"| C\n    B -->|\"发送 NCI 命令\"| D\n    D -->|\"UDP\"| E\n```\n\n### 核心模块\n\n#### 1. index.ts — 服务端入口\n\n负责初始化 MCP SDK 并启动 stdio 通信循环。关键逻辑：\n\n1. 创建 `Server` 实例，注册所有工具\n2. 启动背景连接探测（fire-and-forget），尝试连接 RetroArch 并获取版本号\n3. 监听 stdio 输入并转发至 MCP SDK 处理\n\n```typescript\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(\n    `[mcp-retroarch] note: RetroArch not reachable yet (${ra.describeTarget()}): ${err}\\n` +\n    `             Enable Network Commands in retroarch.cfg\\n`,\n  ));\n```\n\n资料来源：[src/index.ts:1-20]()\n\n#### 2. tools.ts — 工具定义\n\n定义所有 MCP 工具的 JSON Schema，包含：\n\n- **描述字段**：PURPOSE / USAGE / BEHAVIOR / RETURNS 模板\n- **输入参数**：TypeScript 类型约束和取值范围\n- **错误处理**：明确标注各工具的错误条件和边界情况\n\n工具列表：\n\n| 工具名 | 功能 |\n|---|---|\n| `retroarch_get_status` | 获取运行状态和游戏信息 |\n| `retroarch_get_config` | 读取 RetroArch 配置参数 |\n| `retroarch_read_memory` | 读取 libretro 系统内存映射 |\n| `retroarch_read_ram` | 读取 CHEEVOS 地址空间 |\n| `retroarch_write_memory` | 写入系统内存映射 |\n| `retroarch_write_ram` | 写入 CHEEVOS 地址空间 |\n| `retroarch_pause_toggle` | 切换暂停状态 |\n| `retroarch_frame_advance` | 推进一帧 |\n| `retroarch_reset` | 重置游戏 |\n| `retroarch_screenshot` | 保存截图 |\n| `retroarch_show_message` | 显示通知 |\n| `retroarch_save_state_current` | 保存到当前槽位 |\n| `retroarch_load_state_current` | 从当前槽位加载 |\n| `retroarch_load_state_slot` | 从指定槽位加载 |\n| `retroarch_state_slot_plus` | 当前槽位 +1 |\n| `retroarch_state_slot_minus` | 当前槽位 -1 |\n\n资料来源：[src/tools.ts:1-200]()\n\n#### 3. retroarch.ts — NCI 通信层\n\n处理与 RetroArch 的 UDP 通信，实现两种发送模式：\n\n| 模式 | 方法 | 用途 |\n|---|---|---|\n| 发送即忘 | `send(command)` | 热键类命令，无需等待响应 |\n| 查询等待 | `query(command)` | 需要读取返回值 |\n\n关键特性：\n\n- **序列化保证**：同时只能有一个查询在飞，第二个调用会抛出错误\n- **超时机制**：默认超时时间可配置，超时后拒绝 pending 回调\n- **Socket 复用**：UDP socket 创建后保持连接\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:30-60]()\n\n## 配置选项\n\n### 环境变量\n\n| 环境变量 | 默认值 | 说明 |\n|---|---|---|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机地址 |\n| `RETROARCH_PORT` | `55355` | UDP 端口，需与 RetroArch 配置的 `network_cmd_port` 匹配 |\n\n资料来源：[README.md: Configuration]()\n\n## 内存读取 API 详解\n\n项目提供两条内存读取路径，理解其区别对正确使用至关重要：\n\n```mermaid\ngraph LR\n    A[内存地址] --> B{选择路径}\n    B -->|\"系统内存映射\"| C[READ_CORE_MEMORY]\n    B -->|\"CHEEVOS 地址\"| D[READ_CORE_RAM]\n    C --> E[libretro 核心定义<br/>e.g. SNES WRAM 0x7E0000]\n    D --> F[RetroAchievements 规范<br/>e.g. SNES WRAM 0x000000]\n```\n\n| 路径 | 工具 | 地址空间 | 适用场景 |\n|---|---|---|---|\n| 系统内存映射 | `retroarch_read_memory` | libretro 核心定义 | 首选方案，支持此路径的核心 |\n| CHEEVOS | `retroarch_read_ram` | RetroAchievements 规范 | 无内存映射的核心（如 SwanStation PSX） |\n\n资料来源：[src/tools.ts: 内存读写工具描述]()\n\n## 开发工作流\n\n### 1. 添加新工具\n\n在 `src/tools.ts` 中按以下模板添加工具定义：\n\n```typescript\n{\n  name: \"tool_name\",\n  description: \"PURPOSE: ...\\nUSAGE: ...\\nBEHAVIOR: ...\\nRETURNS: ...\",\n  inputSchema: {\n    type: \"object\",\n    required: [\"param1\"],\n    properties: {\n      param1: { type: \"integer\", minimum: 0 },\n    },\n    additionalProperties: false,\n  },\n}\n```\n\n### 2. 实现 NCI 命令\n\n在 `src/retroarch.ts` 中添加对应方法：\n\n```typescript\nasync newCommand(): Promise<ReturnType> {\n  const r = await this.query(\"NEW_COMMAND\");\n  return r.toString().trim();\n}\n```\n\n### 3. 在 index.ts 中注册\n\n在 `src/index.ts` 的 switch 语句中添加处理分支：\n\n```typescript\ncase \"new_tool_name\": {\n  const result = await ra.newCommand();\n  return ok(result);\n}\n```\n\n### 4. 更新文档\n\n- 更新 `README.md` 中的工具列表\n- 在 `CHANGELOG.md` 的 `[Unreleased]` 节添加变更记录\n\n## 发布流程\n\n### 版本号管理\n\n项目遵循 Semantic Versioning 规范：\n\n- **主版本号**：不兼容的 API 变更\n- **次版本号**：向后兼容的功能新增\n- **修订号**：向后兼容的问题修复\n\n### Changelog 格式\n\n```markdown\n## [Unreleased]\n\n## [0.1.2] - 2026-05-15\n\n### Changed\n- 变更描述\n```\n\n### MCP 客户端注册\n\n不同平台的 MCP 客户端注册方式：\n\n| 平台 | 注册命令 |\n|---|---|\n| Claude Code | `claude mcp add retroarch --scope user mcp-retroarch` |\n| Claude Desktop | 修改 `claude_desktop_config.json` |\n\n资料来源：[README.md: Register with your MCP client]()\n\n## 常见问题排查\n\n| 症状 | 原因与解决方案 |\n|---|---|\n| `RetroArch query timed out` | Network Commands 未启用，或端口不匹配。确认 `network_cmd_enable = \"true\"` |\n| `READ_CORE_MEMORY failed: no memory map defined` | 核心不暴露内存映射，改用 `retroarch_read_ram`（CHEEVOS 路径） |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址不在核心内存映射范围内，需更换核心或确认地址 |\n| Screenshots 不在预期位置 | 检查 RetroArch GUI 中 Settings → Directory → Screenshot 的配置 |\n\n资料来源：[README.md: Troubleshooting]()\n\n## 依赖说明\n\n### 生产依赖\n\n| 依赖 | 版本 | 用途 |\n|---|---|---|\n| `@modelcontextprotocol/sdk` | ^1.12.0 | MCP 协议实现 |\n\n### 开发依赖\n\n| 依赖 | 版本 | 用途 |\n|---|---|---|\n| `@types/node` | ^22.0.0 | Node.js 类型定义 |\n| `typescript` | ^5.5.0 | TypeScript 编译器 |\n\n资料来源：[package.json: dependencies & devDependencies]()\n\n## 相关项目\n\n| 项目 | 说明 |\n|---|---|\n| [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | Game Boy Advance 支持，包含手柄输入和截图功能 |\n| [mcp-pine](https://github.com/dmang-dev/mcp-pine) | PINE 协议模拟器（PCSX2 等），仅支持内存和存档 |\n\n资料来源：[README.md: Related]()\n\n---\n\n---\n\n## Doramagic 踩坑日志\n\n项目：dmang-dev/mcp-retroarch\n\n摘要：发现 7 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：配置坑 - 可能修改宿主 AI 配置。\n\n## 1. 配置坑 · 可能修改宿主 AI 配置\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。\n- 对用户的影响：安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。\n- 建议检查：列出会写入的配置文件、目录和卸载/回滚步骤。\n- 防护动作：涉及宿主配置目录时必须给回滚路径，不能只给安装命令。\n- 证据：capability.host_targets | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | host_targets=mcp_host, claude\n\n## 2. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：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. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | last_activity_observed missing\n\n## 4. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 5. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 6. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | issue_or_pr_quality=unknown\n\n## 7. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：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 完整输出，末尾追加 Discovery Agent 踩坑日志。",
      "title": "mcp-retroarch 说明书",
      "toc": [
        "https://github.com/dmang-dev/mcp-retroarch 项目说明书",
        "目录",
        "项目概述",
        "项目简介",
        "技术架构",
        "技术特性",
        "通信机制",
        "项目配置",
        "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\n下面内容用于强化 Repomix/AI Context Pack 主体。Human Manual 只提供阅读骨架；踩坑日志会被转成宿主 AI 必须遵守的工作约束。\n\n## Human Manual 骨架\n\n使用规则：这里只是项目阅读路线和显著性信号，不是事实权威。具体事实仍必须回到 repo evidence / Claim Graph。\n\n宿主 AI 硬性规则：\n- 不得把页标题、章节顺序、摘要或 importance 当作项目事实证据。\n- 解释 Human Manual 骨架时，必须明确说它只是阅读路线/显著性信号。\n- 能力、安装、兼容性、运行状态和风险判断必须引用 repo evidence、source path 或 Claim Graph。\n\n- **项目概述**：importance `high`\n  - source_paths: README.md, src/index.ts\n- **系统架构**：importance `high`\n  - source_paths: README.md, src/retroarch.ts\n- **安装与配置**：importance `high`\n  - source_paths: README.md, package.json\n- **RetroArch 集成**：importance `high`\n  - source_paths: README.md\n- **MCP 工具参考**：importance `high`\n  - source_paths: src/tools.ts, src/retroarch.ts\n- **支持的模拟器核心**：importance `medium`\n  - source_paths: README.md, docs/RECIPES.md\n- **内存访问机制**：importance `medium`\n  - source_paths: src/retroarch.ts, README.md\n- **状态管理**：importance `medium`\n  - source_paths: src/retroarch.ts, src/tools.ts\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\n宿主 AI 硬性规则：\n- 没有 repo_clone_verified=true 时，不得声称已经读过源码。\n- 没有 repo_inspection_verified=true 时，不得把 README/docs/package 文件判断写成事实。\n- 没有 quick_start_verified=true 时，不得声称 Quick Start 已跑通。\n\n## Doramagic Pitfall Constraints / 踩坑约束\n\n这些规则来自 Doramagic 发现、验证或编译过程中的项目专属坑点。宿主 AI 必须把它们当作工作约束，而不是普通说明文字。\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: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\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: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\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: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\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: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\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: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\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: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\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: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n",
      "summary": "给宿主 AI 的上下文和工作边界。",
      "title": "AI Context Pack / 带给我的 AI"
    },
    "boundary_risk_card": {
      "asset_id": "boundary_risk_card",
      "filename": "BOUNDARY_RISK_CARD.md",
      "markdown": "# Boundary & Risk Card / 安装前决策卡\n\n项目：dmang-dev/mcp-retroarch\n\n## Doramagic 试用结论\n\n当前结论：可以进入发布前推荐检查；首次使用仍应从最小权限、临时目录和可回滚配置开始。\n\n## 用户现在可以做\n\n- 可以先阅读 Human Manual，理解项目目的和主要工作流。\n- 可以复制 Prompt Preview 做安装前体验；这只验证交互感，不代表真实运行。\n- 可以把官方 Quick Start 命令放到隔离环境中验证，不要直接进主力环境。\n\n## 现在不要做\n\n- 不要把 Prompt Preview 当成项目实际运行结果。\n- 不要把 metadata-only validation 当成沙箱安装验证。\n- 不要把未验证能力写成“已支持、已跑通、可放心安装”。\n- 不要在首次试用时交出生产数据、私人文件、真实密钥或主力配置目录。\n\n## 安装前检查\n\n- 宿主 AI 是否匹配：mcp_host, claude\n- 官方安装入口状态：已发现官方入口\n- 是否在临时目录、临时宿主或容器中验证：必须是\n- 是否能回滚配置改动：必须能\n- 是否需要 API Key、网络访问、读写文件或修改宿主配置：未确认前按高风险处理\n- 是否记录了安装命令、实际输出和失败日志：必须记录\n\n## 当前阻塞项\n\n- review_required: community_discussion_evidence_below_public_threshold\n\n## 项目专属踩坑\n\n- 可能修改宿主 AI 配置（medium）：安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。 建议检查：列出会写入的配置文件、目录和卸载/回滚步骤。\n- 能力判断依赖假设（medium）：假设不成立时，用户拿不到承诺的能力。 建议检查：将假设转成下游验证清单。\n- 维护活跃度未知（medium）：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 下游验证发现风险项（medium）：下游已经要求复核，不能在页面中弱化。 建议检查：进入安全/权限治理复核队列。\n- 存在评分风险（medium）：风险会影响是否适合普通用户安装。 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n\n## 风险与权限提示\n\n- no_demo: medium\n\n## 证据缺口\n\n- 暂未发现结构化证据缺口。\n",
      "summary": "安装、权限、验证和推荐前风险。",
      "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 05:01:44 UTC\n\n## 目录\n\n- [项目概述](#project-overview)\n- [系统架构](#system-architecture)\n- [安装与配置](#installation-configuration)\n- [RetroArch 集成](#retroarch-integration)\n- [MCP 工具参考](#mcp-tools-reference)\n- [支持的模拟器核心](#supported-cores)\n- [内存访问机制](#memory-access)\n- [状态管理](#state-management)\n- [故障排除](#troubleshooting)\n- [开发指南](#development-guide)\n\n<a id='project-overview'></a>\n\n## 项目概述\n\n### 相关页面\n\n相关主题：[系统架构](#system-architecture), [安装与配置](#installation-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- [src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\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- [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# 项目概述\n\n## 项目简介\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的服务端实现，用于通过标准化的 JSON-RPC 接口远程控制 RetroArch 模拟器。该项目采用 TypeScript 开发，以 npm 包的形式分发，充当 MCP 客户端（如 Claude Code、Claude Desktop）与 RetroArch 网络控制接口（Network Control Interface, NCI）之间的桥接层。\n\n项目的核心价值在于将 RetroArch 的底层 UDP 协议封装为人类可读的工具（Tool），使 AI 助手能够直接与运行中的模拟器实例交互，执行内存读写、存档管理、截图、游戏控制等操作。资料来源：[README.md:1]()\n\n## 技术架构\n\n### 整体架构图\n\n```mermaid\ngraph TD\n    subgraph \"MCP 客户端层\"\n        A[Claude Code / Claude Desktop]\n    end\n    \n    subgraph \"mcp-retroarch 桥接层\"\n        B[stdio JSON-RPC 传输]\n        C[MCP Server]\n        D[RetroArch.ts UDP 客户端]\n    end\n    \n    subgraph \"RetroArch 层\"\n        E[RetroArch NCI<br/>UDP :55355]\n        F[libretro Core<br/>+ 游戏]\n    end\n    \n    A -->|stdio| B\n    B --> C\n    C --> D\n    D -->|UDP| E\n    E --> F\n    \n    style B fill:#e1f5fe\n    style D fill:#fff3e0\n```\n\nmcp-retroarch 采用标准的 MCP 服务端架构：服务端通过标准输入输出（stdio）与 MCP 客户端通信，JSON-RPC 2.0 格式封装所有请求和响应。内部通过 `RetroArch.ts` 模块维护一个 UDP socket，与目标主机上的 RetroArch 实例保持长连接。资料来源：[src/index.ts:1-30]()\n\n### 核心模块\n\n| 模块 | 文件路径 | 职责 |\n|------|----------|------|\n| 入口模块 | `src/index.ts` | MCP 服务端初始化、后台连接探测、stdio 生命周期管理 |\n| 工具定义 | `src/tools.ts` | 声明所有 MCP 工具的名称、描述、输入模式 |\n| UDP 通信 | `src/retroarch.ts` | 管理 UDP socket、命令发送、响应解析、超时处理 |\n\n资料来源：[src/index.ts:1-30](), [src/tools.ts:1-100](), [src/retroarch.ts:1-80]()\n\n## 技术特性\n\n### 支持的功能\n\n| 功能类别 | 具体操作 | 备注 |\n|----------|----------|------|\n| **内存读写** | `retroarch_read_memory` / `retroarch_write_memory` | 基于系统内存映射（READ_CORE_MEMORY） |\n| **内存读写（兼容）** | `retroarch_read_ram` / `retroarch_write_ram` | 基于 CHEEVOS 地址空间（READ_CORE_RAM） |\n| **存档管理** | 保存当前槽位、加载指定槽位、切换槽位指针 | |\n| **模拟器控制** | 暂停切换、帧进、退放 | |\n| **游戏控制** | 重置游戏 | |\n| **截图** | 截图保存 | |\n| **状态获取** | 获取游戏状态、系统信息、CRC32 | |\n| **用户通知** | 显示 OSD 消息 | |\n\n资料来源：[README.md:1-50]()\n\n### 内存读取的双路径设计\n\nmcp-retroarch 实现了两种内存读取路径，以最大化兼容性：\n\n```mermaid\ngraph LR\n    A[工具调用] --> B{核心是否暴露<br/>内存映射?}\n    \n    B -->|是| C[READ_CORE_MEMORY]\n    B -->|否| D[READ_CORE_RAM]\n    \n    C --> E[系统内存地址空间]\n    D --> F[CHEEVOS 地址空间]\n    \n    E --> G[例: GBA EWRAM<br/>0x02000000]\n    F --> H[例: SNES WRAM<br/>0x000000]\n```\n\n两种路径的主要区别：\n\n| 特性 | `read_memory` (READ_CORE_MEMORY) | `read_ram` (READ_CORE_RAM) |\n|------|--------------------------------|---------------------------|\n| 地址空间 | libretro 系统内存映射 | CHEEVOS 成就地址空间 |\n| 适用场景 | 首选方案，有内存映射的现代核心 | 无内存映射的核心（旧核心、部分 PlayStation 核心） |\n| 返回确认 | ❌ | ❌ |\n\n资料来源：[src/tools.ts:1-150]()\n\n### 已测试的核心\n\n| 系统 | 核心 | `read_memory` | `read_ram` | 备注 |\n|------|------|---------------|------------|------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA 中断向量表在 `0x0000` 可见 |\n| NES | `mesen_libretro` | ✅ | ✅ | 完整 16 位 NES 地址空间暴露 |\n| NES | `nestopia_libretro` | ❌ | ✅ | 仅 CHEEVOS，64KB 限制 |\n| SNES | `snes9x_libretro` | ❌ | ❌ | |\n\n资料来源：[README.md:30-50]()\n\n## 通信机制\n\n### UDP 传输特性\n\nmcp-retroarch 与 RetroArch 之间的通信基于 UDP 协议，这种设计带来了以下特性：\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP 客户端\n    participant Bridge as mcp-retroarch\n    participant RA as RetroArch\n    \n    Note over Bridge: 建立 UDP socket\n    Bridge->>RA: 发送命令\n    RA-->>Bridge: 返回响应\n    \n    Note over Bridge: 查询操作\n    Bridge->>RA: 发送查询\n    Note over Bridge: 等待响应 (默认 5s 超时)\n    RA-->>Bridge: 返回数据\n```\n\n**关键约束**：\n\n- 大多数命令为 **fire-and-forget**（即发即忘），RetroArch 不返回 ACK\n- `retroarch_write_memory` 是唯一返回写入字节数的命令\n- `retroarch_write_ram` **无确认机制**，无法区分部分写入与完全失败\n- UDP 数据报在高负载下可能丢失（即使在本地回环接口上）\n\n资料来源：[src/retroarch.ts:40-80](), [src/tools.ts:100-150]()\n\n### 连接管理\n\n后台连接探测采用「即发即忘」模式，不会阻塞服务启动：\n\n```typescript\n// src/index.ts 核心逻辑\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\n资料来源：[src/index.ts:15-25]()\n\n## 项目配置\n\n### 环境变量\n\n| 环境变量 | 默认值 | 说明 |\n|----------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机地址 |\n| `RETROARCH_PORT` | `55355` | UDP 端口，必须与 RetroArch 配置中的 `network_cmd_port` 匹配 |\n\n资料来源：[README.md:80-85]()\n\n### RetroArch 端配置\n\n**GUI 方式**：\n1. 进入 Settings → Network → Network Commands → **ON**\n2. 确认 Network Cmd Port 为 `55355`（默认值）\n\n**配置文件方式**（`retroarch.cfg`）：\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n资料来源：[README.md:60-70]()\n\n## MCP 客户端集成\n\n### Claude Code\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\n验证连接：\n```bash\nclaude mcp list\n# retroarch: mcp-retroarch - ✓ Connected\n```\n\n### Claude Desktop\n\n配置文件路径：\n\n| 平台 | 路径 |\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配置示例：\n```json\n{\n  \"mcpServers\": {\n    \"retroarch\": {\n      \"command\": \"mcp-retroarch\"\n    }\n  }\n}\n```\n\n资料来源：[README.md:70-100]()\n\n## 依赖与构建\n\n### 项目依赖\n\n| 依赖类型 | 包名 | 版本要求 |\n|----------|------|----------|\n| 运行时依赖 | `@modelcontextprotocol/sdk` | `^1.12.0` |\n| 开发依赖 | `@types/node` | `^22.0.0` |\n| 开发依赖 | `typescript` | `^5.5.0` |\n\n### 开发命令\n\n| 命令 | 功能 |\n|------|------|\n| `npm install` | 安装依赖 |\n| `npm run dev` | TypeScript 编译监视模式 |\n| `node .scratch/smoke.cjs` | 对运行中的 RetroArch 进行冒烟测试 |\n\n资料来源：[package.json:1-30](), [README.md:115-125]()\n\n## 版本历史\n\n项目采用语义化版本控制（Semantic Versioning），当前版本为 0.1.2。主要版本变更：\n\n| 版本 | 日期 | 关键变更 |\n|------|------|----------|\n| 0.1.2 | 2026-05-15 | 工具描述质量重构，fire-and-forget 语义显式化 |\n| 0.1.0 | - | 初始发布，基础功能实现 |\n\n资料来源：[CHANGELOG.md:1-30]()\n\n## 已知限制\n\n| 限制 | 原因 | 规避方案 |\n|------|------|----------|\n| 无法直接保存到指定槽位 | NCI 协议限制 | 使用 `state_slot_plus`/`state_slot_minus` 切换到目标槽位后再保存 |\n| 游戏手柄输入不可用 | NCI 未暴露此功能 | 参见 [mcp-mgba](https://github.com/dmang-dev/mcp-mgba)（GBA 专用） |\n| 截图路径无法通过命令查询 | `screenshot_directory` 未通过 `GET_CONFIG_PARAM` 暴露 | 通过 RetroArch GUI 查看：Settings → Directory → Screenshot |\n\n资料来源：[README.md:105-120]()\n\n## 相关项目\n\n| 项目 | 地址 | 说明 |\n|------|------|------|\n| [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | Game Boy Advance | 通过 mGBA Lua 桥接，支持手柄输入和截图 |\n| [mcp-pine](https://github.com/dmang-dev/mcp-pine) | PCSX2 等 | 通过 PINE 协议通信，仅内存和存档 |\n\n资料来源：[README.md:130-135]()\n\n---\n\n<a id='system-architecture'></a>\n\n## 系统架构\n\n### 相关页面\n\n相关主题：[项目概述](#project-overview), [MCP 工具参考](#mcp-tools-reference)\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/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- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n</details>\n\n# 系统架构\n\n## 概述\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的桥接工具，它使 MCP 客户端（如 Claude Desktop、Claude Code）能够通过标准化的 JSON-RPC 接口控制 RetroArch 模拟器。该项目充当 MCP 协议与 RetroArch 网络控制接口（NCI）之间的中间层，将高级工具调用转换为底层的 UDP 网络命令。\n\n架构设计遵循**分离关注点**原则，核心组件包括 MCP 服务器层、工具定义层和 RetroArch 通信层。通信默认通过标准输入输出（stdio）传输，而与 RetroArch 的交互则通过 UDP 网络协议完成。\n\n## 架构分层\n\nmcp-retroarch 采用三层架构设计：\n\n```mermaid\ngraph TD\n    subgraph \"MCP 客户端层\"\n        A[\"Claude Desktop / Claude Code\"]\n    end\n    \n    subgraph \"MCP 服务器层 (mcp-retroarch)\"\n        B[\"src/index.ts<br/>MCP 服务器入口\"]\n        C[\"src/tools.ts<br/>工具定义与路由\"]\n        D[\"src/retroarch.ts<br/>UDP 通信封装\"]\n    end\n    \n    subgraph \"RetroArch 目标层\"\n        E[\"RetroArch NCI<br/>UDP :55355\"]\n    end\n    \n    A -->|\"JSON-RPC / stdio\"| B\n    B --> C\n    C -->|\"工具调用\"| D\n    D -->|\"UDP 网络命令\"| E\n    \n    style A fill:#e1f5fe\n    style E fill:#fff3e0\n```\n\n### 各层职责\n\n| 层级 | 文件 | 职责 |\n|------|------|------|\n| 服务器入口 | `src/index.ts` | 初始化 MCP 服务器、建立 UDP 连接探针 |\n| 工具定义 | `src/tools.ts` | 定义所有 MCP 工具的输入模式、处理工具调用路由 |\n| 通信封装 | `src/retroarch.ts` | 管理 UDP socket、实现命令发送与响应接收 |\n| 目标设备 | RetroArch | 执行模拟器控制命令、返回状态信息 |\n\n## 核心模块详解\n\n### 1. RetroArch 通信模块\n\n**文件位置**: `src/retroarch.ts`\n\n该模块封装了所有与 RetroArch NCI 的 UDP 通信逻辑。\n\n#### 连接管理\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP Server\n    participant Socket as UDP Socket\n    participant RA as RetroArch\n    \n    MCP->>Socket: connect()\n    Socket->>Socket: dgram.createSocket(\"udp4\")\n    Socket->>Socket: bind(0)\n    Note over Socket: 动态分配本地端口\n    \n    Socket->>MCP: connection ready\n    MCP->>RA: send(command)\n    Socket->>RA: UDP datagram :55355\n    RA-->>Socket: response\n    Socket-->>MCP: Buffer\n```\n\n#### 核心类：`RetroArchClient`\n\n```typescript\nclass RetroArchClient {\n  private socket: dgram.Socket | null = null;\n  private pending: ((data: Buffer) => void) | null = null;\n  \n  // 发送后不等待响应（热键类命令）\n  async send(command: string): Promise<void>\n  \n  // 发送并等待一个 UDP 响应\n  async query(command: string): Promise<Buffer>\n  \n  // 高层命令封装\n  async getVersion(): Promise<string>\n  async getStatus(): Promise<EmuStatus>\n  async readMemory(addr: number, len: number): Promise<Buffer>\n  // ... 其他命令\n}\n```\n\n#### 通信模式\n\nRetroArchClient 实现两种通信模式：\n\n**1. Fire-and-Forget（单向发送）**\n\n适用于状态切换类命令，无需确认响应：\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:38-45](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts#L38-L45)\n\n**2. Query-Response（请求-响应）**\n\n适用于需要获取返回数据的命令：\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:54-78](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts#L54-L78)\n\n#### 关键设计特性\n\n| 特性 | 实现方式 | 说明 |\n|------|----------|------|\n| 串行化 | `pending` 状态标志 | 阻止并发查询，确保请求-响应配对正确 |\n| 超时控制 | `setTimeout` | 默认超时后清除 pending 并抛出错误 |\n| 错误处理 | `sock.once(\"error\")` | Socket 错误直接拒绝 Promise |\n| 延迟初始化 | 按需 `connect()` | 首次命令调用时才创建 socket |\n\n### 2. 工具定义模块\n\n**文件位置**: `src/tools.ts`\n\n该模块定义所有 MCP 工具的元数据、输入模式和处理逻辑。\n\n#### 工具注册结构\n\n```typescript\nexport const tools: Tool[] = [\n  // 内存操作工具\n  {\n    name: \"retroarch_read_memory\",\n    description: \"PURPOSE: ...\\nUSAGE: ...\\nBEHAVIOR: ...\\nRETURNS: ...\",\n    inputSchema: { type: \"object\", required: [...], properties: {...} }\n  },\n  // 模拟器控制工具\n  {\n    name: \"retroarch_pause_toggle\",\n    description: \"...\",\n    inputSchema: { type: \"object\", properties: {} }\n  },\n  // ... 其他工具\n];\n```\n\n#### 工具调用路由\n\n```typescript\nexport async function handleToolCall(name: string, params: Record<string, unknown>) {\n  switch (name) {\n    case \"retroarch_read_memory\": {\n      const bytes = await ra.readMemory(p.address as number, p.length as number);\n      const hex = Array.from(bytes).map(...).join(\" \");\n      return ok(`${addrHex(p.address as number)} [${bytes.length} bytes]:\\n${hex}`);\n    }\n    case \"retroarch_pause_toggle\":\n      await ra.pauseToggle();\n      return ok(\"Pause toggled\");\n    // ...\n  }\n}\n```\n\n**资料来源**：[src/tools.ts:1-80](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### 3. MCP 服务器入口\n\n**文件位置**: `src/index.ts`\n\n```typescript\nasync function main() {\n  const ra = new RetroArchClient(host, port);\n  \n  const server = new Server(\n    { name: \"mcp-retroarch\", version: \"0.1.2\" },\n    { capabilities: { tools } },\n  );\n  \n  // 注册工具处理\n  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));\n  server.setRequestHandler(CallToolRequestSchema, async (request) => {\n    const { name, arguments: args } = request.params;\n    return handleToolCall(name, args ?? {});\n  });\n  \n  // 启动 stdio 传输\n  await server.connect(new StdioServerTransport());\n  \n  // 后台连接探针\n  ra.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    ));\n}\n```\n\n**资料来源**：[src/index.ts:1-35](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n#### 启动流程\n\n```mermaid\nsequenceDiagram\n    participant OS as 操作系统\n    participant MCP as MCP Server\n    participant RA as RetroArch\n    participant CLI as MCP Client\n    \n    OS->>MCP: 启动进程 (mcp-retroarch)\n    MCP->>MCP: 初始化 RetroArchClient\n    MCP->>MCP: 创建 MCP Server 实例\n    MCP->>MCP: 注册工具处理器\n    MCP->>MCP: 连接 StdioServerTransport\n    Note over MCP: 阻塞等待 MCP 客户端连接\n    \n    CLI->>MCP: tools/list 请求\n    MCP-->>CLI: 工具列表\n    CLI->>MCP: tools/call 请求\n    MCP->>RA: 首次命令触发连接\n    RA-->>MCP: 连接成功/超时\n    \n    alt RetroArch 可达\n        MCP->>RA: 发送 UDP 命令\n        RA-->>MCP: 响应数据\n        MCP-->>CLI: JSON-RPC 响应\n    else RetroArch 不可达\n        MCP-->>CLI: 错误响应\n    end\n```\n\n## 数据流分析\n\n### 工具调用完整流程\n\n```mermaid\ngraph LR\n    A[\"用户请求<br/>retroarch_read_memory\"] --> B[\"MCP JSON-RPC<br/>tools/call\"]\n    B --> C[\"handleToolCall<br/>工具路由\"]\n    C --> D[\"ra.readMemory<br/>参数转换\"]\n    D --> E[\"query()<br/>UDP 封装\"]\n    E --> F[\"socket.send<br/>网络发送\"]\n    F --> G[\"RetroArch NCI\"]\n    G --> H[\"socket.on(message)<br/>响应接收\"]\n    H --> I[\"十六进制格式化\"]\n    I --> J[\"JSON-RPC 响应\"]\n    J --> K[\"返回结果\"]\n```\n\n### 两种内存读取路径\n\nmcp-retroarch 根据 RetroArch 核心能力提供两条内存读取路径：\n\n```mermaid\ngraph TD\n    A[\"内存读取请求\"] --> B{\"核心是否支持<br/>系统内存映射?\"}\n    \n    B -->|是| C[\"READ_CORE_MEMORY<br/>retroarch_read_memory\"]\n    C --> D[\"libretro 系统总线\"]\n    D --> E[\"直接访问硬件地址\"]\n    \n    B -->|否| F[\"READ_CORE_RAM<br/>retroarch_read_ram\"]\n    F --> G[\"CHEEVOS 地址空间\"]\n    G --> H[\"成就系统兼容地址\"]\n    \n    style C fill:#c8e6c9\n    style F fill:#fff9c4\n```\n\n| 路径 | 工具 | 地址空间 | 适用场景 |\n|------|------|----------|----------|\n| 系统内存映射 | `retroarch_read_memory` | libretro 系统总线 | 支持内存映射的核心（Mesen 等） |\n| CHEEVOS 兼容 | `retroarch_read_ram` | 成就系统地址空间 | 不暴露系统映射的核心（SwanStation 等） |\n\n## 配置与环境变量\n\n```mermaid\ngraph LR\n    subgraph \"环境变量配置\"\n        A[\"RETROARCH_HOST\"]\n        B[\"RETROARCH_PORT\"]\n    end\n    \n    subgraph \"RetroArch 配置\"\n        C[\"network_cmd_enable\"]\n        D[\"network_cmd_port\"]\n    end\n    \n    A -->|\"UDP 目标\"| E[\"RetroArchClient\"]\n    B -->|\"UDP 端口\"| E\n    C -->|\"NCI 启用\"| F[\"RetroArch\"]\n    D -->|\"端口同步\"| F\n    \n    E -->|\"UDP :55355\"| F\n```\n\n### 配置参数对照表\n\n| 环境变量 | 默认值 | RetroArch 配置项 | 说明 |\n|----------|--------|------------------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | 无 | UDP 目标主机地址 |\n| `RETROARCH_PORT` | `55355` | `network_cmd_port` | UDP 端口号（两端必须一致） |\n| 无 | `true` | `network_cmd_enable` | 必须启用网络命令 |\n\n**资料来源**：[README.md:80-85](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md#L80-L85)\n\n## 错误处理机制\n\n### 错误分类\n\n| 错误类型 | 触发条件 | 处理方式 |\n|----------|----------|----------|\n| 连接超时 | UDP 查询超时 | 抛出 `RetroArch query \"XXX\" timed out` |\n| 内存映射缺失 | 核心不暴露系统内存 | 建议使用 `retroarch_read_ram` |\n| 地址越界 | 读取地址不在核心描述符范围内 | 返回错误信息 |\n| 并发冲突 | 存在未完成的查询时再次发起查询 | 抛出 `retroarch query already in flight` |\n\n### 错误传播流程\n\n```mermaid\ngraph TD\n    A[\"工具调用\"] --> B{\"执行查询\"}\n    B -->|成功| C[\"格式化响应\"]\n    B -->|超时| D[\"抛出 TimeoutError\"]\n    B -->|核心无映射| E[\"抛出 MemoryMapError\"]\n    B -->|地址无效| F[\"抛出 AddressError\"]\n    D --> G[\"返回错误响应\"]\n    E --> G\n    F --> G\n    C --> H[\"返回成功结果\"]\n```\n\n## 依赖关系\n\n### 项目依赖\n\n```json\n{\n  \"dependencies\": {\n    \"@modelcontextprotocol/sdk\": \"^1.12.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.0.0\",\n    \"typescript\": \"^5.5.0\"\n  }\n}\n```\n\n**资料来源**：[package.json:15-22](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json#L15-L22)\n\n### 依赖层级\n\n```mermaid\ngraph BT\n    A[\"@modelcontextprotocol/sdk\"] --> B[\"mcp-retroarch\"]\n    B --> C[\"Node.js runtime\"]\n    C --> D[\"UDP 网络\"]\n    D --> E[\"RetroArch NCI\"]\n```\n\n## 版本演进\n\n| 版本 | 日期 | 架构变更 |\n|------|------|----------|\n| 0.1.0 | - | 初始版本，支持基础 NCI 命令 |\n| 0.1.1 | 2026-05-11 | 非阻塞启动，连接探针异步化 |\n| 0.1.2 | 2026-05-15 | 工具描述规范化，Fire-and-forget 语义明确 |\n\n**资料来源**：[CHANGELOG.md:1-35](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n\n## 安全性考虑\n\n### 通信安全\n\n- **本地连接**: 默认连接到 `127.0.0.1:55355`，仅限本机通信\n- **无加密**: UDP 协议本身不提供加密，适用于可信网络环境\n- **无认证**: RetroArch NCI 不提供身份验证机制\n\n### 沙箱限制\n\n- **内存操作**: 限制每次读取最多 4096 字节\n- **输入验证**: 工具参数在本地进行 schema 校验\n- **只写模式确认**: `retroarch_write_ram` 的写入结果需要手动验证\n\n## 扩展架构可能性\n\n### 当前限制\n\n| 功能 | 限制原因 | 建议方案 |\n|------|----------|----------|\n| 手柄输入 | NCI 不暴露此功能 | 参见 [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) |\n| 保存到指定槽位 | NCI 协议限制 | 使用 `state_slot_plus/minus` 逐步切换 |\n| 截图路径查询 | NCI 未暴露配置参数 | 通过 RetroArch GUI 手动确认 |\n\n### 模块化扩展\n\n未来扩展可考虑：\n\n1. **多实例支持**: 实例化多个 RetroArchClient 连接不同主机\n2. **命令队列**: 实现请求队列以支持更高的并发度\n3. **自动重试**: 在 UDP 超时时自动重试丢失的包\n\n---\n\n## 总结\n\nmcp-retroarch 通过清晰的三层架构实现了 MCP 协议与 RetroArch NCI 之间的高效桥接。核心设计决策包括：\n\n1. **串行 UDP 查询**: 避免并发导致的请求-响应错配\n2. **按需连接**: 延迟 socket 创建，减少启动开销\n3. **双内存路径**: 兼容不同能力的模拟器核心\n4. **Fire-and-forget 语义**: 明确区分有响应和无响应的命令\n\n这种设计使 mcp-retroarch 成为稳定可靠的 RetroArch 控制解决方案，同时保持了代码的简洁性和可维护性。\n\n---\n\n<a id='installation-configuration'></a>\n\n## 安装与配置\n\n### 相关页面\n\n相关主题：[项目概述](#project-overview), [RetroArch 集成](#retroarch-integration)\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/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# 安装与配置\n\n## 概述\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的服务器，通过 RetroArch 的网络控制接口（Network Control Interface，简称 NCI）实现对模拟器的远程控制与内存读写功能。\n\n本工具允许 MCP 客户端（如 Claude Code、Claude Desktop）通过标准化的 JSON-RPC 协议与运行中的 RetroArch 实例通信，支持内存读取、存档管理、截图、控制模拟器运行状态等操作。\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 系统架构\n\n```\n┌─────────────────┐     stdio (JSON-RPC)     ┌──────────────────┐   UDP :55355   ┌─────────────────┐\n│   MCP 客户端     │ ◄──────────────────────► │  mcp-retroarch   │ ◄─────────────► │   RetroArch     │\n│ (Claude Desktop)│                          │  (TypeScript)    │                 │  (游戏模拟器)   │\n└─────────────────┘                          └──────────────────┘                 └─────────────────┘\n         │                                           │\n         │                                           ▼\n         │                                  ┌──────────────────┐\n         │                                  │   网络控制接口     │\n         │                                  │ (Network Cmd)    │\n         │                                  └──────────────────┘\n```\n\nmcp-retroarch 充当 MCP 客户端与 RetroArch NCI 之间的桥接层，将 MCP 工具调用转换为 UDP 网络命令。\n\n资料来源：[src/index.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n## 前置要求\n\n### 环境要求\n\n| 组件 | 版本要求 |\n|------|---------|\n| Node.js | Node.js 运行时环境 |\n| RetroArch | 启用了 Network Commands 的版本 |\n| MCP 客户端 | Claude Code 或 Claude Desktop |\n\n资料来源：[package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n## 安装步骤\n\n### 方式一：从源码编译\n\n```bash\n# 克隆仓库\ngit clone https://github.com/dmang-dev/mcp-retroarch.git\ncd mcp-retroarch\n\n# 安装依赖\nnpm install\n\n# 编译 TypeScript\nnpm run build\n\n# 可选：链接为全局命令\nnpm link\n```\n\n开发模式下可以使用 `npm run dev` 启动监听模式，TypeScript 会自动重新编译。\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### 方式二：使用 MCP 客户端自动发现\n\nClaude Code 支持直接引用 GitHub 仓库路径进行注册：\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\n## RetroArch 配置\n\n### 启用网络控制接口\n\nRetroArch 必须启用 Network Commands 功能才能接收来自 mcp-retroarch 的命令。\n\n#### 方式一：通过 GUI 配置\n\n1. 进入 RetroArch 主菜单\n2. 导航至 **Settings → Network → Network Commands**\n3. 将 **Network Commands** 设置为 **ON**\n4. 确认 **Network Cmd Port** 为 `55355`（这是默认值）\n\n#### 方式二：通过配置文件配置\n\n编辑 `retroarch.cfg` 文件，添加或修改以下配置项：\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n配置完成后，启动任意 libretro 核心并加载游戏。NCI 功能在启用后是持续有效的，无需额外脚本加载。\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### 配置参数说明\n\n| 配置项 | 默认值 | 说明 |\n|--------|--------|------|\n| `network_cmd_enable` | - | 必须设为 `\"true\"` 以启用 NCI |\n| `network_cmd_port` | `55355` | UDP 通信端口，必须与 MCP 客户端的 `RETROARCH_PORT` 环境变量一致 |\n\n## MCP 客户端配置\n\n### Claude Code\n\n添加 mcp-retroarch 作为用户级 MCP 服务器：\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\n验证连接状态：\n\n```bash\nclaude mcp list\n# retroarch: mcp-retroarch - ✓ Connected\n```\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### Claude Desktop\n\n#### 配置文件路径\n\n根据操作系统不同，配置文件位置如下：\n\n| 操作系统 | 配置文件路径 |\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#### 配置示例\n\n编辑对应操作系统的配置文件，添加 `mcpServers` 条目：\n\n```json\n{\n  \"mcpServers\": {\n    \"retroarch\": {\n      \"command\": \"mcp-retroarch\"\n    }\n  }\n}\n```\n\n配置完成后，需要**重启 Claude Desktop** 以使更改生效。\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 环境变量配置\n\nmcp-retroarch 支持通过环境变量自定义连接参数：\n\n| 环境变量 | 默认值 | 说明 |\n|---------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | RetroArch 所在主机的 IP 地址 |\n| `RETROARCH_PORT` | `55355` | UDP 端口号，必须与 RetroArch 的 `network_cmd_port` 匹配 |\n\n设置示例（Linux/macOS）：\n\n```bash\nexport RETROARCH_HOST=127.0.0.1\nexport RETROARCH_PORT=55355\n```\n\n设置示例（Windows PowerShell）：\n\n```powershell\n$env:RETROARCH_HOST = \"127.0.0.1\"\n$env:RETROARCH_PORT = \"55355\"\n```\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 连接流程\n\n```\nsequenceDiagram\n    participant MCP as MCP 客户端\n    participant MCP_RA as mcp-retroarch\n    participant RA as RetroArch\n\n    Note over MCP_RA: 服务器启动 (stdio)\n    MCP_RA->>RA: 连接探针 (UDP)\n    RA-->>MCP_RA: 连接成功响应\n\n    Note over MCP: 用户调用工具\n    MCP->>MCP_RA: retroarch_get_status\n    MCP_RA->>RA: GET_STATUS (UDP)\n    RA-->>MCP_RA: 状态响应\n    MCP_RA-->>MCP: JSON-RPC 响应\n\n    Note over MCP: 内存读取\n    MCP->>MCP_RA: retroarch_read_memory\n    MCP_RA->>RA: READ_CORE_MEMORY (UDP)\n    RA-->>MCP_RA: 内存数据\n    MCP_RA-->>MCP: hex dump 响应\n```\n\nmcp-retroarch 在启动时会自动发送一个后台连接探测，如果 RetroArch 不可达，会输出警告信息但不会阻止服务器启动。工具调用会在需要时按需建立连接。\n\n资料来源：[src/index.ts](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## 可用工具一览\n\n配置完成后，以下工具即可通过 MCP 客户端调用：\n\n| 工具名称 | 功能说明 |\n|---------|---------|\n| `retroarch_get_status` | 获取模拟器状态（运行/暂停/无内容）和游戏信息 |\n| `retroarch_get_config` | 读取 RetroArch 配置参数 |\n| `retroarch_read_memory` | 通过系统内存映射读取内存（推荐方式） |\n| `retroarch_read_ram` | 通过 CHEEVOS 地址空间读取内存（备用方式） |\n| `retroarch_write_memory` | 通过系统内存映射写入内存 |\n| `retroarch_write_ram` | 通过 CHEEVOS 地址空间写入内存 |\n| `retroarch_save_state_current` | 保存当前存档槽 |\n| `retroarch_load_state_current` | 加载当前存档槽 |\n| `retroarch_load_state_slot` | 加载指定存档槽 |\n| `retroarch_state_slot_plus` | 存档槽指针加一 |\n| `retroarch_state_slot_minus` | 存档槽指针减一 |\n| `retroarch_pause_toggle` | 切换暂停状态 |\n| `retroarch_frame_advance` | 推进一帧 |\n| `retroarch_reset` | 重置游戏 |\n| `retroarch_screenshot` | 截图并保存到 RetroArch 配置的截图目录 |\n| `retroarch_show_message` | 在屏幕上显示通知 |\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## 常见问题排查\n\n| 问题症状 | 原因与解决方案 |\n|---------|---------------|\n| `RetroArch query timed out` | 网络命令未启用或端口不匹配。检查 `retroarch.cfg` 中 `network_cmd_enable = \"true\"` 和端口配置是否与 `RETROARCH_PORT` 环境变量一致。 |\n| `READ_CORE_MEMORY failed: no memory map defined` | 加载的 libretro 核心未暴露系统内存映射。尝试使用 `retroarch_read_ram`（CHEEVOS 方式）。 |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址不在核心内存映射范围内。可能需要使用不同的核心。 |\n| 截图位置与预期不符 | RetroArch 截图保存到配置的截图目录。NCI 不暴露 `screenshot_directory` 参数，可通过 GUI 查看：Settings → Directory → Screenshot。 |\n| 无法保存到指定存档槽 | NCI 协议限制，只能保存到当前选中的槽位。需要通过 `state_slot_plus`/`state_slot_minus` 移动槽位指针。 |\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 开发测试\n\n若需对运行中的 RetroArch 进行冒烟测试，可使用项目提供的测试脚本：\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n此脚本会执行一系列基本操作以验证 mcp-retroarch 与 RetroArch 之间的通信是否正常。\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n<a id='retroarch-integration'></a>\n\n## RetroArch 集成\n\n### 相关页面\n\n相关主题：[安装与配置](#installation-configuration), [故障排除](#troubleshooting)\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# RetroArch 集成\n\n## 概述\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的服务器实现，用于将 AI 助手（如 Claude Code、Claude Desktop）与 RetroArch 模拟器进行集成。通过 RetroArch 的 Network Command Interface (NCI)，该工具提供了对模拟器内存、存档状态、截图等核心功能的程序化访问能力。\n\n主要功能包括：\n\n- 读写模拟器内存（支持系统内存映射和 CHEEVOS 成就地址空间两种模式）\n- 保存与加载存档状态\n- 截图与屏幕消息显示\n- 暂停、帧步进、复位等模拟器控制\n\n资料来源：[README.md]()\n\n## 架构设计\n\n### 系统架构图\n\n```mermaid\ngraph TD\n    subgraph 客户端层\n        MCP[MCP 客户端<br/>Claude Code / Claude Desktop]\n    end\n\n    subgraph 桥接层\n        STDIO[stdio 通信]\n        JSONRPC[JSON-RPC 2.0]\n        mcp_server[mcp-retroarch<br/>MCP 服务器]\n    end\n\n    subgraph 网络层\n        UDP[UDP 协议<br/>端口 55355]\n    end\n\n    subgraph 目标层\n        RA[RetroArch<br/>Network Command Interface]\n        CORE[libretro Core<br/>+ 游戏 ROM]\n    end\n\n    MCP --> STDIO\n    STDIO --> JSONRPC\n    JSONRPC --> mcp_server\n    mcp_server --> UDP\n    UDP --> RA\n    RA --> CORE\n\n    style mcp_server fill:#e1f5fe\n    style RA fill:#fff3e0\n```\n\n### 通信机制\n\nmcp-retroarch 通过 UDP 协议与 RetroArch 的 NCI 进行通信。服务器维护一个序列化查询队列，确保同一时间只有一个查询处于进行中状态，避免并发冲突。\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP 客户端\n    participant Server as mcp-retroarch\n    participant RA as RetroArch NCI\n    participant Core as libretro Core\n\n    MCP->>Server: JSON-RPC 请求\n    Server->>Server: 检查 pending 状态\n    alt 无查询进行中\n        Server->>RA: UDP 命令\n        RA->>Core: 执行指令\n        Core-->>RA: 响应数据\n        RA-->>Server: UDP 响应\n        Server-->>MCP: JSON-RPC 响应\n    else 查询进行中\n        Server-->>MCP: 错误: query already in flight\n    end\n```\n\n### 源码结构\n\n| 文件 | 职责 |\n|------|------|\n| `src/index.ts` | MCP 服务器入口，负责初始化连接探针 |\n| `src/retroarch.ts` | UDP 通信封装，处理连接、查询、发送逻辑 |\n| `src/tools.ts` | MCP 工具定义，描述每个可用命令的输入输出 |\n\n资料来源：[src/index.ts](src/index.ts)()、[src/retroarch.ts](src/retroarch.ts)()、[src/tools.ts](src/tools.ts)()\n\n## 功能模块\n\n### 内存访问\n\nmcp-retroarch 提供两种内存访问路径，适用于不同的 libretro 核心。\n\n#### READ_CORE_MEMORY（系统内存映射）\n\n通过 `retroarch_read_memory` 和 `retroarch_write_memory` 工具访问。这是**首选**方式，当核心暴露系统内存映射时可用。\n\n**支持的地址空间示例：**\n\n| 系统 | 地址范围 | 说明 |\n|------|----------|------|\n| SNES | `0x7E0000-0x7FFFFF` | WRAM |\n| GBA | `0x02000000-0x0203FFFF` | EWRAM |\n| Genesis | `0xFF0000-0xFFFFFF` | 68K RAM |\n\n#### READ_CORE_RAM（CHEEVOS 地址空间）\n\n通过 `retroarch_read_ram` 和 `retroarch_write_ram` 工具访问。作为**降级方案**，当核心不支持内存映射时使用。\n\n> 重要提示：CHEEVOS 路径与系统内存映射使用不同的地址空间，不可混用。\n\n#### 工具参数对比\n\n| 参数 | read_memory / write_memory | read_ram / write_ram |\n|------|---------------------------|---------------------|\n| 地址空间 | libretro 系统内存映射 | CHEEVOS 成就地址空间 |\n| 最大单次传输 | 4096 字节 | 4096 字节 |\n| 返回确认 | `write_memory` 返回写入字节数 | 无确认（fire-and-forget） |\n| 地址示例 | `0x7E0000` (SNES) | 因核心而异 |\n\n资料来源：[src/tools.ts](src/tools.ts)()\n\n### 存档管理\n\n```mermaid\ngraph LR\n    A[当前槽位] -->|state_slot_plus| B[槽位 +1]\n    A -->|state_slot_minus| C[槽位 -1]\n    B -->|save_state_current| D[保存存档]\n    C -->|save_state_current| D\n    E[指定槽位] -->|load_state_slot| F[加载存档]\n```\n\n| 工具 | 功能 | 备注 |\n|------|------|------|\n| `retroarch_save_state_current` | 保存到当前槽位 | 覆盖现有存档 |\n| `retroarch_load_state_current` | 从当前槽位加载 | |\n| `retroarch_load_state_slot` | 从指定槽位加载 | N = 1-10 |\n| `retroarch_state_slot_plus` | 槽位指针 +1 | NCI 无直接设置命令 |\n| `retroarch_state_slot_minus` | 槽位指针 -1 | NCI 无直接设置命令 |\n\n> ⚠️ 存档写入为**破坏性操作**，会无提示覆盖现有存档。建议在修改游戏状态前先调用 `retroarch_save_state_current` 建立回滚点。\n\n资料来源：[src/tools.ts](src/tools.ts)()\n\n### 模拟器控制\n\n| 工具 | 功能 | 使用场景 |\n|------|------|----------|\n| `retroarch_pause_toggle` | 切换暂停状态 | 内存读写前的状态稳定 |\n| `retroarch_frame_advance` | 步进一帧 | 精确帧动画检查 |\n| `retroarch_reset` | 硬复位游戏 | 重新开始当前游戏 |\n| `retroarch_get_status` | 获取模拟器状态 | 查询运行/暂停状态、已加载 ROM 信息 |\n\n### 辅助功能\n\n| 工具 | 功能 | 返回值 |\n|------|------|--------|\n| `retroarch_screenshot` | 保存截图 | 截图保存至 RetroArch 配置的截图目录 |\n| `retroarch_show_message` | 显示通知 | 在模拟器窗口显示 ~3 秒的 OSD 消息 |\n| `retroarch_get_config` | 读取配置参数 | 返回 `NAME = VALUE` 格式 |\n\n> 💡 `retroarch_show_message` 仅支持单行文本，换行符会导致消息截断。建议消息长度控制在 80 字符以内。\n\n资料来源：[src/tools.ts](src/tools.ts)()\n\n## 配置与部署\n\n### 环境变量\n\n| 变量 | 默认值 | 说明 |\n|------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | RetroArch 主机地址 |\n| `RETROARCH_PORT` | `55355` | UDP 端口，需与 `network_cmd_port` 匹配 |\n\n### RetroArch 端配置\n\n**方式一：GUI 配置**\n\n```\nSettings → Network → Network Commands → ON\n确认 Network Cmd Port 为 55355\n```\n\n**方式二：配置文件**\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n配置完成后启动任意 libretro 核心和游戏，NCI 即处于可用状态。\n\n资料来源：[README.md](README.md)()\n\n### MCP 客户端注册\n\n#### Claude Code\n\n```bash\nclaude mcp add retroarch --scope user mcp-retroarch\n```\n\n验证：\n\n```bash\nclaude mcp list\n# retroarch: mcp-retroarch - ✓ Connected\n```\n\n#### Claude Desktop\n\n编辑 `claude_desktop_config.json`，路径因平台而异：\n\n| 平台 | 路径 |\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编辑后需重启 Claude Desktop。\n\n资料来源：[README.md](README.md)()\n\n## 已测试核心\n\n| 系统 | 核心 | read_memory | read_ram | 说明 |\n|------|------|-------------|----------|------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | 中断向量表可见于 `0x0000` |\n| NES | `mesen_libretro` | ✅ | ✅ | 完整 16 位 NES 地址空间 |\n| NES | `nestopia_libretro` | ❌ | ✅ | 仅 CHEEVOS，64KB 限制 |\n| SNES | `snes9x_libretro` | ❌ | ❌ | 待补充 |\n\n资料来源：[README.md](README.md)()\n\n## 功能支持矩阵\n\n| 功能 | 支持状态 | 说明 |\n|------|----------|------|\n| 内存读写 | ✅ | 两种路径：系统内存映射（优先）和 CHEEVOS（降级） |\n| 存档保存/加载 | ✅ | 当前槽位或显式槽位加载 |\n| 截图 | ✅ | 保存至配置的截图目录 |\n| 暂停/帧步进 | ✅ | 暂停切换 + 单帧步进 |\n| 复位 | ✅ | 硬复位当前游戏 |\n| 屏幕消息 | ✅ | 约 3 秒 OSD 通知 |\n| 游戏手柄输入 | ❌ | NCI 不暴露此功能 |\n\n资料来源：[README.md](README.md)()\n\n## 故障排除\n\n| 症状 | 原因与解决方案 |\n|------|---------------|\n| `RetroArch query timed out` | Network Commands 未启用，或端口不匹配。确认 `network_cmd_enable = \"true\"`。UDP 在高负载下可能丢包，重试即可。 |\n| `READ_CORE_MEMORY failed: no memory map defined` | 核心未暴露系统内存映射。使用 `retroarch_read_ram`（CHEEVOS 路径）。SwanStation (PSX) 需使用 read_ram。 |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址超出核心内存映射范围，或核心不支持该区域。 |\n| 截图位置不符合预期 | 截图保存至 RetroArch 配置目录，NCI 不暴露 `screenshot_directory`。通过 GUI 确认：`Settings → Directory → Screenshot`。 |\n| 无法直接保存到指定槽位 | NCI 限制，只能保存到当前槽位。使用 `state_slot_plus`/`state_slot_minus` 步行至目标槽位后再保存。 |\n\n资料来源：[README.md](README.md)()\n\n## 开发指南\n\n### 快速开始\n\n```bash\nnpm install\nnpm run dev      # tsc --watch 模式\n```\n\n### 冒烟测试\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n### 依赖项\n\n| 依赖 | 版本 | 用途 |\n|------|------|------|\n| `@modelcontextprotocol/sdk` | ^1.12.0 | MCP 协议实现 |\n| `typescript` | ^5.5.0 | 开发依赖 |\n\n资料来源：[package.json](package.json)()\n\n## 版本历史\n\n### v0.1.2 (2026-05-15)\n\n工具描述质量重构，遵循 Glama's Tool Definition Quality Score (TDQS) 标准：\n\n- 所有工具描述重写为 **PURPOSE / USAGE / BEHAVIOR / RETURNS** 模板\n- 明确标注 fire-and-forget 语义\n- 破坏性操作（写入、重置、存档加载）均添加警告说明\n- 错误条件与返回值格式明确化\n\n资料来源：[CHANGELOG.md](CHANGELOG.md)()\n\n## 相关项目\n\n| 项目 | 说明 |\n|------|------|\n| [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | GBA 专用集成，通过 mGBA Lua 桥接，支持手柄输入 |\n| [mcp-pine](https://github.com/dmang-dev/mcp-pine) | PINE 协议模拟器（PCSX2 等），仅内存与存档 |\n\n资料来源：[README.md](README.md)()\n\n## 外部参考\n\n- [RetroArch NCI 官方文档](https://docs.libretro.com/development/retroarch/network-control-interface/)\n\n---\n\n<a id='mcp-tools-reference'></a>\n\n## MCP 工具参考\n\n### 相关页面\n\n相关主题：[系统架构](#system-architecture), [内存访问机制](#memory-access), [状态管理](#state-management)\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- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\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# MCP 工具参考\n\n本页面详细描述 mcp-retroarch 提供的所有 MCP 工具，这些工具通过 RetroArch 的网络控制接口（NCI）实现对模拟器的远程控制与内存读写功能。\n\n## 架构概览\n\nmcp-retroarch 作为 MCP 客户端与 RetroArch 实例之间的桥接层，通过标准输入/输出（stdio）上的 JSON-RPC 协议与 MCP 客户端通信，同时使用 UDP 协议与 RetroArch 的 NCI 进行交互。\n\n```mermaid\ngraph LR\n    A[\"MCP 客户端<br/>(Claude Code 等)\"] -->|\"JSON-RPC<br/>stdio\"| B[\"mcp-retroarch<br/>桥接进程\"]\n    B -->|\"UDP :55355\"| C[\"RetroArch<br/>NCI\"]\n    C -->|\"游戏 ROM<br/>libretro Core\"| D[\"模拟器环境\"]\n    \n    B -->|\"连接探测\"| E[\"后台连接状态\"]\n```\n\n### 通信流程\n\n1. MCP 客户端通过 stdio 发送 JSON-RPC 请求\n2. 桥接进程解析请求并转换为 NCI 命令\n3. 通过 UDP 发送至 RetroArch 并等待响应\n4. 将响应封装为 JSON-RPC 格式返回 MCP 客户端\n\n资料来源：[src/index.ts:1-20]()\n\n## 工具分类总览\n\n| 分类 | 工具数量 | 功能描述 |\n|------|----------|----------|\n| 状态查询 | 2 | 获取模拟器状态与配置参数 |\n| 内存读写 | 4 | 系统内存映射与 CHEEVOS 地址空间访问 |\n| 模拟器控制 | 4 | 暂停、帧推进、重置、截图 |\n| 存档管理 | 4 | 存档/读档、槽位切换 |\n| UI 交互 | 1 | 屏幕消息显示 |\n\n资料来源：[src/tools.ts:1-150]()\n\n## 状态查询工具\n\n### retroarch_get_status\n\n查询 RetroArch 当前运行状态，包括模拟器状态、系统标识、加载游戏及 CRC32 校验值。\n\n**用途**：在执行内存操作或存档操作前，确认模拟器处于正确的运行状态。\n\n**参数**：无\n\n**返回格式**：\n```\nState:  playing|paused\nSystem: SYSTEM_ID\nGame:   BASENAME\nCRC32:  XXXXXXXX|(none reported)\n```\n\n**无内容加载时**：返回 `No content loaded`\n\n```typescript\ncase \"retroarch_get_status\": {\n  const s = await ra.getStatus();\n  if (s.state === \"contentless\") return ok(\"No content loaded\");\n  return ok(\n    `State:  ${s.state}\\n` +\n    `System: ${s.system}\\n` +\n    `Game:   ${s.game}\\n` +\n    `CRC32:  ${s.crc32 ?? \"(none reported)\"}`,\n  );\n}\n```\n\n资料来源：[src/tools.ts:50-60]()\n\n### retroarch_get_config\n\n读取 RetroArch 配置参数值。\n\n**用途**：查询 RetroArch 的文件系统路径和运行时设置。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| name | string | 是 | 配置参数名称 |\n\n**行为**：\n- 仅读取 RetroArch NCI 白名单中的参数\n- `screenshot_directory` 未被暴露，无法通过此工具查询\n\n**返回格式**：`NAME = VALUE`\n\n```typescript\ncase \"retroarch_get_config\": {\n  const v = await ra.getConfigParam(p.name as string);\n  return ok(`${p.name} = ${v}`);\n}\n```\n\n资料来源：[src/tools.ts:62-66]()\n\n## 内存读写工具\n\nmcp-retroarch 提供两套独立的内存访问 API，分别对应不同的地址空间：\n\n```mermaid\ngraph TD\n    A[\"内存读取请求\"] --> B{目标地址空间?}\n    B -->|\"系统内存映射\"| C[\"READ_CORE_MEMORY<br/>retroarch_read_memory\"]\n    B -->|\"CHEEVOS 地址空间\"| D[\"READ_CORE_RAM<br/>retroarch_read_ram\"]\n    \n    C --> E[\"优先使用<br/>完整系统总线视图\"]\n    D --> F[\"备选方案<br/>成就系统兼容\"]\n```\n\n资料来源：[src/tools.ts:100-130]()\n\n### retroarch_read_memory\n\n通过系统内存映射读取内存。\n\n**用途**：首选的内存读取方式，适用于暴露完整系统内存映射的核心。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| address | integer | 是 | 起始地址（libretro 系统内存映射地址） |\n| length | integer | 是 | 读取字节数（1-4096） |\n\n**地址空间示例**：\n- SNES WRAM：`0x7E0000-0x7FFFFF`\n- GBA EWRAM：`0x02000000-0x0203FFFF`\n- Genesis 68K RAM：`0xFF0000-0xFFFFFF`\n\n**返回格式**：\n```\nADDR_HEX [N bytes]:\nXX XX XX XX XX XX XX XX ...\n```\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**错误处理**：\n- `no memory map defined`：核心未暴露内存映射，改用 `retroarch_read_ram`\n- `no descriptor for address`：地址不在核心描述符范围内\n\n资料来源：[src/tools.ts:68-77]()\n\n### retroarch_write_memory\n\n通过系统内存映射写入内存。\n\n**用途**：内存作弊、游戏状态修改、调试 poke 操作。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| address | integer | 是 | 起始地址 |\n| bytes | integer[] | 是 | 字节值数组（0-255） |\n\n**行为**：\n- **破坏性操作**：直接覆盖指定地址，无撤销机制\n- **禁用硬核模式**：写入后 RetroArch 自动禁用硬核模式\n- **返回确认**：唯一返回写入字节数确认的工具\n\n```typescript\ncase \"retroarch_write_memory\": {\n  const n = await ra.writeMemory(p.address as number, p.bytes as number[]);\n  return ok(`Wrote ${n} bytes → ${addrHex(p.address as number)}`);\n}\n```\n\n资料来源：[src/tools.ts:79-83]()\n\n### retroarch_read_ram\n\n通过 CHEEVOS 地址空间读取内存。\n\n**用途**：当 `retroarch_read_memory` 返回 \"no memory map defined\" 时的备选方案。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| address | integer | 是 | CHEEVOS 地址空间起始地址 |\n| length | integer | 是 | 读取字节数（1-4096） |\n\n**地址空间说明**：CHEEVOS 地址遵循 RetroAchievements 规范，与 libretro 系统总线地址不同。例如 SNES CHEEVOS WRAM 地址从 `0x000000` 开始，而非系统总线上的 `0x7E0000`。\n\n```typescript\ncase \"retroarch_read_ram\": {\n  const bytes = await ra.readRam(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, CHEEVOS]:\\n${hex}`);\n}\n```\n\n资料来源：[src/tools.ts:85-91]()\n\n### retroarch_write_ram\n\n通过 CHEEVOS 地址空间写入内存。\n\n**用途**：配合 `retroarch_read_ram` 使用，作为 `retroarch_write_memory` 的备选方案。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| address | integer | 是 | CHEEVOS 地址空间起始地址 |\n| bytes | integer[] | 是 | 字节值数组（1-4096 个元素） |\n\n**行为**：\n- **无确认机制**：RetroArch NCI 不对此命令返回确认\n- **单向传输**：即发即忘，无法区分部分写入与完全拒绝\n- **验证方式**：需通过后续的 `retroarch_read_ram` 验证写入结果\n\n```typescript\ncase \"retroarch_write_ram\": {\n  await ra.writeRam(p.address as number, p.bytes as number[]);\n  return ok(`Wrote ${(p.bytes as number[]).length} bytes → ${addrHex(p.address as number)} (CHEEVOS, no ack)`);\n}\n```\n\n资料来源：[src/tools.ts:93-95]()\n\n## 模拟器控制工具\n\n### retroarch_pause_toggle\n\n切换 RetroArch 暂停状态。\n\n**行为**：NCI 仅提供单一切换命令，无独立的暂停/恢复命令。\n\n**用途**：内存检查或存档操作前，确保模拟器处于已知状态。\n\n```typescript\ncase \"retroarch_pause_toggle\":  await ra.pauseToggle();   return ok(\"Pause toggled\");\n```\n\n资料来源：[src/tools.ts:97]()\n\n### retroarch_frame_advance\n\n单帧推进。\n\n**行为**：在暂停状态下执行，推进一帧后恢复暂停。\n\n```typescript\ncase \"retroarch_frame_advance\": await ra.frameAdvance();  return ok(\"Advanced one frame\");\n```\n\n资料来源：[src/tools.ts:98]()\n\n### retroarch_reset\n\n硬重置当前游戏。\n\n**行为**：重新加载当前 ROM，等同于按下重置按钮。\n\n```typescript\ncase \"retroarch_reset\":         await ra.reset();         return ok(\"Game reset\");\n```\n\n资料来源：[src/tools.ts:99]()\n\n### retroarch_screenshot\n\n保存截图。\n\n**行为**：截图保存至 RetroArch 配置的截图目录。\n\n**限制**：NCI 未暴露 `screenshot_directory` 参数，需通过 RetroArch GUI 确认路径（Settings → Directory → Screenshot）。\n\n```typescript\ncase \"retroarch_screenshot\":    await ra.screenshot();    return ok(\"Screenshot saved to RetroArch's configured screenshot directory\");\n```\n\n资料来源：[src/tools.ts:100]()\n\n## 存档管理工具\n\n### 槽位模型说明\n\nNCI 协议存在以下限制：\n\n```mermaid\ngraph LR\n    A[\"save_state_current\"] -->|\"只能写入|当前槽位\"| B[\"槽位指针\"]\n    C[\"load_state_slot N\"] -->|\"可指定槽位\"| B\n    D[\"state_slot_plus<br/>state_slot_minus\"] -->|\"移动指针\"| B\n    \n    B -->|\"GUI 显示\"| E[\"用户需观察确认\"]\n```\n\n| 操作 | NCI 支持 | 限制说明 |\n|------|----------|----------|\n| 保存到当前槽位 | ✅ | 只能写入 GUI 当前选择的槽位 |\n| 从指定槽位加载 | ✅ | 可直接指定槽位号 |\n| 读取当前槽位号 | ❌ | 无法查询当前槽位，需客户端自行跟踪 |\n| 直接保存到指定槽位 | ❌ | 必须通过加减操作移动槽位指针 |\n\n资料来源：[src/tools.ts:100-115]()\n\n### retroarch_save_state_current\n\n保存当前游戏状态到当前槽位。\n\n```typescript\ncase \"retroarch_save_state_current\":  await ra.saveStateCurrent();          return ok(\"Saved to current slot\");\n```\n\n### retroarch_load_state_current\n\n从当前槽位加载游戏状态。\n\n```typescript\ncase \"retroarch_load_state_current\":  await ra.loadStateCurrent();          return ok(\"Loaded from current slot\");\n```\n\n### retroarch_load_state_slot\n\n从指定槽位加载游戏状态。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| slot | integer | 是 | 存档槽位号 |\n\n```typescript\ncase \"retroarch_load_state_slot\":     await ra.loadStateSlot(p.slot as number); return ok(`Loaded from slot ${p.slot}`);\n```\n\n### retroarch_state_slot_plus / retroarch_state_slot_minus\n\n调整当前槽位指针。\n\n**用途**：由于 NCI 无法直接保存到指定槽位，需通过这两个命令逐步移动槽位指针至目标位置。\n\n```typescript\ncase \"retroarch_state_slot_plus\":     await ra.stateSlotPlus();   return ok(\"Slot +1\");\ncase \"retroarch_state_slot_minus\":    await ra.stateSlotMinus();  return ok(\"Slot -1\");\n```\n\n资料来源：[src/tools.ts:102-106]()\n\n## UI 交互工具\n\n### retroarch_show_message\n\n在 RetroArch 窗口显示通知消息。\n\n**用途**：脚本化运行时提示用户注意位置，或确认操作完成。\n\n**参数**：\n\n| 参数名 | 类型 | 必填 | 描述 |\n|--------|------|------|------|\n| message | string | 是 | 显示的消息内容 |\n\n```typescript\ncase \"retroarch_show_message\": {\n  await ra.showMessage(p.message as string);\n  return ok(`Showed: ${p.message}`);\n}\n```\n\n资料来源：[src/tools.ts:101-104]()\n\n## 网络通信层\n\n### UDP 查询机制\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP 客户端\n    participant Bridge as mcp-retroarch\n    participant RA as RetroArch NCI\n    \n    Bridge->>RA: 发送 UDP 命令\n    Note over Bridge: 设置超时计时器\n    RA-->>Bridge: 返回响应\n    Bridge->>Bridge: 清除超时计时器\n    Bridge-->>MCP: JSON-RPC 响应\n```\n\n**关键特性**：\n\n| 特性 | 描述 |\n|------|------|\n| 串行查询 | 一次仅允许一个查询进行中 |\n| 超时机制 | 默认超时可配置，超时后抛出错误 |\n| 异步处理 | 使用 Promise 封装 UDP 双向通信 |\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    this.socket!.send(command, this.port, this.host, (err) => {\n      if (err) {\n        if (timer) { clearTimeout(timer); timer = null; }\n        this.pending = null;\n        reject(err);\n      }\n    });\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:80-110]()\n\n### 环境变量配置\n\n| 环境变量 | 默认值 | 用途 |\n|----------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机 |\n| `RETROARCH_PORT` | `55355` | UDP 端口（需与 `network_cmd_port` 匹配） |\n\n资料来源：[README.md:configuration]()\n\n## 工具模式参考\n\n### 只读检查模式\n\n```\nretroarch_get_status → 确认状态\nretroarch_read_memory / retroarch_read_ram → 读取内存\n```\n\n### 状态修改模式\n\n```\nretroarch_save_state_current → 创建回滚点\nretroarch_pause_toggle → 暂停模拟\nretroarch_write_memory → 修改内存\n```\n\n### 存档操作模式\n\n```\nretroarch_get_status → 确认游戏已加载\nretroarch_state_slot_plus/minus → 调整槽位\nretroarch_save_state_current → 保存\n或\nretroarch_load_state_slot → 加载指定槽位\n```\n\n## 错误处理\n\n| 错误信息 | 原因与解决 |\n|----------|------------|\n| `RetroArch query timed out` | 网络命令未启用或端口不匹配；UDP 在高负载下可能丢包，可重试 |\n| `READ_CORE_MEMORY failed: no memory map defined` | 核心未暴露内存映射，改用 `retroarch_read_ram` |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址超出核心内存描述符范围 |\n| `retroarch query already in flight` | 客户端串行限制，同一时间仅能有一个查询进行 |\n\n资料来源：[README.md:troubleshooting]()\n\n## 依赖项\n\n```json\n{\n  \"@modelcontextprotocol/sdk\": \"^1.12.0\"\n}\n```\n\n资料来源：[package.json:dependencies]()\n\n## 版本历史\n\n| 版本 | 日期 | 主要变更 |\n|------|------|----------|\n| 0.1.2 | 2026-05-15 | 重写所有工具描述，采用 PURPOSE/USAGE/BEHAVIOR/RETURNS 模板 |\n| 0.1.1 | 2026-05-11 | 非阻塞启动，后台连接探测 |\n| 0.1.0 | - | 初始版本 |\n\n资料来源：[CHANGELOG.md:1-50]()\n\n---\n\n<a id='supported-cores'></a>\n\n## 支持的模拟器核心\n\n### 相关页面\n\n相关主题：[内存访问机制](#memory-access), [故障排除](#troubleshooting)\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- [CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n</details>\n\n# 支持的模拟器核心\n\n## 概述\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的服务器，它通过 RetroArch 的网络控制接口 (Network Control Interface, NCI) 与运行中的模拟器进行通信。该项目本身不实现任何模拟器核心，而是充当 MCP 客户端与 RetroArch 之间的桥接层，支持所有兼容 RetroArch NCI 协议的核心。资料来源：[README.md:1-20]()\n\n核心支持程度取决于两个方面：RetroArch NCI 协议层面的通用支持，以及各 libretro 核心对内存映射的暴露程度。不同的模拟器核心在内存读取/写入功能上存在显著差异。\n\n## 架构通信流程\n\n```mermaid\ngraph TD\n    A[\"MCP 客户端<br/>(Claude Code 等)\"] -->|\"JSON-RPC/stdin\"| B[\"mcp-retroarch<br/>服务器进程\"]\n    B -->|\"UDP :55355<br/>NCI 命令\"| C[\"RetroArch<br/>网络控制接口\"]\n    C -->|\"LOADED CORE<br/>libretro 核心\"| D[\"GBA<br/>mgba_libretro\"]\n    C -->|\"LOADED CORE<br/>libretro 核心\"| E[\"NES<br/>mesen_libretro\"]\n    C -->|\"LOADED CORE<br/>libretro 核心\"| F[\"SNES<br/>snes9x_libretro\"]\n    C -->|\"LOADED CORE<br/>libretro 核心\"| G[\"PSX<br/>SwanStation\"]\n    \n    style B fill:#e1f5fe\n    style C fill:#fff3e0\n```\n\n## 已验证的核心\n\n### 核心兼容性总览\n\n| 系统 | 核心 | read_memory | read_ram | 备注 |\n|------|------|-------------|----------|------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA 中断向量表可见于 `0x0000` (显示 `d3 00 00 ea ...`) |\n| NES | `mesen_libretro` | ✅ | ✅ | 全 16 位 NES 地址空间暴露，WRAM 位于 `0x0000-0x07FF` 并镜像至 `0x1FFF`，CHEEVOS 限制在前 64 KB |\n| NES | `nestopia_libretro` | ❌ | ✅ | 无内存映射，仅支持 CHEEVOS，64 KB 限制 |\n| SNES | `snes9x_libretro` | ❌ | 待验证 | 需进一步测试 |\n| PlayStation | SwanStation | ❌ | ✅ | 需使用 `read_ram` |\n\n资料来源：[README.md:80-100]()\n\n### Game Boy Advance (mgba_libretro)\n\nGBA 核心是测试最充分的核心之一，其内存布局如下：\n\n| 内存区域 | 地址范围 | 大小 | 说明 |\n|----------|----------|------|------|\n| IWRAM | `0x03000000-0x03007FFF` | 32 KB | 内部工作 RAM |\n| EWRAM | `0x02000000-0x0203FFFF` | 256 KB | 外部工作 RAM |\n| ROM | 动态映射 | 可变 | 游戏卡带 ROM |\n| VRAM | `0x06000000-0x06017FFF` | 96 KB | 视频 RAM |\n\nGBA 核心通过 `READ_CORE_MEMORY` 命令完整暴露系统内存映射，中断向量表位于 `0x0000` 地址空间起始处，可通过 `retroarch_read_memory` 工具直接读取。资料来源：[README.md:84]()\n\n### NES (mesen_libretro)\n\nMesen 核心是 NES 平台的首选推荐，它提供完整的内存映射支持：\n\n| 地址范围 | 说明 |\n|----------|------|\n| `0x0000-0x07FF` | WRAM (2 KB，内部镜像至 `0x0800-0x1FFF`) |\n| `0x2000-0x3FFF` | PPU 寄存器 (I/O 寄存器) |\n| `0x4000-0x401F` | APU 和控制器寄存器 |\n\nNestopia 核心作为替代方案可用，但不支持 `READ_CORE_MEMORY`，只能通过 CHEEVOS 地址空间 (`read_ram`) 访问内存。资料来源：[README.md:88-92]()\n\n### PlayStation (SwanStation)\n\n对于 PlayStation 模拟，SwanStation 核心不支持 `READ_CORE_MEMORY`，需要使用 `retroarch_read_ram` 通过 CHEEVOS 地址空间读取内存。这种限制要求用户熟悉 PS1 的 CHEEVOS 地址规范。资料来源：[README.md:97]()\n\n## 内存访问 API 分层\n\nmcp-retroarch 提供两套内存访问接口，选择取决于目标核心的能力：\n\n```mermaid\ngraph LR\n    A[\"MCP 工具调用\"] --> B{核心是否支持<br/>系统内存映射?}\n    B -->|是| C[\"retroarch_read_memory<br/>retroarch_write_memory\"]\n    B -->|否| D[\"retroarch_read_ram<br/>retroarch_write_ram\"]\n    \n    C -->|\"READ_CORE_MEMORY<br/>WRITE_CORE_MEMORY\"| E[\"libretro 系统<br/>内存映射\"]\n    D -->|\"READ_CORE_RAM<br/>WRITE_CORE_RAM\"| F[\"CHEEVOS<br/>地址空间\"]\n```\n\n### READ_CORE_MEMORY / WRITE_CORE_MEMORY\n\n这是首选的内存访问方式，直接映射到 libretro 核心的原生系统内存布局：\n\n- **优势**：地址符合硬件实际架构（如 GBA EWRAM 位于 `0x02000000`）\n- **限制**：仅当核心广告内存映射时可用\n- **返回**：确认写入的字节数\n\n资料来源：[src/tools.ts:60-100]()\n\n### READ_CORE_RAM / WRITE_CORE_RAM\n\nCHEEVOS 地址空间，适用于不暴露系统内存映射的核心：\n\n- **优势**：即使核心无内存映射也能工作（RetroAchievements API 广泛支持）\n- **限制**：地址遵循 CHEEVOS 约定，非原生系统总线地址\n- **返回**：不确认写入成功（fire-and-forget 语义）\n\n资料来源：[src/tools.ts:130-170]()\n\n## 功能支持矩阵\n\n| 功能 | GBA (mgba) | NES (Mesen) | NES (Nestopia) | SNES | PSX |\n|------|------------|--------------|----------------|------|-----|\n| 内存读取 | ✅ 系统映射 | ✅ 系统映射 | ❌ 仅 CHEEVOS | ❌ | ❌ 仅 CHEEVOS |\n| 内存写入 | ✅ 系统映射 | ✅ 系统映射 | ❌ | ❌ | ❌ |\n| 存档状态 | ✅ | ✅ | ✅ | ✅ | ✅ |\n| 截图 | ✅ | ✅ | ✅ | ✅ | ✅ |\n| 暂停/帧推进 | ✅ | ✅ | ✅ | ✅ | ✅ |\n| 重置 | ✅ | ✅ | ✅ | ✅ | ✅ |\n| 屏幕消息 | ✅ | ✅ | ✅ | ✅ | ✅ |\n| 手柄输入 | ❌ | ❌ | ❌ | ❌ | ❌ |\n\n资料来源：[README.md:100-130]()\n\n## 核心选择建议\n\n### 内存操作场景\n\n```mermaid\ngraph TD\n    A[\"需要内存读写\"] --> B{\"哪个平台?\"}\n    B -->|GBA| C[\"使用 mgba_libretro<br/>首选 read_memory\"]\n    B -->|NES| D[\"使用 mesen_libretro<br/>首选 read_memory\"]\n    B -->|PSX| E[\"使用 SwanStation<br/>使用 read_ram\"]\n    B -->|其他| F[\"查阅核心文档<br/>尝试 read_memory 后 fallback\"]\n```\n\n对于 **GBA + 内存操作**：强烈推荐 `mgba_libretro`，它完整暴露内存映射且经过充分测试。\n\n对于 **NES + 内存操作**：推荐 `mesen_libretro` 而非 `nestopia_libretro`，前者支持系统内存映射，后者仅支持 CHEEVOS。\n\n对于 **PSX + 内存操作**：使用 `read_ram` (CHEEVOS 路径)，SwanStation 不暴露系统内存映射。\n\n资料来源：[README.md:90-92]()\n\n## 环境配置\n\n核心功能依赖于 RetroArch 网络控制接口的正确配置：\n\n```ini\n# retroarch.cfg 必要配置\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n| 环境变量 | 默认值 | 说明 |\n|----------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机 |\n| `RETROARCH_PORT` | `55355` | UDP 端口（必须与 retroarch.cfg 中的 `network_cmd_port` 匹配） |\n\n资料来源：[README.md:60-75]()\n\n## 已知限制\n\n### 核心无关限制\n\n- **游戏手柄输入**：NCI 协议不暴露手柄输入功能。RetroArch 有独立的 \"Remote RetroPad\" 核心（UDP 端口 55400），但需要加载特定核心，无法驱动现有模拟核心。GBA 平台的手柄输入可参考 [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) 项目。资料来源：[README.md:130-135]()\n\n- **存档槽位写入**：NCI 协议仅暴露\"保存到当前槽位\"命令，无法直接指定目标槽位。需使用 `state_slot_plus` / `state_slot_minus` 遍历到目标槽位后再保存。资料来源：[README.md:145-148]()\n\n- **截图目录查询**：NCI 不通过 `GET_CONFIG_PARAM` 暴露 `screenshot_directory`，需通过 RetroArch GUI (Settings → Directory → Screenshot) 确认。资料来源：[README.md:140-143]()\n\n### 特定核心限制\n\n| 限制 | 影响核心 | 原因 |\n|------|----------|------|\n| 无系统内存映射 | `nestopia_libretro` | 核心设计选择 |\n| 无系统内存映射 | SwanStation | 核心设计选择 |\n| 仅支持 CHEEVOS | 多个核心 | 兼容性和硬件限制 |\n\n## 相关项目\n\nmcp-retroarch 专注于通过 RetroArch NCI 控制模拟器。如需特定平台的高级功能，可参考相关项目：\n\n| 项目 | 平台 | 特性 |\n|------|------|------|\n| [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | Game Boy Advance | 通过 mGBA Lua 桥接，支持手柄输入和截图 |\n| [mcp-pine](https://github.com/dmang-dev/mcp-pine) | PCSX2 等 | 通过 PINE 协议，支持内存和存档状态 |\n\n资料来源：[README.md:150-155]()\n\n## 故障排除\n\n| 症状 | 原因/解决方案 |\n|------|---------------|\n| `RetroArch query timed out` | 网络命令未启用或端口不匹配，检查 `network_cmd_enable = \"true\"` |\n| `READ_CORE_MEMORY failed: no memory map defined` | 核心不支持系统内存映射，尝试 `retroarch_read_ram` |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址不在核心内存映射范围内，需更换核心或确认地址 |\n| Screenshots don't appear | 截图保存至 RetroArch 配置的截图目录，通过 GUI 确认路径 |\n\n资料来源：[README.md:110-145]()\n\n---\n\n<a id='memory-access'></a>\n\n## 内存访问机制\n\n### 相关页面\n\n相关主题：[MCP 工具参考](#mcp-tools-reference), [支持的模拟器核心](#supported-cores)\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- [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- [package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n</details>\n\n# 内存访问机制\n\n## 概述\n\nmcp-retroarch 通过 RetroArch 的网络控制接口（NCI）与模拟器进行通信，提供对模拟器内存的读写访问能力。该项目实现了两种独立的内存读取路径，分别对应不同的底层 API，适用于不同的应用场景和模拟器核心。\n\nmcp-retroarch 的内存访问机制是 MCP 工具服务器的核心功能之一，允许 AI 客户端直接读取和修改模拟器运行时的内存状态，从而实现游戏状态检查、作弊注入、调试辅助等高级功能。\n\n资料来源：[README.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 架构概览\n\n```\n┌─────────────────┐     stdio/JSON-RPC     ┌──────────────────┐    UDP :55355    ┌─────────────────┐\n│    MCP 客户端    │ ◄────────────────────► │   mcp-retroarch  │ ◄──────────────► │   RetroArch     │\n│  (Claude Code)  │                        │   (Node.js)      │                   │   NCI 接口      │\n└─────────────────┘                        └──────────────────┘                   └─────────────────┘\n                                                    │\n                                          ┌─────────┴─────────┐\n                                          │                   │\n                                    ┌─────▼─────┐       ┌─────▼─────┐\n                                    │ READ_CORE │       │ READ_CORE │\n                                    │ _MEMORY   │       │ _RAM      │\n                                    │ (系统内存) │       │ (CHEEVOS) │\n                                    └───────────┘       └───────────┘\n```\n\n## 两种内存 API 的区分\n\nmcp-retroarch 实现了两套独立的内存访问 API，分别对应不同的底层协议和地址空间：\n\n| 特性 | `retroarch_read_memory` / `retroarch_write_memory` | `retroarch_read_ram` / `retroarch_write_ram` |\n|------|---------------------------------------------------|---------------------------------------------|\n| 底层协议 | `CMD_CORE_MEMORY`（READ_CORE_MEMORY / WRITE_CORE_MEMORY） | `READ_CORE_RAM`（CHEEVOS API） |\n| 地址空间 | libretro 核心声明的系统内存映射 | RetroAchievements 的 CHEEVOS 地址空间 |\n| 适用场景 | 需要精确系统总线地址时（如 GBA EWRAM、SNES WRAM） | 核心未暴露系统内存映射时的备用方案 |\n| 核心兼容性 | 仅部分核心支持（如 Mesen libretro） | 大多数核心均支持（即使没有内存映射） |\n| 写入确认 | **有**（返回写入字节数） | **无**（fire-and-forget，无确认） |\n\n资料来源：[README.md - Tested cores](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n### READ_CORE_MEMORY（系统内存映射）\n\n该 API 通过 libretro 核心声明的系统内存描述符列表进行访问，返回的地址对应真实的系统总线地址。\n\n典型地址布局示例：\n\n| 系统 | 地址范围 | 说明 |\n|------|----------|------|\n| SNES | `0x7E0000-0x7FFFFF` | SNES 内部 WRAM |\n| GBA | `0x02000000-0x0203FFFF` | GBA 外部工作内存（EWRAM） |\n| Genesis | `0xFF0000-0xFFFFFF` | MC68000 主内存 |\n\n资料来源：[src/tools.ts:46-48](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### READ_CORE_RAM（CHEEVOS 地址空间）\n\n该 API 通过 RetroAchievements 的地址映射进行内存访问，适用于那些没有完整系统内存映射但启用了成就系统的模拟器核心。\n\nCHEEVOS 地址空间与系统总线地址使用不同的映射规则，例如 SNES CHEEVOS 地址空间中 WRAM 起始地址为 `0x000000`，而非系统总线的 `0x7E0000`。\n\n资料来源：[src/tools.ts:74-78](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## 核心实现\n\n### UDP 传输层\n\n内存访问通过 UDP 数据报实现，核心代码位于 `RetroArch` 类中：\n\n```typescript\n// 连接建立\nasync connect(): Promise<void> {\n  const sock = dgram.createSocket(\"udp4\");\n  // ... socket 初始化逻辑\n}\n\n// 查询并等待响应\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\");\n  }\n  // ... 超时处理和响应接收\n}\n```\n\n资料来源：[src/retroarch.ts:16-58](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n### 内存读取实现\n\n```typescript\nasync readMemory(address: number, length: number): Promise<Buffer> {\n  const cmd = `READ_CORE_MEMORY ${address} ${length}`;\n  return this.query(cmd);\n}\n\nasync readRam(address: number, length: number): Promise<Buffer> {\n  const cmd = `READ_CORE_RAM ${address} ${length}`;\n  return this.query(cmd);\n}\n```\n\n资料来源：[src/retroarch.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n### 内存写入实现\n\n两种写入 API 在确认机制上存在关键差异：\n\n| API | 返回值 | 说明 |\n|-----|--------|------|\n| `writeMemory` | 写入字节数 | RetroArch 协议会返回实际写入的字节数 |\n| `writeRam` | 无确认 | CHEEVOS API 不返回确认，属于 fire-and-forget 模式 |\n\n资料来源：[src/tools.ts:58-60](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## MCP 工具定义\n\n### retroarch_read_memory\n\n```json\n{\n  \"name\": \"retroarch_read_memory\",\n  \"description\": \"PURPOSE: 读取系统内存映射中的字节序列...\",\n  \"inputSchema\": {\n    \"type\": \"object\",\n    \"required\": [\"address\", \"length\"],\n    \"properties\": {\n      \"address\": {\n        \"type\": \"integer\",\n        \"minimum\": 0,\n        \"description\": \"libretro 核心系统内存映射中的起始地址...\"\n      },\n      \"length\": {\n        \"type\": \"integer\",\n        \"minimum\": 1,\n        \"maximum\": 4096,\n        \"description\": \"连续读取的字节数 (1-4096)\"\n      }\n    }\n  }\n}\n```\n\n### retroarch_read_ram\n\n```json\n{\n  \"name\": \"retroarch_read_ram\",\n  \"description\": \"PURPOSE: 通过 CHEEVOS 地址空间读取最多 4096 字节...\",\n  \"inputSchema\": {\n    \"type\": \"object\",\n    \"required\": [\"address\", \"length\"],\n    \"properties\": {\n      \"address\": {\n        \"type\": \"integer\",\n        \"minimum\": 0,\n        \"description\": \"CHEEVOS（成就）地址空间中的起始地址...\"\n      },\n      \"length\": {\n        \"type\": \"integer\",\n        \"minimum\": 1,\n        \"maximum\": 4096\n      }\n    }\n  }\n}\n```\n\n资料来源：[src/tools.ts](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n## 核心兼容性矩阵\n\n| 系统 | 核心 | `read_memory` | `read_ram` | 备注 |\n|------|------|-------------|-----------|------|\n| Game Boy Advance | `mgba_libretro` | ✅ | ✅ | GBA 中断向量表可见于 `0x0000` |\n| NES | `mesen_libretro` | ✅ | ✅ | 完整 16 位 NES 地址空间暴露 |\n| NES | `nestopia_libretro` | ❌ 无内存映射 | ✅ | 仅支持 CHEEVOS |\n| SNES | `snes9x_libretro` | ❌ | ❌ | 暂不支持 |\n\n资料来源：[README.md - Tested cores](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 行为特性与限制\n\n### 单次调用字节限制\n\n所有内存访问工具的单次调用最大字节数均为 **4096 字节**，这是 RetroArch NCI 单数据报大小的硬性限制。超出此限制的操作需要分块进行：\n\n```\n建议分块大小: 4 KiB (4096 bytes)\n对于大型写入操作，请按 4 KiB 分块批量处理\n```\n\n资料来源：[src/tools.ts:52](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### 内存区域边界\n\nRetroArch 可能在读取跨越内存区域边界时返回**少于请求的字节数**，响应中会报告实际返回的字节数。\n\n```typescript\n// 可能返回 fewer bytes than requested\nconst bytes = await ra.readMemory(address, length);\n// bytes.length <= length\n```\n\n### Fire-and-forget 语义\n\n除 `writeMemory` 外，大多数 NCI 命令不会返回确认。返回的成功消息仅表示 UDP 数据报已发送，**不表示** RetroArch 已接收或执行了该命令：\n\n> RetroArch's NCI doesn't acknowledge most state mutations. Every affected tool's BEHAVIOR section now warns that the success message is a UDP-send confirmation only, NOT verification that RetroArch received or acted on the command.\n\n资料来源：[CHANGELOG.md](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n\n### 硬核模式副作用\n\n任何内存写入操作（`write_memory` 或 `write_ram`）都会自动禁用 RetroArch 的硬核模式（Hardcore Mode），这是 RetroArch 协议层面的安全机制。\n\n资料来源：[src/tools.ts:58-60](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n### 状态修改警告\n\n内存写入是**破坏性操作**，会直接覆盖从 `address` 开始的 N 个字节，且无撤销功能。建议在执行写入前使用 `retroarch_save_state_current` 创建还原点：\n\n```typescript\n// 建议的工作流程\nawait ra.saveStateCurrent();           // 1. 保存还原点\nawait ra.writeMemory(address, bytes);   // 2. 执行写入\n// ... 验证操作 ...\nawait ra.loadStateCurrent();            // 3. 如需回滚\n```\n\n## 故障排查\n\n| 症状 | 原因 / 解决方案 |\n|------|----------------|\n| `READ_CORE_MEMORY failed: no memory map defined` | 加载的 libretro 核心未声明系统内存映射，尝试改用 `retroarch_read_ram` |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址不在核心内存描述符覆盖范围内 |\n| UDP 查询超时 | 确认 RetroArch 中 Network Commands 已启用，`network_cmd_enable = \"true\"` |\n| 返回字节数少于请求 | 读取跨越了内存区域边界，这是协议正常行为 |\n\n资料来源：[README.md - Troubleshooting](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n## 环境配置\n\n| 环境变量 | 默认值 | 说明 |\n|----------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机 |\n| `RETROARCH_PORT` | `55355` | UDP 端口（需与 `retroarch.cfg` 中的 `network_cmd_port` 匹配） |\n\n资料来源：[README.md - Configuration](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n<a id='state-management'></a>\n\n## 状态管理\n\n### 相关页面\n\n相关主题：[MCP 工具参考](#mcp-tools-reference)\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- [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# 状态管理\n\n## 概述\n\nmcp-retroarch 通过 UDP 网络协议与 RetroArch 的网络控制接口（NCI）通信，实现对模拟器的状态监控与控制。状态管理涵盖四个核心维度：**连接状态**、**查询状态机**、**模拟器运行状态**以及**存档槽位状态**。\n\n## 架构概览\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│                        mcp-retroarch                                 │\n│  ┌─────────────┐    ┌──────────────────┐    ┌────────────────────┐ │\n│  │ MCP Client  │───▶│  tools.ts        │───▶│  retroarch.ts      │ │\n│  │ (Claude等)  │◀───│  (工具定义)      │◀───│  (NCI通信层)       │ │\n│  └─────────────┘    └──────────────────┘    └─────────┬─────────┘ │\n│                                                       │           │\n│                                              ┌────────▼─────────┐  │\n│                                              │   UDP Socket     │  │\n│                                              │  (dgram模块)     │  │\n│                                              └────────┬─────────┘  │\n└───────────────────────────────────────────────────────┼─────────────┘\n                                                        │\n                                              UDP :55355│\n                                                        ▼\n                                              ┌─────────────────────┐\n                                              │  RetroArch NCI      │\n                                              │  (网络控制接口)      │\n                                              └─────────────────────┘\n```\n\n## 连接状态管理\n\n### 连接生命周期\n\n`RetroArch` 类通过 `connect()` 方法初始化 UDP socket，该方法返回一个 Promise，确保 socket 绑定完成后再进行后续操作。\n\n**关键状态字段：**\n\n| 字段 | 类型 | 说明 |\n|------|------|------|\n| `socket` | `dgram.Socket \\| null` | UDP socket 引用 |\n| `pending` | `((msg: Buffer) => void) \\| null` | 待处理的查询回调 |\n| `host` | `string` | 目标主机地址 |\n| `port` | `number` | 目标 UDP 端口 |\n| `timeoutMs` | `number` | 查询超时时间 |\n\n**初始化流程（源码第15-31行）：**\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;       // 无待处理回调时丢弃\n        this.pending = null;\n        cb(msg);\n      });\n      sock.on(\"error\", () => { /* 静默忽略后续错误 */ });\n      this.socket = sock;\n      resolve();\n    });\n  });\n}\n```\n\n### 连接配置\n\n通过环境变量控制连接目标：\n\n| 环境变量 | 默认值 | 说明 |\n|----------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机 |\n| `RETROARCH_PORT` | `55355` | UDP 端口（需与 RetroArch 配置匹配） |\n\n资料来源：[README.md:配置段落]() \n\n### 断开连接\n\n```typescript\ndisconnect(): void {\n  this.socket?.close();\n  this.socket = null;\n}\n```\n\n资料来源：[src/retroarch.ts:disconnect方法]() \n\n## 查询状态机\n\n### 请求-响应模型\n\nmcp-retroarch 实现了一个**串行查询状态机**：同一时间只允许一个查询在飞行中（in-flight）。这是 UDP 无连接特性的必然要求。\n\n**状态转换图：**\n\n```mermaid\ngraph TD\n    A[空闲] -->|query调用| B[查询中 pending]\n    B -->|收到响应| A\n    B -->|超时| C[错误: query timed out]\n    C -->|重试| A\n    A -->|query调用| B\n    B -->|send时socket未连接| D[自动connect]\n    D --> B\n```\n\n### query 方法实现\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    this.socket!.send(command, this.port, this.host, (err) => {\n      if (err) {\n        if (timer) { clearTimeout(timer); timer = null; }\n        this.pending = null;\n        reject(err);\n      }\n    });\n  });\n}\n```\n\n资料来源：[src/retroarch.ts:query方法:73-99行]()\n\n### 两种发送模式\n\n| 模式 | 方法 | 用途 | 等待响应 |\n|------|------|------|----------|\n| **查询模式** | `query()` | 读取数据（状态、内存、配置） | ✅ 等待 UDP 响应 |\n| **发送模式** | `send()` | 发送命令（暂停、重置、截图） | ❌ 防火遗忘 |\n\n```typescript\n/** 防火遗忘发送，用于热键类命令 */\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:send方法:54-61行]()\n\n## 模拟器状态管理\n\n### 状态查询\n\n通过 `getStatus()` 方法获取 RetroArch 当前运行状态：\n\n```typescript\nasync getStatus(): Promise<EmuStatus> {\n  const r = (await this.query(\"GET_STATUS\")).toString().trim();\n  // 响应格式: \"GET_STATUS PAUSED system_id,game_basename,crc32=XXXXXXXX\"\n  const m = r.match(/^GET_STATUS\\s+(\\w+)(?:\\s+([^,]+),(.+?)(?:,crc32=([0-9A-Fa-f]+))?)?/);\n  // ...\n}\n```\n\n资料来源：[src/retroarch.ts:getStatus方法]() \n\n### 状态类型定义\n\n```typescript\ninterface EmuStatus {\n  state: \"playing\" | \"paused\" | \"contentless\";\n  system?: string;   // 系统标识符\n  game?: string;     // 游戏文件名\n  crc32?: string;    // CRC32 校验值\n}\n```\n\n### 状态值说明\n\n| 状态值 | 含义 | 触发条件 |\n|--------|------|----------|\n| `playing` | 模拟器正在运行游戏 | 加载 ROM 后未暂停 |\n| `paused` | 模拟器暂停 | 用户按暂停或调用 `pause_toggle` |\n| `contentless` | 无内容加载 | RetroArch 在主菜单未加载任何游戏 |\n\n## 存档槽位状态管理\n\n### 存档操作命令\n\n| 操作 | 命令 | 方法 | 槽位支持 |\n|------|------|------|----------|\n| 保存当前槽 | `SAVE_STATE` | `saveStateCurrent()` | 仅当前槽 |\n| 加载当前槽 | `LOAD_STATE` | `loadStateCurrent()` | 仅当前槽 |\n| 加载指定槽 | `LOAD_STATE N` | `loadStateSlot(n)` | 显式槽位号 |\n| 槽位+1 | `STATE_SLOT_PLUS` | `stateSlotPlus()` | 移动指针 |\n| 槽位-1 | `STATE_SLOT_MINUS` | `stateSlotMinus()` | 移动指针 |\n\n### 槽位指针机制\n\nNCI 协议仅暴露当前槽位指针的移动操作，不支持直接跳转到指定槽位：\n\n```mermaid\ngraph LR\n    A[槽位0] -->|STATE_SLOT_PLUS| B[槽位1]\n    B -->|STATE_SLOT_PLUS| C[槽位2]\n    C -->|STATE_SLOT_MINUS| B\n    B -->|SAVE_STATE| D[保存到槽位1]\n```\n\n### 工具层实现\n\n```typescript\ncase \"retroarch_save_state_current\":  \n  await ra.saveStateCurrent();          \n  return ok(\"Saved to current slot\");\ncase \"retroarch_load_state_current\":  \n  await ra.loadStateCurrent();          \n  return ok(\"Loaded from current slot\");\ncase \"retroarch_load_state_slot\":     \n  await ra.loadStateSlot(p.slot as number); \n  return ok(`Loaded from slot ${p.slot}`);\n```\n\n资料来源：[src/tools.ts:存档相关工具:130-136行]()\n\n## 内存访问状态\n\n### 双路径内存读取\n\n| 路径 | 命令 | 用途 | 适用场景 |\n|------|------|------|----------|\n| **READ_CORE_MEMORY** | `readMemory()` | 系统内存映射（优先） | 支持 memory map 的核心 |\n| **READ_CORE_RAM** | `readRam()` | CHEEVOS 地址空间（备用） | 无 memory map 的核心 |\n\n### 写入确认机制\n\n两种写入方法的确认行为不同：\n\n| 方法 | 返回确认 | 说明 |\n|------|----------|------|\n| `writeMemory()` | ✅ 返回写入字节数 | NCI 会响应写入计数 |\n| `writeRam()` | ❌ 无确认 | 纯防火遗忘 |\n\n```typescript\ncase \"retroarch_write_memory\": {\n  const n = await ra.writeMemory(p.address as number, p.bytes as number[]);\n  return ok(`Wrote ${n} bytes → ${addrHex(p.address as number)}`);\n}\n\ncase \"retroarch_write_ram\": {\n  await ra.writeRam(p.address as number, p.bytes as number[]);\n  return ok(`Wrote ${(p.bytes as number[]).length} bytes → ${addrHex(p.address as number)} (CHEEVOS, no ack)`);\n}\n```\n\n资料来源：[src/tools.ts:内存写入工具:45-55行]()\n\n## 错误处理与超时\n\n### 超时配置\n\n```typescript\nconst DEFAULT_TIMEOUT_MS = 5000;\n\nasync query(command: string): Promise<Buffer> {\n  // ... 5秒超时后 reject\n}\n```\n\n### 错误类型\n\n| 错误场景 | 错误信息 | 处理建议 |\n|----------|----------|----------|\n| 超时 | `RetroArch query \"XXX\" timed out after 5000ms` | 确认 RetroArch 运行且网络命令已启用 |\n| 并发冲突 | `retroarch query already in flight` | 等待前一个查询完成 |\n| 连接失败 | Socket error | 检查 `RETROARCH_HOST`/`RETROARCH_PORT` |\n\n### 后台连接探测\n\n`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\n资料来源：[src/index.ts:启动代码段]() \n\n## 状态管理最佳实践\n\n### 已知状态再操作\n\n由于大多数 NCI 命令为防火遗忘，操作前应先查询状态：\n\n```mermaid\ngraph TD\n    A[获取状态] --> B{状态是什么?}\n    B -->|playing| C[暂停]\n    B -->|paused| D[确认后再暂停]\n    C --> E[执行目标操作]\n    D --> E\n```\n\n### 破坏性操作前存档\n\n```typescript\n// 内存写入前保存当前状态\nawait ra.saveStateCurrent();           // 建立回滚点\nawait ra.writeMemory(addr, bytes);     // 执行写入\n// 出错时加载恢复\nawait ra.loadStateCurrent();\n```\n\n### 帧精确控制\n\n```typescript\n// 确保暂停状态\nconst status = await ra.getStatus();\nif (status.state === \"playing\") {\n  await ra.pauseToggle();\n}\n// 单帧步进\nawait ra.frameAdvance();\n```\n\n## 总结\n\nmcp-retroarch 的状态管理建立在三个核心机制之上：\n\n1. **串行查询状态机**：通过 `pending` 回调确保 UDP 响应的正确路由\n2. **双模式发送**：区分需要响应的 `query()` 和防火遗忘的 `send()`\n3. **状态同步**：工具层将 NCI 的文本响应解析为结构化状态对象供 MCP 客户端使用\n\n---\n\n<a id='troubleshooting'></a>\n\n## 故障排除\n\n### 相关页面\n\n相关主题：[RetroArch 集成](#retroarch-integration), [支持的模拟器核心](#supported-cores)\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</details>\n\n# 故障排除\n\n本文档整理了 `mcp-retroarch` 在实际使用过程中可能遇到的常见问题、错误信息及其解决方案。`mcp-retroarch` 通过 RetroArch 的网络控制接口（NCI）与模拟器通信，任何影响网络连接或 NCI 配置的问题都可能导致工具调用失败。\n\n---\n\n## 连接与通信问题\n\n### RetroArch 查询超时\n\n**症状：** 调用任意工具时返回 `RetroArch query timed out` 错误。\n\n**原因分析：**\n\n- RetroArch 端的网络命令（Network Commands）未启用\n- `mcp-retroarch` 的 `RETROARCH_PORT` 环境变量与 RetroArch 的 `network_cmd_port` 配置不匹配\n- UDP 数据报在高负载下可能被丢弃（即使是本地回环地址）\n\n**排查步骤：**\n\n1. 确认 RetroArch 已启用网络命令功能\n2. 验证端口配置一致性\n3. 考虑重试机制\n\n**解决方案：**\n\n1. 在 RetroArch GUI 中启用：**Settings → Network → Network Commands → ON**，确认 `Network Cmd Port` 为 `55355`（默认值）\n2. 或在 `retroarch.cfg` 中配置：\n   ```ini\n   network_cmd_enable = \"true\"\n   network_cmd_port   = \"55355\"\n   ```\n3. 启动任意 libretro 核心和游戏后，NCI 即处于可用状态，无需额外脚本加载\n\n环境变量配置对照表：\n\n| 环境变量 | 默认值 | 说明 |\n|---------|--------|------|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机 |\n| `RETROARCH_PORT` | `55355` | UDP 端口，需与 `retroarch.cfg` 中的 `network_cmd_port` 匹配 |\n\n资料来源：[README.md:40-47](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n### RetroArch 不可达时的启动行为\n\n**说明：** `mcp-retroarch` 服务器启动时不会因 RetroArch 不可达而失败，而是采用后台探测机制。\n\n**启动日志示例：**\n\n```\n[mcp-retroarch] MCP server ready (stdio)\n[mcp-retroarch] connected to 127.0.0.1:55355 — RetroArch <version>\n```\n\n如果 RetroArch 尚未就绪，服务器仍会启动并在标准错误输出中打印提示信息：\n\n```\n[mcp-retroarch] note: RetroArch not reachable yet (127.0.0.1:55355): <error>\n             Enable Network Commands in retroarch.cfg (network_cmd_enable / network_cmd_port)\n             or Settings > Network > Network Commands. Tool calls will connect on demand.\n```\n\n工具调用会在需要时按需连接，无需重启服务器。\n\n资料来源：[src/index.ts:10-19](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/index.ts)\n\n---\n\n## 内存读取问题\n\n### 错误：no memory map defined\n\n**症状：** 调用 `retroarch_read_memory` 返回 `READ_CORE_MEMORY failed: no memory map defined`。\n\n**原因分析：** 当前加载的 libretro 核心未通过 `READ_CORE_MEMORY` 命令公开系统内存映射。这是核心级别的限制，并非 `mcp-retroarch` 的缺陷。\n\n**解决方案：**\n\n切换到 `retroarch_read_ram`（CHEEVOS 路径）。许多核心即使没有完整的内存映射，也会暴露 CHEEVOS 读写接口。\n\n| 已验证核心 | 推荐工具 | 备注 |\n|-----------|----------|------|\n| SwanStation (PSX) | `read_ram` | 使用 CHEEVOS 地址空间 |\n| Game Boy Advance (mgba_libretro) | `read_memory` | 支持完整内存映射 |\n| NES (Mesen) | `read_memory` 或 `read_ram` | 两者均支持 |\n| NES (Nestopia) | `read_ram` | 仅 CHEEVOS，无内存映射 |\n\n**核心选择建议：** 对于 NES + 内存映射需求，优先选择 Mesen 核心。\n\n资料来源：[README.md:80-93](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n### 错误：no descriptor for address\n\n**症状：** 调用 `retroarch_read_memory` 返回 `READ_CORE_MEMORY failed: no descriptor for address`。\n\n**原因分析：** 请求的地址不在核心内存映射的覆盖范围内。\n\n**可能原因：**\n\n- 该核心不支持访问目标地址区域\n- 目标地址属于系统总线之外的区域（如某些核心的视频内存）\n\n**解决方案：**\n\n- 尝试使用 `retroarch_read_ram` 作为替代方案\n- 检查目标地址是否在目标平台的已知内存范围内（如 GBA 的 EWRAM 位于 `0x02000000-0x0203FFFF`）\n- 考虑更换为支持该地址区域的核心\n\n资料来源：[README.md:94-98](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n### 内存读取返回值说明\n\n`retroarch_read_memory` 成功时返回格式如下：\n\n```\nADDR_HEX [N bytes]: <hex dump>\n```\n\n其中十六进制数据采用空格分隔的大写两字符格式。\n\n`retroarch_read_ram` 返回格式类似，但包含 `(CHEEVOS)` 标记以区分地址空间：\n\n```\nADDR_HEX [N bytes, CHEEVOS]: <hex dump>\n```\n\n**限制：** RetroArch 可能返回少于请求的字节数，特别是在读取跨越内存区域边界时。响应会报告实际返回的字节数。\n\n资料来源：[src/tools.ts:28-33](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n---\n\n## 存档与状态管理问题\n\n### 无法直接保存到指定存档槽\n\n**症状：** 需要将游戏状态保存到特定的存档槽（如槽位 5），但协议似乎不支持直接指定。\n\n**说明：** 这是 NCI 协议本身的限制，而非 `mcp-retroarch` 的 bug。NCI 仅提供\"保存到当前槽\"命令，不支持指定槽位号。\n\n**解决方案：**\n\n使用 `state_slot_plus` 和 `state_slot_minus` 逐步移动槽位指针到目标位置，然后调用 `retroarch_save_state_current` 保存。\n\n**操作序列示例：**\n\n1. `retroarch_state_slot_minus` — 减少槽位指针\n2. `retroarch_save_state_current` — 保存到当前槽位\n3. 重复上述步骤直到到达目标槽位\n\n**注意：** 由于 UDP 的\"即发即忘\"特性，大多数状态变更命令不会收到 RetroArch 的确认。调用成功仅表示 UDP 数据报已发送，不保证 RetroArch 已接收或执行。\n\n资料来源：[README.md:99-103](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n### 存档状态加载后状态不确定\n\n**症状：** 调用 `retroarch_load_state_current` 或 `retroarch_load_state_slot` 后，不确定当前状态是否已正确加载。\n\n**说明：** 这些命令执行的是破坏性操作，会覆盖当前游戏状态。NCI 不返回操作结果确认。\n\n**建议：** 在执行可能覆盖状态的操作前，先使用 `retroarch_save_state_current` 创建还原点。\n\n资料来源：[src/tools.ts:55-56](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n---\n\n## 截图与文件系统问题\n\n### 截图保存位置不符合预期\n\n**症状：** 调用 `retroarch_screenshot` 后，截图未出现在预期目录。\n\n**原因分析：** RetroArch 会将截图保存到其配置的截图目录，而非项目工作目录或固定路径。\n\n**重要限制：** NCI 协议不通过 `GET_CONFIG_PARAM` 暴露 `screenshot_directory` 参数，因此 `mcp-retroarch` 无法动态获取该路径。\n\n**解决方案：**\n\n1. 在 RetroArch GUI 中确认截图目录：**Settings → Directory → Screenshot**\n2. 或通过 `retroarch_get_config` 查看其他已暴露的目录配置（`savestate_directory`、`savefile_directory` 等）\n\n**可用配置查询示例：**\n\n| 配置项 | 返回类型 | 说明 |\n|--------|----------|------|\n| `screenshot_directory` | ❌ 不可用 | NCI 不暴露此项 |\n| `savefile_directory` | 路径 | 存档文件目录 |\n| `savestate_directory` | 路径 | 存档状态目录 |\n| `system_directory` | 路径 | 系统目录 |\n\n资料来源：[README.md:94-98](https://github.com/dmang-dev/mcp-retroarch/blob/main/README.md)\n\n---\n\n## 模拟器状态问题\n\n### 暂停与帧推进行为\n\n**说明：** RetroArch 的 NCI 仅提供 `PAUSE_TOGGLE` 命令，不提供独立的暂停/恢复命令。\n\n**影响：** 如果不确定当前状态，调用 `PAUSE_TOGGLE` 可能产生非预期结果。\n\n**正确使用方式：**\n\n```mermaid\ngraph TD\n    A[查询 retroarch_get_status] --> B{当前状态?}\n    B -->|playing| C[调用 pause_toggle 暂停]\n    B -->|paused| D[调用 pause_toggle 恢复]\n    C --> E[执行内存操作]\n    D --> E\n    E --> F[可选: frame_advance 单帧推进]\n    F --> G[使用 save_state_current 保存还原点]\n```\n\n**帧推进限制：** `FRAMEADVANCE` 命令仅在模拟器处于暂停状态时有效。如果模拟器正在运行，调用此命令不会有任何效果。\n\n资料来源：[src/tools.ts:53-54](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/tools.ts)\n\n---\n\n## 网络与协议层问题\n\n### UDP 通信的固有限制\n\n**特性说明：** RetroArch 的 NCI 基于 UDP 协议，UDP 具有以下固有特性：\n\n| 特性 | 影响 |\n|------|------|\n| 无连接 | 不建立握手，可能发送成功但对方未收到 |\n| 无确认机制 | 大多数命令不会收到 RetroArch 的回复 |\n| 可能丢包 | 高负载下数据报可能丢失 |\n\n**工具返回值的含义：**\n\n- `retroarch_write_memory`：唯一返回写入字节数的命令（`Wrote N bytes → ADDR_HEX`）\n- 其他状态变更命令：仅表示 UDP 数据报已发送，不代表 RetroArch 已处理\n\n资料来源：[CHANGELOG.md:17-27](https://github.com/dmang-dev/mcp-retroarch/blob/main/CHANGELOG.md)\n\n---\n\n### 命令处理流程\n\n```mermaid\nsequenceDiagram\n    participant MCP as MCP 客户端\n    participant Bridge as mcp-retroarch\n    participant RA as RetroArch NCI\n\n    MCP->>Bridge: JSON-RPC 请求\n    Bridge->>Bridge: 参数验证\n    Bridge->>RA: UDP 命令\n    RA-->>Bridge: UDP 响应 (仅查询命令)\n    Bridge-->>MCP: JSON-RPC 响应\n\n    Note over Bridge: 即发即忘命令无响应\n    MCP->>Bridge: 状态变更命令\n    Bridge->>RA: UDP 命令\n    Bridge-->>MCP: 发送成功确认\n```\n\n资料来源：[src/retroarch.ts:48-57](https://github.com/dmang-dev/mcp-retroarch/blob/main/src/retroarch.ts)\n\n---\n\n## 开发与调试\n\n### 本地开发环境\n\n**项目初始化：**\n\n```bash\nnpm install\nnpm run dev      # tsc --watch\n```\n\n**烟雾测试：** 可使用测试脚本验证与运行中的 RetroArch 的连接：\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n**依赖信息：**\n\n| 依赖 | 版本 | 用途 |\n|------|------|------|\n| `@modelcontextprotocol/sdk` | ^1.12.0 | MCP 协议实现 |\n| `@types/node` | ^22.0.0 | TypeScript 类型 |\n| `typescript` | ^5.5.0 | 编译工具 |\n\n资料来源：[package.json:18-25](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)\n\n---\n\n## 快速问题对照表\n\n| 症状 | 最可能的原因 | 首选解决方案 |\n|------|-------------|-------------|\n| 所有工具超时 | 网络命令未启用 | 启用 Network Commands |\n| `read_memory` 失败 | 核心无内存映射 | 改用 `read_ram` |\n| `read_memory` 报地址错误 | 地址超出映射范围 | 检查核心文档或换核心 |\n| 截图位置不对 | 默认截图目录配置 | 查看 RetroArch GUI 目录设置 |\n| 无法保存到指定槽 | NCI 协议限制 | 用 `state_slot_plus/minus` 移动指针 |\n| 暂停状态不确定 | 未先查询状态 | 调用 `get_status` 确认后再操作 |\n\n---\n\n## 相关文档\n\n- [RetroArch NCI 官方文档](https://docs.libretro.com/development/retroarch/network-control-interface/)\n- [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) — GBA 专用方案（含手柄输入）\n- [mcp-pine](https://github.com/dmang-dev/mcp-pine) — PCSX2 等 PINE 协议模拟器\n\n---\n\n<a id='development-guide'></a>\n\n## 开发指南\n\n### 相关页面\n\n相关主题：[项目概述](#project-overview)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\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/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# 开发指南\n\n本文档面向希望参与 mcp-retroarch 项目开发的工程师，介绍项目架构、本地开发环境配置、核心模块说明以及发布流程。\n\n## 项目概述\n\nmcp-retroarch 是一个基于 Model Context Protocol (MCP) 的服务端实现，通过 RetroArch 的 Network Control Interface (NCI) 与模拟器通信。项目以 TypeScript 编写，通过 stdio 与 MCP 客户端交换 JSON-RPC 消息，实现对 RetroArch 的远程控制功能。\n\n核心能力包括：\n\n| 功能类别 | 支持情况 | 说明 |\n|---|---|---|\n| 内存读写 | ✅ | `READ_CORE_MEMORY`（系统内存映射）和 `READ_CORE_RAM`（CHEEVOS 地址空间）两种路径 |\n| 存档管理 | ✅ | 当前槽位或指定槽位加载；保存仅支持当前槽位 |\n| 截图 | ✅ | 保存至 RetroArch 配置的截图目录 |\n| 暂停/帧推进 | ✅ | `PAUSE_TOGGLE` 切换状态；`FRAMEADVANCE` 单步一帧 |\n| 重置 | ✅ | 硬重启当前运行游戏 |\n| 屏幕消息 | ✅ | 在 RetroArch 窗口显示通知 |\n| 游戏手柄输入 | ❌ | NCI 协议不暴露此功能 |\n\n资料来源：[README.md: Features]()\n\n## 项目结构\n\n```\nmcp-retroarch/\n├── src/\n│   ├── index.ts       # MCP 服务端入口，stdio 通信循环\n│   ├── tools.ts       # 工具定义和 JSON Schema\n│   └── retroarch.ts   # RetroArch NCI 通信层\n├── package.json\n├── tsconfig.json\n├── Dockerfile\n├── README.md\n├── CHANGELOG.md\n├── glama.json         # MCP 服务器元数据\n└── .scratch/\n    └── smoke.cjs      # 冒烟测试脚本\n```\n\n资料来源：[package.json](https://github.com/dmang-dev/mcp-retroarch/blob/main/package.json)()\n\n## 环境准备\n\n### 前提条件\n\n- **Node.js** >= 18.0.0\n- **npm** >= 9.0.0\n- **RetroArch** 已安装并启用 Network Commands 功能\n\n### RetroArch 配置\n\n**通过 GUI：**\n\nSettings → Network → Network Commands → **ON**，确认 `Network Cmd Port` 为 `55355`（默认值）。\n\n**通过 `retroarch.cfg`：**\n\n```ini\nnetwork_cmd_enable = \"true\"\nnetwork_cmd_port   = \"55355\"\n```\n\n资料来源：[README.md: Setup]()\n\n## 本地开发\n\n### 安装依赖\n\n```bash\nnpm install\n```\n\n### 编译与监听\n\n使用 TypeScript 编译器的 watch 模式进行持续编译：\n\n```bash\nnpm run dev\n```\n\n该命令等价于 `tsc --watch`，监听 `src/` 目录下所有 `.ts` 文件的变更并自动重新编译。\n\n资料来源：[README.md: Development]()\n\n### 编译检查\n\n单独运行一次 TypeScript 编译（不监听）：\n\n```bash\nnpx tsc\n```\n\n### 冒烟测试\n\n在 RetroArch 运行状态下，执行项目提供的冒烟测试脚本验证通信：\n\n```bash\nnode .scratch/smoke.cjs\n```\n\n该脚本会尝试连接 RetroArch 并执行基础查询（如 `VERSION`、`GET_STATUS`）。\n\n资料来源：[README.md: Development]()\n\n## 架构设计\n\n### 系统架构图\n\n```mermaid\ngraph TD\n    subgraph \"MCP 客户端\"\n        A[Claude Code / Claude Desktop]\n    end\n\n    subgraph \"mcp-retroarch\"\n        B[src/index.ts<br/>MCP Server]\n        C[src/tools.ts<br/>Tool Definitions]\n        D[src/retroarch.ts<br/>NCI Client]\n    end\n\n    subgraph \"RetroArch\"\n        E[Network Commands<br/>UDP :55355]\n    end\n\n    A -->|\"stdio JSON-RPC\"| B\n    B -->|\"查询工具定义\"| C\n    B -->|\"发送 NCI 命令\"| D\n    D -->|\"UDP\"| E\n```\n\n### 核心模块\n\n#### 1. index.ts — 服务端入口\n\n负责初始化 MCP SDK 并启动 stdio 通信循环。关键逻辑：\n\n1. 创建 `Server` 实例，注册所有工具\n2. 启动背景连接探测（fire-and-forget），尝试连接 RetroArch 并获取版本号\n3. 监听 stdio 输入并转发至 MCP SDK 处理\n\n```typescript\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(\n    `[mcp-retroarch] note: RetroArch not reachable yet (${ra.describeTarget()}): ${err}\\n` +\n    `             Enable Network Commands in retroarch.cfg\\n`,\n  ));\n```\n\n资料来源：[src/index.ts:1-20]()\n\n#### 2. tools.ts — 工具定义\n\n定义所有 MCP 工具的 JSON Schema，包含：\n\n- **描述字段**：PURPOSE / USAGE / BEHAVIOR / RETURNS 模板\n- **输入参数**：TypeScript 类型约束和取值范围\n- **错误处理**：明确标注各工具的错误条件和边界情况\n\n工具列表：\n\n| 工具名 | 功能 |\n|---|---|\n| `retroarch_get_status` | 获取运行状态和游戏信息 |\n| `retroarch_get_config` | 读取 RetroArch 配置参数 |\n| `retroarch_read_memory` | 读取 libretro 系统内存映射 |\n| `retroarch_read_ram` | 读取 CHEEVOS 地址空间 |\n| `retroarch_write_memory` | 写入系统内存映射 |\n| `retroarch_write_ram` | 写入 CHEEVOS 地址空间 |\n| `retroarch_pause_toggle` | 切换暂停状态 |\n| `retroarch_frame_advance` | 推进一帧 |\n| `retroarch_reset` | 重置游戏 |\n| `retroarch_screenshot` | 保存截图 |\n| `retroarch_show_message` | 显示通知 |\n| `retroarch_save_state_current` | 保存到当前槽位 |\n| `retroarch_load_state_current` | 从当前槽位加载 |\n| `retroarch_load_state_slot` | 从指定槽位加载 |\n| `retroarch_state_slot_plus` | 当前槽位 +1 |\n| `retroarch_state_slot_minus` | 当前槽位 -1 |\n\n资料来源：[src/tools.ts:1-200]()\n\n#### 3. retroarch.ts — NCI 通信层\n\n处理与 RetroArch 的 UDP 通信，实现两种发送模式：\n\n| 模式 | 方法 | 用途 |\n|---|---|---|\n| 发送即忘 | `send(command)` | 热键类命令，无需等待响应 |\n| 查询等待 | `query(command)` | 需要读取返回值 |\n\n关键特性：\n\n- **序列化保证**：同时只能有一个查询在飞，第二个调用会抛出错误\n- **超时机制**：默认超时时间可配置，超时后拒绝 pending 回调\n- **Socket 复用**：UDP socket 创建后保持连接\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:30-60]()\n\n## 配置选项\n\n### 环境变量\n\n| 环境变量 | 默认值 | 说明 |\n|---|---|---|\n| `RETROARCH_HOST` | `127.0.0.1` | UDP 目标主机地址 |\n| `RETROARCH_PORT` | `55355` | UDP 端口，需与 RetroArch 配置的 `network_cmd_port` 匹配 |\n\n资料来源：[README.md: Configuration]()\n\n## 内存读取 API 详解\n\n项目提供两条内存读取路径，理解其区别对正确使用至关重要：\n\n```mermaid\ngraph LR\n    A[内存地址] --> B{选择路径}\n    B -->|\"系统内存映射\"| C[READ_CORE_MEMORY]\n    B -->|\"CHEEVOS 地址\"| D[READ_CORE_RAM]\n    C --> E[libretro 核心定义<br/>e.g. SNES WRAM 0x7E0000]\n    D --> F[RetroAchievements 规范<br/>e.g. SNES WRAM 0x000000]\n```\n\n| 路径 | 工具 | 地址空间 | 适用场景 |\n|---|---|---|---|\n| 系统内存映射 | `retroarch_read_memory` | libretro 核心定义 | 首选方案，支持此路径的核心 |\n| CHEEVOS | `retroarch_read_ram` | RetroAchievements 规范 | 无内存映射的核心（如 SwanStation PSX） |\n\n资料来源：[src/tools.ts: 内存读写工具描述]()\n\n## 开发工作流\n\n### 1. 添加新工具\n\n在 `src/tools.ts` 中按以下模板添加工具定义：\n\n```typescript\n{\n  name: \"tool_name\",\n  description: \"PURPOSE: ...\\nUSAGE: ...\\nBEHAVIOR: ...\\nRETURNS: ...\",\n  inputSchema: {\n    type: \"object\",\n    required: [\"param1\"],\n    properties: {\n      param1: { type: \"integer\", minimum: 0 },\n    },\n    additionalProperties: false,\n  },\n}\n```\n\n### 2. 实现 NCI 命令\n\n在 `src/retroarch.ts` 中添加对应方法：\n\n```typescript\nasync newCommand(): Promise<ReturnType> {\n  const r = await this.query(\"NEW_COMMAND\");\n  return r.toString().trim();\n}\n```\n\n### 3. 在 index.ts 中注册\n\n在 `src/index.ts` 的 switch 语句中添加处理分支：\n\n```typescript\ncase \"new_tool_name\": {\n  const result = await ra.newCommand();\n  return ok(result);\n}\n```\n\n### 4. 更新文档\n\n- 更新 `README.md` 中的工具列表\n- 在 `CHANGELOG.md` 的 `[Unreleased]` 节添加变更记录\n\n## 发布流程\n\n### 版本号管理\n\n项目遵循 Semantic Versioning 规范：\n\n- **主版本号**：不兼容的 API 变更\n- **次版本号**：向后兼容的功能新增\n- **修订号**：向后兼容的问题修复\n\n### Changelog 格式\n\n```markdown\n## [Unreleased]\n\n## [0.1.2] - 2026-05-15\n\n### Changed\n- 变更描述\n```\n\n### MCP 客户端注册\n\n不同平台的 MCP 客户端注册方式：\n\n| 平台 | 注册命令 |\n|---|---|\n| Claude Code | `claude mcp add retroarch --scope user mcp-retroarch` |\n| Claude Desktop | 修改 `claude_desktop_config.json` |\n\n资料来源：[README.md: Register with your MCP client]()\n\n## 常见问题排查\n\n| 症状 | 原因与解决方案 |\n|---|---|\n| `RetroArch query timed out` | Network Commands 未启用，或端口不匹配。确认 `network_cmd_enable = \"true\"` |\n| `READ_CORE_MEMORY failed: no memory map defined` | 核心不暴露内存映射，改用 `retroarch_read_ram`（CHEEVOS 路径） |\n| `READ_CORE_MEMORY failed: no descriptor for address` | 地址不在核心内存映射范围内，需更换核心或确认地址 |\n| Screenshots 不在预期位置 | 检查 RetroArch GUI 中 Settings → Directory → Screenshot 的配置 |\n\n资料来源：[README.md: Troubleshooting]()\n\n## 依赖说明\n\n### 生产依赖\n\n| 依赖 | 版本 | 用途 |\n|---|---|---|\n| `@modelcontextprotocol/sdk` | ^1.12.0 | MCP 协议实现 |\n\n### 开发依赖\n\n| 依赖 | 版本 | 用途 |\n|---|---|---|\n| `@types/node` | ^22.0.0 | Node.js 类型定义 |\n| `typescript` | ^5.5.0 | TypeScript 编译器 |\n\n资料来源：[package.json: dependencies & devDependencies]()\n\n## 相关项目\n\n| 项目 | 说明 |\n|---|---|\n| [mcp-mgba](https://github.com/dmang-dev/mcp-mgba) | Game Boy Advance 支持，包含手柄输入和截图功能 |\n| [mcp-pine](https://github.com/dmang-dev/mcp-pine) | PINE 协议模拟器（PCSX2 等），仅支持内存和存档 |\n\n资料来源：[README.md: Related]()\n\n---\n\n---\n\n## Doramagic 踩坑日志\n\n项目：dmang-dev/mcp-retroarch\n\n摘要：发现 7 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：配置坑 - 可能修改宿主 AI 配置。\n\n## 1. 配置坑 · 可能修改宿主 AI 配置\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。\n- 对用户的影响：安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。\n- 建议检查：列出会写入的配置文件、目录和卸载/回滚步骤。\n- 防护动作：涉及宿主配置目录时必须给回滚路径，不能只给安装命令。\n- 证据：capability.host_targets | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | host_targets=mcp_host, claude\n\n## 2. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：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. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | last_activity_observed missing\n\n## 4. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 5. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 6. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | issue_or_pr_quality=unknown\n\n## 7. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：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 完整输出，末尾追加 Discovery Agent 踩坑日志。",
      "title": "Human Manual / 人类版说明书"
    },
    "pitfall_log": {
      "asset_id": "pitfall_log",
      "filename": "PITFALL_LOG.md",
      "markdown": "# Pitfall Log / 踩坑日志\n\n项目：dmang-dev/mcp-retroarch\n\n摘要：发现 7 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：配置坑 - 可能修改宿主 AI 配置。\n\n## 1. 配置坑 · 可能修改宿主 AI 配置\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。\n- 对用户的影响：安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。\n- 建议检查：列出会写入的配置文件、目录和卸载/回滚步骤。\n- 防护动作：涉及宿主配置目录时必须给回滚路径，不能只给安装命令。\n- 证据：capability.host_targets | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | host_targets=mcp_host, claude\n\n## 2. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：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. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | last_activity_observed missing\n\n## 4. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 5. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | no_demo; severity=medium\n\n## 6. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | issue_or_pr_quality=unknown\n\n## 7. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：evidence.maintainer_signals | github_repo:1234498337 | https://github.com/dmang-dev/mcp-retroarch | release_recency=unknown\n",
      "summary": "用户实践前最可能遇到的身份、安装、配置、运行和安全坑。",
      "title": "Pitfall Log / 踩坑日志"
    },
    "prompt_preview": {
      "asset_id": "prompt_preview",
      "filename": "PROMPT_PREVIEW.md",
      "markdown": "# mcp-retroarch - Prompt Preview\n\n> 复制下面这段 Prompt 到你常用的 AI，先试一次，不需要安装。\n> 它的目标是让你直接体验这个项目的服务方式，而不是阅读项目介绍。\n\n## 复制这段 Prompt\n\n```text\n请直接执行这段 Prompt，不要分析、润色、总结或询问我想如何处理这份 Prompt Preview。\n\n你现在扮演 mcp-retroarch 的“安装前体验版”。\n这不是项目介绍、不是评价报告、不是 README 总结。你的任务是让我用最小成本体验它的核心服务。\n\n我的试用任务：我想用它完成一个真实的工具连接与集成任务。\n我常用的宿主 AI：MCP Client / claude\n\n【体验目标】\n围绕我的真实任务，现场演示这个项目如何把输入转成 示例引导, 判断线索。重点是让我感受到工作方式，而不是给我项目背景。\n\n【业务流约束】\n- 你必须像一个正在提供服务的项目能力包，而不是像一个讲解员。\n- 每一轮只推进一个步骤；提出问题后必须停下来等我回答。\n- 每一步都必须让我感受到一个具体服务动作：澄清、整理、规划、检查、判断或收尾。\n- 每一步都要说明：当前目标、你需要我提供什么、我回答后你会产出什么。\n- 不要安装、不要运行命令、不要写代码、不要声称测试通过、不要声称已经修改文件。\n- 需要真实安装或宿主加载后才能验证的内容，必须明确说“这一步需要安装后验证”。\n- 如果我说“用示例继续”，你可以用虚构示例推进，但仍然不能声称真实执行。\n\n【可体验服务能力】\n- 安装前能力预览: MCP server for RetroArch — exposes memory r/w, save state, screenshot, pause/frameadvance/reset via the Network Control Interface 输入：用户任务, 当前 AI 对话上下文；输出：示例引导, 判断线索。\n\n【必须安装后才可验证的能力】\n- 命令行启动或安装流程: 项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 输入：终端环境, 包管理器, 项目依赖；输出：安装结果, 列表/更新/运行结果。\n\n【核心服务流】\n请严格按这个顺序带我体验。不要一次性输出完整流程：\n1. project-overview：项目概述。围绕“项目概述”模拟一次用户任务，不展示安装或运行结果。\n2. system-architecture：系统架构。围绕“系统架构”模拟一次用户任务，不展示安装或运行结果。\n3. installation-configuration：安装与配置。围绕“安装与配置”模拟一次用户任务，不展示安装或运行结果。\n4. retroarch-integration：RetroArch 集成。围绕“RetroArch 集成”模拟一次用户任务，不展示安装或运行结果。\n5. mcp-tools-reference：MCP 工具参考。围绕“MCP 工具参考”模拟一次用户任务，不展示安装或运行结果。\n\n【核心能力体验剧本】\n每一步都必须按“输入 -> 服务动作 -> 中间产物”执行。不要只说流程名：\n1. project-overview\n输入：用户提供的“项目概述”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n2. system-architecture\n输入：用户提供的“系统架构”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n3. installation-configuration\n输入：用户提供的“安装与配置”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n4. retroarch-integration\n输入：用户提供的“RetroArch 集成”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n5. mcp-tools-reference\n输入：用户提供的“MCP 工具参考”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n【项目服务规则】\n这些规则决定你如何服务用户。不要解释规则本身，而要在每一步执行时遵守：\n- 先确认用户任务、输入材料和成功标准，再模拟项目能力。\n- 每一步都必须形成可检查的小产物，并等待用户确认后再继续。\n- 凡是需要安装、调用工具或访问外部服务的能力，都必须标记为安装后验证。\n\n【每一步的服务约束】\n- Step 1 / project-overview：Step 1 必须围绕“项目概述”形成一个小中间产物，并等待用户确认。\n- Step 2 / system-architecture：Step 2 必须围绕“系统架构”形成一个小中间产物，并等待用户确认。\n- Step 3 / installation-configuration：Step 3 必须围绕“安装与配置”形成一个小中间产物，并等待用户确认。\n- Step 4 / retroarch-integration：Step 4 必须围绕“RetroArch 集成”形成一个小中间产物，并等待用户确认。\n- Step 5 / mcp-tools-reference：Step 5 必须围绕“MCP 工具参考”形成一个小中间产物，并等待用户确认。\n\n【边界与风险】\n- 不要声称已经安装、运行、调用 API、读写本地文件或完成真实任务。\n- 安装前预览只能展示工作方式，不能证明兼容性、性能或输出质量。\n- 涉及安装、插件加载、工具调用或外部服务的能力必须安装后验证。\n\n【可追溯依据】\n这些路径只用于你内部校验或在我追问“依据是什么”时简要引用。不要在首次回复主动展开：\n- https://github.com/dmang-dev/mcp-retroarch\n- https://github.com/dmang-dev/mcp-retroarch#readme\n- README.md\n- src/index.ts\n- src/retroarch.ts\n- package.json\n- src/tools.ts\n\n【首次问题规则】\n- 首次三问必须先确认用户目标、成功标准和边界，不要提前进入工具、安装或实现细节。\n- 如果后续需要技术条件、文件路径或运行环境，必须等用户确认目标后再追问。\n\n首次回复必须只输出下面 4 个部分：\n1. 体验开始：用 1 句话说明你将带我体验 mcp-retroarch 的核心服务。\n2. 当前步骤：明确进入 Step 1，并说明这一步要解决什么。\n3. 你会如何服务我：说明你会先改变我完成任务的哪个动作。\n4. 只问我 3 个问题，然后停下等待回答。\n\n首次回复禁止输出：后续完整流程、证据清单、安装命令、项目评价、营销文案、已经安装或运行的说法。\n\nStep 1 / brainstorming 的二轮协议：\n- 我回答首次三问后，你仍然停留在 Step 1 / brainstorming，不要进入 Step 2。\n- 第二次回复必须产出 6 个部分：澄清后的任务定义、成功标准、边界条件、\n  2-3 个可选方案、每个方案的权衡、推荐方案。\n- 第二次回复最后必须问我是否确认推荐方案；只有我明确确认后，才能进入下一步。\n- 第二次回复禁止输出 git worktree、代码计划、测试文件、命令或真实执行结果。\n\n后续对话规则：\n- 我回答后，你先完成当前步骤的中间产物并等待确认；只有我确认后，才能进入下一步。\n- 每一步都要生成一个小的中间产物，例如澄清后的目标、计划草案、测试意图、验证清单或继续/停止判断。\n- 所有演示都写成“我会建议/我会引导/这一步会形成”，不要写成已经真实执行。\n- 不要声称已经测试通过、文件已修改、命令已运行或结果已产生。\n- 如果某个能力必须安装后验证，请直接说“这一步需要安装后验证”。\n- 如果证据不足，请明确说“证据不足”，不要补事实。\n```\n",
      "summary": "不安装项目也能感受能力节奏的安全试用 Prompt。",
      "title": "Prompt Preview / 安装前试用 Prompt"
    },
    "quick_start": {
      "asset_id": "quick_start",
      "filename": "QUICK_START.md",
      "markdown": "# Quick Start / 官方入口\n\n项目：dmang-dev/mcp-retroarch\n\n## 官方安装入口\n\n### Node.js / npm · 官方安装入口\n\n```bash\nnpm install -g mcp-retroarch\n```\n\n来源：https://github.com/dmang-dev/mcp-retroarch#readme\n\n## 来源\n\n- repo: https://github.com/dmang-dev/mcp-retroarch\n- docs: https://github.com/dmang-dev/mcp-retroarch#readme\n",
      "summary": "从项目官方 README 或安装文档提取的开工入口。",
      "title": "Quick Start / 官方入口"
    }
  },
  "validation_id": "dval_b7fb1b1c9baf4a869e745a8f04409775"
}
