Skip to main content
Glama
nguyennt02

cocos-mcp-v2-ui

by nguyennt02
README.md
# cocos-mcp-v2-ui

MCP server (UI-design tools) for **Cocos Creator 2.x** (verified on 2.4.11), built as an
editor package. It lets an MCP client (Claude Code) drive the editor to build UI —
ideal for translating a Figma design into a Cocos scene: read the design with the Figma
MCP, then create nodes/components/sprites/prefabs here.

Ported (not mechanically) from the 3.8.x `cocos-mcp-server`. 2.x differs fundamentally:
the scene bridge is the callback-based `Editor.Scene.callSceneScript`, node size/anchor
live on the node (no `UITransform`), and the package is plain CommonJS.

## Architecture

```
Claude Code ──stdio(MCP)──▶ bridge/  ──HTTP /rpc──▶ editor package (main proc)
                          (system Node,            core/server + registry + tools
                           @modelcontextprotocol)        │
                                                          ▼  Editor.Scene.callSceneScript
                                                   scene.js (scene proc, cc.* live)
```

- **Editor package** (`main.js`, `core/`, `tools/`, `scene.js`, `scene/`) runs inside
  Cocos Creator. `main.js` starts an HTTP server (`core/server.js`) exposing
  `GET /health`, `POST /rpc {tool,args}`, `GET /tools`, and a stateless `POST /mcp`.
- **Bridge** (`bridge/`) is a separate Node process Claude spawns. It speaks the MCP
  protocol over stdio (via the official SDK) and proxies `tools/list`+`tools/call` to the
  editor's HTTP `/tools`+`/rpc`. Keeping MCP-spec compliance out of the editor's old Node.
- **Single-responsibility / DRY**: tool modules are thin (schema + delegate). Everything
  crossing into the scene goes through one `core/scene-bridge.js#callScene`; one
  `core/response.js` shape; scene-side has one `resolveNode`, one `serialize`, one
  `applyTransform`.

## Install

1. Symlink (or copy) this folder into the project's `packages/`:
   ```
   ln -s /Users/nguyennt/Documents/MCP/cocos-mcp-v2-ui \
         /Users/nguyennt/Documents/Cocos/testMCP/packages/cocos-mcp-v2-ui
   ```
2. Install the bridge deps once: `cd bridge && npm install`.
3. Open the project in Cocos Creator 2.4.x. The package auto-starts the server on
   **port 8585** (`autoStart: true`). Panel: menu **Extension → Cocos MCP v2 UI**.

## Connect to Claude Code

```
claude mcp add cocos-ui --transport stdio -- \
  node /Users/nguyennt/Documents/MCP/cocos-mcp-v2-ui/bridge/bin/cocos-ui-bridge.js --port 8585
```
Verify: `/mcp` in Claude lists `cocos-ui` connected and the 32 tools. The editor must be
running with a scene open for scene tools to work (otherwise they return `No active scene`).

## Tools (32)

| Category | Tools |
|---|---|
| ping | `ping` |
| scene | `get_current_scene`, `get_scene_hierarchy`, `open_scene`, `save_scene`, `capture_node` |
| node | `create_node`, `create_node_tree`, `get_node_info`, `find_nodes`, `set_node_transform`, `set_node_property`, `set_node_properties_batch`, `set_sibling_index`, `delete_node`, `duplicate_node` |
| component | `add_component`, `set_component_property`, `get_components`, `set_component_reference`, `add_click_event`, `set_label_style`, `apply_widget`, `draw_rounded_rect`, `apply_gradient` |
| asset | `import_asset`, `query_asset_uuid` |
| prefab | `create_prefab`, `instantiate_prefab` |
| referenceImage | `add_reference_image`, `set_reference_image_data`, `remove_reference_image` |

### Highlights (added per build-experience feedback)
- **`color` is forgiving**: `set_component_property`/`set_node_property`/tree specs accept `{r,g,b,a}`,
  `[r,g,b,a]`, or a hex string (`"#161718"`).
- **`create_node_tree`**: build an entire node + component + property subtree in ONE call (returns uuids).
- **`capture_node`**: render a node/Canvas to a PNG on disk so the agent can see and self-correct.
- **`draw_rounded_rect`**: native rounded backgrounds/borders via `cc.Graphics` — no texture hacks.
- **`apply_gradient`**: bakes a rounded gradient PNG and binds it as a spriteFrame — real gradient
  buttons/badges (`cc.Graphics` fill is solid-only).
