UNPKG

@felixallistar/coolify-mcp

Version:

Model Context Protocol server for Coolify API integration

528 lines (527 loc) 22.2 kB
import chalk from 'chalk'; import { applicationsHandler } from '../../mcp/tools/applications.js'; export function registerApplicationsCommands(program) { const apps = program.command('apps') .description('Manage applications'); // List applications apps.command('list') .description('List all applications') .action(async () => { try { const result = await applicationsHandler({ operation: 'list' }); console.log(chalk.green('Applications:')); if (Array.isArray(result.data)) { console.table(result.data.map((app) => ({ id: app.uuid, name: app.name, status: app.status, type: app.type, repository: app.git_repository || 'N/A', branch: app.git_branch || 'N/A' }))); } else { console.log(result.data); } } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); // Get application details apps.command('get <id>') .description('Get application details') .action(async (id) => { try { const result = await applicationsHandler({ operation: 'get', id }); console.log(chalk.green('Application Details:')); console.log(JSON.stringify(result.data, null, 2)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); // Create applications apps.command('create-public') .description('Create a new public application') .requiredOption('--name <name>', 'Application name') .requiredOption('--repository <repo>', 'Git repository URL') .requiredOption('--project <projectId>', 'Project ID') .option('--branch <branch>', 'Git branch', 'main') .option('--build-command <command>', 'Build command') .option('--start-command <command>', 'Start command') .option('--description <description>', 'Application description') .action(async (options) => { try { const body = JSON.stringify({ name: options.name, repository: options.repository, projectUuid: options.project, branch: options.branch, ...(options.buildCommand && { build_command: options.buildCommand }), ...(options.startCommand && { start_command: options.startCommand }), ...(options.description && { description: options.description }) }); const result = await applicationsHandler({ operation: 'create_public', body }); console.log(chalk.green('Public application created:')); console.log(JSON.stringify(result.data, null, 2)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); apps.command('create-private-github') .description('Create a new private GitHub application') .requiredOption('--name <name>', 'Application name') .requiredOption('--repository <repo>', 'Private Git repository URL') .requiredOption('--project <projectId>', 'Project ID') .requiredOption('--github-app-id <appId>', 'GitHub App ID') .requiredOption('--github-installation-id <installationId>', 'GitHub Installation ID') .option('--branch <branch>', 'Git branch', 'main') .option('--build-command <command>', 'Build command') .option('--start-command <command>', 'Start command') .action(async (options) => { try { const body = JSON.stringify({ name: options.name, repository: options.repository, projectUuid: options.project, branch: options.branch, github_app_id: options.githubAppId, github_installation_id: options.githubInstallationId, ...(options.buildCommand && { build_command: options.buildCommand }), ...(options.startCommand && { start_command: options.startCommand }) }); const result = await applicationsHandler({ operation: 'create_private_gh', body }); console.log(chalk.green('Private GitHub application created:')); console.log(JSON.stringify(result.data, null, 2)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); apps.command('create-private-key') .description('Create a new private application with deploy key') .requiredOption('--name <name>', 'Application name') .requiredOption('--repository <repo>', 'Private Git repository URL') .requiredOption('--project <projectId>', 'Project ID') .requiredOption('--private-key-id <keyId>', 'Private key ID for repository access') .option('--branch <branch>', 'Git branch', 'main') .option('--build-command <command>', 'Build command') .option('--start-command <command>', 'Start command') .action(async (options) => { try { const body = JSON.stringify({ name: options.name, repository: options.repository, projectUuid: options.project, branch: options.branch, private_key_id: options.privateKeyId, ...(options.buildCommand && { build_command: options.buildCommand }), ...(options.startCommand && { start_command: options.startCommand }) }); const result = await applicationsHandler({ operation: 'create_private_key', body }); console.log(chalk.green('Private key application created:')); console.log(JSON.stringify(result.data, null, 2)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); apps.command('create-dockerfile') .description('Create a new application from Dockerfile') .requiredOption('--name <name>', 'Application name') .requiredOption('--repository <repo>', 'Git repository URL') .requiredOption('--project <projectId>', 'Project ID') .option('--branch <branch>', 'Git branch', 'main') .option('--dockerfile-path <path>', 'Path to Dockerfile', 'Dockerfile') .option('--build-context <context>', 'Build context path', '.') .action(async (options) => { try { const body = JSON.stringify({ name: options.name, repository: options.repository, projectUuid: options.project, branch: options.branch, dockerfile_path: options.dockerfilePath, build_context: options.buildContext }); const result = await applicationsHandler({ operation: 'create_dockerfile', body }); console.log(chalk.green('Dockerfile application created:')); console.log(JSON.stringify(result.data, null, 2)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); apps.command('create-docker-image') .description('Create a new application from Docker image') .requiredOption('--name <name>', 'Application name') .requiredOption('--image <image>', 'Docker image name with tag') .requiredOption('--project <projectId>', 'Project ID') .option('--registry-username <username>', 'Registry username') .option('--registry-password <password>', 'Registry password') .action(async (options) => { try { const body = JSON.stringify({ name: options.name, docker_image: options.image, projectUuid: options.project, ...(options.registryUsername && { registry_username: options.registryUsername }), ...(options.registryPassword && { registry_password: options.registryPassword }) }); const result = await applicationsHandler({ operation: 'create_docker_image', body }); console.log(chalk.green('Docker image application created:')); console.log(JSON.stringify(result.data, null, 2)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); apps.command('create-docker-compose') .description('Create a new application from Docker Compose') .requiredOption('--name <name>', 'Application name') .requiredOption('--repository <repo>', 'Git repository URL with docker-compose.yml') .requiredOption('--project <projectId>', 'Project ID') .option('--branch <branch>', 'Git branch', 'main') .option('--compose-file <file>', 'Docker compose file path', 'docker-compose.yml') .action(async (options) => { try { const body = JSON.stringify({ name: options.name, repository: options.repository, projectUuid: options.project, branch: options.branch, docker_compose_file: options.composeFile }); const result = await applicationsHandler({ operation: 'create_docker_compose', body }); console.log(chalk.green('Docker Compose application created:')); console.log(JSON.stringify(result.data, null, 2)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); // Update application apps.command('update <id>') .description('Update an application') .option('--name <name>', 'Application name') .option('--description <description>', 'Application description') .option('--build-command <command>', 'Build command') .option('--start-command <command>', 'Start command') .option('--install-command <command>', 'Install command') .option('--port <port>', 'Application port') .option('--env <env>', 'Environment variables (JSON string)') .action(async (id, options) => { try { const updateData = {}; if (options.name) updateData.name = options.name; if (options.description) updateData.description = options.description; if (options.buildCommand) updateData.build_command = options.buildCommand; if (options.startCommand) updateData.start_command = options.startCommand; if (options.installCommand) updateData.install_command = options.installCommand; if (options.port) updateData.port = parseInt(options.port); if (options.env) updateData.environment = JSON.parse(options.env); const body = JSON.stringify(updateData); const result = await applicationsHandler({ operation: 'update', id, body }); console.log(chalk.green('Application updated:')); console.log(JSON.stringify(result.data, null, 2)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); // Delete application apps.command('delete <id>') .description('Delete an application') .option('--force', 'Force deletion without confirmation') .action(async (id, options) => { try { if (!options.force) { const inquirer = await import('inquirer'); const { confirm } = await inquirer.default.prompt([ { type: 'confirm', name: 'confirm', message: `Are you sure you want to delete application ${id}?`, default: false } ]); if (!confirm) { console.log(chalk.yellow('Deletion cancelled.')); return; } } await applicationsHandler({ operation: 'delete', id }); console.log(chalk.green(`Application ${id} deleted successfully.`)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); // Application control operations apps.command('start <id>') .description('Start an application') .action(async (id) => { try { const result = await applicationsHandler({ operation: 'start', id }); console.log(chalk.green(`Application ${id} started successfully.`)); if (result.data) { console.log(JSON.stringify(result.data, null, 2)); } } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); apps.command('stop <id>') .description('Stop an application') .action(async (id) => { try { const result = await applicationsHandler({ operation: 'stop', id }); console.log(chalk.green(`Application ${id} stopped successfully.`)); if (result.data) { console.log(JSON.stringify(result.data, null, 2)); } } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); apps.command('restart <id>') .description('Restart an application') .action(async (id) => { try { const result = await applicationsHandler({ operation: 'restart', id }); console.log(chalk.green(`Application ${id} restarted successfully.`)); if (result.data) { console.log(JSON.stringify(result.data, null, 2)); } } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); // Application logs apps.command('logs <id>') .description('Get application logs') .option('--lines <number>', 'Number of log lines to retrieve', '100') .action(async (id, options) => { try { const result = await applicationsHandler({ operation: 'get_logs', id }); console.log(chalk.green(`Logs for application ${id}:`)); console.log(result.data); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); // Execute command in application container apps.command('exec <id>') .description('Execute a command inside the application container') .argument('<command>', 'Command to execute inside the container') .option('--interactive', 'Run command interactively (not yet supported)') .action(async (id, command, options) => { try { const body = JSON.stringify({ command }); const result = await applicationsHandler({ operation: 'execute_command', id, body }); console.log(chalk.green(`Command executed in application ${id}:`)); console.log(result.data); } catch (error) { console.error(chalk.red('Error:'), error.message); if (error.message.includes('not available in this Coolify version')) { console.log(chalk.yellow('\nNote: This feature may not be supported in your Coolify version.')); console.log(chalk.yellow('Alternatives:')); console.log(chalk.yellow('1. SSH into your server and run: docker exec <container_name> <command>')); console.log(chalk.yellow('2. Use Coolify\'s web interface if available')); console.log(chalk.yellow('3. Update to a newer Coolify version that supports this feature')); } process.exit(1); } }); // Environment variables management const envs = apps.command('envs') .description('Manage application environment variables'); envs.command('list <id>') .description('List environment variables for an application') .action(async (id) => { try { const result = await applicationsHandler({ operation: 'list_envs', id }); console.log(chalk.green(`Environment variables for application ${id}:`)); if (Array.isArray(result.data)) { console.table(result.data.map((env) => ({ id: env.id, key: env.key, value: env.value?.substring(0, 50) + (env.value?.length > 50 ? '...' : ''), is_secret: env.is_secret || false }))); } else { console.log(JSON.stringify(result.data, null, 2)); } } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); envs.command('create <id>') .description('Create environment variable for an application') .requiredOption('--key <key>', 'Environment variable key') .requiredOption('--value <value>', 'Environment variable value') .option('--is-secret', 'Mark as secret variable') .action(async (id, options) => { try { const body = JSON.stringify({ key: options.key, value: options.value, is_secret: options.isSecret || false }); const result = await applicationsHandler({ operation: 'create_env', id, body }); console.log(chalk.green('Environment variable created:')); console.log(JSON.stringify(result.data, null, 2)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); envs.command('update <id>') .description('Update environment variable for an application') .requiredOption('--env-id <envId>', 'Environment variable ID') .option('--key <key>', 'Environment variable key') .option('--value <value>', 'Environment variable value') .option('--is-secret', 'Mark as secret variable') .action(async (id, options) => { try { const updateData = {}; if (options.key) updateData.key = options.key; if (options.value) updateData.value = options.value; if (options.isSecret !== undefined) updateData.is_secret = options.isSecret; const body = JSON.stringify(updateData); const result = await applicationsHandler({ operation: 'update_env', id, env_id: options.envId, body }); console.log(chalk.green('Environment variable updated:')); console.log(JSON.stringify(result.data, null, 2)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); envs.command('update-bulk <id>') .description('Update multiple environment variables for an application') .requiredOption('--env-vars <envVars>', 'Environment variables as JSON array') .action(async (id, options) => { try { const envVars = JSON.parse(options.envVars); const body = JSON.stringify({ environment_variables: envVars }); const result = await applicationsHandler({ operation: 'update_envs_bulk', id, body }); console.log(chalk.green('Environment variables updated in bulk:')); console.log(JSON.stringify(result.data, null, 2)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); envs.command('delete <id>') .description('Delete environment variable from an application') .requiredOption('--env-id <envId>', 'Environment variable ID') .option('--force', 'Force deletion without confirmation') .action(async (id, options) => { try { if (!options.force) { const inquirer = await import('inquirer'); const { confirm } = await inquirer.default.prompt([ { type: 'confirm', name: 'confirm', message: `Are you sure you want to delete environment variable ${options.envId}?`, default: false } ]); if (!confirm) { console.log(chalk.yellow('Deletion cancelled.')); return; } } await applicationsHandler({ operation: 'delete_env', id, env_id: options.envId }); console.log(chalk.green(`Environment variable ${options.envId} deleted successfully.`)); } catch (error) { console.error(chalk.red('Error:'), error.message); process.exit(1); } }); }