UNPKG

mcp-config

Version:

CLI client to edit MCP server configurations

126 lines 5.21 kB
import inquirer from 'inquirer'; import { getServerConfig } from './serverConfigs.js'; /** * Configure a server with its command, arguments and environment variables */ export const configureServer = async (serverName, existingConfig) => { // Get the server config by name from available server configs const serverConfig = await getServerConfig(serverName); // Collect all arguments (fixed and configurable), passing existing args if available // Initialize result with command and args from the server config const result = { command: serverConfig.command, args: await configureArgs(serverConfig.args, existingConfig?.args), env: await configureEnvVariables(serverConfig.env, existingConfig?.env), }; if (result.args.length === serverConfig.args.fixed.length && (!result.env || Object.keys(result.env).length === 0)) { console.log(`No arguments or environment variables required to configure ${serverName}.`); } return result; }; /** * Configure environment variables for a server */ const configureEnvVariables = async (envVarsToCollect = [], existingEnv = {}) => { // If no environment variables are required, return empty object if (envVarsToCollect.length === 0) { return {}; } // Create a prompt for each environment variable const envVars = {}; for (const envVar of envVarsToCollect) { const varName = envVar.name; const { [varName]: value } = await inquirer.prompt({ type: 'input', name: varName, message: `Enter value for ${varName} (${envVar.description}):`, default: existingEnv[varName] || '', validate: (input) => { if (input.trim() === '') { return `${varName} cannot be empty.`; } return true; }, }); envVars[varName] = value; } return envVars; }; /** * Collect and return all arguments for a server (fixed and configurable) */ const configureArgs = async (serverArgs, existingArgs = []) => { // Get fixed args const fixedArgs = serverArgs.fixed; // If no configurable arguments are required, return only fixed args if (serverArgs.configurable.length === 0) { return [...fixedArgs]; } // Create a prompt for each configurable argument const configurableArgs = []; for (const arg of serverArgs.configurable) { // Find existing value for this argument if available let defaultValue = ''; if (existingArgs.length > 0 && arg.type === 'named') { const flagIndex = existingArgs.findIndex((a) => a === arg.flag); if (flagIndex !== -1 && flagIndex + 1 < existingArgs.length) { defaultValue = existingArgs[flagIndex + 1]; } } else if (existingArgs.length > 0 && arg.type === 'position') { // For positional args, we'd need more context to match them correctly // This is a simplified approach that assumes order matters const argIndex = serverArgs.configurable.findIndex((a) => a.name === arg.name); if (argIndex !== -1) { // Count how many positional args come before this one const positionsBefore = serverArgs.configurable .slice(0, argIndex) .filter((a) => a.type === 'position').length; // Find all positional args in existing args (those not preceded by a flag) const existingPositionalArgs = []; for (let i = 0; i < existingArgs.length; i++) { const isFlag = existingArgs[i].startsWith('-'); if (isFlag) { // Skip the flag and its value i++; } else { existingPositionalArgs.push(existingArgs[i]); } } if (positionsBefore < existingPositionalArgs.length) { defaultValue = existingPositionalArgs[positionsBefore]; } } } const { value } = await inquirer.prompt({ type: 'input', name: 'value', message: `Enter value for ${arg.name} (${arg.description}):`, default: defaultValue, validate: (input) => { if (arg.required && input.trim() === '') { return `argument ${arg.name} cannot be empty.`; } return true; }, }); if (value.trim() !== '') { if (arg.type === 'named') { if (arg.style === 'equals') { configurableArgs.push(`${arg.flag}=${value}`); } else { configurableArgs.push(arg.flag); configurableArgs.push(value); } } else if (arg.type === 'position') { configurableArgs.push(value); } } } return [...fixedArgs, ...configurableArgs]; }; //# sourceMappingURL=configure.js.map