376 lines
15 KiB
Markdown
376 lines
15 KiB
Markdown
# MCP for Unity 开发工具
|
||
|
||
| [English](README-DEV.md) | [简体中文](README-DEV-zh.md) |
|
||
|---------------------------|------------------------------|
|
||
|
||
欢迎来到 MCP for Unity 开发环境!此目录包含简化 MCP for Unity 核心开发的工具和实用程序。
|
||
|
||
## 🛠️ 开发环境搭建
|
||
|
||
### 安装开发依赖
|
||
|
||
如果你想贡献代码或运行测试,需要使用 `uv` 安装开发依赖:
|
||
|
||
```bash
|
||
# 进入 server 源码目录
|
||
cd Server
|
||
|
||
# 以 editable 模式安装,并包含 dev 依赖
|
||
uv pip install -e ".[dev]"
|
||
```
|
||
|
||
这会安装:
|
||
|
||
- **运行时依赖**:`httpx`, `fastmcp`, `mcp`, `pydantic`, `tomli`
|
||
- **开发依赖**:`pytest`, `pytest-asyncio`
|
||
|
||
### 运行测试
|
||
|
||
```bash
|
||
# 在 server 目录下
|
||
cd Server
|
||
uv run pytest tests/ -v
|
||
```
|
||
|
||
或者从仓库根目录执行:
|
||
|
||
```bash
|
||
# 使用 server 目录中的 uv
|
||
cd Server && uv run pytest tests/ -v
|
||
```
|
||
|
||
只运行集成测试:
|
||
|
||
```bash
|
||
uv run pytest tests/ -v -m integration
|
||
```
|
||
|
||
只运行单元测试:
|
||
|
||
```bash
|
||
uv run pytest tests/ -v -m unit
|
||
```
|
||
|
||
### 代码覆盖率
|
||
|
||
运行带覆盖率追踪的测试:
|
||
|
||
```bash
|
||
cd Server
|
||
uv run pytest tests/ --cov --cov-report=html --cov-report=term
|
||
|
||
# 查看 HTML 报告
|
||
open htmlcov/index.html # macOS
|
||
xdg-open htmlcov/index.html # Linux
|
||
```
|
||
|
||
覆盖率配置位于 `Server/pyproject.toml` 的 `[tool.coverage.*]` 部分。
|
||
|
||
## 🚀 可用的开发特性
|
||
|
||
### ✅ 开发部署脚本
|
||
|
||
用于快速部署与测试 MCP for Unity 核心更改的工具。
|
||
|
||
**Development Mode Toggle**:内置 Unity 编辑器开发特性(现在作为 Advanced Setting 提供)
|
||
|
||
**Hot Reload System**:无需重启 Unity 的实时更新(Roslyn Runtime_Compilation Custom Tools)
|
||
|
||
**Plugin Development Kit**:用于创建 MCP for Unity 扩展的工具(Custom Tools)
|
||
|
||
### 🔄 即将推出
|
||
|
||
- **自动化测试套件**:为贡献提供更完整的测试框架
|
||
- **调试面板**:更高级的调试与监控工具
|
||
|
||
---
|
||
|
||
## Advanced Settings(编辑器窗口)
|
||
|
||
使用 MCP for Unity 编辑器窗口(Window > MCP for Unity),在 Settings 选项卡内打开 **Advanced Settings**,可以在开发期间覆盖工具路径、切换 server 源、并将本地包部署到项目中。
|
||
|
||

