Files
mingyuansi b65a4f22c3 fix: Windows spawn, prefab path, preview API, asset deps, error messages; add execute-context resource, tool descriptions, scene/script/asset tools
Bug fixes (verified against Cocos Creator 3.8.8):
- diagnostics: shell:true for .cmd/.bat on Windows (T125/T126)
- prefabs: duplicatePrefab target resolves under assets/ (T420)
- cocos-project: add preview.open candidate for 3.8.8 (T444)
- assets-advanced: detect directory assets in inspectAssetDependencies (T110)
- scene: improve component-not-found errors with compilation hint (T429)

Documentation improvements:
- tool-registry: add enum and injected vars to execute_javascript, path format examples, asset ref limitation note
- resources: add cocos://mcp/execute-context resource with variables, patterns, pitfalls

New tools (core 37->38, full 101->110):
- scene-management: create_scene, query_scene_state (core), copy_paste_node, rename_node, reparent_node
- scripts: create_script with component/plain templates
- prefabs: create_prefab
- assets-advanced: batch_asset_ops, find_unused_assets
2026-06-30 21:53:06 +08:00

54 KiB
Raw Permalink Blame History

funplay-cocos-mcp 集成测试文档

目标:AI Agent 读取本文档后,可全程自动循环执行所有测试,输出结构化测试报告,验证 funplay-cocos-mcp 全部 101 个工具、10 个资源、4 个 prompt 在 Cocos Creator 3.8.8 下的兼容性。

测试项目:一次性测试项目,测完丢弃。

调用方式:curl(协议层 + 独立工具)与 execute_javascript(链式编排)结合。


1. 测试环境搭建

1.1 前置条件

条件 要求
Cocos Creator 3.8.8
Node.js >= 18Cocos 自带即可)
操作系统 Windows / macOS / Linux 均可
funplay-cocos-mcp 已 clone 或安装到 Cocos 项目 extensions/ 目录

1.2 创建一次性测试项目

  1. 打开 Cocos Creator 3.8.8,新建一个 Empty(2D) 项目,命名为 mcp-test-disposable
  2. 项目创建后会自动生成一个默认场景 assets/scene.scene,保留它
  3. assets/ 下创建文件夹 scriptsprefabs

1.3 安装 funplay-cocos-mcp 扩展

# 方式一:符号链接(开发模式)
cd /path/to/mcp-test-disposable/extensions
# Windows: mklink /D funplay-cocos-mcp C:\Users\wangj\data\src\mcp\funplay-cocos-mcp
# macOS/Linux: ln -s /path/to/funplay-cocos-mcp funplay-cocos-mcp

# 方式二:直接复制
cp -r /path/to/funplay-cocos-mcp /path/to/mcp-test-disposable/extensions/funplay-cocos-mcp

回到 Cocos Creator,重新加载扩展(菜单 → 扩展 → 重新载入)。

1.4 启动 MCP 服务器

  1. 打开菜单:Funplay > MCP Server
  2. 在面板中确认 Tool Profile 设置为 full(测试全部 101 个工具)
  3. 点击启动服务器
  4. 确认面板显示服务器运行在 http://127.0.0.1:8765/

1.5 验证连通性

# 健康检查
curl -s http://127.0.0.1:8765/health

# 预期返回:
# {"ok":true,"name":"Funplay Cocos MCP - mcp-test-disposable","version":"0.4.0",...}

如果端口被占用,服务器会自动回退到下一个可用端口。请从 /health 响应中确认实际端口,后续所有测试中使用该端口。

1.6 测试数据初始化

在正式测试前,通过 execute_javascript 在编辑器上下文中创建测试所需的基础数据:

# 设置变量
MCP_URL="http://127.0.0.1:8765"

# 初始化测试数据:创建 Canvas + 测试节点 + 测试脚本文件
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "execute_javascript",
      "arguments": {
        "context": "scene",
        "code": "const { Canvas, UITransform, Label, Button, director, find, Node } = cc; const scene = director.getScene(); let canvas = find(\"Canvas\"); if (!canvas) { canvas = new Node(\"Canvas\"); canvas.addComponent(Canvas); canvas.addComponent(UITransform); scene.addChild(canvas); } let testNode = find(\"Canvas/TestNode\"); if (!testNode) { testNode = new Node(\"TestNode\"); testNode.addComponent(UITransform); testNode.addComponent(Label); testNode.addComponent(Button); canvas.addChild(testNode); } return { canvasUuid: canvas.uuid, testNodeUuid: testNode.uuid, sceneName: scene.name };"
      }
    }
  }'
# 创建测试脚本文件
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "write_file",
      "arguments": {
        "path": "assets/scripts/TestComponent.ts",
        "content": "import { _decorator, Component, Label } from \"cc\";\nconst { ccclass, property } = _decorator;\n\n@ccclass(\"TestComponent\")\nexport class TestComponent extends Component {\n    @property({ type: Label })\n    label: Label | null = null;\n\n    @property\n    speed: number = 10;\n\n    start() {\n        console.log(\"TestComponent started\");\n    }\n\n    update(dt: number) {\n        // test method\n    }\n\n    public greet(name: string): string {\n        return `Hello, ${name}!`;\n    }\n}\n"
      }
    }
  }'
# 刷新资源数据库
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "refresh_assets",
      "arguments": {}
    }
  }'
# 保存场景,确保 TestNode 已持久化
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{
    "jsonrpc": "2.0",
    "id": 4,
    "method": "tools/call",
    "params": {
      "name": "save_current_scene",
      "arguments": {}
    }
  }'
# 从 TestNode 创建预制体(funplay-cocos-mcp 无 create_prefab 工具,通过 execute_javascript 调用 Editor API
# 将 <TEST_NODE_UUID> 替换为前面初始化返回的 testNodeUuid
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{
    "jsonrpc": "2.0",
    "id": 5,
    "method": "tools/call",
    "params": {
      "name": "execute_javascript",
      "arguments": {
        "context": "editor",
        "code": "const testNodeUuid = \"<TEST_NODE_UUID>\"; const savePath = \"db://assets/prefabs/TestPrefab.prefab\"; const result = await Editor.Message.request(\"scene\", \"create-prefab\", testNodeUuid, savePath); return { result: result, savePath: savePath };"
      }
    }
  }'
# 刷新资源数据库,确保新预制体被索引
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{
    "jsonrpc": "2.0",
    "id": 6,
    "method": "tools/call",
    "params": {
      "name": "refresh_assets",
      "arguments": {"path": "assets/prefabs"}
    }
  }'
# 查询预制体 uuid,供后续测试使用
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{
    "jsonrpc": "2.0",
    "id": 7,
    "method": "tools/call",
    "params": {
      "name": "list_prefabs",
      "arguments": {}
    }
  }'

AI Agent 注意:记录以下初始化返回值,后续链式测试需要使用:

  • canvasUuid — Canvas 节点 UUID
  • testNodeUuid — TestNode 节点 UUID
  • prefabUuid — TestPrefab 预制体 UUID(从最后一步 list_prefabs 返回中获取)
  • prefabPathdb://assets/prefabs/TestPrefab.prefab