- **`set_component_reference`** + **`add_click_event`**: wire `ScrollView.content`, `Widget.target`,
  button handlers, etc.
- **Enum names**: enum props accept names (`type:"VERTICAL"`, `sizeMode:"CUSTOM"`) as well as numbers.
- **`import_asset`** auto-creates the destination folder, auto-rasterizes SVG-content files, and fails
  loudly instead of silently importing nothing. **spriteFrame** assignment now preserves node size.

MCP tool name = `<category>_<method>` (e.g. `node_create_node`,
`referenceImage_add_reference_image`).

## Figma → Cocos workflow

1. Read the design with the Figma MCP (positions, sizes, colors, text).
2. `scene_get_scene_hierarchy` → find the `Canvas` uuid.
3. (optional) export a screenshot from Figma → `asset_import_asset` →
   `referenceImage_add_reference_image { spriteFrameUuid }` to trace it.
4. `node_create_node` per element → `component_add_component` (`cc.Sprite`/`cc.Label`/
   `cc.Button`/`cc.Widget`/`cc.Layout`) → `component_set_component_property`
   (string, fontSize, color, spriteFrame) → `node_set_node_transform` to place/size.
5. For images: `asset_import_asset` returns **`spriteFrameUuid`** — pass that to
   `set_component_property property:"spriteFrame"` (it persists; the texture uuid does not).
6. Reusable bits: `prefab_create_prefab` → `prefab_instantiate_prefab`.
7. `scene_save_scene`.

## Notes & limitations (2.x specifics)

- **`capture_node` framing (edit-mode)** — in the editor (not Play), only a screen-aligned camera
  renders to an off-screen texture; a custom orthographic projection comes back blank. So `capture_node`
  renders through the scene's game camera at the scene's **design resolution**. It captures correctly
  when the UI is authored at that design resolution; a node much larger than the design resolution is
  framed to the design-res region (not the whole node). Tip: set the scene's design resolution to your
  screen size (e.g. 1080×2400) for full-screen captures.
- **One render component per node (2.x)** — `cc.Sprite`, `cc.Graphics`, `cc.Label`, `cc.RichText`
  all derive from `cc.RenderComponent` and are **mutually exclusive** on a node. So a node can't have
  both `draw_rounded_rect` (Graphics) and `apply_gradient`/`spriteFrame` (Sprite). This is an engine
  rule, not a tool bug — `add_component` reports the exact conflict, and `apply_gradient` auto-applies
  to a child node when the target already has a render component.
- **Reference image is simulated** — Cocos 2.x has no native reference-image gizmo. We add
  a low-opacity `Sprite` node `__ReferenceImage__` behind the UI. Remove it before shipping
  (`remove_reference_image`); it is a real scene node.
- **Editor Hierarchy/Inspector may not refresh instantly** after mutations made through the
  cc runtime — the live scene/canvas does update; reselect a node or reload the scene to
  refresh the panels. Not a tool failure.
- **No main-process hot-reload** in 2.4.x: editing `main.js`/`core/`/`tools/`/`scene/`
  during development requires a full editor restart (Developer → Reload Editor). At runtime
  this is irrelevant — the server starts on project open.
- **spriteFrame**: importing a PNG yields a texture *and* a `sprite-frame` sub-asset. Bind
  the **sub-asset** uuid (returned as `spriteFrameUuid`). Passing a texture uuid is handled
  as a best-effort wrap but does not persist on save.
- Verified editor IPC (2.4.11): save `scene:stash-and-save`, open `scene:open-by-uuid`,
  asset query/import `asset-db:query-uuid-by-url` / `asset-db:import-assets`, prefab create
  `scene:create-prefab` (url, serialized-content) via the `_Scene.PrefabUtils` recipe.

## Tests

- **Unit** (pure logic — colors, enums, PNG encoder, gradient, SVG sniff; no editor needed):
  ```
  node test/unit.test.js
  ```
- **Integration** (error/edge paths for the scene & component tools; needs the editor running with a
  scene open — creates a temp container node and deletes it afterwards):
  ```
  node test/integration.test.js --port 8585
  ```
- See `test/manual-checklist.md` for the per-tool manual verification steps.