gareve/mesen-lua-bridge-mcp

GitHub: gareve/mesen-lua-bridge-mcp

一个MCP服务器,使大语言模型能在Mesen 2模拟器中远程执行Lua代码,以支持逆向工程和游戏修改。

Stars: 0 | Forks: 0

# mesen-lua-桥接-mcp 一个 MCP 服务器,允许 LLM 在运行中的 Mesen 2 模拟器内执行任意 Lua 代码。LLM 可以阅读 MESEN 2 的 Lua 文档并生成任意 Lua 代码,无需将 API 编码到 MCP 命令中。这使得架构和版本兼容性变得简单得多,同时也为 LLM 提供了更大的自由度来构思有趣的解决方案。 应适用于 Mesen 2 支持的任何系统;已使用 SNES 进行测试。 每次调用都附带一段简短描述,记录到 Mesen 的脚本窗口中,因此你可以跟踪、审计运行的内容并从中学习——这使它非常适合在 LLM 叙述每个步骤的情况下学习逆向工程。之后你可以询问 LLM 为何执行某些步骤。 下方是演示(为保持简短略有编排,但基于真实的调试会话) https://github.com/user-attachments/assets/3379bf00-03aa-425e-a089-717eec883cae 我使用此 MCP + Claude Code 逆向工程并编写了这个 [Inindo Way of the Ninja 补丁器 Web 工具](https://github.com/gareve/inindo-way-of-the-ninja-snes-patcher) ## 前提条件 - macOS、Linux 或 Windows(桥接目录从 `TMPDIR` / `TMP` / `TEMP` 解析,回退到 `/tmp`) - Node.js ≥ 18(在 22 上测试通过) - [Mesen 2](https://www.mesen.ca/) - Mesen 支持的任意系统的 ROM ## 一次性 Mesen 设置 在 Mesen 的 UI 中: 1. 启动 Mesen,加载任意 ROM。 2. **工具 → 脚本窗口**。 3. 在脚本窗口中,打开其 **设置**(齿轮图标或菜单)并启用 **“允许访问 I/O 和操作系统功能”**。不需要启用“允许网络访问”开关。 4. 在同一设置对话框中,将 **“脚本超时”** 从默认的 1 秒提高到 **10 秒**。默认的 1 秒会中止合法的 RE 代码片段(如内存扫描)。 5. 将 **“加载时自动启动脚本”**、**“文件更改时自动重新加载脚本”** 和 **“通电后自动重启脚本”** 保持默认设置(全部开启)。这些为你提供了干净的重启用户体验。 https://github.com/user-attachments/assets/3d1a4c9d-0ab6-46a8-b2ba-331ba4b2c1ea ## 安装服务器 ``` git clone https://github.com/gareve/mesen-lua-bridge-mcp.git cd mesen-lua-bridge-mcp npm install ``` ## 在 Mesen 中加载桥接脚本 在 Mesen 的脚本窗口中:**文件 → 打开** → 选择你克隆的此仓库中的 `lua/mesen_bridge.lua` → 点击 **运行**。 你应该在脚本控制台中看到一行: ``` [mesen-mcp] bridge registered; waiting for an MCP server to claim /mesen-mcp/active ``` (或者如果 MCP 服务器已在运行,则是 `[mesen-mcp] bound to session ...`) ## 接入 Claude Code(或任何其他兼容 MCP 的 LLM) 此仓库中已提交了一个项目范围的 `.mcp.json`,因此当你在项目目录中运行 `claude` 时,Claude Code 会自动加载它。可通过以下命令确认: ``` claude mcp list ``` 如果你更愿意以用户范围接入(从任何目录可用),请在克隆的仓库内运行: ``` claude mcp add mesen --cwd "$(pwd)" -- npx tsx src/server.ts ``` **其他 MCP 客户端**(ChatGPT、Cursor、Cline、Zed、Continue 等)——这是一个标准的 stdio MCP 服务器。请将你的客户端配置为运行 `npx tsx src/server.ts`,并将克隆的仓库作为其工作目录。 ## LLM 冒烟测试 在你的 MCP 客户端中(例如 Claude): 期望输出 `2`。然后尝试一个真实的调用: 期望输出一个 0–255 之间的数字(RAM 的一个字节)。 ## LLM 可靠性检查清单(手动端到端验证) 逐一执行以下步骤,确认无需重启的方案可行。每个步骤都假设上述冒烟测试已成功。 | # | 测试 | 期望结果 | |---|------|----------| | 1 | `execute_lua("return 1+1")` 冷启动 | `2` | | 2 | 终止 MCP 服务器(找到其 PID,`kill `),再次调用 | 无需操作 Mesen 即可工作——MCP 客户端会重新生成服务器 | | 3 | 退出 Mesen,重新启动,重新加载 ROM,再次调用 | 工作正常(脚本自动启动,epoch 递增) | | 4 | 在 Mesen 的脚本窗口中:先停止,然后运行桥接脚本 | 工作正常 | | 5 | 在 Mesen 中更换 ROM,调用 | 工作正常(桥接自动重启) | | 6 | 退出并重启 MCP 客户端 | 工作正常(新的 MCP PID,旧的会话目录被垃圾回收) | | 7 | 快速连续发出 50 次调用 | 全部按顺序返回 | | 8 | `execute_lua("for i=1,1e9 do end")` | Mesen 在 `Script timeout` 后中止脚本;MCP 返回超时诊断信息 | | 9 | 在运行时执行 `rm -rf /tmp/mesen-mcp//`,调用 | 在 ~1 秒内恢复 | | 10 | 关闭“允许访问 I/O 和操作系统功能”,重新加载脚本,调用 | MCP 超时,并附带“检查 AllowIoOsAccess”提示 | | 11 | 退出 ROM(保持 Mesen 打开),调用 | MCP 超时;加载 ROM → 下次调用成功 | | 12 | `execute_lua("return emu.read(0x7E0000)")` | 数字结果 | ## 故障排除 **"timeout: no response from Mesen Lua bridge"** ——诊断消息列出了常见原因。通常是: - `Allow access to I/O and OS functions`(允许访问 I/O 和操作系统功能)已关闭 → 桥接无法写入文件。 - 桥接脚本未加载(或已加载但已停止)。 - 没有正在运行的 ROM → 没有 `endFrame` 回调 → 没有轮询。 - 代码片段超出了 Mesen 的 `Script timeout` → Mesen 中止了脚本。 **"Error from Mesen Lua: ... attempt to call a nil value"** ——你的代码片段引用了一个在加载的系统上不存在的 `emu.*` 函数。请查阅 [API 参考](https://www.mesen.ca/docs/apireference.html)——某些函数是特定于系统的。 **超时后出现陈旧结果** ——通过线协议中的 SEQ 标签已修复;如果遇到此问题,请提交 issue。 **你的 MCP 客户端看不到工具** ——对于 Claude Code,`claude mcp list` 应显示 `mesen`;检查 `.mcp.json` 是否被加载(在项目目录中使用 `claude`)或运行上述的 `claude mcp add` 命令。对于其他客户端,请验证 stdio 服务器是否以仓库作为工作目录启动。 ## 已知限制(PoC 范围) - **每个会话仅允许一个进行中的请求。** 并发的 `execute_lua` 调用通过互斥锁序列化。对于交互式逆向工程工作足够;如果需要管道化的批量操作,请重新评估。 - **基于 `tostring()` 的结果渲染。** 表格会返回为 `table: 0x...`。当出现第一个嵌套结果用例时,在 Lua 中添加一个小的 JSON 编码器。 - **无流式输出。** 代码片段内的 `print()` 会丢失(它只输出到 Mesen 的脚本控制台)。如果你想获取代码片段的标准输出,请追加到会话目录中的日志文件,并让服务器收集它。 ## 为什么使用基于文件的传输,而不是套接字 套接字是可行的,但不可靠:Mesen 的 Lua `accept()` 在每个脚本生命周期内只接受一个客户端,然后需要重新加载脚本——这与 MCP 客户端生成和重新生成服务器的方式相冲突。文件要简单得多,也更可靠。 额外优点: - **可靠性。** 能承受 MCP 服务器、Mesen、桥接脚本、MCP 客户端以及 ROM 更换在任何顺序下的重启。 - **带宽。** 没有套接字缓冲区或分片限制。多兆字节的响应(内存转储、截图)无需分块或调优即可工作——仅受 tmpfs/磁盘限制。 - **无需网络访问权限。** 只需启用 I/O/操作系统功能开关;“允许网络访问”保持关闭。 - **可用 `cat` 检查。** 进行中的请求只是一个文件。
标签:DLL 劫持, GNU通用公共许可证, Lua脚本, MCP协议, Mesen 2, MITM代理, Node.js, rizin, SNES模拟, 云资产清单, 大语言模型, 审计日志, 开发辅助, 教育工具, 数字取证, 游戏模拟器, 自动化脚本, 自定义脚本, 跨平台支持, 远程执行, 逆向工程