UNPKG

@aurracloud/mcp-cli

Version:

A command-line tool to install, manage, and setup MCP (Model Context Protocol) servers with Docker support

325 lines 12.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.checkDockerAvailability = checkDockerAvailability; exports.ensureDockerImage = ensureDockerImage; exports.hasDockerfile = hasDockerfile; exports.hasPythonPackageFiles = hasPythonPackageFiles; exports.hasNodePackageFiles = hasNodePackageFiles; exports.detectRuntimeType = detectRuntimeType; exports.generateDockerImageName = generateDockerImageName; exports.buildDockerImage = buildDockerImage; exports.dockerImageExists = dockerImageExists; exports.detectAndBuildCustomDockerImage = detectAndBuildCustomDockerImage; exports.getDefaultNodeDockerImage = getDefaultNodeDockerImage; exports.getDefaultPythonDockerImage = getDefaultPythonDockerImage; exports.getDefaultDockerImage = getDefaultDockerImage; exports.ensureDefaultRuntimeImage = ensureDefaultRuntimeImage; exports.detectRuntimeAndBuildImage = detectRuntimeAndBuildImage; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const logger_1 = require("./utils/logger"); const child_process_1 = require("child_process"); const util_1 = require("util"); const execPromise = (0, util_1.promisify)(child_process_1.exec); const NODE_DOCKER_IMAGE = "node:latest"; const PYTHON_DOCKER_IMAGE = "ghcr.io/astral-sh/uv:latest"; /** * Checks if Docker is installed and running */ async function checkDockerAvailability() { try { await execPromise('docker --version'); // Check if Docker daemon is running await execPromise('docker info'); return true; } catch (error) { return false; } } /** * Checks if a Docker image is available locally and pulls it if not */ async function ensureDockerImage(imageName) { try { // Check if image exists locally const { stdout } = await execPromise(`docker images -q ${imageName}`); if (!stdout.trim()) { logger_1.logger.info(`Docker image ${imageName} not found locally. Pulling now...`); // Pull the image await execPromise(`docker pull ${imageName}`); logger_1.logger.success(`Successfully pulled ${imageName}`); } else { logger_1.logger.info(`Docker image ${imageName} is already available`); } return true; } catch (error) { logger_1.logger.error(`Failed to ensure Docker image ${imageName}`, error); return false; } } /** * Checks if a Dockerfile exists in the given directory */ function hasDockerfile(directoryPath) { logger_1.logger.info(`Checking for Dockerfile in ${directoryPath}`); const dockerfilePath = path.join(directoryPath, 'Dockerfile'); logger_1.logger.info(`Dockerfile path: ${dockerfilePath}`); return fs.existsSync(dockerfilePath); } /** * Checks if Python package files exist in the given directory */ function hasPythonPackageFiles(directoryPath) { const pythonFiles = [ 'pyproject.toml', 'setup.py', 'requirements.txt', 'Pipfile', 'poetry.lock' ]; return pythonFiles.some(file => fs.existsSync(path.join(directoryPath, file))); } /** * Checks if Node package files exist in the given directory */ function hasNodePackageFiles(directoryPath) { const nodeFiles = [ 'package.json', 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml' ]; return nodeFiles.some(file => fs.existsSync(path.join(directoryPath, file))); } /** * Detects the runtime type based on package files in the directory */ function detectRuntimeType(directoryPath) { const hasPython = hasPythonPackageFiles(directoryPath); const hasNode = hasNodePackageFiles(directoryPath); // If both are present, prefer the one with more specific files if (hasPython && hasNode) { // Check for more specific indicators if (fs.existsSync(path.join(directoryPath, 'pyproject.toml'))) { return 'python'; } if (fs.existsSync(path.join(directoryPath, 'package.json'))) { return 'node'; } } if (hasPython) { return 'python'; } // Default to node if no clear indicators or only node files return 'node'; } /** * Generates a Docker image name from package name and version */ function generateDockerImageName(packageName, version) { // Clean package name for Docker image naming const cleanName = packageName .replace(/[@\/]/g, '-') .replace(/[^a-zA-Z0-9\-_.]/g, '') .toLowerCase(); const versionTag = version ? `:${version}` : ':latest'; return `mcp-${cleanName}${versionTag}`; } /** * Builds a Docker image from a Dockerfile in the given directory */ async function buildDockerImage(directoryPath, imageName, packageName, dockerfilePath) { try { logger_1.logger.info(`Building Docker image ${imageName} from Dockerfile...`); // Determine the Dockerfile path relative to the build context let dockerfileArg = 'Dockerfile'; if (dockerfilePath && dockerfilePath !== directoryPath) { // Calculate relative path from build context to Dockerfile dockerfileArg = path.relative(directoryPath, path.join(dockerfilePath, 'Dockerfile')); } // Build the Docker image const buildCommand = `docker build -t ${imageName} -f ${dockerfileArg} .`; logger_1.logger.info(`Running: ${buildCommand}`); logger_1.logger.info(`Build context: ${directoryPath}`); if (dockerfilePath && dockerfilePath !== directoryPath) { logger_1.logger.info(`Dockerfile location: ${dockerfilePath}`); } const { stdout, stderr } = await execPromise(buildCommand, { cwd: directoryPath, maxBuffer: 1024 * 1024 * 10 // 10MB buffer for build output }); if (stderr && !stderr.includes('WARNING')) { logger_1.logger.warn(`Docker build warnings: ${stderr}`); } logger_1.logger.success(`Successfully built Docker image ${imageName}`); return true; } catch (error) { logger_1.logger.error(`Failed to build Docker image ${imageName}`, error); // Log the error output for debugging if (error.stderr) { logger_1.logger.error(`Docker build error output: ${error.stderr}`); } return false; } } /** * Checks if a Docker image exists locally */ async function dockerImageExists(imageName) { try { const { stdout } = await execPromise(`docker images -q ${imageName}`); return stdout.trim().length > 0; } catch (error) { return false; } } /** * Detects and builds custom Docker image if Dockerfile is present */ async function detectAndBuildCustomDockerImage(packageName, clonePath, packageVersion, dockerfilePath, buildContext, runtime = 'node') { if (!clonePath) { return { useCustomImage: false }; } // Determine where to look for the Dockerfile and where to build from const dockerfileLocation = dockerfilePath || clonePath; const buildContextPath = buildContext || clonePath; if (!hasDockerfile(dockerfileLocation)) { return { useCustomImage: false }; } logger_1.logger.info(`🐳 Dockerfile detected in ${packageName} repository!`); const imageName = generateDockerImageName(packageName, packageVersion); // Check if image already exists const imageExists = await dockerImageExists(imageName); if (imageExists) { logger_1.logger.info(`Docker image ${imageName} already exists locally`); return { useCustomImage: true, imageName }; } logger_1.logger.info(`BuildDockerImage: ${buildContextPath}, ${imageName}, ${packageName}, ${dockerfileLocation}`); // Build the custom Docker image from the correct context const buildSuccess = await buildDockerImage(buildContextPath, imageName, packageName, dockerfileLocation); if (buildSuccess) { logger_1.logger.success(`✅ Custom Docker image ${imageName} built successfully!`); return { useCustomImage: true, imageName }; } else { // this could be because of the cwd is pointing at the repo root, not the server root // so we need to try again with the server root as the cwd const buildSuccess = await buildDockerImage(dockerfileLocation, imageName, packageName, dockerfileLocation); if (buildSuccess) { logger_1.logger.success(`✅ Custom Docker image ${imageName} built successfully!`); return { useCustomImage: true, imageName }; } const fallbackRuntime = runtime === 'node' ? 'Node' : 'Python'; logger_1.logger.warn(`❌ Failed to build custom Docker image, falling back to generic ${fallbackRuntime} image`); return { useCustomImage: false }; } } /** * Gets the default Node Docker image name */ function getDefaultNodeDockerImage() { return NODE_DOCKER_IMAGE; } /** * Gets the default Python Docker image name */ function getDefaultPythonDockerImage() { return PYTHON_DOCKER_IMAGE; } /** * Gets the default Docker image for a given runtime type */ function getDefaultDockerImage(runtime) { switch (runtime) { case 'node': return NODE_DOCKER_IMAGE; case 'python': return PYTHON_DOCKER_IMAGE; default: throw new Error(`Unsupported runtime type: ${runtime}`); } } /** * Ensures the default Docker image for a runtime is available */ async function ensureDefaultRuntimeImage(runtime) { const imageName = getDefaultDockerImage(runtime); return ensureDockerImage(imageName); } /** * Detects runtime and builds custom Docker image with automatic fallback */ async function detectRuntimeAndBuildImage(packageName, clonePath, packageVersion, dockerfilePath, buildContext, forceRuntime) { if (!dockerfilePath) { logger_1.logger.info(`No dockerfilePath provided, using clonePath: ${clonePath}`); } if (!clonePath) { const defaultRuntime = forceRuntime || 'node'; return { useCustomImage: false, runtime: defaultRuntime, fallbackImage: getDefaultDockerImage(defaultRuntime) }; } // Detect runtime type if not forced const detectedRuntime = forceRuntime || detectRuntimeType(clonePath); logger_1.logger.info(`🔍 Detected runtime: ${detectedRuntime}`); // Try to build custom image const customImageResult = await detectAndBuildCustomDockerImage(packageName, clonePath, packageVersion, dockerfilePath, buildContext, detectedRuntime); const fallbackImage = getDefaultDockerImage(detectedRuntime); if (customImageResult.useCustomImage) { return { useCustomImage: true, imageName: customImageResult.imageName, runtime: detectedRuntime }; } else { // Ensure fallback image is available await ensureDefaultRuntimeImage(detectedRuntime); return { useCustomImage: false, runtime: detectedRuntime, fallbackImage }; } } //# sourceMappingURL=docker.js.map