@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
JavaScript
;
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