UNPKG

lokalise-mcp

Version:

The Lokalise MCP Server brings Lokalise's localization power to Claude and AI assistants—manage projects, keys, and translations by chat.

159 lines (158 loc) 6.29 kB
import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import dotenv from "dotenv"; import { Logger } from "./logger.util.js"; /** * Configuration loader that handles multiple sources with priority: * 1. Direct ENV pass (process.env) * 2. .env file in project root * 3. Global config file at $HOME/.mcp/configs.json */ class ConfigLoader { /** * Create a new ConfigLoader instance * @param packageName The package name to use for global config lookup */ constructor(packageName) { this.configLoaded = false; this.packageName = packageName; } /** * Load configuration from all sources with proper priority */ load() { const methodLogger = Logger.forContext("utils/config.util.ts", "load"); if (this.configLoaded) { methodLogger.debug("Configuration already loaded, skipping"); return; } methodLogger.debug("Loading configuration..."); // Priority 3: Load from global config file this.loadFromGlobalConfig(); // Priority 2: Load from .env file this.loadFromEnvFile(); // Priority 1: Direct ENV pass is already in process.env // No need to do anything as it already has highest priority this.configLoaded = true; methodLogger.debug("Configuration loaded successfully"); } /** * Load configuration from .env file in project root */ loadFromEnvFile() { const methodLogger = Logger.forContext("utils/config.util.ts", "loadFromEnvFile"); try { const result = dotenv.config(); if (result.error) { methodLogger.debug("No .env file found or error reading it"); return; } methodLogger.debug("Loaded configuration from .env file"); } catch (error) { methodLogger.error("Error loading .env file", error); } } /** * Load configuration from global config file at $HOME/.mcp/configs.json */ loadFromGlobalConfig() { const methodLogger = Logger.forContext("utils/config.util.ts", "loadFromGlobalConfig"); try { const homedir = os.homedir(); const globalConfigPath = path.join(homedir, ".mcp", "configs.json"); if (!fs.existsSync(globalConfigPath)) { methodLogger.debug("Global config file not found"); return; } const configContent = fs.readFileSync(globalConfigPath, "utf8"); const config = JSON.parse(configContent); // Determine the potential keys for the current package const shortKey = "boilerplate"; // Project-specific short key const fullPackageName = this.packageName; // e.g., '@aashari/boilerplate-mcp-server' const unscopedPackageName = fullPackageName.split("/")[1] || fullPackageName; // e.g., 'boilerplate-mcp-server' const potentialKeys = [shortKey, fullPackageName, unscopedPackageName]; let foundConfigSection = null; let usedKey = null; for (const key of potentialKeys) { if (config[key] && typeof config[key] === "object" && config[key].environments) { foundConfigSection = config[key]; usedKey = key; methodLogger.debug(`Found configuration using key: ${key}`); break; // Stop once found } } if (!foundConfigSection || !foundConfigSection.environments) { methodLogger.debug(`No configuration found for ${this.packageName} using keys: ${potentialKeys.join(", ")}`); return; } const environments = foundConfigSection.environments; for (const [key, value] of Object.entries(environments)) { // Only set if not already defined in process.env if (process.env[key] === undefined) { process.env[key] = String(value); } } methodLogger.debug(`Loaded configuration from global config file using key: ${usedKey}`); } catch (error) { methodLogger.error("Error loading global config file", error); } } /** * Get a configuration value * @param key The configuration key * @param defaultValue The default value if the key is not found * @returns The configuration value or the default value */ get(key, defaultValue) { return process.env[key] || defaultValue; } /** * Get the Lokalise hostname from the configuration * @param defaultValue The default value if the key is not found * @returns The Lokalise hostname or the default value */ getLokaliseHostname(defaultValue) { const value = this.get("LOKALISE_API_HOSTNAME"); if (value === undefined) { return defaultValue; } try { const url = new URL(value); const hostname = url.hostname; const parts = hostname.split("."); // If we have more than 2 parts, include the first subdomain // api.stage.lokalise.cloud → stage.lokalise.cloud // api.lokalise.com → lokalise.com if (parts.length > 2) { return parts.slice(-3).join("."); } if (parts.length >= 2) { return parts.slice(-2).join("."); } return hostname; } catch { return defaultValue; } } /** * Get a boolean configuration value * @param key The configuration key * @param defaultValue The default value if the key is not found * @returns The boolean configuration value or the default value */ getBoolean(key, defaultValue = false) { const value = this.get(key); if (value === undefined) { return defaultValue; } return value.toLowerCase() === "true"; } } // Create and export a singleton instance with the package name from package.json export const config = new ConfigLoader("@aashari/boilerplate-mcp-server");