UNPKG

@insforge/install

Version:

CLI tool for installing Insforge MCP servers across different AI clients

135 lines (130 loc) 4.84 kB
// src/client-config.ts import fs from "fs"; import os from "os"; import path from "path"; import process from "process"; // src/logger.ts import { createConsola } from "consola"; var logger = createConsola({}); var verbose = (msg) => logger.verbose(msg); // src/client-config.ts var homeDir = os.homedir(); var platformPaths = { win32: { baseDir: process.env.APPDATA || path.join(homeDir, "AppData", "Roaming"), vscodePath: path.join("Code", "User", "globalStorage") }, darwin: { baseDir: path.join(homeDir, "Library", "Application Support"), vscodePath: path.join("Code", "User", "globalStorage") }, linux: { baseDir: process.env.XDG_CONFIG_HOME || path.join(homeDir, ".config"), vscodePath: path.join("Code/User/globalStorage") } }; var platform = process.platform; var { baseDir, vscodePath } = platformPaths[platform]; var clientPaths = { "claude-code": { type: "file", path: path.join(homeDir, ".claude", "claude_mcp_config.json") }, cursor: { type: "file", path: path.join(homeDir, ".cursor", "mcp.json"), localPath: path.join(process.cwd(), ".cursor", "mcp.json") }, windsurf: { type: "file", path: path.join(homeDir, ".codeium", "windsurf", "mcp_config.json") }, cline: { type: "file", path: path.join(baseDir, vscodePath, "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json") }, roocode: { type: "file", path: path.join(baseDir, vscodePath, "rooveterinaryinc.roo-cline", "settings", "mcp_settings.json") } }; var clientNames = Object.keys(clientPaths); function getConfigPath(client, local) { const normalizedClient = client?.toLowerCase() || "claude-code"; verbose(`Getting config path for client: ${normalizedClient}${local ? " (local)" : ""}`); const configTarget = clientPaths[normalizedClient]; if (!configTarget) { throw new Error(`Unsupported client: ${client}. Supported clients: ${clientNames.join(", ")}`); } if (local && configTarget.localPath) { verbose(`Using local config path for ${normalizedClient}: ${configTarget.localPath}`); return { ...configTarget, path: configTarget.localPath }; } verbose(`Using default config path for ${normalizedClient}: ${configTarget.path}`); return configTarget; } function readConfig(client, local) { verbose(`Reading config for client: ${client}${local ? " (local)" : ""}`); try { const configPath = getConfigPath(client, local); verbose(`Checking if config file exists at: ${configPath.path}`); if (!fs.existsSync(configPath.path)) { verbose("Config file not found, returning default empty config"); // Return appropriate default structure for each client return { mcpServers: {} }; } verbose("Reading config file content"); const rawConfig = JSON.parse(fs.readFileSync(configPath.path, "utf8")); verbose(`Config loaded successfully: ${JSON.stringify(rawConfig, null, 2)}`); // Return the raw config to preserve existing structure return rawConfig; } catch (error) { verbose(`Error reading config: ${error instanceof Error ? error.stack : JSON.stringify(error)}`); return { mcpServers: {} }; } } function writeConfig(config, client, local) { verbose(`Writing config for client: ${client || "default"}${local ? " (local)" : ""}`); verbose(`Config data: ${JSON.stringify(config, null, 2)}`); // All clients use mcpServers if (!config.mcpServers || typeof config.mcpServers !== "object") { verbose("Invalid mcpServers structure in config"); throw new Error("Invalid mcpServers structure"); } const configPath = getConfigPath(client, local); writeConfigFile(config, configPath); } function writeConfigFile(config, target) { const configDir = path.dirname(target.path); verbose(`Ensuring config directory exists: ${configDir}`); if (!fs.existsSync(configDir)) { verbose(`Creating directory: ${configDir}`); fs.mkdirSync(configDir, { recursive: true }); } let existingConfig = { mcpServers: {} }; try { if (fs.existsSync(target.path)) { verbose("Reading existing config file for merging"); existingConfig = JSON.parse(fs.readFileSync(target.path, "utf8")); verbose(`Existing config loaded: ${JSON.stringify(existingConfig, null, 2)}`); } } catch (error) { verbose(`Error reading existing config for merge: ${error instanceof Error ? error.message : String(error)}`); } verbose("Merging configs"); const mergedConfig = { ...existingConfig, ...config }; verbose(`Merged config: ${JSON.stringify(mergedConfig, null, 2)}`); verbose(`Writing config to file: ${target.path}`); fs.writeFileSync(target.path, JSON.stringify(mergedConfig, null, 2)); verbose("Config successfully written"); } export { logger, clientNames, getConfigPath, readConfig, writeConfig };