内容
# AkerMCP



<p align="center">
<img src="readmeData/AkerMCP.png" alt="AkerMCP — Aker, the twin lions, bridging the AI and the game engine" width="680">
</p>
> *Aker(埃及神话:ꜣkr)是古埃及的土地神,形象为**两只狮子背靠背**,面朝相反的地平线——塞夫和杜奥(昨天和今天)——守护太阳安全穿过冥界。在这个架构中,Aker 是桥梁:一面用 **JSON-RPC** 与 **LLM** 对话,另一面通过 **IPC** 操作**引擎的主线程**。*
> **赋予你的 AI 助手(Claude, Cursor, Copilot, Antigravity)直接操控任何 C# 游戏引擎的能力。**
传统上,AI 编码助手只能建议代码供你复制粘贴。而使用 **AkerMCP**,你可以授予你的 AI 能力,让它实时**看到**和**触摸**你的游戏项目。
> ### 🦁🦁 唯一支持 **Unity, Godot 和 Stride** 作为一流引擎的 MCP —— 所有工具,在所有三个引擎上功能对等。
100% C# 引擎无关的核心意味着**相同的** AI 工作流程 —— 检查、修改、执行 C#、截图、构建 —— 在 **Unity 编辑器**、**Godot** 或 **Stride Game Studio** 中**完全相同**,并且可以移植到 Flax Engine 或任何自定义 C# 引擎,只需一个轻量级适配器。目前没有其他开源 MCP 服务器能够在三个不同引擎上提供这种程度的编辑器控制。
### 🎮 支持的引擎 —— 功能对等
| 功能 | Unity | Godot | Stride |
|---|:--:|:--:|:--:|
| 检查 · 查询 · 获取/设置属性(包括嵌套) | ✅ | ✅ | ✅ |
| `call_method` · `create` · `delete` (原生撤销) | ✅ | ✅ | ✅ |
| `execute` —— 通过 Roslyn 执行任意 C# | ✅ | ✅ | ✅ |
| 选择 · 控制台日志 · 重新编译/编译错误 | ✅ | ✅ | ✅ |
| 带有编辑器 gizmos 的场景视图截图 | ✅ | ✅ | ✅ |
| 平台/构建工具(列表 · 切换 · 构建玩家) | ✅ | ✅ | ✅ |
每一行都在每个引擎的编辑器中实施并实时验证 —— 不是一个路线图。同时还有引擎无关的 OS 工具(`list_windows` / `capture_window`)来截图机器上的任何窗口。
### 🧠 无限制:编辑器的主线程上执行任意 C#
结构化工具是一条便捷的路径 —— 但真正的力量在于 **`execute`** 工具,它直接编译并运行 **任意** C#(通过 Roslyn)针对实时编辑器。这意味着**整个** 引擎 + 编辑器 API,你自己的项目程序集,资产管道,文件系统 —— **编辑器本身可以做的任何事情,AI 都可以做。** 基本上没有限制它可以完成的事情。
简而言之:AkerMCP 给了 AI **眼睛** (检查,查询,截图)和 **手** (设置,创建,调用,执行,构建)来做你实际需要的事情 —— 不是一个固定的菜单,而是开放的能力,在所有支持的引擎上完全相同。
### 🪄 “Wow” 因子:与引擎对话
想象一下问你的 AI:
> *"让 Player 角色大 20%,把所有敌人材质变成红色,并在地面平面上生成 50 个树。"*
- **没有 AkerMCP:** AI 编写一个自定义脚本,解释如何放置它,你切换到 Unity,附加它,运行并希望它有效。
- **有 AkerMCP:** AI 直接完成。瞬间。在你的编辑器中 —— Unity,Godot 或 Stride。你看着场景在你眼前变化。
AkerMCP 充当一个无缝的桥梁。它允许 AI 代理检查你的场景层次,修改对象,甚至在运行时执行复杂的程序 C# 脚本。不再需要手动重复点击检查器 —— 只需告诉你的 AI 你想要什么。
**示例:** *"在半径为 10 的圆圈中生成 10 个球体。"*
```csharp
for (int i = 0; i < 10; i++) {
float angle = i * Mathf.PI * 2 / 10f;
Vector3 pos = new Vector3(Mathf.Cos(angle) * 10f, 0, Mathf.Sin(angle) * 10f);
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = pos;
sphere.name = $"Aker_Sphere_{i}";
}
```

