UNPKG

@grebyn/toolflow-mcp-server

Version:

MCP server for managing other MCP servers - discover, install, organize into bundles, and automate with workflows. Uses StreamableHTTP transport with dual OAuth/API key authentication.

176 lines 8.13 kB
/** * Run System Command Tool * Execute system commands using the toolflow CLI */ import { exec } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); export const runSystemCommandTool = { name: 'run_system_command', description: 'Execute system commands for installing dependencies, checking versions, or testing server functionality. Essential for installing packages like \'npm install\' or \'pip install\' before configuring servers.', inputSchema: { type: 'object', properties: { command: { type: 'string', description: 'Command to execute (e.g., \'npm\', \'pip\', \'python\', \'node\')', minLength: 1 }, args: { type: 'array', items: { type: 'string' }, description: 'Array of command arguments (e.g., [\'install\', \'package-name\'])', default: [] }, timeout: { type: 'number', description: 'Command timeout in milliseconds', default: 30000, minimum: 1000, maximum: 300000 }, working_directory: { type: 'string', description: 'Directory to run the command in (defaults to current working directory)' }, capture_output: { type: 'boolean', description: 'Whether to capture and return stdout/stderr', default: true } }, required: ['command'], }, async execute(args, context) { try { const timeout = args.timeout || 30000; const commandArgs = args.args || []; // Build the full command for the CLI // The CLI exec command takes: toolflow exec <command> [args...] const cliArgs = [args.command, ...commandArgs]; const cliCommand = `npx @grebyn/toolflow-cli@latest exec ${cliArgs.join(' ')}`; // Add working directory option if provided let finalCommand = cliCommand; if (args.working_directory) { // The CLI might not support working directory directly, so we'll use shell cd if (process.platform === 'win32') { finalCommand = `cd "${args.working_directory}" && ${cliCommand}`; } else { finalCommand = `cd "${args.working_directory}" && ${cliCommand}`; } } const startTime = Date.now(); try { // Execute the command via CLI const { stdout, stderr } = await execAsync(finalCommand, { timeout, maxBuffer: 1024 * 1024 // 1MB buffer }); const executionTime = Date.now() - startTime; return { content: [ { type: 'text', text: formatCommandResult({ success: true, command_line: `${args.command} ${commandArgs.join(' ')}`, exit_code: 0, stdout: args.capture_output !== false ? stdout : '', stderr: args.capture_output !== false ? stderr : '', execution_time: executionTime }) } ] }; } catch (error) { const executionTime = Date.now() - startTime; // Handle command execution errors const isTimeout = error.killed && error.signal === 'SIGTERM'; return { content: [ { type: 'text', text: formatCommandResult({ success: false, command_line: `${args.command} ${commandArgs.join(' ')}`, exit_code: error.code || -1, stdout: args.capture_output !== false ? (error.stdout?.toString() || '') : '', stderr: args.capture_output !== false ? (isTimeout ? `Command timed out after ${timeout}ms` : (error.stderr?.toString() || error.message)) : '', execution_time: executionTime }) } ] }; } } catch (error) { console.error(`System command execution failed: ${error.message}`); return { content: [ { type: 'text', text: `**System Command Execution Failed**\n\nError: ${error.message}\n\nThis indicates a system-level issue with command execution.` } ] }; } } }; /** * Format command execution result for display */ function formatCommandResult(result) { const status = result.success ? 'Success' : 'Failed'; let output = `**Command Execution ${status}**\n\n`; output += `**Command**: \`${result.command_line}\`\n`; output += `**Exit Code**: ${result.exit_code}\n`; output += `**Execution Time**: ${result.execution_time}ms\n\n`; // Show stdout if present if (result.stdout && result.stdout.trim()) { output += `**Output:**\n\`\`\`\n${result.stdout.trim()}\n\`\`\`\n\n`; } // Show stderr if present (could be warnings even on success) if (result.stderr && result.stderr.trim()) { const errorLabel = result.success ? 'Warnings/Info' : 'Error Output'; output += `**${errorLabel}:**\n\`\`\`\n${result.stderr.trim()}\n\`\`\`\n\n`; } if (!result.success) { output += `**Troubleshooting Tips:**\n`; const errorLower = result.stderr.toLowerCase(); if (result.exit_code === 127 || errorLower.includes('not found') || errorLower.includes('is not recognized')) { output += `- Command not found: Ensure the command is installed and in your PATH\n`; output += `- Check spelling and verify the command exists on your system\n`; } else if (errorLower.includes('permission denied') || errorLower.includes('eacces')) { output += `- Permission denied: Try running with administrator/sudo privileges\n`; output += `- Check file and directory permissions\n`; } else if (errorLower.includes('timeout') || errorLower.includes('timed out')) { output += `- Command timed out: Increase the timeout value or check for hung processes\n`; } else if (result.exit_code !== 0) { output += `- Non-zero exit code indicates the command failed\n`; output += `- Check the error output above for specific details\n`; } output += `- For package installation commands, ensure you have internet connectivity\n`; output += `- For version check commands, ensure the software is properly installed\n`; } else { // Success case - provide helpful context based on command const cmdLower = result.command_line.toLowerCase(); if (cmdLower.includes('--version') || cmdLower.includes('-v')) { output += `**Version Check**: The command executed successfully and the software is available.\n`; } else if (cmdLower.includes('install')) { output += `**Installation**: The package installation appears to have completed successfully.\n`; } else if (cmdLower.includes('test') || cmdLower.includes('start')) { output += `**Service Test**: The command executed successfully, indicating the service is working.\n`; } } return output; } //# sourceMappingURL=run-system-command.js.map