2. AI Agent 自动化测试框架

2.1 通用变量与辅助函数

AI Agent 在执行测试前,先设置以下变量:

MCP_URL="http://127.0.0.1:8765"
PROTO_VER="2025-11-25"
TEST_ID=0
PASS_COUNT=0
FAIL_COUNT=0
SKIP_COUNT=0
RESULTS_FILE="/tmp/mcp-test-results.json"

辅助函数(AI Agent 可用 shell 函数或等价逻辑实现):

# MCP initialize
mcp_init() {
  curl -s -X POST "$MCP_URL" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json, text/event-stream" \
    -d "{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"$PROTO_VER\",\"clientInfo\":{\"name\":\"test-agent\",\"version\":\"1.0\"}}}"
}

# MCP tools/call
mcp_tool() {
  local tool_name="$1"
  local args="${2:-{}}"
  local id="${3:-1}"
  curl -s -X POST "$MCP_URL" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json, text/event-stream" \
    -H "MCP-Protocol-Version: $PROTO_VER" \
    -d "{\"jsonrpc\":\"2.0\",\"id\":$id,\"method\":\"tools/call\",\"params\":{\"name\":\"$tool_name\",\"arguments\":$args}}"
}

# MCP resources/read
mcp_resource() {
  local uri="$1"
  curl -s -X POST "$MCP_URL" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json, text/event-stream" \
    -H "MCP-Protocol-Version: $PROTO_VER" \
    -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"resources/read\",\"params\":{\"uri\":\"$uri\"}}"
}

# MCP prompts/get
mcp_prompt() {
  local name="$1"
  curl -s -X POST "$MCP_URL" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json, text/event-stream" \
    -H "MCP-Protocol-Version: $PROTO_VER" \
    -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"prompts/get\",\"params\":{\"name\":\"$name\"}}"
}

# 从 tools/call 响应中提取 structuredContent.data 的 JSON
extract_data() {
  local response="$1"
  echo "$response" | python3 -c "
import sys, json
resp = json.load(sys.stdin)
sc = resp.get('result', {}).get('structuredContent', {})
print(json.dumps(sc.get('data', {})))
" 2>/dev/null
}

# 从 tools/call 响应中提取 ok 字段
extract_ok() {
  local response="$1"
  echo "$response" | python3 -c "
import sys, json
resp = json.load(sys.stdin)
sc = resp.get('result', {}).get('structuredContent', {})
print(sc.get('ok', 'missing'))
" 2>/dev/null
}

# 从 tools/call 响应中提取 isError
extract_is_error() {
  local response="$1"
  echo "$response" | python3 -c "
import sys, json
resp = json.load(sys.stdin)
print(resp.get('result', {}).get('isError', False))
" 2>/dev/null
}

# 记录测试结果
record_result() {
  local test_id="$1"
  local tool_name="$2"
  local status="$3"  # pass / fail / skip
  local detail="$4"
  echo "{\"id\":\"$test_id\",\"tool\":\"$tool_name\",\"status\":\"$status\",\"detail\":\"$detail\"}" >> "$RESULTS_FILE"
  if [ "$status" = "pass" ]; then PASS_COUNT=$((PASS_COUNT+1));
  elif [ "$status" = "fail" ]; then FAIL_COUNT=$((FAIL_COUNT+1));
  else SKIP_COUNT=$((SKIP_COUNT+1)); fi
}

2.2 通用判定规则

每个测试用例的判定遵循以下通用规则,叠加各用例的特定规则:

规则编号 规则 判定方法
R1 HTTP 状态码 200 curl 退出码为 0 且响应包含 "jsonrpc"
R2 响应包含 result 字段 响应 JSON 有 result
R3 result.isError 不为 true extract_is_error 返回 False
R4 structuredContent.oktrue extract_ok 返回 True
R5 structuredContent.data 存在 extract_data 返回非空 JSON
R6 error 顶层字段 响应 JSON 无 error

例外:截图工具返回 image contentdata:image/png;base64,...),不适用 R4/R5,改用"content 中包含 image 类型项"判定。

2.3 测试报告格式

测试结果以 JSON 数组形式写入 $RESULTS_FILE

[
  {"id":"T001","tool":"initialize","status":"pass","detail":"protocol 2025-11-25 negotiated"},
  {"id":"T101","tool":"get_project_info","status":"pass","detail":"projectPath=/path/to/project, cocosVersion=3.8.8"},
  {"id":"T201","tool":"create_node","status":"fail","detail":"ok=false, error=Scene not loaded"}
]

最终汇总报告:

========== funplay-cocos-mcp 集成测试报告 ==========
测试时间: 2026-06-30T12:00:00Z
Cocos Creator 版本: 3.8.8
MCP 服务器版本: 0.4.0
工具配置档: full
================================================
通过: 95    失败: 4    跳过: 2    总计: 101
================================================
失败详情:
  T201 create_node: ok=false, error=Scene not loaded
  T432 simulate_mouse_click: No visible window found
  ...
================================================
兼容性结论: [PASS/PARTIAL/FAIL]

2.4 AI Agent 执行循环流程

1. 执行 Phase 0 协议测试
   → 全部通过才继续;失败则中止并报告

2. 执行测试数据初始化(1.6 节)
   → 记录 canvasUuid, testNodeUuid

3. 按顺序执行 Phase 1 → Phase 6
   每个测试用例:
   a. 检查前置条件(如需要场景已加载、需要 preview 运行等)
   b. 执行 curl 命令或 execute_javascript 链式调用
   c. 解析响应 JSON
   d. 执行判定规则(R1-R6 + 特定规则)
   e. 记录结果到 $RESULTS_FILE
   f. 如果是链式测试,提取输出数据(uuid 等)供后续测试使用
   g. 如果失败,记录详情,继续下一个测试

4. 链式测试特殊处理:
   - 前一步失败时,后续依赖步骤标记为 skip
   - 提取 uuid 等数据时使用 python3 解析 JSON

5. 全部完成后:
   a. 汇总 PASS/FAIL/SKIP 计数
   b. 列出所有失败项详情
   c. 输出兼容性结论
   d. 将 $RESULTS_FILE 内容输出为结构化报告

3. Phase 0: MCP 协议合规性测试

T001: initialize 握手

  • 方法: curl
  • 前置条件: MCP 服务器已启动
mcp_init
  • 判定: R1 + R2 + 响应 result.protocolVersion 为受支持版本 + result.capabilities 包含 tools/resources/prompts + result.serverInfo.name 包含 Funplay
  • 记录: 协商出的协议版本

T002: tools/list

  • 方法: curl
  • 前置条件: T001 通过
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: $PROTO_VER" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
  • 判定: R1 + R2 + result.tools 为数组 + 数组长度 > 0 + 每个工具有 name/description/inputSchema
  • 记录: 工具总数(full 模式应为 101)

T003: resources/list

curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: $PROTO_VER" \
  -d '{"jsonrpc":"2.0","id":1,"method":"resources/list","params":{}}'
  • 判定: R1 + R2 + result.resources 为数组 + 长度 >= 10 + 每项有 uri/name/description

T004: resources/templates/list

curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: $PROTO_VER" \
  -d '{"jsonrpc":"2.0","id":1,"method":"resources/templates/list","params":{}}'
  • 判定: R1 + R2 + result.resourceTemplates 为数组 + 长度 >= 3 + 每项有 uriTemplate

T005: prompts/list

curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: $PROTO_VER" \
  -d '{"jsonrpc":"2.0","id":1,"method":"prompts/list","params":{}}'
  • 判定: R1 + R2 + result.prompts 为数组 + 长度 >= 4 + 每项有 name/description

T006: Accept header 缺失应拒绝

curl -s -o /dev/null -w "%{http_code}" -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
  • 判定: HTTP 状态码为 406Accept header 校验失败)

