Skip to main content
Glama

Cocos MCP Log Bridge

by czh2774
LogBridge.ts9.74 kB
import * as net from 'net'; import { Config } from './config/Config'; interface LogEntry { type: 'log' | 'warn' | 'error'; message: string; stack?: string; date: Date; } interface Command { type: string; params: any; } interface CommandResponse { status: string; result?: any; error?: string; } // 场景脚本接口类型定义 interface ExecuteSceneScriptOptions { name: string; method: string; args?: any[]; } export class LogBridge { private static instance: LogBridge; private server!: net.Server; private isRunning: boolean = false; private commandHandlers: Map<string, (params: any) => Promise<any>> = new Map(); private constructor() { this.setupCommandHandlers(); this.startTcpServer(); this.setupLogListener(); } public static getInstance(): LogBridge { if (!LogBridge.instance) { LogBridge.instance = new LogBridge(); } return LogBridge.instance; } public getConfig() { return Config; } private setupCommandHandlers() { // 注册命令处理器 this.commandHandlers.set('QUERY_LOGS', this.handleQueryLogs.bind(this)); this.commandHandlers.set('CLEAR_LOGS', this.handleClearLogs.bind(this)); this.commandHandlers.set('ping', this.handlePing.bind(this)); // 添加场景相关命令 this.commandHandlers.set('OPEN_SCENE', this.handleOpenScene.bind(this)); this.commandHandlers.set('GET_SCENE_INFO', this.handleGetSceneInfo.bind(this)); this.commandHandlers.set('LIST_SCENE_NODES', this.handleListSceneNodes.bind(this)); } private startTcpServer() { this.server = net.createServer((socket) => { console.log('Client connected to Cocos MCP bridge'); socket.on('data', async (data) => { try { // 处理可能的ping命令(简单字符串,不是JSON) const message = data.toString().trim(); if (message === 'ping') { const response: CommandResponse = { status: 'success', result: { message: 'pong' } }; socket.write(JSON.stringify(response)); return; } // 处理JSON命令 const command: Command = JSON.parse(message); const response = await this.executeCommand(command); socket.write(JSON.stringify(response)); } catch (error: any) { const errorResponse: CommandResponse = { status: 'error', error: `Error processing command: ${error.message}` }; socket.write(JSON.stringify(errorResponse)); } }); socket.on('close', () => { console.log('Client disconnected from Cocos MCP bridge'); }); socket.on('error', (err) => { console.error('Socket error:', err); }); }); this.server.listen(Config.TCP_PORT, Config.TCP_HOST, () => { console.log(`Cocos MCP TCP bridge running on ${Config.TCP_HOST}:${Config.TCP_PORT}`); this.isRunning = true; }); this.server.on('error', (err) => { console.error('TCP Server error:', err); this.isRunning = false; }); } private setupLogListener() { // 监听编辑器日志消息,但不再广播,由客户端查询获取 Editor.Message.addBroadcastListener('console:log', (log: LogEntry) => { // 只记录日志,不再广播 console.debug('Log captured by Cocos MCP bridge:', log); }); } private async executeCommand(command: Command): Promise<CommandResponse> { try { const { type, params = {} } = command; const handler = this.commandHandlers.get(type); if (!handler) { return { status: 'error', error: `Unknown command type: ${type}` }; } const result = await handler(params); return { status: 'success', result }; } catch (error: any) { console.error(`Error executing command: ${error.message}`); return { status: 'error', error: error.message }; } } private async handleQueryLogs(params: any): Promise<any> { try { const showLogs = params.show_logs !== false; const showWarnings = params.show_warnings !== false; const showErrors = params.show_errors !== false; const searchTerm = params.search_term || ''; const moduleFilter = params.module_filter || ''; // 直接使用 Editor.Logger.query() API 获取日志列表 console.log('Querying logs with Editor.Logger.query()...'); // @ts-ignore - Editor.Logger 是 Cocos Creator 编辑器 API const logs = await Editor.Logger.query() || []; console.log(`Found ${logs.length} logs`); // 根据类型过滤 let filteredLogs = logs.filter((log: LogEntry) => { const type = log.type.toLowerCase(); return ( (showLogs && type === 'log') || (showWarnings && type === 'warn') || (showErrors && type === 'error') ); }); // 根据模块过滤 if (moduleFilter) { console.log(`Filtering logs by module: "${moduleFilter}"`); const modulePattern = `[${moduleFilter}]`; filteredLogs = filteredLogs.filter((log: LogEntry) => { return log.message.includes(modulePattern); }); console.log(`Found ${filteredLogs.length} logs matching module filter`); } // 根据搜索词过滤 if (searchTerm) { console.log(`Filtering logs by search term: "${searchTerm}"`); const terms = searchTerm.toLowerCase().split(' '); const searchResults = filteredLogs.filter((log: LogEntry) => { const content = log.message.toLowerCase(); return terms.every((term: string) => content.includes(term)); }); console.log(`Found ${searchResults.length} logs matching search term`); return { logs: searchResults }; } return { logs: filteredLogs }; } catch (error: any) { console.error('Error querying logs:', error); console.error('Error details:', error.message, error.stack); throw error; } } private async handleClearLogs(params: any): Promise<any> { try { console.log('Clearing logs with Editor.Logger.clear()...'); // @ts-ignore - Editor.Logger 是 Cocos Creator 编辑器 API await Editor.Logger.clear(); return { message: 'Console logs cleared successfully' }; } catch (error: any) { console.error('Error clearing logs:', error); throw error; } } private async handlePing(params: any): Promise<any> { return { message: 'pong' }; } private async handleOpenScene(params: any): Promise<any> { try { const { sceneUuid } = params; if (!sceneUuid) { throw new Error('Missing sceneUuid parameter'); } // 调用场景脚本的 open_scene 方法 const result = await Editor.Message.request('scene', 'execute-scene-script', { name: 'cocos-mcp', method: 'openScene', args: [sceneUuid] }); return result; } catch (error: any) { console.error(`Error opening scene: ${error.message}`); throw error; } } /** * 处理获取场景信息命令 */ private async handleGetSceneInfo(params: any): Promise<any> { try { // 调用场景脚本的 getSceneInfo 方法 const result = await Editor.Message.request('scene', 'execute-scene-script', { name: 'cocos-mcp', method: 'getSceneInfo', args: [] }); return result; } catch (error: any) { console.error(`Error getting scene info: ${error.message}`); throw error; } } /** * 处理列出场景节点命令 */ private async handleListSceneNodes(params: any): Promise<any> { try { // 调用场景脚本的 listSceneNodes 方法 const result = await Editor.Message.request('scene', 'execute-scene-script', { name: 'cocos-mcp', method: 'listSceneNodes', args: [] }); return result; } catch (error: any) { console.error(`Error listing scene nodes: ${error.message}`); throw error; } } public destroy() { if (this.server && this.isRunning) { this.server.close(); this.isRunning = false; } } }

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/czh2774/cocosMCP'

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