UNPKG

unity-editor-mcp

Version:

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

167 lines (150 loc) 4.94 kB
import { BaseToolHandler } from '../base/BaseToolHandler.js'; /** * Handler for validating C# scripts in Unity */ export class ValidateScriptToolHandler extends BaseToolHandler { constructor(unityConnection) { super( 'validate_script', 'Validate a C# script for syntax and Unity compatibility', { type: 'object', properties: { scriptPath: { type: 'string', description: 'Full path to the script file (e.g., Assets/Scripts/PlayerController.cs)' }, scriptContent: { type: 'string', description: 'Script content to validate directly' }, scriptName: { type: 'string', description: 'Name of the script to search for (alternative to scriptPath)' }, searchPath: { type: 'string', default: 'Assets/', description: 'Directory to search in when using scriptName' }, checkSyntax: { type: 'boolean', default: true, description: 'Check for syntax errors' }, checkUnityCompatibility: { type: 'boolean', default: true, description: 'Check for Unity API compatibility' }, suggestImprovements: { type: 'boolean', default: false, description: 'Provide code improvement suggestions' } }, required: [] } ); this.unityConnection = unityConnection; } /** * Validates the input parameters * @param {Object} params - The input parameters * @throws {Error} If validation fails */ validate(params) { const { scriptPath, scriptContent, scriptName, searchPath } = params; // At least one input method must be provided if (!scriptPath && !scriptContent && !scriptName) { throw new Error('Either scriptPath, scriptContent, or scriptName must be provided'); } // Validate scriptPath if provided if (scriptPath) { if (!scriptPath.startsWith('Assets/')) { throw new Error('scriptPath must start with Assets/'); } if (!scriptPath.endsWith('.cs')) { throw new Error('scriptPath must end with .cs'); } } // Validate scriptName if provided if (scriptName) { const classNameRegex = /^[A-Za-z_][A-Za-z0-9_]*$/; if (!classNameRegex.test(scriptName)) { throw new Error('scriptName must be a valid C# class name (alphanumeric and underscore only, cannot start with number)'); } // Validate searchPath when using scriptName if (searchPath && !searchPath.startsWith('Assets/')) { throw new Error('searchPath must start with Assets/'); } } } /** * Executes the script validation * @param {Object} params - The input parameters * @returns {Promise<Object>} The result of the script validation */ async execute(params) { const { scriptPath, scriptContent, scriptName, searchPath = 'Assets/', checkSyntax = true, checkUnityCompatibility = true, suggestImprovements = false } = params; // Ensure connection to Unity if (!this.unityConnection.isConnected()) { await this.unityConnection.connect(); } // Prepare command parameters const commandParams = { checkSyntax, checkUnityCompatibility, suggestImprovements }; // Set the input method if (scriptPath) { commandParams.scriptPath = scriptPath; } else if (scriptContent) { commandParams.scriptContent = scriptContent; } else { commandParams.scriptName = scriptName; commandParams.searchPath = searchPath.endsWith('/') ? searchPath : searchPath + '/'; } // Send command to Unity const response = await this.unityConnection.sendCommand('validate_script', commandParams); // Handle Unity response if (response.success === false || response.status === 'error') { throw new Error(response.error || 'Failed to validate script'); } // Handle nested data structure from Unity const data = response.data || response; // Build result object const result = { isValid: data.isValid, errors: data.errors || [], warnings: data.warnings || [], message: data.message || 'Script validation completed' }; // Include optional data if available if (data.suggestions && Array.isArray(data.suggestions)) { result.suggestions = data.suggestions; } if (data.scriptPath) { result.scriptPath = data.scriptPath; } if (data.statistics) { result.statistics = data.statistics; } if (data.validationTime !== undefined) { result.validationTime = data.validationTime; } if (data.unityVersion) { result.unityVersion = data.unityVersion; } return result; } }