UNPKG

@akiojin/unity-editor-mcp

Version:

MCP server for Unity Editor integration - enables AI assistants to control Unity Editor

134 lines (121 loc) 3.96 kB
/** * Base class for all tool handlers * Provides common functionality for validation, execution, and error handling */ import { logger } from '../../core/config.js'; export class BaseToolHandler { constructor(name, description, inputSchema = {}) { this.name = name; this.description = description; this.inputSchema = inputSchema; } /** * Validates the input parameters against the schema * Override this method for custom validation * @param {object} params - Input parameters * @throws {Error} If validation fails */ validate(params) { // Basic validation - check required fields from schema if (this.inputSchema.required) { for (const field of this.inputSchema.required) { if (params[field] === undefined || params[field] === null) { throw new Error(`Missing required parameter: ${field}`); } } } } /** * Executes the tool logic * Must be implemented by subclasses * @param {object} params - Validated input parameters * @returns {Promise<object>} Tool result */ async execute(params) { throw new Error('execute() must be implemented by subclass'); } /** * Main handler method that orchestrates validation and execution * @param {object} params - Input parameters * @returns {Promise<object>} Standardized response */ async handle(params = {}) { logger.debug(`[Handler ${this.name}] Starting handle() with params:`, params); try { // Validate parameters logger.debug(`[Handler ${this.name}] Validating parameters...`); this.validate(params); logger.debug(`[Handler ${this.name}] Validation passed`); // Execute tool logic logger.debug(`[Handler ${this.name}] Executing tool logic...`); const startTime = Date.now(); const result = await this.execute(params); const duration = Date.now() - startTime; logger.info(`[Handler ${this.name}] Execution completed in ${duration}ms`); // Return success response in new format return { status: 'success', result }; } catch (error) { logger.error(`[Handler ${this.name}] Error occurred: ${error.message}`); if (error.stack) { logger.debug(`[Handler ${this.name}] Error stack: ${error.stack}`); } // Return error response in new format return { status: 'error', error: error.message, code: error.code || 'TOOL_ERROR', details: { tool: this.name, params: this.summarizeParams(params), stack: process.env.NODE_ENV === 'development' ? error.stack : undefined } }; } } /** * Summarizes parameters for error reporting * @param {object} params - Parameters to summarize * @returns {string} Summary string */ summarizeParams(params) { if (!params || typeof params !== 'object') { return 'No parameters'; } const entries = Object.entries(params); if (entries.length === 0) { return 'Empty parameters'; } return entries .map(([key, value]) => { let valueStr = ''; if (value === null) { valueStr = 'null'; } else if (value === undefined) { valueStr = 'undefined'; } else if (typeof value === 'string') { // Truncate long strings valueStr = value.length > 50 ? `"${value.substring(0, 47)}..."` : `"${value}"`; } else if (typeof value === 'object') { valueStr = Array.isArray(value) ? `[Array(${value.length})]` : '[Object]'; } else { valueStr = String(value); } return `${key}: ${valueStr}`; }) .join(', '); } /** * Returns the tool definition for MCP * @returns {object} Tool definition */ getDefinition() { return { name: this.name, description: this.description, inputSchema: this.inputSchema }; } }