DeftSolutions-dev/mcp-serotonin
GitHub: DeftSolutions-dev/mcp-serotonin
一个基于 MCP 的桥接器,将 LLM 代理连接到 Roblox 的 Serotonin Lua 运行时,实现安全可控的游戏遍历与操作自动化。
Stars: 0 | Forks: 0
# mcp-serotonin
一个用于连接任何支持 MCP 的代理与 [Serotonin](https://serotonin-1.gitbook.io/serotonin-docs) Lua 运行时的 MCP 桥接器。
我编写这个工具,是因为通过 Serotonin 盲目操作 Roblox 游戏(猜测实例名称、希望 `entity.GetPlayers` 在某种模式下有效)很快就令人厌倦了。加载桥接器后,代理可以直接查看游戏:遍历工作区,列出带有世界坐标的在线玩家,找到最近的人形角色,读取内存,将坐标投影到屏幕。然后它会编写在该特定模式下真正有效的 Lua 代码,而不是通用的 ESP 模板。
## 工作原理
```
MCP client <-- stdio --> server.py <-- HTTP :8765 --> bridge.lua <--> Serotonin <--> Roblox
```
`bridge.lua` 在 Serotonin 内部运行,并长轮询 Python 协调器。当工具调用到达时,Lua 端执行它,序列化结果(实例变为可传递的句柄;Vector3/Color3 保持其类型),并将其返回。异步信号量加一次只允许一个轮询意味着并行的 MCP 调用无法在 Serotonin 内部堆叠并行求值——这种路径会可靠地导致作弊崩溃。
## 崩溃保护
Serotonin 中的某些 Lua 表达式会触发原生 C++ 异常,而 `pcall` 无法捕获——它们会杀死作弊 DLL。读取 `_G`、`game.DataModel`、`game.PlaceID`、`game.LocalPlayer.Backpack`,调用 `Color3:ToHSV()`——所有这些都确认为崩溃行为。此版本附带:
- **安全模式预检**:在 `server.py` 中,每个操作在离开 Python 进程前都会对照 `crash_blacklist.json` 进行检查。安全模式(默认开启)下,被阻止的操作永远不会到达作弊程序。
- **基于类的属性允许列表**:在 `bridge.lua` 中,只有有文档记录的属性可通过 `safe_inspect` / `dive` 读取。未记录的字段是已知的崩溃向量(Serotonin 的代理会尝试通过原始内存解析它们,并在未知偏移量处出错)。
- **`/crash_report` 端点**:当你提交最近一次不良操作时,它会自动提取黑名单规则。一次学习,永不重复。
如果遇到新的崩溃情况,请将其 POST 到 `/crash_report`,它将被持久化。
## 需求
- Windows 10/11 + Serotonin
- Python 3.10+
- `mcp`、`aiohttp`(请参见 `requirements.txt`)
## 安装
```
git clone https://github.com//mcp-serotonin.git
cd mcp-serotonin
pip install -r requirements.txt
```
将 `bridge.lua` 放入你的 Serotonin 脚本文件夹中——通常位置为:
```
C:\Serotonin\scripts\bridge.lua
```
(脚本选项卡中有一个“打开脚本文件夹”按钮。)
## 将其连接到 MCP 客户端
该服务器使用标准 I/O 通信,因此每种客户端的配置格式相同。只需将路径指向 `python C:/path/to/mcp-serotonin/server.py`。
大多数客户端读取一个 JSON 文件,其格式如下:
```
{
"mcpServers": {
"serotonin-bridge": {
"command": "python",
"args": ["C:/path/to/mcp-serotonin/server.py"],
"env": { "PYTHONUNBUFFERED": "1" }
}
}
}
```
将其放置在你客户端期望的位置(项目本地的 `.mcp.json`、用户级配置或 IDE 设置)。本仓库中的 `.mcp.json.example` 是同一文件的副本,可直接复制使用。
## 运行
1. 启动 Roblox + Serotonin。
2. 在脚本选项卡中 **加载** `bridge.lua`。你应该看到:
[serotonin-bridge v2] loaded, polling http://127.0.0.1:8765
[serotonin-bridge v2] ops: ping eval inspect safe_inspect snapshot dive live_dump class_counts list_scripts search
3. 启动你的 MCP 客户端——它会在需要时通过标准 I/O 启动 `server.py`。
4. 调用 `serotonin_ping`。如果返回 `"pong"`,说明一切就绪。
如果超时,桥接器未运行或无法连接到 `127.0.0.1:8765`。请重新加载 Lua 脚本,并检查作弊控制台是否有错误。
## 工具
| 工具 | 功能 |
|---|---|
| `serotonin_ping` | 活跃性检查。 |
| `serotonin_eval` | 运行任意 Lua。实例 / Vector3 / Color3 会自动序列化。在安全模式下,被阻止的模式不会到达作弊程序。 |
| `serotonin_inspect` | 对一个实例进行属性、特性、子项检查。可接受点路径或句柄。 |
| `serotonin_search_instances` | 遍历 `GetDescendants`,支持名称子字符串和可选的类名过滤。 |
| `serotonin_tree` | 递归输出名称/类名,最多 N 层。 |
| `serotonin_find_by_class` | 查找特定类名的所有后代。 |
| `serotonin_find_player_model` | 在 `Workspace.Live` 中按名称查找玩家 Model 及其子项与 HRP。 |
| `serotonin_nearest` | 查找半径内最近的类实例。原点默认为 LocalPlayer。 |
| `serotonin_descendants_stats` | 子树的类名直方图。 |
| `serotonin_get_scripts` | 所有 `Script` / `LocalScript` / `ModuleScript` 及其点路径(不公开源码)。 |
| `serotonin_list_players` | `entity.GetPlayers()` 加上缓存字段。 |
| `serotonin_players_full` | 实体字段 + 实时 HumanoidRootPart + 屏幕投影。推荐使用此工具。 |
| `serotonin_list_parts` | `entity.GetParts()`,支持可选半径过滤。 |
| `serotonin_get_bones` | 玩家索引对应命名骨骼的位置/大小/旋转。 |
| `serotonin_project_to_screen` | `utility.WorldToScreen` 用于 Vector3。 |
| `serotonin_screen_info` | 窗口大小、摄像机、鼠标、延迟时间、菜单状态。 |
| `serotonin_memory_read` | `memory.Read(type, addr)`。 |
| `serotonin_memory_write` | `memory.Write(type, addr, value)`。 |
| `serotonin_memory_base` | `memory.GetBase()`。 |
## HTTP 端点(用于 Shell / 调试)
除了 MCP 工具外,`server.py` 还暴露了若干 HTTP 路由,便于你使用 `curl` 或其他脚本直接驱动桥接器:
| 方法 | 路径 | 用途 |
|---|---|---|
| POST | `/exec` | 执行单个操作(`{op, args, timeout}`)。会经过黑名单预检。 |
| POST | `/cancel` | 丢弃所有排队的命令并取消所有待处理操作。崩溃后使用。 |
| GET / POST | `/safe_mode` | 获取或切换(`{enabled: true/false}`)。 |
| GET | `/blacklist` | 完整黑名单导出。 |
| POST | `/blacklist` | 补丁(`{add: {paths, dive_depth_limits, eval_code_blocked}, remove: {...}}`)。 |
| POST | `/blacklist/reload` | 重新读取 `crash_blacklist.json`。 |
| POST | `/crash_report` | 报告崩溃(`{last_op, last_args, note}`)。自动提取已知崩溃模式的规则。 |
| GET | `/health` | 队列深度。 |
## 容易踩坑的问题(以及本版本的应对方式)
**内存类型。** 经验证可接受的类型为:`byte`、`short`、`ushort`、`int`、`uint`、`int64`、`uint64`、`float`、`double`、`bool`、`string`、`ptr`、`pointer`、`vector2`、`vector3`、`color3`、`cframe`(只读)。所有 13 种数值/指针类型均已在 `memory.GetBase()` 上测试通过。旧的 `int8/16/32` 快捷方式不被接受。
**`_G` 是原生崩溃源。** 不仅仅是 nil——即使在 `pcall` 中使用 `type(_G)` 也会导致 DLL 崩溃。被黑名单正则匹配为 `\b_G\b`。如需环境表,请使用 `getfenv(1)`。
**`game.GetService` 使用点语法,而非冒号。** `game.GetService("Players")` 有效;而 `game:GetService(...)` 会返回 `calling 'GetService' on NN` 错误。Lua 中的 `game` 是一个沙箱代理表,因此 `:IsDescendantOf` / `:IsAncestorOf` 在其上调用会因相同原因失败。
**实体 API 返回用户数据,而非索引。** 文档称 `entity.GetPlayers()` 返回整数,实际上它返回用户数据。应以 `p.Name`、`p.Health` 方式访问字段,调用骨骼方法时使用 `p:GetBonePosition("HumanoidRootPart")`。
**`entity.Position` 通常已过时。** 在 FFA 或坦克风格模式中,缓存的位置可能仍为 `(0,0,0)`。请使用 `p:GetBonePosition("HumanoidRootPart")` 获取实时值。`serotonin_players_full` 已为你完成此操作。
**有文档但已损坏。** `Vector3:FuzzyEq` 不存在(Lua 错误);`Color3:ToHSV()` 会崩溃(原生);`game.GetFFlag` / `game.SetFFlag` 也会崩溃。无论文档如何,这些都已被列入黑名单。
**未记录的 LocalPlayer 字段会崩溃。** `game.LocalPlayer.Backpack` 是已知的原生崩溃源。`PlayerGui`、`PlayerScripts`、`StarterGear`、`AccountAge`、`FollowUserId` 以及数十个其他未记录的 Player 属性均通过单个正则表达式被列入黑名单。如确实需要,可关闭安全模式、禁用该模式并自行承担风险。
**不要并行化求值。** 两个同时的求值会导致 Serotonin 崩溃。服务器通过信号量强制串行执行;只要使用工具即可保持安全。
## 配置
环境变量:
- `SEROTONIN_HTTP_HOST`(默认 `127.0.0.1`)
- `SEROTONIN_HTTP_PORT`(默认 `8765`)
- `SEROTONIN_HTTP_ONLY=1` - 仅启动 HTTP 协调器,跳过标准 I/O MCP。适用于使用 `curl` 调试。
`bridge.lua` 中的可调参数(文件顶部,`CFG` 表):
- `base_url` - 必须与上述主机/端口匹配
- `poll_interval_ms` - 轮询之间的最小间隔(默认 100)
- `inflight_ttl_ms` - 如果 `http.Get` 回调从未触发,则 watchdog 重置(默认 12000)
- `max_depth` - 默认序列化深度(默认 3)
超时时间同步:轮询保持(9 秒)< 服务器默认超时(10 秒)< 桥接器 inflight TTL(12 秒)。不要破坏此顺序,否则 watchdog 会与客户端竞争并导致你看到幻象重置。
## 许可证
MIT。
标签:asyncio, ATT&CK 框架, C++异常, DLL 劫持, ESP, HTTP长轮询, LLM, Lua运行时, MCP, MCP服务器, Python协调器, rizin, Roblox, Serotonin, STDIO通信, Unmanaged PE, 代理, 作弊工具, 内存读取, 坐标投影, 大语言模型, 安全检查, 安全模式, 实例操作, 崩溃保护, 工作区遍历, 并发控制, 无文件攻击, 桥接, 桥接工具, 游戏开发, 游戏脚本, 游戏自动化, 游戏逆向, 类属性白名单, 自动化控制, 逆向工具, 高性能, 黑名单