https://github.com/killop/puerts-unity-mcp
unity-mcp driven by tencent puerts , invoke js/ts call c# in your cell phone and unity editor
https://github.com/killop/puerts-unity-mcp
Last synced: 21 days ago
JSON representation
unity-mcp driven by tencent puerts , invoke js/ts call c# in your cell phone and unity editor
- Host: GitHub
- URL: https://github.com/killop/puerts-unity-mcp
- Owner: killop
- License: mit
- Created: 2026-06-26T10:13:34.000Z (27 days ago)
- Default Branch: main
- Last Pushed: 2026-07-01T11:37:55.000Z (22 days ago)
- Last Synced: 2026-07-01T22:28:16.584Z (22 days ago)
- Language: C#
- Size: 81.9 MB
- Stars: 34
- Watchers: 0
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README-zh.md
Awesome Lists containing this project
README
PuerTS Unity MCP
通过 MCP 控制 Unity Editor、Play Mode 和真实手机游戏,并在运行中的游戏里动态执行 PuerTS JavaScript。
Android · iOS · IL2CPP · Editor JS · Runtime JS · C# 和 JS MCP Tool · Domain Reload 恢复
English · 中文
---
## 功能特性
| 能力 | 说明 |
|---|---|
| 手机直连动态调试 | Agent 可以直接连接 Android、iOS 或 standalone Unity Player,在真实运行中的游戏里执行 PuerTS JavaScript。 |
| 支持 IL2CPP Player | 构建脚本会加入 PuerTS 包、native plugin、StreamingAssets 配置、Android 权限库和保留提示,用于手机和 IL2CPP 构建。 |
| Editor 执行 JS 不触发 Domain Reload | `editor.js.eval` 在 Editor PuerTS VM 里执行 JS,不生成 C# 文件,不调用 `AssetDatabase.Refresh`,正常自动化流程不会触发 Unity domain reload。 |
| Runtime 执行 JS | `runtime.js.eval` 可以指向本地 Play Mode,也可以指向远程 Player MCP,包括手机。 |
| C# 和 JS 扩展 MCP Tool | 核心工具用 C# 写,项目工具可以放在 `puerts-unity-mcp-extension/Editor/editor-tools` 和 `Runtime/runtime-tools` 里用 JS 写。 |
| Domain Reload 稳定性 | Editor MCP 会持久化 operation、compile result、reload hint,并在 Unity domain reload 后自动恢复 HTTP endpoint。 |
## 它控制什么
PuerTS Unity MCP 把每个可控制的 Unity 整体都看成一个 endpoint。
```text
Agent / MCP client
|
| stdio JSON-RPC
v
Node stdio proxy
|
| HTTP JSON-RPC POST /mcp
v
+----------------------+ direct C# route +-----------------------+
| Unity Editor MCP | ------------------------> | Play Mode Runtime MCP |
| endpointKind=editor | | endpointKind=player |
| C# + Editor PuerTS | | C# + Runtime PuerTS |
+----------------------+ +-----------------------+
|
| LAN discovery or direct target URL
v
+----------------------+
| Phone / Player MCP |
| Android, iOS, build |
| C# + Runtime PuerTS |
+----------------------+
```
Editor Play Mode 不是第三种 MCP。它是运行在 Unity Editor 进程内的同一套 Runtime MCP 实现。
## 快速开始
### 拉取 PuerTS 依赖
```bash
node Packages/puerts-unity-mcp/Tools~/vendor-puerts.mjs
```
这个命令会下载并校验 PuerTS `Unity_v3.0.2` Core 和 V8 包,放到 `third_party/puerts`。
### 同步到 Unity 工程
```bash
node Packages/puerts-unity-mcp/Tools~/sync-local-package.mjs --unity-project-root
```
Unity 工程里会出现:
```text
/puerts-unity-mcp
/puerts-unity-mcp-extension
/.puerts-unity-mcp
```
### 注册本地 UPM 包
同步脚本会在 `Packages/manifest.json` 里加入三个本地依赖:
```json
{
"dependencies": {
"com.tencent.puerts.core": "file:../puerts-unity-mcp/third_party/puerts/unity/upms/core",
"com.tencent.puerts.v8": "file:../puerts-unity-mcp/third_party/puerts/unity/upms/v8",
"puerts-unity-mcp": "file:../puerts-unity-mcp/Packages/puerts-unity-mcp"
}
}
```
### 配置 Agent
同步后打开 Unity 工程内的 Agent 配置说明:
```text
/puerts-unity-mcp/Packages/puerts-unity-mcp/setup-for-agent.md
```
Codex 的 MCP 配置示例:
```toml
[mcp_servers."puerts-unity-mcp"]
command = "node"
args = [
"/puerts-unity-mcp/Packages/puerts-unity-mcp/Tools~/puerts-unity-mcp-stdio-proxy.js",
"--config",
"/puerts-unity-mcp-extension/editor-mcp-config.json"
]
```
## 手机和 IL2CPP 构建
QA 手机和真实 Player 构建需要把 Runtime MCP 编进包:
```bash
node /puerts-unity-mcp/Packages/puerts-unity-mcp/Tools~/add-pum-to-build.mjs --unity-project-root
```
从 Player 构建里移除:
```bash
node /puerts-unity-mcp/Packages/puerts-unity-mcp/Tools~/remove-pum-from-build.mjs --unity-project-root
```
`add-pum-to-build.mjs` 会做这些事:
- 添加本地 PuerTS 和 PuerTS Unity MCP package 依赖
- 把 `puerts-unity-mcp-extension/mobile-mcp-config.json` 复制到 `Assets/StreamingAssets/PuertsUnityMcp/mobile-mcp-config.json`
- 确认 `third_party/puerts` 下官方 PuerTS Android native libraries 存在,并使用 `Packages/puerts-unity-mcp/Runtime/Plugins/Android` 下随包提供的 MCP Android 权限库
- 使用适合手机的低 IO 默认配置
`remove-pum-from-build.mjs` 会移除构建依赖和复制到 `StreamingAssets` 的配置,但不会删除 package 自带的 Android plugin 文件。
手机里的 Runtime MCP 会暴露:
```text
GET /health
POST /mcp
```
Agent 不开 Unity Editor 也可以直接连手机:
```bash
node /puerts-unity-mcp/Packages/puerts-unity-mcp/Tools~/puerts-unity-mcp-stdio-proxy.js \
--config /puerts-unity-mcp-extension/editor-mcp-config.json \
--target-kind player \
--target-url http://PHONE_IP:18991
```
LAN discovery 使用 UDP `18992` 和 `name_group`。如果办公 Wi-Fi、AP 隔离、跨 VLAN、VPN 策略或防火墙禁掉 UDP broadcast/multicast,可以使用 HTTP fallback:
```json
{
"selectedTargetKind": "player",
"name_group": "default",
"lanHttpProbeHosts": ["192.168.1.55"],
"lanHttpProbeCidrs": ["192.168.1.0/24"],
"lanHttpProbeTimeoutMs": 1000
}
```
## Editor JS 不触发 Domain Reload
使用 `editor.js.eval` 做 Editor 自动化。它在现有 Editor PuerTS VM 中执行 JS,不创建 C# 脚本,也不触发编译。
```json
{
"name": "editor.js.eval",
"arguments": {
"mode": "expression",
"code": "CS.UnityEditor.EditorApplication.isPlaying"
}
}
```
这和临时生成 C# 文件完全不同。JS eval 不调用 `AssetDatabase.Refresh`,所以常规 Editor 自动化流程不会触发 Unity domain reload,操作会更流畅。
如果项目 C# 修改导致 domain reload 无法避免,Editor MCP 会把 operation 状态写到 `.puerts-unity-mcp/ops`,保存 compile result hint,并在 `afterAssemblyReload` 后恢复 HTTP endpoint。
## MCP Tool 扩展
核心工具由 C# 注册。项目工具可以用 JS 写,放在 Unity 工程的 extension 目录里。
```text
/puerts-unity-mcp-extension
Editor/editor-tools Editor 侧 JavaScript MCP tools
Runtime/runtime-tools Runtime / Player 侧 JavaScript MCP tools
skills 给 Agent 使用的项目技能
```
每个 JavaScript MCP tool 使用一个 manifest 指向模块:
```json
{
"name": "runtime.activeScene",
"description": "Return the active Unity scene through the runtime PuerTS VM.",
"modulePath": "active-scene.mjs",
"functionName": "execute",
"inputSchema": {
"type": "object",
"additionalProperties": true
}
}
```
Runtime JS tool 会通过 `runtime.js.eval` 执行,所以同一套工具模型可以同时用于 Play Mode 和真实手机。
## 内置 MCP Tools
`tools/list` 会返回当前 endpoint 实际可用的工具。下面是 package 自带的 C# 内置工具;项目自己的 JS tools 会额外从 `puerts-unity-mcp-extension` 加载,例如 `game.*` 这类工具不属于通用内置工具。
### Editor MCP
| Tool | 用途 |
|---|---|
| `mcp.info` | 返回 Editor endpoint metadata、health 和 capability。 |
| `editor.state` | 返回 Unity Editor 当前状态。 |
| `editor.buildSettings.startupScene` | 返回 Build Settings 第一个启用场景。 |
| `editor.js.eval` | 在 Editor PuerTS VM 中执行 JS,不生成 C#,正常情况下不触发 domain reload。 |
| `editor.scriptTools.list` | 列出 `puerts-unity-mcp-extension/Editor/editor-tools` 中的项目 JS tools。 |
| `editor.scriptTools.reload` | 重新加载 Editor 项目 JS tools。 |
| `editor.skills.list` | 列出 `puerts-unity-mcp-extension/skills` 中的项目 skills。 |
| `editor.skill.load` | 加载一个项目 skill。 |
| `editor.playmode.set` | 延迟进入、退出或切换 Play Mode。 |
| `editor.playmode.state` | 返回 Play Mode 状态。 |
| `editor.playmode.set.immediate` | 立即进入、退出或切换 Play Mode。 |
| `editor.targets.list` | 列出当前 Editor 和同 `name_group` 的 LAN Editor endpoints。 |
| `runtime.targets.list` | 列出本地 Play Mode Runtime 和发现到的 Player endpoints。 |
| `targets.list` | 列出 Editor、Play Mode Runtime、LAN Editors 和真实 Player targets。 |
| `lan.discovery.scan` | 发送 LAN discovery,并按配置执行 HTTP fallback 探测。 |
| `runtime.js.eval` | 从 Editor 转发 JS 到本地 Play Mode Runtime 或远程 Player/手机。 |
| `runtime.tool.call` | 从 Editor 调用本地 Play Mode 或远程 Player 的 runtime MCP tool。 |
| `editor.compile` | 触发 `AssetDatabase.Refresh`,并持久化编译结果 hint,用于 domain reload 恢复测试。 |
| `op.status` | 读取持久 operation 状态或结果。 |
### Runtime / Player MCP
这些工具在 Editor Play Mode、Android、iOS 和 standalone Player 中可用;手机直连时 Agent 也是调用这一组。
| Tool | 用途 |
|---|---|
| `mcp.info` | 返回 Runtime/Player endpoint metadata、health 和 capability。 |
| `runtime.status` | 返回 Runtime/Player endpoint 状态。 |
| `runtime.targets.list` | 列出当前 Player endpoint 和该 Player 发现到的 LAN endpoints。 |
| `targets.list` | `runtime.targets.list` 的别名。 |
| `lan.discovery.scan` | 发送同 `name_group` 的 LAN discovery query。 |
| `runtime.js.eval` | 在 Runtime PuerTS VM 中执行 JS。 |
| `runtime.reflection.invoke` | 通过反射 gateway 调用静态 C# 方法。 |
| `runtime.scriptTools.list` | 列出 `puerts-unity-mcp-extension/Runtime/runtime-tools` 中的项目 JS tools。 |
| `runtime.scriptTools.reload` | 重新加载 Runtime 项目 JS tools。 |
| `runtime.skills.list` | 列出项目 skills。 |
| `runtime.skill.load` | 加载一个项目 skill。 |
| `op.status` | 读取持久 operation 状态或结果。 |
| `runtime.logs` | 返回 Runtime log ring buffer 中的最近日志。 |
| `runtime.logs.clear` | 清空 Runtime log ring buffer。 |
| `screen.screenshot` | 截取 Player 画面;手机默认使用 memory PNG base64,减少设备 IO。 |
| `runtime.ui.snapshot` | 返回可见 UGUI canvas、button 和可点击控件快照。 |
| `runtime.ui.find` | 按 text、name、path 或 canvas 查找 UGUI 控件。 |
| `runtime.ui.raycast` | 对屏幕点或目标控件执行 UI raycast。 |
| `runtime.ui.click` | 按坐标、path 或 instanceId 点击 UGUI 控件。 |
| `input.tap` | `runtime.ui.click` 的别名。 |
## Agent PuerTS JS 速查
这一节是专门写给 Agent 的,用于生成 `editor.js.eval`、`runtime.js.eval` 或项目 JavaScript MCP tool 的代码。
### 选择目标 VM
| 任务 | Tool | VM |
|---|---|---|
| Unity Editor 自动化 | `editor.js.eval` | Editor PuerTS VM |
| Play Mode Runtime 自动化 | `runtime.js.eval` 指向本地 Play Mode target | Runtime PuerTS VM |
| Android、iOS、standalone 自动化 | `runtime.js.eval` 指向 `targetId` 或 `httpUrl` | 手机或 Player 里的 Runtime PuerTS VM |
Editor 和 Runtime 是两个独立的 PuerTS `ScriptEnv`。Editor 代码可以使用 `UnityEditor` API。Runtime 和手机代码应使用运行时安全的 API。
### 基础 PuerTS 写法
优先使用 PuerTS 的 `CS` 全局对象。
```js
CS.UnityEngine.Debug.Log("hello from PuerTS Unity MCP");
var productName = CS.UnityEngine.Application.productName;
var sceneName = CS.UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
return {
ok: true,
productName: productName,
sceneName: sceneName
};
```
`mode: "expression"` 会自动返回表达式:
```js
CS.UnityEngine.Application.version
```
`mode: "script"` 需要显式 `return`:
```js
var go = CS.UnityEngine.GameObject.Find("Canvas");
return {
found: !!go,
name: go ? go.name : ""
};
```
### 反射 fallback
如果某个 C# 类型没有生成 wrap,使用 `__unity_mcp`。这个项目当前走 reflection-first,适合开发阶段和项目特有的 IL2CPP 排查。
```js
return __unity_mcp.invokeStatic(
"UnityEngine.Debug",
"Log",
"hello through reflection"
);
```
常用 helper:
```js
__unity_mcp.typeExists("UnityEngine.Application");
__unity_mcp.getStatic("UnityEngine.Application", "productName");
__unity_mcp.getStaticPath("UnityEngine.Screen", "width");
__unity_mcp.setStatic("UnityEngine.Time", "timeScale", 1);
__unity_mcp.invokeStatic("UnityEngine.Debug", "Log", "message");
```
在 IL2CPP 包里,反射取决于类型和成员是否被 stripping。遇到被裁剪的类型时,用 link.xml 或项目包装类补保留。
### 手机 UI 自动化模式
黑盒自动玩手机游戏时,先观察,再操作。
```js
var root = CS.UnityEngine.GameObject.Find("UICanvas");
return {
hasUiCanvas: !!root,
screen: {
width: CS.UnityEngine.Screen.width,
height: CS.UnityEngine.Screen.height
}
};
```
然后组合 runtime MCP 工具:
- `screen.screenshot`
- `runtime.ui.snapshot`
- `runtime.ui.find`
- `runtime.ui.raycast`
- `runtime.ui.click`
- `input.tap`
稳定的项目流程不要一直生成一次性 eval 脚本,应该沉淀到 `puerts-unity-mcp-extension/Runtime/runtime-tools`。
### 返回值规则
返回 JSON 可序列化数据:字符串、数字、布尔值、数组和普通对象。不要直接返回 Unity 对象。
```js
var camera = CS.UnityEngine.Camera.main;
return {
hasMainCamera: !!camera,
cameraName: camera ? camera.name : ""
};
```
## 协议表面
HTTP endpoints:
| Endpoint | 用途 |
|---|---|
| `GET /health` | endpoint 元数据、运行状态、能力摘要 |
| `GET /api/ping` | 轻量 health alias |
| `POST /mcp` | 同步 JSON-RPC MCP 调用 |
主要 MCP methods:
- `initialize`
- `ping`
- `tools/list`
- `tools/call`
C# 侧 JSON 序列化只使用 Unity `JsonUtility`。项目不依赖 Newtonsoft.Json 或其他第三方 JSON 库。
## 配置和状态目录
持久项目配置:
| 路径 | 用途 |
|---|---|
| `puerts-unity-mcp-extension/editor-mcp-config.json` | Editor、Agent、target 选择、LAN discovery 配置 |
| `puerts-unity-mcp-extension/mobile-mcp-config.json` | Runtime / Player 配置,会复制进构建 |
| `Packages/puerts-unity-mcp/Runtime/Plugins/Android` | 随包提供的 MCP Android 权限库;PuerTS native libraries 来自 `third_party/puerts` 官方 UPM 包 |
| `Assets/puerts-unity-mcp/Runtime/Generated/Plugins/puerts_il2cpp` | 当前 Unity 工程生成的 PuerTS IL2CPP bridge 文件;应忽略并按工程重新生成,不要当成通用 package 源码提交 |
| `puerts-unity-mcp-extension/Editor/editor-tools` | 项目 Editor JS MCP tools |
| `puerts-unity-mcp-extension/Runtime/runtime-tools` | 项目 Runtime JS MCP tools |
| `puerts-unity-mcp-extension/skills` | 给 Agent 使用的项目技能 |
临时状态和 operation 数据:
| 路径 | 用途 |
|---|---|
| `.puerts-unity-mcp/editors/{editorId}/heartbeat.json` | Editor heartbeat |
| `.puerts-unity-mcp/players/{playerId}/heartbeat.json` | 可选 Player heartbeat |
| `.puerts-unity-mcp/ops/{operationId}` | 持久 operation 状态和结果 |
| `.puerts-unity-mcp/temp/compile-results` | 编译结果提示 |
## Unity 工程 `.gitignore`
在 Unity 工程的 `.gitignore` 里加入:
```gitignore
# PuerTS Unity MCP 运行状态和工程本地生成文件
.puerts-unity-mcp/
Assets/puerts-unity-mcp/Runtime/Generated/
Assets/puerts-unity-mcp/Runtime/Generated/Plugins/puerts_il2cpp/
```
不要忽略整个 `puerts-unity-mcp-extension` 目录。这个目录里的项目配置、JS tools、skills 属于持久项目资产,如果它们需要随项目走,可以提交。也不要忽略 `puerts-unity-mcp/Packages/puerts-unity-mcp/Runtime/Plugins/Android`,这里是 package 自带的 Android 权限库。PuerTS 官方 `.so` 来自 `third_party/puerts`,不要在 MCP package 里重复提交。
`puerts-unity-mcp/third_party/puerts/unity/.gitignore` 来自官方 PuerTS,会忽略 Unity 为 vendored PuerTS UPM 包自动生成的 `*.meta`。这些文件在本机打开 Unity 后出现是正常的,不需要提交;官方已经提供的 native plugin `.meta` 会随源码保留。
## 目录结构
```text
puerts-unity-mcp
Packages/puerts-unity-mcp
Editor/ Editor MCP endpoint 和 Unity 菜单
Runtime/ Editor Play Mode、Android、iOS 和 standalone 共用的 Runtime MCP assembly
Plugins/ 随 package 提供的 Runtime native/plugin assets
Tools~/ Node 安装、构建、同步和 stdio proxy 工具
Tests/ Unity Editor tests
docs/
protocol.md
third_party/puerts/
Vendored PuerTS UPM packages 和 native plugins
```
## 发布前注意
当前根目录没有 `LICENSE` 文件。公开发布前建议补一个 license。