@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
JavaScript
/**
* 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