fusion-mcp-cli
Version:
CLI tool for Fusion MCP Hub - Manage custom and community MCP servers. Web App: https://fusion-mcp-hub.vercel.app (General) | https://fusion-mcp-prod.isc-code-connect.dal.app.cirrus.ibm.com (IBM)
264 lines • 10 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;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDefaultServersPath = getDefaultServersPath;
exports.downloadFile = downloadFile;
exports.extractZip = extractZip;
exports.ensureDir = ensureDir;
exports.dirExists = dirExists;
exports.fileExists = fileExists;
exports.readJsonFile = readJsonFile;
exports.writeJsonFile = writeJsonFile;
exports.getLocalServerMetadata = getLocalServerMetadata;
exports.saveLocalServerMetadata = saveLocalServerMetadata;
exports.downloadAndExtractServer = downloadAndExtractServer;
exports.createZipFromDirectory = createZipFromDirectory;
exports.getDirectoryFiles = getDirectoryFiles;
exports.calculateFileHash = calculateFileHash;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const axios_1 = __importDefault(require("axios"));
const adm_zip_1 = __importDefault(require("adm-zip"));
const https = __importStar(require("https"));
const os = __importStar(require("os"));
const config_1 = require("./config");
/**
* Get the default servers directory path
*/
function getDefaultServersPath() {
return path_1.default.join(os.homedir(), ".fusion-mcp", "servers");
}
/**
* Download file from URL
*/
async function downloadFile(url, outputPath) {
const token = (0, config_1.getApiToken)();
// Create HTTPS agent that accepts self-signed certificates for localhost and Cirrus environments
const isLocalhost = url.includes('localhost') || url.includes('127.0.0.1');
const isCirrusEnvironment = url.includes('.cirrus.ibm.com');
const allowSelfSignedCerts = isLocalhost || isCirrusEnvironment;
const httpsAgent = new https.Agent({
rejectUnauthorized: !allowSelfSignedCerts, // Allow self-signed certs for localhost and Cirrus environments
});
const response = await (0, axios_1.default)({
url,
method: "GET",
responseType: "stream",
headers: token
? {
Authorization: `Bearer ${token}`,
}
: undefined,
httpsAgent,
});
const writer = fs_extra_1.default.createWriteStream(outputPath);
response.data.pipe(writer);
return new Promise((resolve, reject) => {
writer.on("finish", resolve);
writer.on("error", reject);
});
}
/**
* Extract zip file to directory
*/
async function extractZip(zipPath, outputDir) {
const zip = new adm_zip_1.default(zipPath);
zip.extractAllTo(outputDir, true);
}
/**
* Create directory if it doesn't exist
*/
async function ensureDir(dirPath) {
await fs_extra_1.default.ensureDir(dirPath);
}
/**
* Check if directory exists
*/
function dirExists(dirPath) {
return fs_extra_1.default.existsSync(dirPath) && fs_extra_1.default.statSync(dirPath).isDirectory();
}
/**
* Check if file exists
*/
function fileExists(filePath) {
return fs_extra_1.default.existsSync(filePath) && fs_extra_1.default.statSync(filePath).isFile();
}
/**
* Read JSON file
*/
async function readJsonFile(filePath) {
const content = await fs_extra_1.default.readFile(filePath, "utf-8");
return JSON.parse(content);
}
/**
* Write JSON file
*/
async function writeJsonFile(filePath, data) {
await fs_extra_1.default.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
}
/**
* Get server metadata from local directory
*/
async function getLocalServerMetadata(serverDir) {
const metadataPath = path_1.default.join(serverDir, ".fusion-mcp-metadata.json");
if (!fileExists(metadataPath)) {
return null;
}
return readJsonFile(metadataPath);
}
/**
* Save server metadata to local directory
*/
async function saveLocalServerMetadata(serverDir, metadata) {
const metadataPath = path_1.default.join(serverDir, ".fusion-mcp-metadata.json");
await writeJsonFile(metadataPath, metadata);
}
/**
* Download and extract server package
*/
async function downloadAndExtractServer(serverId, serverName, downloadUrl, outputDir) {
// Create output directory if it doesn't exist
await ensureDir(outputDir);
// Use original server name for directory
const serverDir = path_1.default.join(outputDir, serverName);
// Check if directory already exists
if (dirExists(serverDir)) {
throw new Error(`Directory already exists: ${serverDir}. Please remove it first or use a different output directory.`);
}
// Server directory name (sanitized) for temp file only
const serverDirName = serverName.replace(/[^a-zA-Z0-9-_]/g, "_");
const tempZipPath = path_1.default.join(outputDir, `${serverDirName}.zip`);
const tempExtractDir = path_1.default.join(outputDir, `${serverDirName}_temp`);
try {
await downloadFile(downloadUrl, tempZipPath);
// Extract zip to temp directory
await extractZip(tempZipPath, tempExtractDir);
// Check if contents are in a nested subdirectory
const entries = await fs_extra_1.default.readdir(tempExtractDir, { withFileTypes: true });
// If there's only one subdirectory and no package.json at root, use that subdirectory
const subdirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith("."));
const hasPackageJson = entries.some((e) => e.isFile() && e.name === "package.json");
if (!hasPackageJson && subdirs.length === 1) {
const nestedPath = path_1.default.join(tempExtractDir, subdirs[0].name);
const nestedEntries = await fs_extra_1.default.readdir(nestedPath, {
withFileTypes: true,
});
const hasNestedPackageJson = nestedEntries.some((e) => e.isFile() && e.name === "package.json");
if (hasNestedPackageJson) {
// Nested structure detected, move the nested directory to final location
await fs_extra_1.default.move(nestedPath, serverDir);
}
else {
// No nested package.json, move temp dir as-is
await fs_extra_1.default.move(tempExtractDir, serverDir);
}
}
else {
// No nesting, move temp dir directly
await fs_extra_1.default.move(tempExtractDir, serverDir);
}
// Clean up temp files
await fs_extra_1.default.remove(tempZipPath);
// Clean up temp extract directory if it still exists
if (await fs_extra_1.default.pathExists(tempExtractDir)) {
await fs_extra_1.default.remove(tempExtractDir);
}
if (await fs_extra_1.default.pathExists(tempExtractDir)) {
await fs_extra_1.default.remove(tempExtractDir);
}
return serverDir;
}
catch (error) {
// Clean up on error
if (fileExists(tempZipPath)) {
await fs_extra_1.default.remove(tempZipPath);
}
if (dirExists(tempExtractDir)) {
await fs_extra_1.default.remove(tempExtractDir);
}
if (dirExists(serverDir)) {
await fs_extra_1.default.remove(serverDir);
}
throw error;
}
}
/**
* Create a zip file from directory
*/
async function createZipFromDirectory(sourceDir, outputZipPath) {
const zip = new adm_zip_1.default();
// Add the entire directory
zip.addLocalFolder(sourceDir);
// Write zip file
zip.writeZip(outputZipPath);
}
/**
* Get list of files in directory
*/
async function getDirectoryFiles(dirPath, relativeTo) {
const files = [];
async function walk(dir) {
const entries = await fs_extra_1.default.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path_1.default.join(dir, entry.name);
if (entry.isDirectory()) {
// Skip node_modules and hidden directories
if (entry.name !== "node_modules" && !entry.name.startsWith(".")) {
await walk(fullPath);
}
}
else {
const relativePath = relativeTo
? path_1.default.relative(relativeTo, fullPath)
: fullPath;
files.push(relativePath);
}
}
}
await walk(dirPath);
return files;
}
/**
* Calculate file hash for comparison
*/
async function calculateFileHash(filePath) {
const crypto = require("crypto");
const content = await fs_extra_1.default.readFile(filePath);
return crypto.createHash("sha256").update(content).digest("hex");
}
//# sourceMappingURL=file.js.map