**相同的请求,相同的工具 —— 在 Stride Game Studio 中。** AI 通过 `execute` (通过 Stride 的资产/Quantum 层,所以它们是**真实的,可选的,已保存的实体** —— 注意左边的场景层次中的 `AkerSphere_*`),然后捕获编辑器本身。工作流程相同,不同的引擎:
<img src="readmeData/Stride.png" alt="AkerMCP in Action — Stride Game Studio" width="1024">
*(想了解内部技术细节?跳转到 [架构](#architecture) 部分)。*
### 🏆 真实案例研究
为了真正理解 AkerMCP 前所未有的强大功能,请考虑这两个真实案例:
#### 案例研究 1: “隐形” GPU 错误
开发人员的自定义体素环境遮蔽(AO)渲染完全扁平,使地下洞穴过于明亮。
- **没有 AkerMCP,** AI 助手是盲目的。它只能读取你的着色器代码,猜测可能出错的地方,并给你一个需要手动检查的清单。你只能重新编译,进入 Play 模式,附加调试器,并迭代盲目地几个小时,因为状态完全存在于 GPU 内存中。
- **有 AkerMCP,** AI 坐在你的办公桌上:
1. **视觉验证:** 通过在场景视图上调用 `take_screenshot`,AI 直观地确认了用户的报告: *"整体外观是扁平和褪色的。洞穴根本不黑暗。"*
2. **动态编辑器控制:** AI 编写了一个即时的 C# Roslyn 脚本,通过 `execute` 工具将 `VoxelWorldGI` 管道强制设置为纯“调试 10(灰度 AO)”模式。第二个截图确认 AO 通道完全是白色的(AO ≈ 1.0)。
3. **CPU 内存检查:** 为了检查体素化是否失败,AI 编写了另一个脚本来读取 `_cells` 数组的 CPU 内存,计算了 **29,408 个占用实体像素**。 *体素化工作完美。*
4. **3D 纹理读取:** 实现该错误位于锥体追踪通道中,AI 编写了一个复杂的脚本来执行 `Texture3D` 辐射缓冲区 的 GPU 读取。 Unity 默认只返回 0 深度切片,因此 AI 重写了脚本以迭代和聚合所有 104 个卷积层。
5. **罪魁祸首:** 通过分析聚合的缓冲区,AI 发现 alpha 通道镜像原始占用数据而不是计算的 AO。它立即指出了确切的故障:一个空的 mip-map 链生成步骤意味着锥体无法追踪任何遮蔽。
仅需几分钟,AI 就诊断出一个复杂的、数据依赖的 GPU 错误。它不仅编写了代码,还像技术艺术家一样操作 —— 触发编辑器管道,从 VRAM 读取多维数组,拍摄视觉快照,并通过交互式反馈确认假设。
#### 案例研究 2: “上下文感知” 着色器架构师
在另一个会话中,用户希望标准(非体素)网格对自定义体素引擎生成的照明数据做出反应。
- **没有 AkerMCP:** AI 可能会提供通用 HLSL 代码。用户必须手动创建 `.hlsl` 包含文件,弄清楚如何将它们连接到 Unity 的 Shader Graph 作为自定义功能节点,并希望变量名称与引擎内部结构匹配。
- **有 AkerMCP(和 LynxMCP):**
1. AI 搜索项目的自定义 C# 和着色器代码,以了解自定义体素引擎如何存储其照明缓冲区(例如 `_VoxelGridMipped`)。
2. 它编写了一个专门针对项目架构特点的 HLSL 包含文件。
3. 使用 `execute` 工具,AI 利用 Unity 的 `AssetDatabase` 自动创建并保存 `.hlsl` 文件到正确的 `Assets/` 目录中。
4. 它不仅限于代码。认识到 Unity 的着色器图是底层 JSON 文件,AI 使用 `execute` 工具以编程方式构造并保存一个完整的 `.shadergraph` 资产直接到项目中。该图自动将新的 HLSL 自定义功能节点连接到 PBR 主节点。
5. **视觉 A/B 测试(零用户输入):** 最后,AI 没有直接假设它有效。它使用 `execute` 创建一个新的使用生成着色器的材质,在场景中生成两个相同的测试对象 —— 一个使用标准着色器,另一个使用新的体素 GI 着色器 —— 并应用材质。然后它拍摄 `take_screenshot` 以视觉比较它们,证明自定义全局照明正确贡献,完全自主。
AkerMCP 将 AI 从一个简单的“代码生成器”转变为一个自主的技术艺术家,不仅编写着色器,还原生地将它们集成到引擎的资产管道中。
---
## 🦁 底层工作原理
传统的 MCP 游戏引擎集成需要 100 多个手工编写的工具 —— 每个操作一个,每个组件类型一个。每次引擎更新都会破坏它们。
AkerMCP 用 **20+ 通用工具** 取代了所有这些工具,这些工具由运行时反射和 **Roslyn** 提供支持。一个 `set_property` 工具可以修改 *任意* 对象上的 *任意* 属性,在 *任意* 引擎中,而 `execute` 工具通过 C# 脚本实现复杂的程序生成。 `take_screenshot` 工具闭环,提供一种视觉验证 AI 操作的方法。引擎特定的适配器提供与引擎 API 直接交互所需的层。
```
AI: "将玩家的 position 设置为 (10, 0, 5)"
→ set_property {"object_path": "/Player", "property_path": "position", "value": {"x":10,"y":0,"z":5}}
← 属性 'position' 成功设置在 /Player
```
不需要自定义工具类。不需要代码生成。只有反射。
---
## 功能
- **平等支持所有引擎 —— 目前是 Unity、Godot 和 Stride:** 不是 Unity 工具的侧端口。所有三个都是首选适配器,具有完整的特性对等(参见上表);没有一个是“主要”引擎,并且没有可比较的多引擎替代品。
- **20+ 通用基于反射的工具:** 对任何对象或组件操作,无需自定义工具定义 —— 相同的工具表面跨所有引擎。
- **Roslyn 支持的动态执行:** 通过 `execute` 工具发送任意 C# 脚本,以执行复杂的过程任务或批量操作,直接在编辑器中(Unity / Godot / Stride Game Studio)。
- **视觉验证(`take_screenshot`):** 引擎内部场景视图捕获 **带有编辑器 gizmos** 的所有三个引擎,以及 **跨平台 OS 级别备用** (`PrintWindow` 在 Windows 上,Quartz `CGWindowListCreateImage` 在 macOS 上)和独立的 `list_windows` / `capture_window` 工具,用于任何窗口。输出自动调整大小并使用 ImageSharp 编码为 JPEG 以适应 AI 图像限制。
- **MessagePack IPC 协议:** 独立 MCP 服务器和引擎插件之间高性能、低延迟的二进制通信。
- **强大的类型系统:** 无缝序列化/反序列化引擎结构体(`Vector3`、`Color`、`Bounds`,...)对于 Unity、Godot 和 Stride 来说是无缝的,不区分大小写。
- **引擎无关的核心:** 共享的 .NET Standard 2.1 核心;添加第四个引擎(Flax 或任何自定义 C# 引擎)只是一个适配器 —— 服务器和工具永远不会改变。
---
## 最佳组合:AkerMCP + LynxMCP
AkerMCP 为您的 AI 代理提供 **操纵活动场景** 和执行运行时代码的能力。但要真正有效,AI 还需要大脑来理解您的整个项目架构和依赖关系。
我们强烈建议将 AkerMCP 与 [**LynxMCP**](https://github.com/lorenzo-cambiaghi/LynxMCP)结合使用,我们为代码库设计的本地 RAG(检索增强生成)服务器。
当结合使用时,您的 AI 可以获得 **完整的全局视野**:
- **LynxMCP** 提供对您自定义 C# 脚本和最新 Unity/库文档的深入语义搜索(为 AI 提供确切的 API 和模式,否则它无法从其标准训练数据中了解)。
- **AkerMCP** 使用确切的上下文编写并执行无缝的 Roslyn 脚本,直接在您的编辑器中。
---
## 目录
- [最佳组合:AkerMCP + LynxMCP](#最佳组合-akermcp--lynxmcp)
- [快速入门(推荐)](#快速入门推荐)
- [连接 AI 客户端](#连接-ai-客户端)
- [Claude 代码(CLI)](#claude-代码-cli)
- [Claude 桌面版](#claude-桌面版)
- [Cursor](#cursor)
- [Windsurf](#windsurf)
- [谷歌 Antigravity](#谷歌-antigravity)
- [VS Code + Copilot](#vs-code--copilot)
- [高级:从源代码构建(适用于开发人员)](#高级从源代码构建适用于开发人员)
- [验证连接](#验证连接)
- [MCP 工具](#mcp-工具)
- [MCP 资源](#mcp-资源)
- [类型系统](#类型系统)
- [示例会话](#示例会话)
- [架构](#架构)
- [编写引擎适配器](#编写引擎适配器)
- [AI 集成规则](#ai-集成规则)
- [故障排除](#故障排除)
- [许可证](#许可证)
---
## 快速入门(推荐)
两个步骤:**(1)** 为您的引擎安装适配器 —— Unity、Godot 或 Stride(它们是同等重要的;请选择您使用的一个),然后 **(2)** 运行独立的 MCP 服务器,它是所有这些引擎相同的,并且自动发现正在运行的引擎。
### 1a. Unity 设置
> 您不需要安装 .NET SDK 或为 Unity 编译任何代码。
1. 转到 [最新的 GitHub 版本](https://github.com/lorenzo-cambiaghi/AkerMCP/releases/latest) 并下载 `AkerMCP.unitypackage`。
2. 打开您的 Unity 项目并双击软件包以导入。
*(此软件包已经包含所有必要的 C# 脚本、依赖项和 Roslyn 编译器)。*
3. **(可选)** 打开菜单 **AkerMcp → 设置测试场景** 以创建可测试的场景。
4. 打开 **Window → AkerMcp** 并点击 **启动 AkerMcp 插件**。您应该看到绿色 **正在运行** 状态。
*(提示:插件必须在启动服务器之前运行。服务器通过锁文件自动发现它。)*

### 1b. Godot 设置
AkerMCP 配备了 **Godot 4.x(.NET/C#)适配器**,具有与 Unity 相同的 **完整工具集**。由于 Godot 项目是一个真正的 `.csproj`,因此没有要复制的 DLL —— 引用和 Roslyn 引擎来自 NuGet/ProjectReference。
1. 从 [最新的 Release](https://github.com/lorenzo-cambiaghi/AkerMCP/releases/latest) 下载 `AkerMcp.Godot-addon.zip` 并解压它,以便您获得 `addons/aker_mcp/` 在您的 Godot 项目中(或复制此存储库的 `plugins/godot` 文件夹作为 `addons/aker_mcp`)。
2. 将 AkerMcp 核心添加到您的游戏 `.csproj`(或直接使用包含的 `samples/godot` 项目 - 先运行 `setup-samples` 以链接附加组件):
```xml
<ProjectReference Include="path/to/AkerMcp.Shared.csproj" />
<ProjectReference Include="path/to/AkerMcp.Client.csproj" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.8.0" />
```
确保您的项目有 `<EnableDynamicLoading>true</EnableDynamicLoading>`(编辑器插件所需)。
3. */
```xml
<ProjectReference Include="path/to/AkerMcp.Shared.csproj" />
<ProjectReference Include="path/to/AkerMcp.Client.csproj" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.8.0" />
```
确保您的项目有 `<EnableDynamicLoading>true</EnableDynamicLoading>`(编辑器插件所需)。
3. 构建 C# 解决方案一次(**项目 → 工具 → C#:创建/构建**),然后在启用插件的情况下 **项目 → 项目设置 → 插件 → AkerMcp**。
插件在编辑器启动时自动启动,并为每个帧的请求提供管道服务。场景路径遵循编辑场景的根目录(例如 `/TestScene/Box`),属性路径不区分大小写(`position.x` 解析为 `Position.X`),快照捕获编辑器的 3D 视口。独立的 MCP 服务器自动发现 Godot 插件 - 无需服务器更改。
### 1c. Stride 设置
AkerMCP 配备了 **Stride(游戏工作室)适配器**,具有与 Unity 相同的 **完整工具集** - 包括可撤销编辑(通过 Stride 的 Quantum 图)、`execute`(Roslyn)、实际场景视图快照(编辑器后缓冲区,带有 gizmos),以及平台/构建工具(`dotnet build` 每个可执行项目)。
> Stride 支持作为 Game Studio 编辑器插件运行。 Game Studio 目前没有第三方插件发现功能,因此当前设置会构建适配器以对抗您的 Stride 并通过一次性钩子加载它 - 它比 Unity/Godot 更复杂。
1. 从源代码 **构建 Stride Game Studio**。请参阅 [Stride 构建文档](https://github.com/stride3d/stride)。
2. 将适配器加载器添加到 `Stride.GameStudio/Program.cs`(在其内置插件注册后),以便 Game Studio 加载放置在 `AkerMcpPlugins` 文件夹中的任何适配器:
```csharp
var akerPluginsDir = System.IO.Path.Combine(System.AppContext.BaseDirectory, "AkerMcpPlugins");
if (System.IO.Directory.Exists(akerPluginsDir))
foreach (var dll in System.IO.Directory.GetFiles(akerPluginsDir, "*.dll"))
try { foreach (var t in System.Reflection.Assembly.LoadFrom(dll).GetTypes())
if (!t.IsAbstract && typeof(AssetsPlugin).IsAssignableFrom(t) && t.GetConstructor(System.Type.EmptyTypes) != null)
AssetsPlugin.RegisterPlugin(t); }
catch { /* skip incompatible DLLs */ }
```
3. 使用 `setup-stride.ps1` 构建并部署适配器到 Game Studio(设置 `-StrideBin` 为您的 Game Studio 构建输出),然后启动 Game Studio 并 **打开项目 + 场景** - 插件在项目打开时启动管道服务器。
然后独立的 MCP 服务器自动发现 Stride 引擎 - 与 Unity/Godot 相同。
### 2. MCP 服务器设置
1. 转到 [最新的 GitHub 版本](https://github.com/lorenzo-cambiaghi/AkerMCP/releases/latest)。
2. 下载适用于您所在平台的独立服务器(`AkerMcp.Server-win-x64.zip`、`-osx-x64.zip` 或 `-linux-x64.zip`)。
3. 将存档解压到计算机上的任意位置。
---
## 连接 AI 客户端
将您的 AI 客户端指向您在步骤 2 中提取的独立可执行文件。
> **重要:** 在使用 AI 客户端的任何工具之前,请确保 Unity 插件正在运行(AkerMcp 窗口为绿色状态)。
### Claude 代码(命令行界面)
```bash
claude mcp add game-engine -- /绝对路径/到提取的/AkerMcp.Server
```
### Claude 桌面版 / Cursor / Windsurf
打开 MCP 设置(或 `claude_desktop_config.json`)并添加服务器:
```json
{
"mcpServers": {
"game-engine": {
"command": "/绝对路径/到提取的/AkerMcp.Server",
"args": []
}
}
}
```
> **Windows 用户:** 将命令路径替换为 `.exe` 的完整 Windows 路径,例如 `"C:\\Tools\\AkerMcp.Server\\AkerMcp.Server.exe"`。请记住在 JSON 中使用双反斜杠!
### Google 反重力
反重力从其用户数据目录(`~/.gemini/antigravity/` 或 `%USERPROFILE%\.gemini\antigravity\`)读取 `mcp_config.json`。添加:
```json
{
"mcpServers": {
"game-engine": {
"command": "C:/Tools/AkerMcp.Server/AkerMcp.Server.exe",
"args": [],
"type": "stdio"
}
}
}
```
### VS Code + Copilot
将以下内容添加到您的 `.vscode/settings.json` 或使用 **MCP: 添加服务器** 命令:
```json
{
"mcp": {
"servers": {
"game-engine": {
"command": "C:\\Tools\\AkerMcp.Server\\AkerMcp.Server.exe",
"args": []
}
}
}
}
```
### 替代:从源代码运行(适用于开发人员)
如果您克隆了存储库或更喜欢通过 .NET SDK 运行而不是使用独立二进制文件,请使用 `dotnet run`。如果您正在积极修改 MCP 服务器代码,这通常是必要的。
**命令行:**
```bash
claude mcp add game-engine -- dotnet run --project /绝对路径/到/AkerMCP/Server -c Release --verbosity quiet --nologo
```
**JSON 配置(适用于 Claude Code 配置、Cursor、Antigravity 等):**
```json
{
"mcpServers": {
"game-engine": {
"type": "stdio",
"command": "dotnet",
"args": [
"run",
"--project",
"C:/绝对路径/到/AkerMCP/Server",
"-c",
"Release",
"--verbosity",
"quiet",
"--nologo"
]
}
}
}
```
---
## 高级:从源代码构建(适用于开发人员)
如果您想要修改 AkerMCP 或测试包含的 Unity 项目,您将需要 **.NET 8.0+ SDK**。
### 步骤 1 — 克隆和构建
```bash
git clone https://github.com/lorenzo-cambiaghi/AkerMCP.git
cd AkerMCP
dotnet build -c Release
dotnet publish Shared/AkerMcp.Shared.csproj -c Release -o .publish
```
### 步骤 2 — Unity 插件设置
如果您正在修改源代码并希望将更改推送到您自己的 Unity 项目:
1. 将此存储库的 `plugins/unity` 文件夹复制到您自己的 Unity 项目中,命名为 `Assets/AkerMcp`。
2. 创建 `Assets/AkerMcp/Plugins/` 并复制所有 `.dll` 文件从 `.publish/` 和 `Client/bin/Release/netstandard2.1/`。
3. 将 Unity Roslyn 编译器(`Microsoft.CodeAnalysis.dll` 等)从您的 Unity 编辑器安装(`.../Editor/Data/MonoBleedingEdge/lib/mono/4.5/`)复制到 `Plugins/` 文件夹。
如果您只需要运行包含的示例,请运行 `./setup-samples.sh`(或 Windows 上的 `setup-samples.bat`)一次,将插件链接到 `samples/unity`,然后运行 `./copy-dlls.sh`(或 `copy-dlls.bat`)以构建和复制所有依赖项。在 Unity 中打开 `samples/unity`。
### 打包发布
在 Windows 上,`.\publish-release.ps1 -Version v1.2.3` 通过一个命令完成整个发布:构建软件包(Unity 必须关闭),标记提交,创建 [GitHub 发布](https://github.com/lorenzo-cambiaghi/AkerMCP/releases) 并通过 GitHub API 上传五个工件(通过 `GITHUB_TOKEN` 或存储的 git 凭证进行身份验证)。使用 `-DryRun` 预览,使用 `-SkipBuild` 重用现有的 `Build/` 输出。
六个发布工件是:`AkerMCP.unitypackage`(Unity 插件),`AkerMcp.Godot-addon.zip`(Godot 插件 - 提取到您的项目的 `addons/`),`AkerMcp.Stride-source.zip`(Stride 适配器 **源代码** - 针对您的 Game Studio 进行构建,请参阅 [1c. Stride 设置](#1c-stride-setup);它不是预构建的二进制文件,因为它链接到您特定的 Stride 编辑器程序集),以及三个独立服务器构建(`AkerMcp.Server-{win,osx,linux}-x64.zip`)。
或者,运行 `build-package.bat`(Windows)或 `./build-package.sh`(Mac/Linux)仅在本地 `Build/` 文件夹(gitignored)中生成工件,然后手动上传它们作为发布资产。 二进制文件通过 Releases 发布,而不是提交到存储库。
---
## 验证连接
一旦 Unity 插件和 AI 客户端都运行,您就可以验证连接:
1. **在 Unity 中** - AkerMcp 窗口应显示 **运行中**(绿色)
2. **在 AI 客户端中** - 请求 AI 使用 `inspect` 工具:
```
"检查场景层次结构"
```
您应该收到一个包含组件的对象树:
```
Player [Transform, Rigidbody]
PlayerCamera [Transform, Camera]
Enemy_1 [Transform, MeshFilter, MeshRenderer, BoxCollider, Rigidbody]
Enemy_2 [Transform, MeshFilter, MeshRenderer, BoxCollider, Rigidbody]
Ground [Transform, MeshFilter, MeshRenderer, MeshCollider]
```
如果您看到此内容,则一切正常。
---
## MCP 工具
### 场景操作
| 工具 | 描述 |
|------|-------------|
| `inspect` | 返回场景对象或类型的组件、属性、方法和子项 |
| `get_property` | 通过点表示法路径读取属性(例如 `transform.position.x`) |
| `set_property` | 写入属性 - 支持基元、结构体、数组、嵌套对象 |
| `call_method` | 在场景对象或静态类方法上调用方法 |
| `query` | 按类型名称、名称模式、标签或属性值查找对象 |
| `create` | 将新对象添加到场景中,可选初始属性 |
| `delete` | 从场景中删除对象(支持撤销) |
| `select` | 在编辑器中选择对象 - 在层次结构和检查器中突出显示 |
| `get_selection` | 获取当前选定的对象及其组件、属性和子项 |
### 开发工作流
| 工具 | 描述 |
|------|-------------|
| `refresh_scripts` | 强制脚本重新编译并立即返回错误/警告 |
| `get_compile_errors` | 检索编译错误,包含文件路径、行和列 |
| `get_console_logs` | 读取引擎控制台条目,支持日志级别和文本过滤 |
| `execute` | 在引擎上下文中运行任意 C# 代码(Roslyn)- 无固定 API 表面 |
### 平台和构建
引擎中立的构建管道控制(由可选的 `IBuildManager` 支持;为 Unity、Godot 和 Stride 实现)。
| 工具 | 描述 |
|------|-------------|
| `list_platforms` | 列出引擎已知的构建平台,标记为活动/可构建 |
| `get_platform_settings` | 读取平台的构建/播放器设置作为键值映射 |
| `set_platform_settings` | 更改平台设置(例如应用 ID、最小 SDK、脚本后端) |
| `switch_build_target` | 使平台成为活动构建目标(处理重新编译/重新加载) |
| `build_player` | 为平台构建项目(APK/AAB/exe/app 包)并返回构建报告 |
> 引擎差异得到优雅处理:例如,Godot 和 Stride 没有全局活动目标,因此 `switch_build_target` 会报告这一点,您可以直接将平台传递给 `build_player`。
### 视觉验证
| 工具 | 描述 |
|------|-------------|
| `take_screenshot` | 捕获编辑器的 Scene/Game 视图(带有 gizmos)并返回 JPEG 给 AI |
| `list_windows` | 列出可见的顶级 OS 窗口(标题、进程、PID) 在服务器机器上 |
| `capture_window` | 捕获 **任何** 窗口与标题子字符串匹配 - 甚至遮挡,无需焦点窃取 |
`list_windows` / `capture_window` 是 OS 级别的,与引擎无关:它们无需连接引擎即可工作,并且可以捕获外部应用程序(浏览器、仪表板、其他编辑器)- 适用于调试和跨应用程序工作流。
#### `take_screenshot` 工作原理
该工具遵循 **混合捕获策略**,优先考虑质量但始终成功:
1. **引擎内部路径**(由所有三个适配器实现)- 直接从编辑器的渲染缓冲区捕获 **Scene 视图**,**包括 gizmos**(Unity `GrabPixels`,Godot 视口,Stride 编辑器后缓冲区 `Texture.Save`)。即使编辑器窗口被遮挡或部分在屏幕外,此方法也有效。 最高质量。
2. **OS 级别后备**(自动,跨平台支持 Windows + macOS)- 捕获引擎的主窗口而不窃取前景焦点。适用于任何 C# 引擎,无需适配器代码。 每个 OS 实现在运行时选择:
- **Windows** - Win32 `PrintWindow(PW_RENDERFULLCONTENT)` 通过 `user32.dll`
- **macOS** - Quartz `CGWindowListCreateImage` 通过 `CoreGraphics.framework` + `ImageIO.framework`。 窗口发现:枚举屏幕上的窗口,由引擎 PID 所有;其中,任何标题包含引擎名称(任何位置 - 匹配“Unity 6000…”和“… Godot Engine”)的子集,首选区域最大者。如果标题不包含引擎名称,则回退到 PID 拥有的最大窗口
- **Linux** - 未实现;引擎适配器必须实现 `IScreenCapture`
输出自动(跨平台通过 ImageSharp):
- **调整大小** 至最大 1920px 在最长边
- **重新编码为 JPEG** (质量 85)
典型输出大小: **~150-400 KB**,舒适地低于 Claude API 图像限制(~5 MB)。
**参数:
```json
{ "view": "game" } // 默认 - 捕获 Game View
{ "view": "scene" } // 捕获带有 gizmos 的活动 Scene View(Unity / Godot / Stride)
```
**示例:
```
→ set_property {"object_path": "/Player", "property_path": "Light.color", "value": {"r":1,"g":0,"b":0,"a":1}}
← 属性 'Light.color' 成功设置在 /Player
→ take_screenshot {"view": "scene"}
← [JPEG 图像,1920×1080,287 KB] // AI 现在看到红色灯光
```
#### macOS: 屏幕录制权限
在 macOS 10.15+ 上,从另一个进程捕获窗口需要 **屏幕录制权限** 用于运行 AkerMcp 服务器的二进制文件。 这仅影响 OS 级别路径(`capture_window` 和 `take_screenshot` 后备)- 引擎内部 `IScreenCapture` 路径(由所有三个引擎适配器实现)无需任何权限授予。
**首次设置:
1. OS 级别后备调用时,macOS 会显示二进制文件运行服务器的权限提示(通常为 `dotnet`)。
2. 如果您错过了提示或拒绝了它,请打开: **系统设置 → 隐私和安全 → 屏幕录制**
3. 添加(或启用切换)运行 AkerMcp 的二进制文件:
- 如果您通过 `dotnet run --project Server` 启动 → 条目为 `dotnet`(或 `dotnet [版本]`)
- 如果您发送自包含构建 → 条目是您的发布可执行文件
4. **重启服务器.** macOS 缓存拒绝决定,直到进程重启 - 仅授予权限是不够的。
**验证:
```bash
# 触发截图从您的 AI 客户端。如果缺少权限,该工具会返回:
# "macOS 拒绝屏幕捕获(CGWindowListCreateImage 返回 NULL...)"
# 按照上述步骤并尝试再次启动服务器。
```
**为什么 Unity(和其他引擎)不需要权限:** Unity 适配器使用其自己的 Camera/SceneView 渲染缓冲区实现 `IScreenCapture`。 这发生在 **内部** Unity 进程中,因此 macOS 不将其视为跨进程屏幕捕获,因此不需要权限。 只有当没有适配器捕获存在时,AkerMcp 才会回退到 OS 级别路径,从而触发权限流程。
### 动态代码执行(`execute`)
`execute` 工具在实时编辑器中运行任意 C# 代码 - **Unity、Godot 或 Stride** - 使用 Roslyn。 这是最强大的工具:它可以做任何引擎的编辑器 API 允许的事情,没有固定的工具表面。
**它启用:
- 程序化场景生成(spawn 100 个对象网格,创建地形等)
- 批量属性修改跨多个对象
- 资产操作(创建材质、导入纹理、修改预制件)
- 复杂查询,超出 `query` 支持
- 编辑器自动化(菜单项、构建管道、自定义导入器)
- 您可以在编辑器脚本中执行任何操作
**内置全局变量** 可在您的代码中显示(显示为 Unity 适配器;Godot 和 Stride 适配器也提供等效全局变量):
| 全局变量 | 类型 | 描述 |
|--------|------|-------------|
| `selectedObject` | `GameObject?` | 编辑器中当前选定的 GameObject |
| `Find(name)` | `GameObject?` | `GameObject.Find(name)` 的快捷方式 |
| `FindAll<T>()` | `T[]` | 查找所有 T 类型对象 |
| `Create(name)` | `GameObject` | 创建新的空 GameObject |
| `Log(message)` | `void` | 记录到 Unity 控制台 |
**导入命名空间**(无需 `using` 需要):`System`、`System.Collections.Generic`、`System.Linq`,以及引擎的命名空间 - `UnityEngine`/`UnityEditor`(Unity),`Godot`(Godot),`Stride.Engine`/`Stride.Core.Mathematics`(Stride)。
需要另一个命名空间?在 **顶部** 的代码片段中添加 `using ...;` 指令,它们会自动提升到文件范围(例如 `using System.IO;`)。
**示例**(Unity-flavored;相同的模式适用于每个引擎的 API):```csharp
// 创建一个立方体网格
for (int x = 0; x < 5; x++)
for (int z = 0; z < 5; z++) {
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.name = $"Cube_{x}_{z}";
cube.transform.position = new Vector3(x * 2, 0, z * 2) }
```csharp
// 将所有敌人设置为红色
var enemies = FindAll<Renderer>()
.Where(r => r.gameObject.name.StartsWith("Enemy`)
.ToArray();
foreach (var r in enemies)
r.material.color = Color.red;
return $"Colored {enemies.Length} enemies“```csharp
// 返回场景统计
var objects = FindAll<GameObject>();
var types = objects
.SelectMany(go => go.GetComponents<Component>()
.Where(c => c != null)
.GroupBy(c => c.GetType().Name)
.Select(g => $"{g.Key}: {g.Count()}")
.ToArray();
return string.Join("\n", types)```json
```json
{
"x": 1.`
```
---
## MCP 资源
| URI | 描述 |
|-----|-------------|
| `scene://hierarchy` | 完整的场景树,每个对象列出组件 |
| `project://info` | 引擎名称/版本,项目路径,活动场景 |
| `editor://logs` | 最近的控制台条目 |
| `editor://compile_status` | 编译状态,错误/警告计数 |
| `engine://types` | 已注册的引擎类型名称 |
---
## 类型系统
序列化器通过反射在 JSON 和 .NET 类型之间进行转换。 它处理:
- **基本类型** - `int`、`float`、`double`、`bool`、`string`、`enum`
- **结构体** - 任意值类型,通过 JSON 中的字段/属性匹配构造
- **数组** - JSON 数组中的 `T[]`
- **列表** - JSON 数组中的 `List<T>`
- **字典** - JSON 对象中的 `Dictionary<string, T>`
- **嵌套类型** - 递归解析(例如 `Bounds` 包含 `Vector3` 字段)
- **可空类型** - 自动解包
Unity 适配器注册了优化的转换器:
```
Vector2 Vector3 Vector4 Vector2Int Vector3Int
Quaternion Color Color32 Rect RectInt
Bounds BoundsInt LayerMask
```
JSON 示例:
```json
{ "x": 1.0, "y": 0.0, "z": 1.0 } // Vector3
{ "r": 0.5, "g": 0.0, "b": 1.0, "a": 1.0 } // Color
{ "center": { "x": 0, "y": 0, "z": 0 }, "size": { "x": 10, "y": 10, "z": 10 }} // Bounds
[{ "x": 0, "y": 0, "z": 0 }, { "x": 1, "y": 1, "z": 1 }] // Vector3[]
```
---
## 示例会话
```
→ inspect {"target": "/Player"}
← {
"typeName": "Rigidbody",
"path": "/Player",
"components": [
{"name": "Transform", "enabled": true},
{"name": "Rigidbody", "enabled": true}
],
"properties": [
{"name": "position", "type": "Vector3", "value": {"x":0,"y":1,"z":0}},
{"name": "Rigidbody.mass", "type": "float", "value": 1.0},
...
],
"childNames": ["PlayerCamera"]
}
→ select {"object_path": "/Player/PlayerCamera"}
← {"selected": true, "path": "/Player/PlayerCamera", "name": "PlayerCamera",
"components": [{"name":"Transform"}, {"name":"Camera"}]}
→ set_property {
"object_path": "/Player",
"property_path": "position",
"value": {"x": 10, "y": 0, "z": 5}
}
← Property 'position' set successfully on /Player
→ query {"type_filter": "Camera"}
← [{"path": "/Player/PlayerCamera", "type": "Camera", "name": "PlayerCamera"}]
→ refresh_scripts {}
← Recompilation requested. Status: idle
Last compile: 14:32:05
Result: SUCCESS
No errors or warnings.
→ get_console_logs {"level_filter": "error", "count": 0}
← (No matching log entries)
```
## 架构
```
┌──────────────────────┐
│ LLM (Claude 等) │
└──────────┬───────────┘
│ JSON-RPC 2.0 / stdio
┌──────────▼───────────┐
│ AkerMCP 服务器 │ .NET 8 控制台进程
│ 20+ MCP 工具 │
│ 5 MCP 资源 │
└──────────┬───────────┘
│ 命名管道 + MessagePack
┌──────────▼───────────┐
│ 引擎插件 │ 在 Unity / Godot / Stride / Flax 中运行
│ ISceneGraph 实现 │
└──────────────────────┘
```
| 项目 | 目标 | 描述 |
|---------|--------|-------------|
| `AkerMcp.Shared` | netstandard2.1 | 协议模型、引擎抽象、反射引擎、序列化、IPC |
| `AkerMcp.Server` | net8.0 | MCP 服务器 — 通过 stdio 的 JSON-RPC,将工具调用路由到引擎插件 |
| `AkerMcp.Client` | netstandard2.1 | 插件基类 — 在引擎内运行,处理 IPC 和主线程调度 |
### 工作原理
1. **引擎插件** 启动一个命名管道服务器,并将锁定文件写入系统临时目录。
2. **MCP 服务器** 扫描锁定文件,连接到管道,并开始转发工具调用。
3. **LLM** 通过 stdio 发送 JSON-RPC 请求。服务器通过 MessagePack IPC 将请求转发到引擎插件,并以 JSON 格式返回结果。
4. **引擎插件** 将请求调度到主线程,通过 `ISceneGraph` / `ISceneNode` 执行基于反射的操作,并返回结果。
属性路径如 `transform.position.x` 在运行时由 `PropertyPathResolver` 解析,该解析器通过缓存的反射元数据遍历对象图。结构体值类型传播是自动处理的。
### 项目结构
```
AkerMCP/
├── AkerMcp.sln
├── Shared/ AkerMcp.Shared (netstandard2.1)
│ ├── Protocol/ JSON-RPC 和 MCP 消息模型
│ ├── Abstraction/ 引擎无关接口
│ ├── Reflection/ PropertyPathResolver、检查器、缓存
│ ├── Serialization/ 泛型序列化器、TypeRegistry
│ └── Ipc/ 命名管道通道、 二进制分帧
├── Server/ AkerMcp.Server (net8.0 控制台应用)
│ ├── McpServer.cs JSON-RPC 调度器、MCP 生命周期
│ ├── ToolRegistry.cs 20+ 通用工具定义
│ ├── ResourceRegistry.cs 5 资源定义
│ ├── EngineConnection.cs 引擎插件的 IPC 客户端
│ ├── StdioTransport.cs stdin/stdout 传输
│ ├── ImageProcessor.cs 缩放 + JPEG 归一化(跨平台通过 ImageSharp)
│ └── Platform/ 操作系统级窗口捕获
│ ├── IPlatformScreenCapture.cs 公共接口
│ ├── PlatformScreenCapture.cs 运行时操作系统工厂
│ ├── Windows/
│ │ └── WindowsScreenCapture.cs Win32 PrintWindow + GDI+
│ └── Mac/
│ └── MacScreenCapture.cs Quartz CGWindowListCreateImage + ImageIO P/Invoke
├── Client/ AkerMcp.Client (netstandard2.1)
│ ├── EnginePluginBase.cs 适配器的抽象基类
│ ├── IpcRequestHandler.cs 请求路由和执行
│ ├── PluginDiscovery.cs 基于锁定文件的自动发现
│ ├── MainThreadDispatcherBase.cs 基于 TCS 模式的线程安全队列
│ └── ClientConfiguration.cs 客户端设置
├── plugins/ 规范的引擎适配器(可交付的插件)
│ ├── unity/ Unity 适配器(→ Assets/AkerMcp 在项目中)
│ │ ├── UnitySceneGraph.cs 场景遍历和节点创建
│ │ ├── UnitySceneNode.cs GameObjects 的反射包装器
│ │ ├── UnityTypeRegistration.cs MessagePack 类型和别名
│ │ └── Editor/ 编辑器专用工具
│ │ ├── DynamicEvaluatorV2.cs Roslyn 驱动的 C# 执行引擎
│ │ ├── McpEditorWindow.cs Unity 编辑器 UI 用于 MCP 服务器
│ │ ├── UnityCompilationSupport.cs 脚本编译工具
│ │ ├── UnityEditorContext.cs 活动选择和控制台日志
│ │ ├── UnityMainThreadDispatcher.cs Unity 主线程调度
│ │ ├── UnityScreenCapture.cs 游戏/场景视图渲染缓冲区捕获
│ │ └── UnityMcpPlugin.cs 插件入口点
│ ├── godot/ Godot 4.x (.NET) 适配器(→ addons/aker_mcp 在项目中)
│ ├── AkerMcpEditorPlugin.cs [Tool] 编辑器插件入口 + 主线程泵
│ ├── GodotMcpPlugin.cs EnginePluginBase 子类
│ ├── GodotSceneGraph.cs 编辑场景遍历和节点创建
│ ├── GodotSceneNode.cs 节点的反射包装器(无组件)
│ ├── GodotCapabilities.cs 类型解析和引擎元数据
│ ├── GodotTypeRegistration.cs Vector/Color/Rect2/Aabb 转换器
│ ├── GodotMainThreadDispatcher.cs 编辑器插件的队列排空
│ ├── GodotEditorContext.cs 选择、场景 I/O、日志缓冲区
│ ├── GodotCompilationSupport.cs `dotnet build` + MSBuild 诊断
│ ├── GodotScreenCapture.cs 编辑器视口捕获
│ └── GodotCodeExecutor.cs Roslyn 驱动的 C# 执行引擎
│ └── stride/ Stride(Game Studio)适配器(.csproj + 源代码)
│ ├── StrideMcpPlugin.cs AssetsPlugin 入口(Game Studio 钩子)
│ ├── StrideEnginePlugin.cs EnginePluginBase(组合;托管 IPC 服务器)
│ ├── StrideSceneGraph.cs 实时编辑场景遍历
│ ├── StrideSceneNode.cs 实体 + 组件的反射包装器
│ ├── StrideSceneBridge.cs 量子写入(撤销)+ 编辑器-游戏访问
│ ├── StrideCapabilities.cs 类型解析和引擎元数据
│ ├── StrideMainThreadDispatcher.cs WPF 调度器调度
│ ├── StrideEditorContext.cs 选择 + GlobalLogger 控制台捕获
│ ├── StrideCompilationSupport.cs `dotnet build` + MSBuild 诊断
│ ├── StrideScreenCapture.cs 场景视图后台缓冲区捕获(Texture.Save)
│ ├── StrideBuildManager.cs 平台/构建(可执行项目)
│ └── StrideCodeExecutor.cs Roslyn 驱动的 C# 执行引擎
├── samples/ 最小限度示例项目(在编辑器中打开)
│ ├── unity/ Unity 项目;Assets/AkerMcp → 目录链接到 plugins/unity
│ └── godot/ Godot 项目;addons/aker_mcp → 目录链接到 plugins/godot
└── setup-samples.bat / .sh 克隆后重新创建示例目录链接
```
> `plugins/` 下的插件是规范的、可交付的源代码。`samples/` 项目是薄壳,它们通过目录链接(由 `setup-samples` 创建)将插件链接到项目中,因此每个适配器都有一份**单一副本** — 编辑器在原地编辑它。目录链接被 gitignore;克隆后运行一次 `setup-samples`。
---
## 编写引擎适配器
要支持新引擎(例如 Godot、Stride、Flax),请子类化 `EnginePluginBase` 并实现所需的接口:
```csharp
public class MyEnginePlugin : EnginePluginBase
{
// 必需
protected override ISceneGraph CreateSceneGraph() => new MySceneGraph();
protected override IEngineCapabilities CreateCapabilities() => new MyCapabilities();
protected override IMainThreadDispatcher CreateDispatcher() => new MyDispatcher();
// 可选
protected override IEditorContext? CreateEditorContext() => new MyEditorContext();
protected override IAssetManager? CreateAssetManager() => null;
protected override ICompilationSupport? CreateCompilationSupport() => new MyCompilationSupport();
protected override IScreenCapture? CreateScreenCapture() => new MyScreenCapture();
protected override void Log(string message) { /* ... */ }
protected override void LogError(string message) { /* ... */ }
}
```
| 接口 | 目的 | 必需 |
|-----------|---------|:--------:|
| `ISceneGraph` | 场景树遍历、创建/删除、查询 | 是 |
| `ISceneNode` | 属性获取/设置、方法调用、组件列表 | 是 |
| `IEngineCapabilities` | 类型解析、引擎元数据 | 是 |
| `IMainThreadDispatcher` | 将操作调度到引擎的主线程 | 是 |
| `IEditorContext` | 选择、场景管理、控制台日志 | 否 |
| `IAssetManager` | 资产搜索、加载、保存、删除 | 否 |
| `ICompilationSupport` | 脚本重新编译、错误检索 | 否 |
| `IScreenCapture` | 引擎内部渲染缓冲区捕获(游戏/场景视图) | 否 — 在 Windows 上回退到操作系统级捕获(`PrintWindow`)和 macOS(Quartz)。在 Linux 上,此接口是必需的 |
> **macOS 操作系统级回退提示:** `IEngineCapabilities.EngineName` 用作窗口标题首选项信号 — macOS 捕获路径更倾向于拥有 PID 的窗口,其标题**包含**此字符串(在标题的任何位置)以消除编辑器的主窗口和检查器/浮动面板的歧义。匹配是大小写不敏感的,适用于前缀样式的标题(Unity:`"Unity 6000.x …"`)和后缀样式的标题(Godot:`"Scene - Project - Godot Engine"`)。如果没有窗口匹配,则使用最大的 PID 拥有窗口作为回退,因此即使不匹配的 `EngineName` 也不会破坏捕获。
为引擎特定的结构体注册自定义类型转换器:
```csharp
TypeRegistry.Instance.RegisterCustomSerializer<Vector3>(
v => new Dictionary<string, object?> { ["x"] = v.x, ["y"] = v.y, ["z"] = v.z },
d => new Vector3(F(d, "x"), F(d, "y"), F(d, "z"))
);
```
---
## AI 集成规则
AkerMCP 在通过 MCP 协议提供的**每个工具的描述中**嵌入了综合使用说明。这意味着任何 AI 客户端(Claude、Cursor、Copilot、Antigravity)都可以自动学习如何正确使用所有工具 — 包括属性路径语法、检查 → 修改 → 验证工作流、Roslyn 执行全局变量、编译验证和通过截图进行视觉验证 — **无需配置**。
### 可选:使用规则文件增强
为了获得更好的结果,您可以为项目根目录添加一个规则文件。这强化了内置的说明,并为 AI 提供了有关常见工作流和反模式的额外上下文。
| 平台 | 文件 | 范围 |
|----------|------|-------|
| Claude Code | `CLAUDE.md`(项目根目录) | 每个项目 |
| Antigravity | `AGENTS.md`(项目根目录) | 每个项目 |
| Cursor | `.cursor/rules/AkerMCP.md` | 每个项目 |
| 跨工具 | `AGENTS.md`(项目根目录) | 与大多数客户端配合使用 |
> **推荐:** 在项目根目录中使用 `AGENTS.md`。这是最广泛支持的约定。
### 规则模板
将以下代码块中的所有内容复制到您的规则文件中:
---
<details>
<summary><strong>点击展开完整的规则模板</strong></summary>
```markdown
<agent_instructions>
#### AkerMCP — AI 集成规则
您可以通过 `game-engine` MCP 服务器访问 C# 游戏引擎 — **Unity、Godot 或 Stride**(所有引擎都同样受支持)— ,这为您提供了 20 多种工具来检查、查询、修改、脚本编写和视觉验证活动场景,以及平台/构建控制 — 所有这些都来自编辑器。`execute` 工具在实时编辑器上运行任意 C#(Roslyn),因此实际上没有限制您可以做的事情。
#### 可用工具(快速参考)
| 工具 | 使用场景 |
|------|-------------|
| `inspect` | 您需要查看对象上的内容 — 组件、属性、子项 |
| `get_property` | 您确切知道路径并想要单个值 |
| `set_property` | 您要更改一个属性并支持撤销 |
| `call_method` | 您需要调用方法(例如 `SetActive`、`AddForce`) |
| `query` | 您需要按类型、名称模式或标签查找对象 |
| `create` | 您需要在场景中添加新对象 |
| `delete` | 您需要删除对象(破坏性,有撤销) |
| `select` | 您要在 Unity 的 Hierarchy/Inspector 中高亮显示对象 |
| `get_selection` | 您要知道用户当前选择了什么 |
| `refresh_scripts` | 您刚刚编写或修改了 `.cs` 文件,需要触发重新编译 |
| `get_compile_errors` | 您需要检查脚本是否编译成功 |
| `get_console_logs` | 您需要读取运行时错误、警告或调试输出 |
| `execute` | 您需要运行任意 C# 代码(程序生成、批量操作、复杂逻辑) |
| `take_screenshot` | 您需要**看到**更改的结果(放置、材质、照明、UI) |
| `list_platforms` / `get_platform_settings` / `set_platform_settings` | 您需要检查或更改平台的构建/玩家设置 |
| `switch_build_target` / `build_player` | 您需要切换活动平台或生成构建(APK/exe/…) |
| `list_windows` / `capture_window` | 您需要截图任意 OS 窗口(包括外部应用程序),而不仅仅是引擎 |
#### 核心工作流:检查 → 修改 → 验证
始终遵循此模式:
1. **首先检查。** 在修改任何内容之前,请调用 `inspect` 以查看对象的组件、属性和当前值。永远不要猜测。
2. **修改。** 对于单个更改使用 `set_property`,对于复杂操作使用 `execute`。
3. **验证。** 再次调用 `get_property` 或 `inspect` 以确认更改已生效。如果某些内容似乎有问题,请检查 `get_console_logs`。
4. **视觉验证(当相关时)。** 对于影响用户**看到**的内容的更改 — 放置、材质、照明、UI 布局、缩放 — 在更改后调用 `take_screenshot` 以确认结果看起来正确。这可以捕获属性值无法揭示的问题(例如,对象放置在另一个对象内,编译后材质渲染为粉色,UI 元素截断屏幕外)。
```
错误: set_property "/Player" "mass" 5 ← "mass" 可能无法解析(它在 Rigidbody 上)
正确: inspect "/Player" → 看到 "Rigidbody.mass" 存在 → set_property "/Player" "Rigidbody.mass" 5
```
#### 属性路径语法
属性使用通过反射解析的**点表示法**:
```
position → Transform.position(首先搜索 Transform)
position.x → float
Rigidbody.mass → 专门针对 Rigidbody 组件
Rigidbody.useGravity → bool
MeshRenderer.material.color → Color
```
**规则:**
- Transform 属性(`position`、`rotation`、`localScale`、`eulerAngles`)不需要前缀
- 其他组件需要类型前缀:`Rigidbody.mass`、`Camera.fieldOfView`、`Light.intensity`
- 支持嵌套属性:`MeshRenderer.material.color.r`
- 支持数组索引:`mesh.vertices[0]`
**结构体作为 JSON 对象传递:**
```json
{"x": 1.0, "y": 2.0, "z": 3.0} // Vector3
{"r": 1.0, "g": 0.0, "b": 0.0, "a": 1.0} // Color
```
#### 何时使用 `execute` 而不是其他工具
| 场景 | 使用 |
|----------|-----|
| 更改一个属性 | `set_property` |
| 读取一个值 | `get_property` |
| 查找对象 | `query` |
| 创建一个对象 | `create` |
| 在循环中修改 10+ 对象 | `execute` |
| 生成程序内容 | `execute` |
| 访问编辑器 API(AssetDatabase、Undo 组等) | `execute` |
| 复杂条件逻辑 | `execute` |
| 创建材质、着色器、ScriptableObjects | `execute` |
| 确认视觉更改实际上看起来正确 | `take_screenshot` |
| 向用户显示场景当前外观 | `take_screenshot` |
#### 编写 `execute` 脚本
**可用全局变量**(无需设置)— 显示为 Unity 适配器;Godot 和 Stride 通过其各自的 `Node` / `Entity` 类型提供等效变量:
```csharp
selectedObject // 当前选定对象(或 null)
Find("Player") // 按名称查找
FindAll<Rigidbody>() // 查找所有类型的组件/节点
Create("MyObject") // 创建空对象
Log("message") // 记录到引擎控制台
```
**预导入命名空间**:`System`、`System.Collections.Generic`、`System.Linq`,以及引擎的命名空间(`UnityEngine`/`UnityEditor`,或 `Godot`,或 `Stride.Engine`/`Stride.Core.Mathematics`)。对于其他命名空间,请在代码片段顶部放置 `using ...;` 指令 — 它们会自动提升到文件范围。
**状态在调用之间**不保留**。每个脚本都编译并独立运行 — 编写自包含的脚本:
```csharp
// 错误 — 来自先前调用的 'player' 不再存在
return player.transform.position;
// 正确 — 在同一个脚本中重新获取所需内容
var player = Find("Player");
return player.transform.position;
```
**返回值**会发送回您。始终返回有意义的结果:
```csharp
// 好 — 返回有用信息
var count = FindAll<Rigidbody>().Length;
return $"找到 {count} 个刚体";
// 差 — 无反馈
FindAll<Rigidbody>(); // 返回 null,您不会知道结果
```
**超时:** 默认值为 5 秒。为较长的操作传递 `timeout_ms`。注意:超时只会停止*等待* — 运行中的脚本无法中止,继续在引擎主线程上运行,因此避免无限制的循环,并在超时后验证场景状态。
```
#### 可视化验证 `take_screenshot`
在用户询问“它看起来怎么样?”,“是否有效?”,或进行任何具有**可视化结果**的更改后使用:
| 情况 | 是否应该截图? |
|-----------|------------------------|
| 移动/创建/删除对象 | ✅ 是 — 确认位置 |
| 更改材质、颜色或纹理 | ✅ 是 — 颜色可能会静默失败(粉色备用着色器) |
| 修改照明 | ✅ 是 — 强度/颜色变化很难通过数值预测 |
| 修改 UI 布局 | ✅ 是 — 锚定/缩放错误仅为视觉错误 |
| 生成程序内容 | ✅ 是 — 验证生成的合理性 |
| 更改非视觉属性(质量、标签、名称、层) | ❌ 否 — 使用 `get_property` 足够 |
| 编写脚本 | ❌ 否 — 使用 `get_compile_errors` 代替 |
**参数:**
```json
{ "view": "game" } // 默认 — 游戏视图,玩家看到的内容
{ "view": "scene" } // 场景视图,用于检查带有 gizmo 的完整编辑器
```
输出为 JPEG(~150-400 KB,最大 1920px)。您将以图像内容块的形式接收它 — 像读取其他图像一样读取它。
**模式:更改 → 截图 → 反应**
```
→ 执行 "for (int i = 0; i < 50; i++) { var t = GameObject.CreatePrimitive(PrimitiveType.Cube); t.transform.position = new Vector3(Random.Range(-20,20), 0, Random.Range(-20,20)); t.name = $\"Tree_{i}\"; } return \"spawned 50\";"
← 生成了 50 个
→ take_screenshot {"view": "scene"}
← [JPEG 图像]
← AI 看到:立方体聚集在一个角落太紧密 — 分布看起来不对
→ 修复脚本并重新运行。
```
**不要为每次微小更改都截图。** 这并不免费 — AI 客户端渲染图像并消耗上下文。在逻辑编辑结束时使用,而不是在序列中的每个 `set_property` 之后。
#### 编写或修改 C# 脚本后
每次在 Unity 项目中创建或编辑 `.cs` 文件时:
1. 调用 `refresh_scripts` — 这强制 Unity 重新编译
2. 调用 `get_compile_errors` — 检查错误
3. 如果存在错误,请修复它们并重复
```
→ refresh_scripts {}
← 请求重新编译。结果:失败
=== 错误 (1) ===
Assets/Scripts/Player.cs(15,9): error CS1002: ; expected
→ (修复文件)
→ refresh_scripts {}
← 结果:成功。无错误或警告。
```
**永远不要假设脚本更改已成功编译。** 始终验证。
#### 场景导航
**路径** 从场景根目录使用正斜杠:
```
/Player
/Player/PlayerCamera
/Environment/Trees/Oak_01
```
**查找对象** 当您不知道路径时:
- `query {"name_pattern": "Player*"} `— 通配符搜索
- `query {"type_filter": "Camera"}` — 按组件类型
- `query {"tag": "Enemy"}` — 按标签
**浏览整个场景:**
- 读取 `scene://hierarchy` 资源 — 返回完整的树结构和组件
- 或对根对象调用 `inspect`
#### 反模式
| 不应做的事 | 代替做法 |
|-------|------------|
| 猜测属性名称 | 首先 `inspect` 对象 |
| 未检查直接修改 | 检查 → 修改 → 验证 |
| 为单个属性更改使用 `execute` | `set_property` (支持撤销) |
| 编写脚本后忽略编译错误 | `refresh_scripts` → `get_compile_errors` |
| 假设路径不区分大小写 | 在引擎端,它们区分大小写 |
| 逐个属性创建复杂对象 | 使用 `execute` 和单个脚本 |
| 在 `execute` 中忘记 `return` 值 | 始终返回描述发生情况的字符串 |
| 每次微小更改后截图 | 在逻辑编辑结束时截图 |
| 仅凭属性值信任视觉更改 | `take_screenshot` 确认实际渲染结果 |
#### 错误恢复
如果工具调用失败:
1. **阅读错误消息** — 它通常会准确告诉您错误原因
2. **检查目标** — 对象可能不存在,或属性名称可能不同
3. **检查控制台** — `get_console_logs {"level_filter": "error"}` 显示运行时错误
4. **编译错误** — `get_compile_errors` 显示确切的文件、行和列
</agent_instructions>
```
</details>
---
## 故障排除
**服务器提示“未发现引擎插件”**
Unity 插件必须在 MCP 服务器启动**之前**启动。打开 **Window → AkerMcp** 在 Unity 中并先点击 **Start**。
**Unity 显示 DLL 加载错误**
确保您已复制 `.publish/` 文件夹中的**所有** DLL,包括 `System.Text.Json.dll`。Unity 默认不附带此库。
**组件上找不到属性**
在属性名前加上组件类型名称:`Rigidbody.mass` 而不是 `mass`。这样可以消除多个组件共享属性名称时的歧义。
**第一次启动服务器很慢**
`dotnet run` 在首次启动时编译服务器。后续启动速度很快。您也可以提前使用 `dotnet build -c Release`,然后直接运行编译后的二进制文件:
```bash
./Server/bin/Release/net8.0/AkerMcp.Server
```
**Unity 重新编译脚本后连接断开**
Unity 中的域重载会拆除插件以安全释放文件锁。在重新编译后,单击 AkerMcp 窗口中的 **Start**。MCP 服务器具有无限后台重试循环,并会自动检测新实例并重新连接 — 您**不需要**重启服务器。
**macOS:`take_screenshot` 返回“macOS 拒绝屏幕截图”**
仅在使用 OS 级别回退时发生(引擎适配器未实现 `IScreenCapture`)。打开 **系统设置 → 隐私和安全 → 屏幕录制**,启用正在运行服务器的二进制文件(通常为 `dotnet`)的条目,然后 **重启服务器** — macOS 会缓存拒绝决策,直到进程重启。有关完整过程,请参见 [macOS: 屏幕录制权限](#macos-screen-recording-permission)。
**macOS:`take_screenshot` 返回“未找到 PID 的屏幕窗口”**
仅在使用 OS 级别回退时发生。引擎的主窗口无法通过标题前缀定位。验证您的适配器中的 `IEngineCapabilities.EngineName` 是否与实际的编辑器窗口标题前缀(例如 Unity 编辑器的 `"Unity"`)匹配。匹配不区分大小写,但必须是前缀。
**Unity 提示“打开文件失败:访问被拒绝”**
如果您在 Windows 上下载存储库为 ZIP 或克隆,Unity 可能会抱怨 `.asset` 或 `.meta` 文件是只读的。要解决此问题:
1. 在 Windows 资源管理器中右键单击 `samples\unity` 文件夹。
2. 转到 **属性**。
3. 取消选中 **只读** 框并点击应用(应用于所有文件夹、子文件夹和文件)。
或者,打开命令提示符并运行:`attrib -R "samples\unity\*.*" /S /D`
---
## License
[Apache 2.0](LICENSE)
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器