Skip to main content
Glama
DaxianLee

Cocos Creator MCP Server Plugin

by DaxianLee
scene-advanced-tools.ts29 kB
import { ToolDefinition, ToolResponse, ToolExecutor } from '../types'; export class SceneAdvancedTools implements ToolExecutor { getTools(): ToolDefinition[] { return [ { name: 'reset_node_property', description: 'Reset node property to default value', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Node UUID' }, path: { type: 'string', description: 'Property path (e.g., position, rotation, scale)' } }, required: ['uuid', 'path'] } }, { name: 'move_array_element', description: 'Move array element position', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Node UUID' }, path: { type: 'string', description: 'Array property path (e.g., __comps__)' }, target: { type: 'number', description: 'Target item original index' }, offset: { type: 'number', description: 'Offset amount (positive or negative)' } }, required: ['uuid', 'path', 'target', 'offset'] } }, { name: 'remove_array_element', description: 'Remove array element at specific index', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Node UUID' }, path: { type: 'string', description: 'Array property path' }, index: { type: 'number', description: 'Target item index to remove' } }, required: ['uuid', 'path', 'index'] } }, { name: 'copy_node', description: 'Copy node for later paste operation', inputSchema: { type: 'object', properties: { uuids: { oneOf: [ { type: 'string' }, { type: 'array', items: { type: 'string' } } ], description: 'Node UUID or array of UUIDs to copy' } }, required: ['uuids'] } }, { name: 'paste_node', description: 'Paste previously copied nodes', inputSchema: { type: 'object', properties: { target: { type: 'string', description: 'Target parent node UUID' }, uuids: { oneOf: [ { type: 'string' }, { type: 'array', items: { type: 'string' } } ], description: 'Node UUIDs to paste' }, keepWorldTransform: { type: 'boolean', description: 'Keep world transform coordinates', default: false } }, required: ['target', 'uuids'] } }, { name: 'cut_node', description: 'Cut node (copy + mark for move)', inputSchema: { type: 'object', properties: { uuids: { oneOf: [ { type: 'string' }, { type: 'array', items: { type: 'string' } } ], description: 'Node UUID or array of UUIDs to cut' } }, required: ['uuids'] } }, { name: 'reset_node_transform', description: 'Reset node position, rotation and scale', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Node UUID' } }, required: ['uuid'] } }, { name: 'reset_component', description: 'Reset component to default values', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Component UUID' } }, required: ['uuid'] } }, { name: 'restore_prefab', description: 'Restore prefab instance from asset', inputSchema: { type: 'object', properties: { nodeUuid: { type: 'string', description: 'Node UUID' }, assetUuid: { type: 'string', description: 'Prefab asset UUID' } }, required: ['nodeUuid', 'assetUuid'] } }, { name: 'execute_component_method', description: 'Execute method on component', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Component UUID' }, name: { type: 'string', description: 'Method name' }, args: { type: 'array', description: 'Method arguments', default: [] } }, required: ['uuid', 'name'] } }, { name: 'execute_scene_script', description: 'Execute scene script method', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Plugin name' }, method: { type: 'string', description: 'Method name' }, args: { type: 'array', description: 'Method arguments', default: [] } }, required: ['name', 'method'] } }, { name: 'scene_snapshot', description: 'Create scene state snapshot', inputSchema: { type: 'object', properties: {} } }, { name: 'scene_snapshot_abort', description: 'Abort scene snapshot creation', inputSchema: { type: 'object', properties: {} } }, { name: 'begin_undo_recording', description: 'Begin recording undo data', inputSchema: { type: 'object', properties: { nodeUuid: { type: 'string', description: 'Node UUID to record' } }, required: ['nodeUuid'] } }, { name: 'end_undo_recording', description: 'End recording undo data', inputSchema: { type: 'object', properties: { undoId: { type: 'string', description: 'Undo recording ID from begin_undo_recording' } }, required: ['undoId'] } }, { name: 'cancel_undo_recording', description: 'Cancel undo recording', inputSchema: { type: 'object', properties: { undoId: { type: 'string', description: 'Undo recording ID to cancel' } }, required: ['undoId'] } }, { name: 'soft_reload_scene', description: 'Soft reload current scene', inputSchema: { type: 'object', properties: {} } }, { name: 'query_scene_ready', description: 'Check if scene is ready', inputSchema: { type: 'object', properties: {} } }, { name: 'query_scene_dirty', description: 'Check if scene has unsaved changes', inputSchema: { type: 'object', properties: {} } }, { name: 'query_scene_classes', description: 'Query all registered classes', inputSchema: { type: 'object', properties: { extends: { type: 'string', description: 'Filter classes that extend this base class' } } } }, { name: 'query_scene_components', description: 'Query available scene components', inputSchema: { type: 'object', properties: {} } }, { name: 'query_component_has_script', description: 'Check if component has script', inputSchema: { type: 'object', properties: { className: { type: 'string', description: 'Script class name to check' } }, required: ['className'] } }, { name: 'query_nodes_by_asset_uuid', description: 'Find nodes that use specific asset UUID', inputSchema: { type: 'object', properties: { assetUuid: { type: 'string', description: 'Asset UUID to search for' } }, required: ['assetUuid'] } } ]; } async execute(toolName: string, args: any): Promise<ToolResponse> { switch (toolName) { case 'reset_node_property': return await this.resetNodeProperty(args.uuid, args.path); case 'move_array_element': return await this.moveArrayElement(args.uuid, args.path, args.target, args.offset); case 'remove_array_element': return await this.removeArrayElement(args.uuid, args.path, args.index); case 'copy_node': return await this.copyNode(args.uuids); case 'paste_node': return await this.pasteNode(args.target, args.uuids, args.keepWorldTransform); case 'cut_node': return await this.cutNode(args.uuids); case 'reset_node_transform': return await this.resetNodeTransform(args.uuid); case 'reset_component': return await this.resetComponent(args.uuid); case 'restore_prefab': return await this.restorePrefab(args.nodeUuid, args.assetUuid); case 'execute_component_method': return await this.executeComponentMethod(args.uuid, args.name, args.args); case 'execute_scene_script': return await this.executeSceneScript(args.name, args.method, args.args); case 'scene_snapshot': return await this.sceneSnapshot(); case 'scene_snapshot_abort': return await this.sceneSnapshotAbort(); case 'begin_undo_recording': return await this.beginUndoRecording(args.nodeUuid); case 'end_undo_recording': return await this.endUndoRecording(args.undoId); case 'cancel_undo_recording': return await this.cancelUndoRecording(args.undoId); case 'soft_reload_scene': return await this.softReloadScene(); case 'query_scene_ready': return await this.querySceneReady(); case 'query_scene_dirty': return await this.querySceneDirty(); case 'query_scene_classes': return await this.querySceneClasses(args.extends); case 'query_scene_components': return await this.querySceneComponents(); case 'query_component_has_script': return await this.queryComponentHasScript(args.className); case 'query_nodes_by_asset_uuid': return await this.queryNodesByAssetUuid(args.assetUuid); default: throw new Error(`Unknown tool: ${toolName}`); } } private async resetNodeProperty(uuid: string, path: string): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'reset-property', { uuid, path, dump: { value: null } }).then(() => { resolve({ success: true, message: `Property '${path}' reset to default value` }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async moveArrayElement(uuid: string, path: string, target: number, offset: number): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'move-array-element', { uuid, path, target, offset }).then(() => { resolve({ success: true, message: `Array element at index ${target} moved by ${offset}` }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async removeArrayElement(uuid: string, path: string, index: number): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'remove-array-element', { uuid, path, index }).then(() => { resolve({ success: true, message: `Array element at index ${index} removed` }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async copyNode(uuids: string | string[]): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'copy-node', uuids).then((result: string | string[]) => { resolve({ success: true, data: { copiedUuids: result, message: 'Node(s) copied successfully' } }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async pasteNode(target: string, uuids: string | string[], keepWorldTransform: boolean = false): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'paste-node', { target, uuids, keepWorldTransform }).then((result: string | string[]) => { resolve({ success: true, data: { newUuids: result, message: 'Node(s) pasted successfully' } }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async cutNode(uuids: string | string[]): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'cut-node', uuids).then((result: any) => { resolve({ success: true, data: { cutUuids: result, message: 'Node(s) cut successfully' } }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async resetNodeTransform(uuid: string): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'reset-node', { uuid }).then(() => { resolve({ success: true, message: 'Node transform reset to default' }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async resetComponent(uuid: string): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'reset-component', { uuid }).then(() => { resolve({ success: true, message: 'Component reset to default values' }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async restorePrefab(nodeUuid: string, assetUuid: string): Promise<ToolResponse> { return new Promise((resolve) => { (Editor.Message.request as any)('scene', 'restore-prefab', nodeUuid, assetUuid).then(() => { resolve({ success: true, message: 'Prefab restored successfully' }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async executeComponentMethod(uuid: string, name: string, args: any[] = []): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'execute-component-method', { uuid, name, args }).then((result: any) => { resolve({ success: true, data: { result: result, message: `Method '${name}' executed successfully` } }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async executeSceneScript(name: string, method: string, args: any[] = []): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'execute-scene-script', { name, method, args }).then((result: any) => { resolve({ success: true, data: result }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async sceneSnapshot(): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'snapshot').then(() => { resolve({ success: true, message: 'Scene snapshot created' }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async sceneSnapshotAbort(): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'snapshot-abort').then(() => { resolve({ success: true, message: 'Scene snapshot aborted' }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async beginUndoRecording(nodeUuid: string): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'begin-recording', nodeUuid).then((undoId: string) => { resolve({ success: true, data: { undoId: undoId, message: 'Undo recording started' } }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async endUndoRecording(undoId: string): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'end-recording', undoId).then(() => { resolve({ success: true, message: 'Undo recording ended' }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async cancelUndoRecording(undoId: string): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'cancel-recording', undoId).then(() => { resolve({ success: true, message: 'Undo recording cancelled' }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async softReloadScene(): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'soft-reload').then(() => { resolve({ success: true, message: 'Scene soft reloaded successfully' }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async querySceneReady(): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'query-is-ready').then((ready: boolean) => { resolve({ success: true, data: { ready: ready, message: ready ? 'Scene is ready' : 'Scene is not ready' } }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async querySceneDirty(): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'query-dirty').then((dirty: boolean) => { resolve({ success: true, data: { dirty: dirty, message: dirty ? 'Scene has unsaved changes' : 'Scene is clean' } }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async querySceneClasses(extendsClass?: string): Promise<ToolResponse> { return new Promise((resolve) => { const options: any = {}; if (extendsClass) { options.extends = extendsClass; } Editor.Message.request('scene', 'query-classes', options).then((classes: any[]) => { resolve({ success: true, data: { classes: classes, count: classes.length, extendsFilter: extendsClass } }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async querySceneComponents(): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'query-components').then((components: any[]) => { resolve({ success: true, data: { components: components, count: components.length } }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async queryComponentHasScript(className: string): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'query-component-has-script', className).then((hasScript: boolean) => { resolve({ success: true, data: { className: className, hasScript: hasScript, message: hasScript ? `Component '${className}' has script` : `Component '${className}' does not have script` } }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } private async queryNodesByAssetUuid(assetUuid: string): Promise<ToolResponse> { return new Promise((resolve) => { Editor.Message.request('scene', 'query-nodes-by-asset-uuid', assetUuid).then((nodeUuids: string[]) => { resolve({ success: true, data: { assetUuid: assetUuid, nodeUuids: nodeUuids, count: nodeUuids.length, message: `Found ${nodeUuids.length} nodes using asset` } }); }).catch((err: Error) => { resolve({ success: false, error: err.message }); }); }); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DaxianLee/cocos-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server