T007: 不支持的方法应返回 -32601

curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: $PROTO_VER" \
  -d '{"jsonrpc":"2.0","id":1,"method":"nonexistent/method","params":{}}'
  • 判定: R1 + 响应包含 error.code 为 -32601

T008: GET /tools 调试端点

curl -s "$MCP_URL/tools"
  • 判定: R1 + 响应包含 tools 数组 + count 字段 + ok: true

4. Phase 1: Core 只读工具测试

以下工具均为 core 配置档中的只读/安全工具,可独立执行,无副作用。

T101: get_project_info

mcp_tool "get_project_info" '{}'
  • 判定: R1-R5 + data.projectPath 非空 + data.cocosVersion 包含 3.8
  • 记录: projectPath, cocosVersion

T102: get_editor_state

mcp_tool "get_editor_state" '{}'
  • 判定: R1-R5 + data 包含项目信息

T103: get_tool_catalog

mcp_tool "get_tool_catalog" '{}'
  • 判定: R1-R5 + data 为数组 + 长度 > 0 + 每项有 name/profile/category

T104: get_scene_info

mcp_tool "get_scene_info" '{}'
  • 判定: R1-R5 + data.sceneNamedata.name 非空
  • 注意: 需要场景已加载,如失败则后续场景相关测试标记 skip

T105: get_hierarchy

mcp_tool "get_hierarchy" '{}'
  • 判定: R1-R5 + data 包含节点树结构

T106: list_scenes

mcp_tool "list_scenes" '{}'
  • 判定: R1-R5 + data 为数组 + 长度 >= 1
  • 记录: 第一个场景的 uuid 和 path,供 T107 使用

T107: open_scene

# 使用 T106 记录的场景 uuid
mcp_tool "open_scene" "{\"uuid\":\"<SCENE_UUID>\"}"
  • 判定: R1-R4 + 无 isError
  • 注意: 替换 <SCENE_UUID> 为 T106 获取的实际值

T108: list_assets

mcp_tool "list_assets" '{"pattern":"db://assets/**/*"}'
  • 判定: R1-R5 + data 为数组 + 长度 > 0
  • 记录: 第一个资产的 uuid,供 T109/T110 使用

T109: inspect_asset

# 使用 T108 记录的 asset uuid
mcp_tool "inspect_asset" "{\"uuid\":\"<ASSET_UUID>\"}"
  • 判定: R1-R5 + data 包含资产信息

T110: inspect_asset_dependencies

mcp_tool "inspect_asset_dependencies" "{\"uuid\":\"<ASSET_UUID>\"}"
  • 判定: R1-R4 + data 存在(即使无依赖也应返回空数组)

T111: validate_asset_dependencies

mcp_tool "validate_asset_dependencies" "{\"uuid\":\"<ASSET_UUID>\"}"
  • 判定: R1-R4 + data 存在

T112: inspect_prefab

# 先列出预制体
mcp_tool "list_assets" '{"pattern":"db://assets/**/*.prefab"}'
  • 判定: 如果有预制体,inspect_prefab 返回 R1-R5;如无预制体则 skip
  • 注意: AI Agent 应先检查是否有 .prefab 资产,有则取 uuid 调用 inspect_prefab

T113: inspect_prefab_instance

mcp_tool "inspect_prefab_instance" '{"path":"Canvas/TestNode"}'
  • 判定: R1-R4TestNode 非预制体实例,应返回有效响应说明非实例)

T114: validate_prefab_references

# 如果 T112 有预制体 uuid 则使用,否则 skip
mcp_tool "validate_prefab_references" "{\"uuid\":\"<PREFAB_UUID>\"}"
  • 判定: R1-R4

T115: validate_scene

mcp_tool "validate_scene" '{}'
  • 判定: R1-R5 + data 包含验证结果

T116: get_selection

mcp_tool "get_selection" '{}'
  • 判定: R1-R5 + data 存在

T117: set_selection

# 使用初始化时记录的 testNodeUuid
mcp_tool "set_selection" "{\"type\":\"node\",\"uuid\":\"<TEST_NODE_UUID>\"}"
  • 判定: R1-R4

T118: get_runtime_state

mcp_tool "get_runtime_state" '{}'
  • 判定: R1-R5 + data 存在

T119: get_performance_snapshot

mcp_tool "get_performance_snapshot" '{}'
  • 判定: R1-R5 + data 存在

T120: get_build_status

mcp_tool "get_build_status" '{}'
  • 判定: R1-R4 + data 存在

T121: list_editor_windows

mcp_tool "list_editor_windows" '{}'
  • 判定: R1-R5 + data 为数组 + 长度 > 0
  • 记录: 窗口列表,供截图和输入模拟测试使用

T122: get_recent_logs

mcp_tool "get_recent_logs" '{}'
  • 判定: R1-R5 + data 存在

T123: search_project_logs

mcp_tool "search_project_logs" '{"query":"error"}'
  • 判定: R1-R4 + data 存在

T124: clear_logs

mcp_tool "clear_logs" '{}'
  • 判定: R1-R4

T125: run_script_diagnostics

mcp_tool "run_script_diagnostics" '{}'
  • 判定: R1-R5 + data 存在(diagnostics 数组,即使为空)

T126: get_script_diagnostic_context

mcp_tool "get_script_diagnostic_context" '{}'
  • 判定: R1-R5 + data 存在

T127: check_for_updates

mcp_tool "check_for_updates" '{}'
  • 判定: R1-R5 + data 存在

T128: list_project_instructions

mcp_tool "list_project_instructions" '{}'
  • 判定: R1-R5 + data 为数组

T129: read_project_instruction

# 如果 T128 返回有指令文件则读取第一个,否则 skip
mcp_tool "read_project_instruction" "{\"name\":\"<INSTRUCTION_NAME>\"}"
  • 判定: R1-R4(有指令文件时)或 skip(无指令文件时)

T130: capture_editor_screenshot

mcp_tool "capture_editor_screenshot" '{}'
  • 判定: R1-R3 + result.content 包含 type: "image"
  • 注意: 需要编辑器窗口可见

T131: capture_scene_screenshot

mcp_tool "capture_scene_screenshot" '{}'
  • 判定: R1-R3 + result.content 包含 type: "image"

T132: capture_preview_screenshot

mcp_tool "capture_preview_screenshot" '{}'
  • 判定: R1-R3 + result.content 包含 image 项
  • 注意: 需要 preview 窗口可见;如无 preview 运行则 skip

