@insforge/install
Version:
CLI tool for installing Insforge MCP servers across different AI clients
135 lines (130 loc) • 4.84 kB
JavaScript
// 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
};