mcp-repl
Version:
MCP REPL with code execution, semantic code search, and comprehensive ast-grep integration
187 lines (160 loc) • 8.28 kB
JavaScript
// Tool execution handlers for MCP REPL server
// Consolidates all tool execution logic with consistent error handling
import { writeFileSync, unlinkSync } from 'fs';
import * as path from 'node:path';
import { createErrorResponse, createSuccessResponse, validateRequiredParams } from './common-errors.js';
import { validateWorkingDirectory } from './validation-utils.js';
import { applyTruncation } from './output-truncation.js';
import { executeNodeCode, executeDenoCode, executeBashCommands } from './process-executor.js';
import { handleRetrieveOverflow } from './overflow-handler.js';
import { convertToMCPFormat } from './mcp-format.js';
/**
* Handle Node.js code execution
*/
export async function handleNodeExecution(args, defaultWorkingDir) {
const startTime = Date.now();
const paramError = validateRequiredParams(args, ['code', 'workingDirectory'], startTime);
if (paramError) return convertToMCPFormat(paramError, 'executenodejs');
const dirValidation = validateWorkingDirectory(args.workingDirectory, defaultWorkingDir);
if (!dirValidation.valid) {
const errorResponse = createErrorResponse(dirValidation.error, startTime);
return convertToMCPFormat(errorResponse, 'executenodejs');
}
const result = await executeNodeCode(args.code, {
workingDirectory: dirValidation.effectiveDir,
timeout: args.timeout || 120000
});
const mcpResponse = convertToMCPFormat(result, 'executenodejs');
return applyTruncation(mcpResponse, dirValidation.effectiveDir, 'executenodejs');
}
/**
* Handle Deno code execution
*/
export async function handleDenoExecution(args, defaultWorkingDir) {
const startTime = Date.now();
const paramError = validateRequiredParams(args, ['code', 'workingDirectory'], startTime);
if (paramError) return convertToMCPFormat(paramError, 'executedeno');
const dirValidation = validateWorkingDirectory(args.workingDirectory, defaultWorkingDir);
if (!dirValidation.valid) {
const errorResponse = createErrorResponse(dirValidation.error, startTime);
return convertToMCPFormat(errorResponse, 'executedeno');
}
const result = await executeDenoCode(args.code, {
workingDirectory: dirValidation.effectiveDir,
timeout: args.timeout || 120000
});
const mcpResponse = convertToMCPFormat(result, 'executedeno');
return applyTruncation(mcpResponse, dirValidation.effectiveDir, 'executedeno');
}
/**
* Handle bash command execution
*/
export async function handleBashExecution(args, defaultWorkingDir) {
const startTime = Date.now();
const paramError = validateRequiredParams(args, ['commands'], startTime);
if (paramError) return convertToMCPFormat(paramError, 'executebash');
const dirValidation = validateWorkingDirectory(args.workingDirectory, defaultWorkingDir);
if (!dirValidation.valid) {
const errorResponse = createErrorResponse(dirValidation.error, startTime);
return convertToMCPFormat(errorResponse, 'executebash');
}
const result = await executeBashCommands(args.commands, {
workingDirectory: dirValidation.effectiveDir,
timeout: args.timeout || 120000
});
const mcpResponse = convertToMCPFormat(result, 'executebash');
return applyTruncation(mcpResponse, dirValidation.effectiveDir, 'executebash');
}
/**
* Handle semantic code search
*/
export async function handleCodeSearch(args, defaultWorkingDir, getVectorIndexer) {
const startTime = Date.now();
const paramError = validateRequiredParams(args, ['query', 'workingDirectory'], startTime);
if (paramError) return convertToMCPFormat(paramError, 'searchcode');
try {
const { searchSemantic } = await getVectorIndexer();
const results = await searchSemantic(args.query, args);
const response = createSuccessResponse({ results }, startTime);
const mcpResponse = convertToMCPFormat(response, 'searchcode');
return applyTruncation(mcpResponse, args.workingDirectory, 'searchcode');
} catch (error) {
const errorResponse = createErrorResponse(error, startTime);
return convertToMCPFormat(errorResponse, 'searchcode');
}
}
/**
* Create tool handlers map for delegation
*/
export function createToolHandlers(defaultWorkingDir, getVectorIndexer, getAstGrepUtils, getEnhancedUtils, getBatchHandler, getBashHandler) {
const handlers = {
executenodejs: (args) => handleNodeExecution(args, defaultWorkingDir),
executedeno: (args) => handleDenoExecution(args, defaultWorkingDir),
executebash: (args) => handleBashExecution(args, defaultWorkingDir),
// AST tools - delegate to existing handlers
astgrep_search: async (args) => {
const { astgrepHandlers } = await getAstGrepUtils();
return astgrepHandlers.handleAstGrepSearch(args, defaultWorkingDir, getAstGrepUtils);
},
astgrep_replace: async (args) => {
const { astgrepHandlers } = await getAstGrepUtils();
return astgrepHandlers.handleAstGrepReplace(args, defaultWorkingDir, getAstGrepUtils);
},
astgrep_lint: async (args) => {
const { astgrepHandlersAdvanced } = await getAstGrepUtils();
return astgrepHandlersAdvanced.handleAstGrepLint(args, defaultWorkingDir, getAstGrepUtils);
},
astgrep_analyze: async (args) => {
const { astgrepHandlersAdvanced } = await getAstGrepUtils();
return astgrepHandlersAdvanced.handleAstGrepAnalyze(args, defaultWorkingDir, getAstGrepUtils);
},
// Enhanced AST tools - delegate to enhanced handlers
astgrep_enhanced_search: async (args) => {
const { astgrepEnhancedHandlers } = await getEnhancedUtils();
return astgrepEnhancedHandlers.handleAstGrepEnhancedSearch(args, defaultWorkingDir, getEnhancedUtils);
},
astgrep_multi_pattern: async (args) => {
const { astgrepEnhancedHandlers } = await getEnhancedUtils();
return astgrepEnhancedHandlers.handleAstGrepMultiPatternSearch(args, defaultWorkingDir, getEnhancedUtils);
},
astgrep_constraint_search: async (args) => {
const { astgrepEnhancedHandlers } = await getEnhancedUtils();
return astgrepEnhancedHandlers.handleAstGrepConstraintSearch(args, defaultWorkingDir, getEnhancedUtils);
},
astgrep_project_init: async (args) => {
const { astgrepEnhancedHandlers } = await getEnhancedUtils();
return astgrepEnhancedHandlers.handleAstGrepProjectInit(args, defaultWorkingDir, getEnhancedUtils);
},
astgrep_project_scan: async (args) => {
const { astgrepEnhancedHandlers } = await getEnhancedUtils();
return astgrepEnhancedHandlers.handleAstGrepProjectScan(args, defaultWorkingDir, getEnhancedUtils);
},
astgrep_test: async (args) => {
const { astgrepEnhancedHandlers } = await getEnhancedUtils();
return astgrepEnhancedHandlers.handleAstGrepTest(args, defaultWorkingDir, getEnhancedUtils);
},
astgrep_validate_rules: async (args) => {
const { astgrepEnhancedHandlers } = await getEnhancedUtils();
return astgrepEnhancedHandlers.handleAstGrepValidateRules(args, defaultWorkingDir, getEnhancedUtils);
},
astgrep_debug_rule: async (args) => {
const { astgrepEnhancedHandlers } = await getEnhancedUtils();
return astgrepEnhancedHandlers.handleAstGrepDebugRule(args, defaultWorkingDir, getEnhancedUtils);
},
// Sequential thinking tool
sequentialthinking: async (args) => {
const { handleSequentialThinking } = await import('./thinking-handler.js');
return handleSequentialThinking(args, defaultWorkingDir);
},
// Overflow content retrieval
retrieve_overflow: (args) => handleRetrieveOverflow(args, defaultWorkingDir),
// Batch execution
batch_execute: async (args) => {
const { handleBatchExecute } = await getBatchHandler();
return handleBatchExecute(args, defaultWorkingDir, () => createToolHandlers(defaultWorkingDir, getVectorIndexer, getAstGrepUtils, getEnhancedUtils, getBatchHandler, getBashHandler));
}
};
// Include semantic search with ARM64-compatible vector indexer
handlers.searchcode = (args) => handleCodeSearch(args, defaultWorkingDir, getVectorIndexer);
return handlers;
}