T133: execute_javascript (scene context)

mcp_tool "execute_javascript" '{"context":"scene","code":"return { sceneName: scene.name, childCount: scene.children.length };"}'
  • 判定: R1-R5 + data.sceneName 非空

T134: execute_javascript (editor context)

mcp_tool "execute_javascript" '{"context":"editor","code":"return { projectPath: context.projectPath, toolCount: helpers.listTools().length };"}'
  • 判定: R1-R5 + data.projectPath 非空 + data.toolCount > 0

T135: execute_scene_script

mcp_tool "execute_scene_script" '{"code":"return { sceneName: scene.name };"}'
  • 判定: R1-R5 + data.sceneName 非空

T136: execute_editor_script

mcp_tool "execute_editor_script" '{"code":"return { projectPath: context.projectPath };"}'
  • 判定: R1-R5 + data.projectPath 非空

T137: open_asset

# 使用 T108 记录的 asset uuid
mcp_tool "open_asset" "{\"uuid\":\"<ASSET_UUID>\"}"
  • 判定: R1-R4

T138: select_asset

mcp_tool "select_asset" "{\"uuid\":\"<ASSET_UUID>\"}"
  • 判定: R1-R4

5. Phase 2: Core 变更工具链式测试

以下测试有副作用,按链式顺序执行。前一步的输出作为后一步的输入。

链 A: 节点创建 → 变换 → 删除

T201: create_node

mcp_tool "create_node" '{"name":"ChainTestNode","parentPath":"Canvas"}'
  • 判定: R1-R5 + data.uuid 非空
  • 记录: createdNodeUuid = data.uuid