|
||
|
||
- **UV/UVX Path Override**:当系统 PATH 解析不正确时,可在 UI 中指定 `uv`/`uvx` 可执行文件路径(例如使用自定义安装)。清空后会回退到自动发现。
|
||
- **Server Source Override**:为 Python server(`uvx --from <url> mcp-for-unity`)设置本地文件夹或 git URL。清空后使用默认打包版本。
|
||
- **Dev Mode(强制全新安装 server)**:启用后,生成的 `uvx` 命令会在启动前添加 `--no-cache --refresh`。会更慢,但可避免在迭代 `Server/` 时误用旧缓存构建。
|
||
- **Local Package Deployment**:选择本地 `MCPForUnity` 文件夹(必须包含 `Editor/` 与 `Runtime/`),点击 **Deploy to Project** 后会将其复制到当前已安装的 package 路径(来自 `Packages/manifest.json` / Package Manager)。会在 `Library/MCPForUnityDeployBackups` 下保存带时间戳的备份,点击 **Restore Last Backup** 可回滚最近一次部署。
|
||
|
||
提示:
|
||
|
||
- 部署/回滚后,Unity 会自动刷新脚本;若不确定,可重新打开 MCP window 并在 Advanced Settings 里确认目标路径标签。
|
||
- 保持 source 与 target 不要混用(不要把 source 指向已经安装的 `PackageCache` 文件夹)。
|
||
- 推荐使用被 gitignore 的工作目录进行快速迭代;部署流程只会复制 `Editor` 与 `Runtime`。
|
||
|
||
## 快速切换 MCP 包源
|
||
|
||
从 unity-mcp 仓库运行,而不是从游戏的根目录。使用 `mcp_source.py` 可以在不同的 MCP for Unity 包源之间快速切换:
|
||
|
||
**用法:**
|
||
|
||
```bash
|
||
python mcp_source.py [--manifest /path/to/manifest.json] [--repo /path/to/unity-mcp] [--choice 1|2|3]
|
||
```
|
||
|
||
**选项:**
|
||
|
||
- **1** 上游 main(CoplayDev/unity-mcp)
|
||
- **2** 远程当前分支(origin + branch)
|
||
- **3** 本地工作区(file: MCPForUnity)
|
||
|
||
切换后,打开 Package Manager 并 Refresh 以重新解析依赖。
|
||
|
||
## Development Deployment Scripts
|
||
|
||
这些部署脚本帮助你快速测试 MCP for Unity 核心代码的更改。
|
||
|
||
## Scripts
|
||
|
||
### `deploy-dev.bat`
|
||
|
||
将你的开发代码部署到实际安装位置以便测试。
|
||
|
||
**它会做什么:**
|
||
|
||
1. 将原始文件备份到一个带时间戳的文件夹
|
||
2. 将 Unity Bridge 代码复制到 Unity 的 package cache
|
||
3. 将 Python Server 代码复制到 MCP 安装目录
|
||
|
||
**用法:**
|
||
|
||
1. 运行 `deploy-dev.bat`
|
||
2. 输入 Unity package cache 路径(脚本会给出示例)
|
||
3. 输入 server 路径(或使用默认:`%LOCALAPPDATA%\Programs\UnityMCP\UnityMcpServer\src`)
|
||
4. 输入备份位置(或使用默认:`%USERPROFILE%\Desktop\unity-mcp-backup`)
|
||
|
||
**注意:** Dev deploy 会跳过 `.venv`, `__pycache__`, `.pytest_cache`, `.mypy_cache`, `.git`;减少变动并避免复制虚拟环境。
|
||
|
||
### `restore-dev.bat`
|
||
|
||
从备份恢复原始文件。
|
||
|
||
**它会做什么:**
|
||
|
||
1. 列出所有带时间戳的备份
|
||
2. 让你选择要恢复的备份
|
||
3. 同时恢复 Unity Bridge 与 Python Server 文件
|
||
|
||
### `prune_tool_results.py`
|
||
|
||
将对话 JSON 中体积很大的 `tool_result` 内容压缩为简洁的一行摘要。
|
||
|
||
**用法:**
|
||
|
||
```bash
|
||
python3 prune_tool_results.py < reports/claude-execution-output.json > reports/claude-execution-output.pruned.json
|
||
```
|
||
|
||
脚本从 `stdin` 读取对话并将裁剪版本输出到 `stdout`,使日志更容易检查或存档。
|
||
|
||
这些默认策略可以显著降低 token 使用量,同时保留关键的信息。
|
||
|
||
## 查找 Unity Package Cache 路径
|
||
|
||
Unity 会把 Git 包存储在一个“版本号或哈希”的文件夹下,例如:
|
||
|
||
```
|
||
X:\UnityProject\Library\PackageCache\com.coplaydev.unity-mcp@<version-or-hash>
|
||
```
|
||
|
||
示例(哈希):
|
||
|
||
```
|
||
X:\UnityProject\Library\PackageCache\com.coplaydev.unity-mcp@272123cfd97e
|
||
|
||
```
|
||
|
||
可靠的查找方式:
|
||
|
||
1. 打开 Unity Package Manager
|
||
2. 选择 “MCP for Unity” package
|
||
3. 右键 package 并选择 “Show in Explorer”
|
||
4. Unity 会打开该项目实际使用的 cache 文件夹
|
||
|
||
注意:在近期版本中,Python server 的源码也会打包在该 package 内的 `Server` 目录下。这对本地测试或让 MCP client 直接指向打包 server 很有用。
|
||
|
||
## Payload 大小与分页默认值(推荐)
|
||
|
||
某些 Unity 工具调用可能返回*非常大的* JSON payload(例如深层级场景、带完整序列化属性的组件)。为避免 MCP 响应过大、以及 Unity 卡死/崩溃,建议优先使用 **分页 + 先摘要后细节** 的读法,仅在需要时再拉取完整属性。
|
||
|
||
### `manage_scene(action="get_hierarchy")`
|
||
|
||
- **默认行为**:返回根 GameObject(无 `parent`)或指定 `parent` 的直接子节点的 **分页摘要**。不会内联完整递归子树。
|
||
- **分页参数**:
|
||
- **`page_size`**:默认 **50**,限制 **1..500**
|
||
- **`cursor`**:默认 **0**
|
||
- **`next_cursor`**:当还有更多结果时返回 **字符串**;完成时为 `null`
|
||
- **其他安全阀**:
|
||
- **`max_nodes`**:默认 **1000**,限制 **1..5000**
|
||
- **`include_transform`**:默认 **false**
|
||
|
||
### `manage_gameobject(action="get_components")`
|
||
|
||
- **默认行为**:仅返回 **分页的组件元数据**(`typeName`, `instanceID`)。
|
||
- **分页参数**:
|
||
- **`page_size`**:默认 **25**,限制 **1..200**
|
||
- **`cursor`**:默认 **0**
|
||
- **`max_components`**:默认 **50**,限制 **1..500**
|
||
- **`next_cursor`**:当还有更多结果时返回 **字符串**;完成时为 `null`
|
||
- **按需读取属性**:
|
||
- **`include_properties`** 默认 **false**
|
||
- 当 `include_properties=true` 时,会启用保守的响应大小预算(约 **~250KB** JSON 文本),返回条数可能少于 `page_size`;使用 `next_cursor` 继续。
|
||
|
||
### 实用默认值(我们在 prompts/tests 中的推荐)
|
||
|
||
- **Hierarchy roots**:从 `page_size=50` 开始,根据 `next_cursor` 继续(大场景通常 1–2 次调用)。
|
||
- **Children**:按 `parent` 分页,`page_size=10..50`(根据预期广度)。
|
||
- **Components**:
|
||
- 先用 `include_properties=false` 且 `page_size=10..25`
|
||
- 需要完整属性时,用 `include_properties=true` 且保持较小 `page_size`(例如 **3..10**)来控制峰值 payload。
|
||
|
||
## MCP Bridge 压力测试
|
||
|
||
一个按需的压力测试工具会用多个并发客户端测试 MCP bridge,同时通过“立即脚本编辑”触发真实的脚本 reload(无需菜单调用)。
|
||
|
||
### 脚本
|
||
|
||
- `tools/stress_mcp.py`
|
||
|
||
### 它做什么
|
||
|
||
- 对 MCP for Unity bridge 启动 N 个 TCP 客户端(默认端口从 `~/.unity-mcp/unity-mcp-status-*.json` 自动发现)。
|
||
- 发送轻量 framed `ping` 维持并发。
|
||
- 同时,使用 `manage_script.apply_text_edits` 对目标 C# 文件在 EOF 追加唯一标记注释,并设置:
|
||
- `options.refresh = "immediate"` 来立即触发 import/compile(会引发 domain reload),以及
|
||
- 从当前文件内容计算 `precondition_sha256` 来避免漂移。
|
||
- 使用 EOF 插入避免头部/`using` guard 的编辑。
|
||
|
||
### 用法(本地)
|
||
|
||
```bash
|
||
# 推荐:使用测试项目中包含的大型脚本
|
||
python3 tools/stress_mcp.py \
|
||
--duration 60 \
|
||
--clients 8 \
|
||
--unity-file "TestProjects/UnityMCPTests/Assets/Scripts/LongUnityScriptClaudeTest.cs"
|
||
```
|
||
|
||
### Flags
|
||
|
||
- `--project` Unity 项目路径(默认自动检测到仓库自带的测试项目)
|
||
- `--unity-file` 要编辑的 C# 文件(默认为长测试脚本)
|
||
- `--clients` 并发客户端数量(默认 10)
|
||
- `--duration` 运行秒数(默认 60)
|
||
|
||
### 预期结果
|
||
|
||
- Unity Editor 在 reload churn 下不崩溃
|
||
- 每次应用编辑后立即 reload(无需 `Assets/Refresh` 菜单调用)
|
||
- 在 domain reload 期间可能会有少量短暂断线或失败调用;工具会重试并继续
|
||
- 最后输出 JSON 汇总,例如:
|
||
- `{"port": 6400, "stats": {"pings": 28566, "applies": 69, "disconnects": 0, "errors": 0}}`
|
||
|
||
### 说明与排障
|
||
|
||
- Immediate vs debounced:
|
||
- 工具设置 `options.refresh = "immediate"` 让每次改动都立刻编译。如果你只想测试 churn(不关心每次确认),可以改成 debounced 来减少中途失败。
|
||
- 需要 precondition:
|
||
- 对较大文件,`apply_text_edits` 需要 `precondition_sha256`。工具会先读文件计算 SHA。
|
||
- 编辑位置:
|
||
- 为避免头部 guards 或复杂范围,工具每轮都在 EOF 追加一行 marker。
|
||
- Read API:
|
||
- bridge 当前支持 `manage_script.read` 用于读文件。可能会看到弃用提示;对该内部工具无影响。
|
||
- 瞬时失败:
|
||
- 偶尔出现 `apply_errors` 往往意味着连接在回包时发生 reload。通常编辑仍然已应用;循环会继续下一轮。
|
||
|
||
### CI 指导
|
||
|
||
- 由于 Unity/editor 依赖与运行时波动,不建议把它放进默认 PR CI。
|
||
- 可选择作为手动 workflow 或 nightly job 在支持 Unity 的 runner 上运行。
|
||
|
||
## CI 测试工作流(GitHub Actions)
|
||
|
||
我们提供 CI 作业来对 Unity 测试项目运行自然语言编辑套件:它会启动 headless Unity 容器并通过 MCP bridge 连接。要在 fork 上运行,你需要以下 GitHub Secrets:`ANTHROPIC_API_KEY` 以及 Unity 凭据(通常为 `UNITY_EMAIL` + `UNITY_PASSWORD` 或 `UNITY_LICENSE` / `UNITY_SERIAL`)。这些会在日志中被脱敏,因此不会泄露。
|
||
|
||
***如何运行***
|
||
|
||
- 触发:在 GitHub Actions 中手动触发 `workflow dispatch`(`Claude NL/T Full Suite (Unity live)`)。
|
||
- 镜像:`UNITY_IMAGE`(UnityCI)使用 tag 拉取;作业会在运行时解析 digest。日志会被清理。
|
||
- 执行:单次执行,每个测试生成一个片段(严格:每个文件只允许一个 `<testcase>`)。若任何片段只是裸 ID,会被占位符 guard 快速判失败。暂存目录(`reports/_staging`)会被提升到 `reports/` 以减少部分写入。
|
||
- 报告:JUnit 输出到 `reports/junit-nl-suite.xml`,Markdown 输出到 `reports/junit-nl-suite.md`。
|
||
- 发布:JUnit 会被规范化为 `reports/junit-for-actions.xml` 并发布;Artifacts 会上传 `reports/` 下的全部文件。
|
||
|
||
### 测试目标脚本
|
||
|
||
- 仓库包含一个很长且独立的 C# 脚本,用于验证大文件编辑与窗口读取:
|
||
- `TestProjects/UnityMCPTests/Assets/Scripts/LongUnityScriptClaudeTest.cs`
|
||
本地与 CI 都建议用它来测试多编辑批次、anchor insert、windowed read 等。
|
||
|
||
### 调整 tests / prompts
|
||
|
||
- 修改 `.claude/prompts/nl-unity-suite-t.md` 来调整 NL/T 步骤。遵循约定:每个测试在 `reports/<TESTID>_results.xml` 下生成一个 XML 片段,且每个片段恰好包含一个 `<testcase>`,其 `name` 必须以 test ID 开头。不要包含 prologue/epilogue 或代码围栏。
|
||
- 保持改动最小、可回滚,并给出简洁证据。
|
||
|
||
### 运行套件
|
||
|
||
1) 推送你的分支,然后在 Actions 标签页手动运行 workflow。
|
||
2) 作业把 reports 写入 `reports/` 并上传 artifacts。
|
||
3) “JUnit Test Report” check 会汇总结果;打开 Job Summary 查看完整 Markdown。
|
||
|
||
### 查看结果
|
||
|
||
- Job Summary:Actions 中的内联 Markdown 汇总
|
||
- Check:“JUnit Test Report”
|
||
- Artifacts:`claude-nl-suite-artifacts`,包含 XML 与 MD
|
||
|
||
### MCP 连接调试
|
||
|
||
- 在 MCP for Unity 窗口(Editor 内)*启用 debug logs*,可以看到连接状态、auto-setup 结果与 MCP client 路径,包括:
|
||
- bridge 启动/端口、client 连接、strict framing 协商、解析后的 frame
|
||
- auto-config 路径检测(Windows/macOS/Linux)、uv/claude 解析与错误提示
|
||
- CI 中如启动失败,作业会 tail Unity 日志(serial/license/password/token 已脱敏),并打印 socket/status JSON 诊断。
|
||
|
||
## Workflow
|
||
|
||
1. **修改** 此目录中的源码
|
||
2. **Deploy** 使用 `deploy-dev.bat`
|
||
3. **在 Unity 中测试**(先重启 Unity Editor)
|
||
4. **迭代** - 按需重复 1-3
|
||
5. **Restore** 完成后用 `restore-dev.bat` 恢复原始文件
|
||
|
||
## Troubleshooting
|
||
|
||
### 运行 .bat 时出现 "Path not found"
|
||
|
||
- 确认 Unity package cache 路径正确
|
||
- 确认 MCP for Unity package 已安装
|
||
- 确认 server 已通过 MCP client 安装
|
||
|
||
### 出现 "Permission denied"
|
||
|
||
- 用管理员权限运行 cmd
|
||
- 部署前关闭 Unity Editor
|
||
- 部署前关闭所有 MCP client
|
||
|
||
### 出现 "Backup not found"
|
||
|
||
- 先运行 `deploy-dev.bat` 生成初始备份
|
||
- 检查备份目录权限
|
||
- 确认备份路径正确
|
||
|
||
### Windows uv 路径问题
|
||
|
||
- 在 Windows 上测试 GUI client 时,优先使用 WinGet Links 下的 `uv.exe`;若存在多个 `uv.exe`,可用 “Choose `uv` Install Location” 固定 Links shim。
|
||
|
||
### Unity 退到后台时 Domain Reload Tests 卡住
|
||
|
||
在测试过程中触发脚本编译(例如 `DomainReloadResilienceTests`)时,如果 Unity 不是前台窗口,测试可能会卡住。这是操作系统层面的限制——macOS 会限制后台应用的主线程,从而阻止编译完成。
|
||
|
||
**Workarounds:**
|
||
|
||
- 运行 domain reload tests 时保持 Unity 在前台
|
||
- 在测试套件最开始运行它们(在 Unity 被切到后台之前)
|
||
- 使用 `[Explicit]` 属性将其从默认运行中排除
|
||
|
||
**注意:** MCP workflow 本身不受影响——socket 消息会给 Unity 提供外部刺激,使其即使在后台也保持响应。该限制主要影响 Unity 内部测试协程的等待。
|