UNPKG

mcpipe

Version:

Decorate stdio MCP servers with debugging and other capabilities.

142 lines (141 loc) 5.05 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.findEnvFilePath = findEnvFilePath; exports.loadEnvironmentVariablesFromFile = loadEnvironmentVariablesFromFile; exports.executeCommand = executeCommand; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const os_1 = __importDefault(require("os")); const child_process_1 = require("child_process"); const ENV_FILENAME = '.env.mcp'; function reportError(message, error) { console.error(message); if (error) { console.error(error); } } /** * Finds the closest .env.mcp file by traversing up the directory tree * @param startDir The directory to start searching from * @returns The path to the found .env.mcp file or undefined if not found */ function findEnvFilePath(startDir = process.cwd()) { let currentDir = startDir; // Continue checking until we reach the root directory while (true) { const envFilePath = path_1.default.join(currentDir, ENV_FILENAME); try { if (fs_1.default.existsSync(envFilePath)) { return envFilePath; } } catch (err) { reportError(`Error checking file at ${envFilePath}:`, err); } // Move up to the parent directory const parentDir = path_1.default.dirname(currentDir); // Stop if we've reached the root directory if (parentDir === currentDir) { break; } currentDir = parentDir; } // Special case: Check for ~/.env.mcp const homeDir = os_1.default.homedir(); const homeEnvFile = path_1.default.join(homeDir, ENV_FILENAME); try { if (fs_1.default.existsSync(homeEnvFile)) { return homeEnvFile; } } catch (err) { reportError(`Error checking file at ${homeEnvFile}:`, err); } return undefined; } /** * Parses an environment file and returns its contents as key-value pairs * @param filePath Path to the environment file * @returns Object containing environment variables */ function parseEnvFile(filePath) { const content = fs_1.default.readFileSync(filePath, 'utf8'); const result = {}; // Split by newlines and process each line const lines = content.split('\n'); for (const line of lines) { // Skip empty lines and comments const trimmedLine = line.trim(); if (!trimmedLine || trimmedLine.startsWith('#')) { continue; } // Parse key=value format const match = trimmedLine.match(/^([^=]+)=(.*)$/); if (match) { const key = match[1].trim(); let value = match[2].trim(); // Remove surrounding quotes if present if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) { value = value.substring(1, value.length - 1); } result[key] = value; } } return result; } /** * Loads environment variables from a file * @param filePath Path to the env file * @returns True if environment variables were loaded, false otherwise */ function loadEnvironmentVariablesFromFile(filePath) { try { const envVars = parseEnvFile(filePath); // Add variables to process.env Object.entries(envVars).forEach(([key, value]) => { process.env[key] = value; }); return true; } catch (error) { reportError(`Error loading ${ENV_FILENAME} file:`, error); return false; } } /** * Executes a command with the given arguments, inheriting stdio. * @param command The command to execute * @param args The arguments for the command * @returns The spawned ChildProcess */ function executeCommand(command, args = []) { var _a, _b; const childProcess = (0, child_process_1.spawn)(command, args, { stdio: ['inherit', 'pipe', 'pipe'], // inherit stdin, pipe stdout/stderr shell: true, env: process.env }); // Pipe child stdout/stderr to parent streams (_a = childProcess.stdout) === null || _a === void 0 ? void 0 : _a.pipe(process.stdout); (_b = childProcess.stderr) === null || _b === void 0 ? void 0 : _b.pipe(process.stderr); // Handle errors during spawn for direct execution as well childProcess.on('error', (err) => { console.error(`[mcpipe] Failed to start child process: ${err.message}`); process.exit(1); }); // Exit mcpipe when the direct child process exits childProcess.on('close', (code, signal) => { if (signal) { console.warn(`[mcpipe] Child process terminated by signal: ${signal}`); process.kill(process.pid, signal); } else { process.exit(code !== null && code !== void 0 ? code : 1); } }); return childProcess; }