T202: set_node_transform(依赖 T201

mcp_tool "set_node_transform" "{\"uuid\":\"<CREATED_NODE_UUID>\",\"position\":{\"x\":100,\"y\":200,\"z\":0},\"scale\":{\"x\":2,\"y\":2,\"z\":1}}"
  • 判定: R1-R4
  • 前置: T201 通过

T203: delete_node(依赖 T201

mcp_tool "delete_node" "{\"uuid\":\"<CREATED_NODE_UUID>\"}"
  • 判定: R1-R4
  • 前置: T201 通过
  • 清理: 删除 T201 创建的节点

链 B: 组件添加 → 设置属性 → 移除

T204: add_component(依赖 T201 或使用已有的 TestNode

# 使用初始化时的 testNodeUuid
mcp_tool "add_component" "{\"path\":\"Canvas/TestNode\",\"componentType\":\"cc.Sprite\"}"
  • 判定: R1-R4

T205: set_component_property(依赖 T204

mcp_tool "set_component_property" "{\"path\":\"Canvas/TestNode\",\"componentType\":\"cc.Sprite\",\"property\":\"color\",\"value\":{\"r\":255,\"g\":0,\"b\":0,\"a\":255}}"
  • 判定: R1-R4
  • 前置: T204 通过

T206: remove_component(依赖 T204

mcp_tool "remove_component" "{\"path\":\"Canvas/TestNode\",\"componentType\":\"cc.Sprite\"}"
  • 判定: R1-R4
  • 前置: T204 通过
  • 清理: 移除 T204 添加的组件

T207: save_current_scene

mcp_tool "save_current_scene" '{}'
  • 判定: R1-R4
  • 注意: 保存前面所有变更

6. Phase 3: Full 额外只读工具测试

以下工具仅在 full 配置档中可用。

T301: find_nodes

mcp_tool "find_nodes" '{"name":"TestNode"}'
  • 判定: R1-R5 + data 为数组 + 长度 >= 1

T302: inspect_node

mcp_tool "inspect_node" '{"path":"Canvas/TestNode"}'
  • 判定: R1-R5 + data.uuid 非空 + data.nameTestNode

T303: list_components

mcp_tool "list_components" '{"path":"Canvas/TestNode"}'
  • 判定: R1-R5 + data 为数组 + 长度 >= 1(至少有 UITransform

T304: inspect_component

mcp_tool "inspect_component" '{"path":"Canvas/TestNode","componentType":"cc.Label"}'
  • 判定: R1-R5 + data 存在

T305: list_cameras

mcp_tool "list_cameras" '{}'
  • 判定: R1-R5 + data 为数组

T306: list_animations

mcp_tool "list_animations" '{}'
  • 判定: R1-R5 + data 为数组

T307: list_prefabs

mcp_tool "list_prefabs" '{}'
  • 判定: R1-R5 + data 为数组
  • 记录: 如有预制体,记录第一个的 uuid

T308: get_editor_selection

mcp_tool "get_editor_selection" '{}'
  • 判定: R1-R5 + data 存在

T309: exists

mcp_tool "exists" '{"path":"assets/scripts/TestComponent.ts"}'
  • 判定: R1-R5 + data.existstrue

T310: read_file

mcp_tool "read_file" '{"path":"assets/scripts/TestComponent.ts"}'
  • 判定: R1-R5 + data.content 包含 TestComponent

T311: get_file_snippet

mcp_tool "get_file_snippet" '{"path":"assets/scripts/TestComponent.ts","line":3,"context":3}'
  • 判定: R1-R5 + data 存在

T312: list_directory

mcp_tool "list_directory" '{"path":"assets/scripts"}'
  • 判定: R1-R5 + data 为数组 + 长度 >= 1

T313: search_files

mcp_tool "search_files" '{"pattern":"*.ts"}'
  • 判定: R1-R5 + data 为数组 + 长度 >= 1

T314: capture_desktop_screenshot

mcp_tool "capture_desktop_screenshot" '{}'
  • 判定: R1-R3 + result.content 包含 image 项

T315: capture_game_screenshot

mcp_tool "capture_game_screenshot" '{}'
  • 判定: R1-R3 + result.content 包含 image 项
  • 注意: 需要 Game 面板可见

7. Phase 4: Full 额外变更工具测试

以下工具会修改项目状态,按子阶段链式执行。

4a. UI 创建工具

T401: create_canvas

mcp_tool "create_canvas" '{"name":"TestCanvas"}'
  • 判定: R1-R5 + data.uuid 非空
  • 记录: canvasUuid = data.uuid

T402: create_label(依赖 T401 或使用已有 Canvas

mcp_tool "create_label" '{"name":"TestLabel","parentPath":"Canvas","text":"Hello MCP"}'
  • 判定: R1-R5 + data.uuid 非空

T403: create_button(依赖 T401

mcp_tool "create_button" '{"name":"TestButton","parentPath":"Canvas","text":"Click Me"}'
  • 判定: R1-R5 + data.uuid 非空
  • 记录: buttonUuid = data.uuid(供 4g 事件测试使用)

T404: create_sprite(依赖 T401

mcp_tool "create_sprite" '{"name":"TestSprite","parentPath":"Canvas"}'
  • 判定: R1-R5 + data.uuid 非空

4b. 摄像机工具

T405: create_camera

mcp_tool "create_camera" '{"name":"TestCamera"}'
  • 判定: R1-R5 + data.uuid 非空
  • 记录: cameraUuid = data.uuid

T406: set_camera_properties(依赖 T405

mcp_tool "set_camera_properties" "{\"uuid\":\"<CAMERA_UUID>\",\"properties\":{\"projection\":1}}"
  • 判定: R1-R4
  • 前置: T405 通过

4c. 动画工具

T407: add_animation_clip

mcp_tool "add_animation_clip" '{"path":"Canvas/TestNode","clipName":"TestClip"}'
  • 判定: R1-R4
  • 注意: 如节点无 Animation 组件,工具应自动添加或返回明确错误

T408: play_animation(依赖 T407

mcp_tool "play_animation" '{"path":"Canvas/TestNode","clipName":"TestClip"}'
  • 判定: R1-R4
  • 前置: T407 通过

T409: stop_animation(依赖 T407

mcp_tool "stop_animation" '{"path":"Canvas/TestNode","clipName":"TestClip"}'
  • 判定: R1-R4
  • 前置: T407 通过

4d. 预制体生命周期测试

前置条件: 1.6 测试数据初始化已创建 TestPrefab.prefabAI Agent 已记录 prefabUuidprefabPath

本阶段测试完整的预制体生命周期:创建验证 → 实例化 → 修改实例 → 应用回预制体 → 验证保存 → 还原 → JSON编辑 → 复制 → 引用验证。

T410: instantiate_prefab — 实例化预制体到场景

# 使用初始化记录的 prefabUuid
mcp_tool "instantiate_prefab" "{\"prefabUuid\":\"<PREFAB_UUID>\",\"parentPath\":\"Canvas\"}"
  • 判定: R1-R5 + data.uuid 非空
  • 记录: instance1Uuid = data.uuidinstance1Path = "Canvas/TestPrefab"(或返回的实际路径)

T411: create_prefab_instance — 创建链接预制体实例

mcp_tool "create_prefab_instance" "{\"prefabUuid\":\"<PREFAB_UUID>\",\"parentPath\":\"Canvas\"}"
  • 判定: R1-R5 + data.uuid 非空
  • 记录: instance2Uuid = data.uuidinstance2Path = "Canvas/TestPrefab"(或返回的实际路径)
  • 注意: 如与 T410 实例名冲突,AI Agent 应使用不同名称或跳过此步

T412: inspect_prefab_instance — 检查实例链接状态(依赖 T410)

mcp_tool "inspect_prefab_instance" "{\"path\":\"<INSTANCE1_PATH>\"}"
  • 判定: R1-R5 + data 存在 + data.isPrefabInstancetrue 或包含预制体关联信息
  • 前置: T410 通过

T413: set_node_transform — 修改实例节点属性(依赖 T410)

# 修改实例节点的位置,作为待应用的变更
mcp_tool "set_node_transform" "{\"uuid\":\"<INSTANCE1_UUID>\",\"position\":{\"x\":200,\"y\":300,\"z\":0},\"scale\":{\"x\":1.5,\"y\":1.5,\"z\":1}}"
  • 判定: R1-R4
  • 前置: T410 通过
  • 记录: 修改的位置值 modifiedPosition = {x:200, y:300},供 T415 验证

T414: apply_prefab_instance — 将修改应用回预制体(依赖 T413)

mcp_tool "apply_prefab_instance" "{\"path\":\"<INSTANCE1_PATH>\"}"
  • 判定: R1-R5 + data 存在
  • 前置: T413 通过
  • 说明: 此操作将实例上的变更保存回 .prefab 源文件,等同于"保存预制体"

T415: inspect_prefab — 验证修改已保存到预制体(依赖 T410, T414)

mcp_tool "inspect_prefab" "{\"uuid\":\"<PREFAB_UUID>\"}"
  • 判定: R1-R5 + data 存在 + 包含预制体序列化信息
  • 前置: T414 通过
  • 验证点: 预制体数据应反映 T413 的修改(位置/缩放变更)

T416: read_file — 读取 .prefab 文件验证持久化(依赖 T414)

mcp_tool "read_file" '{"path":"assets/prefabs/TestPrefab.prefab"}'
  • 判定: R1-R5 + data.content 非空 + 包含有效的 JSON 结构
  • 前置: T414 通过
  • 验证点: 文件内容应包含 T413 修改的位置值("x":200"y":300
  • 说明: 这是验证预制体确实已保存到磁盘的关键步骤

T417: revert_prefab_instance — 还原实例到预制体状态(依赖 T410)

mcp_tool "revert_prefab_instance" "{\"path\":\"<INSTANCE1_PATH>\"}"
  • 判定: R1-R5 + data 存在
  • 前置: T410 通过
  • 验证点: 实例节点应恢复为预制体的原始状态(T413 的修改被撤销)
  • 说明: revert 撤销的是实例上的 override,不影响已 apply 的预制体文件

T418: edit_prefab_json — 直接编辑预制体 JSON(依赖 T410)

mcp_tool "edit_prefab_json" '{"prefabPath":"db://assets/prefabs/TestPrefab.prefab","jsonPath":"_name","value":"EditedTestPrefab"}'
  • 判定: R1-R5 + data 存在
  • 前置: T410 通过
  • 说明: 直接修改 .prefab 文件的 JSON 字段,绕过场景编辑

T419: inspect_prefab — 验证 JSON 编辑生效(依赖 T418)

mcp_tool "inspect_prefab" "{\"uuid\":\"<PREFAB_UUID>\"}"
  • 判定: R1-R5 + data 存在
  • 前置: T418 通过
  • 验证点: 预制体名称应反映 T418 的修改(EditedTestPrefab
  • 说明: 也可通过 read_file 读取 .prefab 文件验证 _name 字段已变更

T420: duplicate_prefab — 复制预制体(依赖 T410)

mcp_tool "duplicate_prefab" "{\"prefabUuid\":\"<PREFAB_UUID>\",\"newName\":\"TestPrefabCopy\"}"
  • 判定: R1-R5 + data 存在 + data.uuiddata.url 非空
  • 前置: T410 通过
  • 记录: duplicatedPrefabUuid = data.uuid(如有)
  • 验证点: 新预制体应存在于 assets/prefabs/ 目录,且 UUID 与原预制体不同

T421: validate_prefab_references — 验证预制体引用完整性(依赖 T410)

mcp_tool "validate_prefab_references" "{\"uuid\":\"<PREFAB_UUID>\"}"
  • 判定: R1-R5 + data 存在 + 无断引错误
  • 前置: T410 通过
  • 说明: 检查预制体内部的所有 UUID 引用是否有效

T422: validate_prefab_references — 验证复制的预制体引用(依赖 T420)

# 使用 T420 返回的 duplicatedPrefabUuid
mcp_tool "validate_prefab_references" "{\"uuid\":\"<DUPLICATED_PREFAB_UUID>\"}"
  • 判定: R1-R5 + data 存在 + 无断引错误
  • 前置: T420 通过
  • 清理: 测试完成后可删除复制的预制体(delete_asset

4e. 文件工具

T423: write_file

mcp_tool "write_file" '{"path":"assets/scripts/test-output.txt","content":"MCP test output\n"}'
  • 判定: R1-R4

T424: replace_in_file

mcp_tool "replace_in_file" '{"path":"assets/scripts/test-output.txt","search":"MCP test output","replace":"MCP test output (updated)"}'
  • 判定: R1-R4
  • 前置: T423 通过

T425: refresh_assets

mcp_tool "refresh_assets" '{"path":"assets/scripts"}'
  • 判定: R1-R4

4f. 资源操作工具

T426: open_asset(已在 T137 测试,此处跳过)

T427: select_asset(已在 T138 测试,此处跳过)

T428: delete_asset

# 删除 T423 创建的测试文件
mcp_tool "delete_asset" '{"url":"db://assets/scripts/test-output.txt"}'
  • 判定: R1-R4
  • 清理: 删除测试文件

4g. 事件工具

T429: bind_button_click_event(依赖 T403

mcp_tool "bind_button_click_event" "{\"buttonPath\":\"Canvas/TestButton\",\"targetPath\":\"Canvas/TestNode\",\"componentName\":\"TestComponent\",\"handler\":\"greet\"}"
  • 判定: R1-R4
  • 前置: T403 通过 + TestComponent 脚本已编译
  • 注意: 如 TestComponent 未编译完成则 skip

T430: list_button_click_events(依赖 T429

mcp_tool "list_button_click_events" '{"path":"Canvas/TestButton"}'
  • 判定: R1-R5 + data 为数组
  • 前置: T429 通过

T431: simulate_button_click(依赖 T403

mcp_tool "simulate_button_click" '{"path":"Canvas/TestButton"}'
  • 判定: R1-R4
  • 前置: T403 通过

T432: emit_node_event

mcp_tool "emit_node_event" '{"path":"Canvas/TestNode","eventName":"test-event","data":{"value":42}}'
  • 判定: R1-R4

4h. 组件方法调用

T433: invoke_component_method

mcp_tool "invoke_component_method" '{"path":"Canvas/TestNode","componentType":"cc.Label","method":"toString"}'
  • 判定: R1-R4
  • 注意: 调用 Label 组件的 toString 方法作为安全测试

4i. 运行时控制工具

T434: pause_runtime

mcp_tool "pause_runtime" '{}'
  • 判定: R1-R4
  • 注意: 需要 preview 运行中;如未运行则 skip

T435: set_time_scale(依赖 T434

mcp_tool "set_time_scale" '{"scale":0.5}'
  • 判定: R1-R4
  • 前置: T434 通过或 skip

T436: resume_runtime

mcp_tool "resume_runtime" '{}'
  • 判定: R1-R4

T437: run_scene_asset

# 使用 T106 记录的场景 uuid
mcp_tool "run_scene_asset" "{\"uuid\":\"<SCENE_UUID>\"}"
  • 判定: R1-R4
  • 注意: 会重新加载场景

4j. 输入模拟工具

前置条件: 需要 Cocos Creator 编辑器窗口可见且处于前台。

T438: simulate_mouse_click

mcp_tool "simulate_mouse_click" '{"x":400,"y":300,"windowKind":"editor"}'
  • 判定: R1-R4
  • 注意: 需要编辑器窗口可见

T439: simulate_mouse_drag

mcp_tool "simulate_mouse_drag" '{"startX":100,"startY":100,"endX":300,"endY":300,"windowKind":"editor"}'
  • 判定: R1-R4

T440: simulate_key_press

mcp_tool "simulate_key_press" '{"keyCode":"S","modifiers":["control"],"windowKind":"editor"}'
  • 判定: R1-R4
  • 注意: Ctrl+S 会触发保存场景

T441: simulate_key_combo

mcp_tool "simulate_key_combo" '{"keyCode":"P","modifiers":["control"],"windowKind":"editor"}'
  • 判定: R1-R4

T442: simulate_preview_input

mcp_tool "simulate_preview_input" '{"mode":"click","x":200,"y":200}'
  • 判定: R1-R4
  • 注意: 需要 preview 窗口运行

4k. 构建与编辑器工具

T443: open_build_panel

mcp_tool "open_build_panel" '{}'
  • 判定: R1-R4
  • 注意: 会打开构建面板

T444: run_project_preview

mcp_tool "run_project_preview" '{}'
  • 判定: R1-R4
  • 注意: 会启动预览;后续依赖 preview 的测试(T434-T442)应在此之后执行

4l. 偏好与广播工具

T445: get_editor_preference

mcp_tool "get_editor_preference" '{"name":"general","path":"language"}'
  • 判定: R1-R4 + data 存在

T446: set_editor_preference

mcp_tool "set_editor_preference" '{"name":"general","path":"language","value":"zh"}'
  • 判定: R1-R4
  • 清理: 将语言设回原值

T447: broadcast_editor_message

mcp_tool "broadcast_editor_message" '{"message":"scene:ready","data":{"test":true}}'
  • 判定: R1-R4

4m. 项目指令工具

T448: write_project_instruction

mcp_tool "write_project_instruction" '{"name":"AGENTS.md","content":"# Test Instructions\nThis is a test.\n"}'
  • 判定: R1-R4

T449: create_project_skill

mcp_tool "create_project_skill" '{"skillName":"test-skill","content":"# Test Skill\nTest content.\n"}'
  • 判定: R1-R4

T450: create_cocos_mcp_project_skill

mcp_tool "create_cocos_mcp_project_skill" '{}'
  • 判定: R1-R4

T451: reset_component_property

mcp_tool "reset_component_property" '{"path":"Canvas/TestNode","componentType":"cc.Label","property":"string"}'
  • 判定: R1-R4

8. Phase 5: MCP Resources 测试

T501: cocos://project/context

mcp_resource "cocos://project/context"
  • 判定: R1-R2 + result.contents 为数组 + 首项有 text 字段 + 非空

T502: cocos://project/summary

mcp_resource "cocos://project/summary"
  • 判定: R1-R2 + result.contents[0].text 非空

T503: cocos://scene/active

mcp_resource "cocos://scene/active"
  • 判定: R1-R2 + result.contents[0].text 非空

T504: cocos://scene/current

mcp_resource "cocos://scene/current"
  • 判定: R1-R2 + result.contents[0].text 非空

T505: cocos://selection/current

mcp_resource "cocos://selection/current"
  • 判定: R1-R2 + result.contents[0].text 非空

T506: cocos://selection/asset

mcp_resource "cocos://selection/asset"
  • 判定: R1-R2 + result.contents[0].text 非空

T507: cocos://errors/scripts

mcp_resource "cocos://errors/scripts"
  • 判定: R1-R2 + result.contents[0].text 非空

T508: cocos://logs/editor

mcp_resource "cocos://logs/editor"
  • 判定: R1-R2 + result.contents[0].text 非空

T509: cocos://logs/project

mcp_resource "cocos://logs/project"
  • 判定: R1-R2 + result.contents[0].text 非空

T510: cocos://mcp/interactions

mcp_resource "cocos://mcp/interactions"
  • 判定: R1-R2 + result.contents[0].text 非空

T511: Resource Template — cocos://scene/node/{path}

mcp_resource "cocos://scene/node/Canvas/TestNode"
  • 判定: R1-R2 + result.contents[0].text 非空 + 包含 TestNode

T512: Resource Template — cocos://asset/path/{relative_path}

mcp_resource "cocos://asset/path/assets/scripts/TestComponent.ts"
  • 判定: R1-R2 + result.contents[0].text 非空 + 包含 TestComponent

T513: Resource Template — cocos://asset/info/{uuid_or_path}

mcp_resource "cocos://asset/info/db://assets/scene.scene"
  • 判定: R1-R2 + result.contents[0].text 非空

9. Phase 6: MCP Prompts 测试

T601: fix_script_errors

mcp_prompt "fix_script_errors"
  • 判定: R1-R2 + result.messages 为数组 + 长度 >= 1 + 首项有 content.text + 包含 execute_javascript

T602: create_playable_prototype

mcp_prompt "create_playable_prototype"
  • 判定: R1-R2 + result.messages[0].content.text 非空 + 包含 execute_javascript

T603: scene_validation

mcp_prompt "scene_validation"
  • 判定: R1-R2 + result.messages[0].content.text 非空 + 包含 execute_javascript

T604: auto_wire_scene

mcp_prompt "auto_wire_scene"
  • 判定: R1-R2 + result.messages[0].content.text 非空 + 包含 execute_javascript

10. 测试报告与结论

10.1 汇总统计

测试全部完成后,AI Agent 输出以下汇总:

========== funplay-cocos-mcp 集成测试报告 ==========
测试时间: <ISO_TIMESTAMP>
Cocos Creator 版本: <从 T101 获取>
MCP 服务器版本: <从 T001 获取>
工具配置档: full
测试端口: <实际端口>
====================================================
Phase 0 (协议合规):     <X>/8 通过
Phase 1 (Core 只读):   <X>/38 通过
Phase 2 (Core 变更):   <X>/7 通过
Phase 3 (Full 只读):   <X>/15 通过
Phase 4 (Full 变更):   <X>/51 通过
Phase 5 (Resources):   <X>/13 通过
Phase 6 (Prompts):     <X>/4 通过
----------------------------------------------------
总计: <PASS>/<TOTAL> 通过, <FAIL> 失败, <SKIP> 跳过
====================================================

10.2 失败详情格式

每个失败项输出:

[FAIL] <TEST_ID> <tool_name>
  调用: <curl 命令摘要>
  参数: <arguments JSON>
  响应: <response JSON 前 500 字符>
  判定: <哪条规则失败>
  可能原因: <AI Agent 分析>

10.3 兼容性结论模板

兼容性结论: <PASS / PARTIAL / FAIL>

依据:
- <PASS>: 全部 101 个工具 + 13 个资源 + 4 个 prompt 测试通过
- <PARTIAL>: 核心功能通过,但有 <N> 个工具失败,失败工具列表: <...>
- <FAIL>: 协议层或核心工具大面积失败

3.8.8 特定问题:
- <列出仅在 3.8.8 下出现的问题,如 API 不兼容、方法不存在等>

建议:
- <基于测试结果给出的建议>

10.4 结果文件格式

完整测试结果以 JSON 文件保存:

{
  "testDate": "2026-06-30T12:00:00Z",
  "cocosVersion": "3.8.8",
  "mcpVersion": "0.4.0",
  "toolProfile": "full",
  "serverPort": 8765,
  "summary": {
    "total": 136,
    "passed": 125,
    "failed": 3,
    "skipped": 2
  },
  "results": [
    {
      "id": "T001",
      "phase": 0,
      "tool": "initialize",
      "status": "pass",
      "duration_ms": 120,
      "detail": "protocol 2025-11-25 negotiated"
    },
    {
      "id": "T201",
      "phase": 2,
      "tool": "create_node",
      "status": "fail",
      "duration_ms": 5000,
      "detail": "ok=false, error=Scene not loaded",
      "response": "..."
    }
  ],
  "conclusion": "PARTIAL",
  "issues": [
    "T201 create_node: Scene not loaded - 可能需要先 open_scene",
    "T432 simulate_mouse_click: No visible window - 需要编辑器窗口在前台"
  ]
}

附录 A: 测试用例索引

Phase 范围 用例编号 数量
0 MCP 协议合规 T001-T008 8
1 Core 只读工具 T101-T138 38
2 Core 变更工具(链式) T201-T207 7
3 Full 额外只读 T301-T315 15
4 Full 额外变更 T401-T451 51
5 MCP Resources T501-T513 13
6 MCP Prompts T601-T604 4
总计 136

附录 B: 工具与测试用例映射

工具名 配置档 测试 ID 类型
initialize T001 协议
tools/list T002 协议
resources/list T003 协议
resources/templates/list T004 协议
prompts/list T005 协议
(Accept header) T006 协议
(unknown method) T007 协议
GET /tools T008 协议
get_project_info core T101 只读
get_editor_state core T102 只读
get_tool_catalog core T103 只读
get_scene_info core T104 只读
get_hierarchy core T105 只读
list_scenes core T106 只读
open_scene core T107 状态
list_assets core T108 只读
inspect_asset core T109 只读
inspect_asset_dependencies core T110 只读
validate_asset_dependencies core T111 只读
inspect_prefab core T112 只读
inspect_prefab_instance core T113 只读
validate_prefab_references core T114 只读
validate_scene core T115 只读
get_selection core T116 只读
set_selection core T117 变更
get_runtime_state core T118 只读
get_performance_snapshot core T119 只读
get_build_status core T120 只读
list_editor_windows core T121 只读
get_recent_logs core T122 只读
search_project_logs core T123 只读
clear_logs core T124 变更
run_script_diagnostics core T125 只读
get_script_diagnostic_context core T126 只读
check_for_updates core T127 只读
list_project_instructions core T128 只读
read_project_instruction core T129 只读
capture_editor_screenshot core T130 只读
capture_scene_screenshot core T131 只读
capture_preview_screenshot core T132 只读
execute_javascript (scene) core T133 执行
execute_javascript (editor) core T134 执行
execute_scene_script core T135 执行
execute_editor_script core T136 执行
open_asset core T137 状态
select_asset core T138 状态
create_node full T201 变更
set_node_transform full T202 变更
delete_node full T203 变更
add_component full T204 变更
set_component_property full T205 变更
remove_component full T206 变更
save_current_scene full T207 状态
find_nodes full T301 只读
inspect_node full T302 只读
list_components full T303 只读
inspect_component full T304 只读
list_cameras full T305 只读
list_animations full T306 只读
list_prefabs full T307 只读
get_editor_selection full T308 只读
exists full T309 只读
read_file full T310 只读
get_file_snippet full T311 只读
list_directory full T312 只读
search_files full T313 只读
capture_desktop_screenshot full T314 只读
capture_game_screenshot full T315 只读
create_canvas full T401 变更
create_label full T402 变更
create_button full T403 变更
create_sprite full T404 变更
create_camera full T405 变更
set_camera_properties full T406 变更
add_animation_clip full T407 变更
play_animation full T408 变更
stop_animation full T409 变更
instantiate_prefab full T410 变更
create_prefab_instance full T411 变更
inspect_prefab_instance full T412 只读
set_node_transform (实例修改) full T413 变更
apply_prefab_instance full T414 变更
inspect_prefab (验证保存) full T415 只读
read_file (验证 .prefab 持久化) full T416 只读
revert_prefab_instance full T417 变更
edit_prefab_json full T418 变更
inspect_prefab (验证 JSON 编辑) full T419 只读
duplicate_prefab full T420 变更
validate_prefab_references full T421, T422 只读
write_file full T423 变更
replace_in_file full T424 变更
refresh_assets full T425 状态
delete_asset full T428 变更
bind_button_click_event full T429 变更
list_button_click_events full T430 只读
simulate_button_click full T431 变更
emit_node_event full T432 变更
invoke_component_method full T433 变更
pause_runtime full T434 变更
set_time_scale full T435 变更
resume_runtime full T436 变更
run_scene_asset full T437 变更
simulate_mouse_click full T438 变更
simulate_mouse_drag full T439 变更
simulate_key_press full T440 变更
simulate_key_combo full T441 变更
simulate_preview_input full T442 变更
open_build_panel full T443 状态
run_project_preview full T444 状态
get_editor_preference full T445 只读
set_editor_preference full T446 变更
broadcast_editor_message full T447 状态
write_project_instruction full T448 变更
create_project_skill full T449 变更
create_cocos_mcp_project_skill full T450 变更
reset_component_property full T451 变更

附录 C: AI Agent 执行注意事项

C.1 环境依赖

测试阶段 环境要求 失败处理
Phase 0 MCP 服务器运行 全部中止
Phase 1 场景已加载 场景相关测试 skip
Phase 2 场景已加载 链式 skip
Phase 3 场景已加载 + 测试脚本已编译 脚本相关 skip
Phase 4a-4d 场景已加载 + 预制体已创建 链式 skip
Phase 4i preview 运行中 skip
Phase 4j 编辑器窗口可见且前台 skip
Phase 5 服务器运行 全部 skip
Phase 6 服务器运行 全部 skip

C.2 链式测试依赖图

T106 (list_scenes) ──→ T107 (open_scene)
                   ──→ T437 (run_scene_asset)

T108 (list_assets) ──→ T109 (inspect_asset)
                   ──→ T110 (inspect_asset_dependencies)
                   ──→ T111 (validate_asset_dependencies)
                   ──→ T137 (open_asset)
                   ──→ T138 (select_asset)

T201 (create_node) ──→ T202 (set_node_transform)
                   ──→ T203 (delete_node)

T204 (add_component) ──→ T205 (set_component_property)
                     ──→ T206 (remove_component)

T307 (list_prefabs) ──→ T112 (inspect_prefab)
                    ──→ T114 (validate_prefab_references)

T410 (instantiate_prefab) ──→ T412 (inspect_prefab_instance)
                           ──→ T413 (set_node_transform 修改实例)
                           ──→ T414 (apply_prefab_instance 保存回预制体)
                           │   ──→ T415 (inspect_prefab 验证已保存)
                           │   ──→ T416 (read_file 验证 .prefab 持久化)
                           ──→ T417 (revert_prefab_instance 还原实例)

T418 (edit_prefab_json) ──→ T419 (inspect_prefab 验证 JSON 编辑)

T420 (duplicate_prefab) ──→ T422 (validate_prefab_references 验证副本)

T421 (validate_prefab_references 验证原件)

T401 (create_canvas) ──→ T402 (create_label)
                     ──→ T403 (create_button) ──→ T429 (bind_button_click_event)
                     │                        ──→ T431 (simulate_button_click)
                     └──→ T404 (create_sprite)

T405 (create_camera) ──→ T406 (set_camera_properties)

T407 (add_animation_clip) ──→ T408 (play_animation)
                           ──→ T409 (stop_animation)

T423 (write_file) ──→ T424 (replace_in_file)
                  ──→ T428 (delete_asset) [清理]

T434 (pause_runtime) ──→ T435 (set_time_scale)
                     ──→ T436 (resume_runtime)

T444 (run_project_preview) ──→ T434-T442 (需要 preview 运行的测试)

C.3 推荐执行顺序

为最大化测试覆盖并减少 skip,建议按以下顺序执行:

1. Phase 0 (协议) — 必须全部通过
2. 测试数据初始化 (1.6 节) — 含预制体创建
3. Phase 1 (Core 只读) — 先 T106 拿场景 uuid, T108 拿资产 uuid
4. Phase 3 (Full 只读) — T307 验证预制体已创建
5. Phase 2 (Core 变更链式) — T201→T202→T203, T204→T205→T206
6. Phase 4a-4c (UI/摄像机/动画)
7. Phase 4d (预制体生命周期) — T410→T412→T413→T414→T415→T416, T417, T418→T419, T420→T422, T421
8. Phase 4e-4h (文件/资源/事件/组件方法)
9. T444 (run_project_preview) — 启动 preview
10. Phase 4i (Runtime) — 需要 preview 运行
11. Phase 4j (Input) — 需要 preview 运行 + 窗口可见
12. Phase 4k-4m (Build/Preference/Instruction)
13. Phase 5 (Resources)
12. Phase 6 (Prompts)
13. 生成测试报告

C.4 错误处理策略

场景 策略
协议测试失败 中止全部测试,报告协议不兼容
场景未加载 跳过所有场景相关测试,继续非场景测试
预制体不存在 跳过预制体相关测试,记录 skip
preview 未运行 先执行 T438 启动 preview,再重试
窗口不可见 跳过截图和输入模拟测试
链式前驱失败 后续依赖步骤标记 skip
超时(>30秒无响应) 标记 fail,记录超时,继续下一个
HTTP 500 标记 fail,记录响应体,继续

C.5 execute_javascript 链式编排示例

对于需要多步链式操作且数据传递复杂的场景,可使用 execute_javascript 在编辑器上下文中一次性完成:

# 示例:创建节点 → 添加组件 → 设置属性 → 验证 → 清理,一步完成
mcp_tool "execute_javascript" '{
  "context": "editor",
  "code": "const createResult = await helpers.callTool(\"create_node\", {name:\"ChainNode\",parentPath:\"Canvas\"}); const createData = JSON.parse(createResult); const nodeUuid = createData.data.uuid; await helpers.callTool(\"add_component\", {path:\"Canvas/ChainNode\",componentType:\"cc.Sprite\"}); await helpers.callTool(\"set_component_property\", {path:\"Canvas/ChainNode\",componentType:\"cc.Sprite\",property:\"color\",value:{r:255,g:0,b:0,a:255}}); const inspectResult = await helpers.callTool(\"inspect_component\", {path:\"Canvas/ChainNode\",componentType:\"cc.Sprite\"}); const inspectData = JSON.parse(inspectResult); await helpers.callTool(\"remove_component\", {path:\"Canvas/ChainNode\",componentType:\"cc.Sprite\"}); await helpers.callTool(\"delete_node\", {uuid:nodeUuid}); return { created: true, inspected: inspectData.ok, cleaned: true };"
}'
  • 判定: R1-R5 + data.created === true + data.inspected === true + data.cleaned === true
  • 优势: 减少网络往返,原子性更好,适合复杂链式验证