il2cpp-dump-analyzer-mcp
Version:
Agentic RAG system for analyzing IL2CPP dump.cs files from Unity games
277 lines • 11.1 kB
JavaScript
"use strict";
/**
* Base Tool Handler for MCP Tools
* Eliminates code duplication by providing a common foundation for all MCP tool implementations
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseGenerationToolHandler = exports.BaseAnalysisToolHandler = exports.BaseSearchToolHandler = exports.BaseMCPToolHandler = void 0;
const parameter_validator_1 = require("../utils/parameter-validator");
const mcp_response_formatter_1 = require("../utils/mcp-response-formatter");
const error_types_1 = require("./error-types");
/**
* Abstract base class for all MCP tool handlers
*/
class BaseMCPToolHandler {
constructor(config, context) {
this.startTime = 0;
this.config = config;
this.context = context;
}
/**
* Main execution method - handles the complete tool lifecycle
*/
async execute(params) {
this.startTime = Date.now();
try {
// Step 1: Ensure system is initialized
this.ensureInitialized();
// Step 2: Log tool execution start
this.logToolStart(params);
// Step 3: Validate parameters
const validation = await this.validateParameters(params);
if (!validation.isValid) {
throw new parameter_validator_1.ParameterValidationError(validation.errors, validation.warnings);
}
// Step 4: Apply parameter adjustments
const adjustedParams = this.applyParameterAdjustments(params, validation.adjustedValues);
// Step 5: Execute core tool logic
const result = await this.executeCore(adjustedParams);
// Step 6: Format and return response
const response = this.formatResponse(result, validation.warnings);
// Step 7: Log successful completion
this.logToolCompletion(result);
return response;
}
catch (error) {
// Handle and format errors consistently
return this.handleError(error, params);
}
}
/**
* Validate tool parameters - can be overridden by subclasses
*/
async validateParameters(params) {
if (!this.config.enableParameterValidation) {
return { isValid: true, errors: [], warnings: [] };
}
// Default validation using common parameters
return parameter_validator_1.ParameterValidator.validateCommonParams(params);
}
/**
* Apply parameter adjustments from validation
*/
applyParameterAdjustments(originalParams, adjustedValues) {
if (!adjustedValues) {
return originalParams;
}
return { ...originalParams, ...adjustedValues };
}
/**
* Format the tool response - can be overridden by subclasses
*/
formatResponse(result, warnings = []) {
if (!this.config.enableResponseFormatting) {
return mcp_response_formatter_1.MCPResponseFormatter.formatTextResponse(result);
}
const executionTime = Date.now() - this.startTime;
let response = mcp_response_formatter_1.MCPResponseFormatter.formatAnalysisResults(result, this.config.name, {}, executionTime);
if (warnings.length > 0) {
response = mcp_response_formatter_1.MCPResponseFormatter.addWarnings(response, warnings);
}
return mcp_response_formatter_1.MCPResponseFormatter.addExecutionTiming(response, this.startTime, this.config.name);
}
/**
* Handle errors consistently across all tools
*/
handleError(error, params) {
const executionTime = Date.now() - this.startTime;
this.context.logger.error(`Error in ${this.config.name} tool:`, error);
// Handle parameter validation errors
if (error instanceof parameter_validator_1.ParameterValidationError) {
return mcp_response_formatter_1.MCPResponseFormatter.formatValidationResults(false, error.errors, error.warnings);
}
// Handle MCP server errors
if (error instanceof error_types_1.MCPServerError) {
throw error; // Re-throw MCP errors to be handled by the framework
}
// Handle generic errors
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
throw new error_types_1.MCPServerError(`Tool execution error: ${errorMessage}`, error_types_1.ErrorType.TOOL_EXECUTION_ERROR);
}
/**
* Ensure the system is properly initialized
*/
ensureInitialized() {
if (!this.context.isInitialized()) {
throw new error_types_1.MCPServerError('MCP server not initialized. Please wait for initialization to complete.', error_types_1.ErrorType.INITIALIZATION_ERROR);
}
}
/**
* Log tool execution start
*/
logToolStart(params) {
this.context.logger.debug(`Tool call: ${this.config.name}`, { parameters: this.sanitizeParamsForLogging(params) });
}
/**
* Log tool execution completion
*/
logToolCompletion(result) {
const executionTime = Date.now() - this.startTime;
this.context.logger.debug(`${this.config.name} completed successfully in ${executionTime}ms`);
}
/**
* Sanitize parameters for logging (remove sensitive data)
*/
sanitizeParamsForLogging(params) {
// Override in subclasses if needed to remove sensitive parameters
return params;
}
/**
* Helper method for vector store searches with consistent error handling
*/
async performVectorSearch(query, filter = {}, limit = 5) {
try {
if (Object.keys(filter).length > 0) {
return await this.context.vectorStore.searchWithFilter(query, filter, limit);
}
else {
return await this.context.vectorStore.similaritySearch(query, limit);
}
}
catch (error) {
this.context.logger.error('Vector search failed:', error);
throw new error_types_1.MCPServerError(`Search operation failed: ${error instanceof Error ? error.message : 'Unknown error'}`, error_types_1.ErrorType.TOOL_EXECUTION_ERROR);
}
}
/**
* Helper method to create search filters from parameters
*/
createSearchFilter(params) {
const filter = {};
if (params.filter_type)
filter.type = params.filter_type;
if (params.filter_namespace)
filter.namespace = params.filter_namespace;
if (params.filter_monobehaviour)
filter.isMonoBehaviour = true;
return filter;
}
/**
* Helper method to extract and validate query from parameters
*/
extractQuery(params) {
return parameter_validator_1.ParameterValidator.validateQuery(params.query || params.class_name || '');
}
}
exports.BaseMCPToolHandler = BaseMCPToolHandler;
/**
* Specialized base class for search-based tools
*/
class BaseSearchToolHandler extends BaseMCPToolHandler {
/**
* Execute search and format results
*/
async executeCore(params) {
const query = this.extractQuery(params);
const filter = this.createSearchFilter(params);
const limit = params.top_k || 5;
return await this.performVectorSearch(query, filter, limit);
}
/**
* Format search results with metadata
*/
formatResponse(results, warnings = []) {
const query = this.extractQuery({});
const filter = this.createSearchFilter({});
let response = mcp_response_formatter_1.MCPResponseFormatter.formatSearchResults(results, query, filter, {
totalTime: Date.now() - this.startTime,
warnings
});
return mcp_response_formatter_1.MCPResponseFormatter.addExecutionTiming(response, this.startTime, this.config.name);
}
}
exports.BaseSearchToolHandler = BaseSearchToolHandler;
/**
* Specialized base class for analysis tools
*/
class BaseAnalysisToolHandler extends BaseMCPToolHandler {
/**
* Perform analysis with consistent error handling and logging
*/
async performAnalysis(analysisFunction) {
try {
this.context.logger.debug(`Starting ${this.config.name} analysis`);
const result = await analysisFunction();
this.context.logger.debug(`${this.config.name} analysis completed`);
return result;
}
catch (error) {
this.context.logger.error(`${this.config.name} analysis failed:`, error);
throw error;
}
}
}
exports.BaseAnalysisToolHandler = BaseAnalysisToolHandler;
/**
* Specialized base class for code generation tools
*/
class BaseGenerationToolHandler extends BaseMCPToolHandler {
/**
* Perform code generation with consistent error handling and logging
*/
async performGeneration(generationFunction) {
try {
this.context.logger.debug(`Starting ${this.config.name} code generation`);
const result = await generationFunction();
this.context.logger.debug(`${this.config.name} code generation completed`);
return result;
}
catch (error) {
this.context.logger.error(`${this.config.name} code generation failed:`, error);
throw error;
}
}
/**
* Validate class name for generation
*/
validateClassNameForGeneration(className) {
const errors = [];
const warnings = [];
if (!className || typeof className !== 'string') {
errors.push('class_name is required and must be a string');
}
else {
const trimmed = className.trim();
if (trimmed.length === 0) {
errors.push('class_name cannot be empty');
}
else if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(trimmed)) {
errors.push('class_name must be a valid identifier (letters, numbers, underscore, starting with letter)');
}
else if (!/^[A-Z]/.test(trimmed)) {
warnings.push('class_name should follow PascalCase convention');
}
}
return {
isValid: errors.length === 0,
errors,
warnings
};
}
/**
* Format generation results with metadata
*/
formatGenerationResponse(generatedCode, metadata, warnings = []) {
const allWarnings = [...warnings, ...(metadata.warnings || [])];
let response = mcp_response_formatter_1.MCPResponseFormatter.formatGenerationResults(generatedCode, {
...metadata,
warnings: allWarnings
});
if (allWarnings.length > 0) {
response = mcp_response_formatter_1.MCPResponseFormatter.addWarnings(response, allWarnings);
}
return mcp_response_formatter_1.MCPResponseFormatter.addExecutionTiming(response, this.startTime, this.config.name);
}
}
exports.BaseGenerationToolHandler = BaseGenerationToolHandler;
//# sourceMappingURL=base-tool-handler.js.map