Skip to main content
Glama
config-loader.ts8.14 kB
import { readFileSync } from "fs"; import { Config, ConfigSchema } from "./types.js"; export interface ConfigOptions { configFile?: string; baseUrl?: string; swaggerUrl?: string; authType?: "token" | "login"; token?: string; username?: string; password?: string; loginEndpoint?: string; tokenField?: string; timeout?: number; retries?: number; } export class ConfigLoader { static loadConfig(): Config { // 1. Try to load from command line arguments const args = process.argv.slice(2); const cliConfig = this.parseCliArgs(args); // 2. Try to load from environment variables const envConfig = this.parseEnvVars(); // 3. Try to load from config file (if specified) let fileConfig: Partial<Config> = {}; const configFile = cliConfig.configFile || envConfig.configFile || process.env.MCP_REST_CONFIG_FILE; if (configFile) { try { const fileContent = readFileSync(configFile, "utf-8"); fileConfig = JSON.parse(fileContent); } catch (error) { console.warn( `Warning: Could not load config file ${configFile}:`, error instanceof Error ? error.message : "Unknown error" ); } } // 4. Merge configurations (CLI > ENV > FILE) - only merge defined values const mergedConfig = { ...fileConfig }; // Merge environment variables (only defined values) Object.entries(envConfig).forEach(([key, value]) => { if (value !== undefined) { (mergedConfig as any)[key] = value; } }); // Merge CLI arguments (only defined values) Object.entries(cliConfig).forEach(([key, value]) => { if (value !== undefined) { (mergedConfig as any)[key] = value; } }); // 5. Build the final configuration const config = this.buildConfig(mergedConfig); // 6. Validate the configuration try { return ConfigSchema.parse(config); } catch (error) { throw new Error( `Invalid configuration: ${ error instanceof Error ? error.message : "Unknown error" }` ); } } private static parseCliArgs(args: string[]): Partial<ConfigOptions> { const config: Partial<ConfigOptions> = {}; for (let i = 0; i < args.length; i++) { const arg = args[i]; const nextArg = args[i + 1]; switch (arg) { case "--config": case "-c": config.configFile = nextArg; i++; break; case "--base-url": config.baseUrl = nextArg; i++; break; case "--swagger-url": config.swaggerUrl = nextArg; i++; break; case "--auth-type": config.authType = nextArg as "token" | "login"; i++; break; case "--token": config.token = nextArg; i++; break; case "--username": config.username = nextArg; i++; break; case "--password": config.password = nextArg; i++; break; case "--login-endpoint": config.loginEndpoint = nextArg; i++; break; case "--token-field": config.tokenField = nextArg; i++; break; case "--timeout": config.timeout = parseInt(nextArg, 10); i++; break; case "--retries": config.retries = parseInt(nextArg, 10); i++; break; } } return config; } private static parseEnvVars(): Partial<ConfigOptions> { return { configFile: process.env.MCP_REST_CONFIG_FILE, baseUrl: process.env.MCP_REST_BASE_URL, swaggerUrl: process.env.MCP_REST_SWAGGER_URL, authType: process.env.MCP_REST_AUTH_TYPE as "token" | "login", token: process.env.MCP_REST_TOKEN, username: process.env.MCP_REST_USERNAME, password: process.env.MCP_REST_PASSWORD, loginEndpoint: process.env.MCP_REST_LOGIN_ENDPOINT, tokenField: process.env.MCP_REST_TOKEN_FIELD, timeout: process.env.MCP_REST_TIMEOUT ? parseInt(process.env.MCP_REST_TIMEOUT, 10) : undefined, retries: process.env.MCP_REST_RETRIES ? parseInt(process.env.MCP_REST_RETRIES, 10) : undefined, }; } private static buildConfig( options: Partial<ConfigOptions> & Partial<Config> ): Partial<Config> { // Handle direct config object (from file) if ( options.auth && typeof options.auth === "object" && "type" in options.auth ) { return options as Config; } // Handle flattened options (from CLI/env) if (!options.baseUrl) { throw new Error( "Base URL is required. Provide it via --base-url, MCP_REST_BASE_URL, or config file." ); } if (!options.authType) { throw new Error( "Auth type is required. Provide it via --auth-type, MCP_REST_AUTH_TYPE, or config file." ); } let auth; if (options.authType === "token") { if (!options.token) { throw new Error( "Token is required for token authentication. Provide it via --token, MCP_REST_TOKEN, or config file." ); } auth = { type: "token" as const, token: options.token, }; } else if (options.authType === "login") { if (!options.username || !options.password || !options.loginEndpoint) { throw new Error( "Username, password, and login endpoint are required for login authentication." ); } auth = { type: "login" as const, username: options.username, password: options.password, loginEndpoint: options.loginEndpoint, tokenField: options.tokenField || "access_token", }; } else { throw new Error(`Invalid auth type: ${options.authType}`); } return { baseUrl: options.baseUrl, swaggerUrl: options.swaggerUrl, auth, timeout: options.timeout || 30000, retries: options.retries || 3, }; } static printUsage(): void { console.log(` MCP REST Server Configuration Options: Command Line Arguments: -c, --config <file> Path to JSON configuration file --base-url <url> Base URL for the REST API (required) --swagger-url <url> URL to Swagger/OpenAPI documentation --auth-type <type> Authentication type: 'token' or 'login' (required) --token <token> API token (required for token auth) --username <username> Username (required for login auth) --password <password> Password (required for login auth) --login-endpoint <path> Login endpoint path (required for login auth) --token-field <field> Token field name in login response (default: access_token) --timeout <ms> Request timeout in milliseconds (default: 30000) --retries <count> Number of retries for failed requests (default: 3) Environment Variables: MCP_REST_CONFIG_FILE Path to JSON configuration file MCP_REST_BASE_URL Base URL for the REST API MCP_REST_SWAGGER_URL URL to Swagger/OpenAPI documentation MCP_REST_AUTH_TYPE Authentication type: 'token' or 'login' MCP_REST_TOKEN API token MCP_REST_USERNAME Username MCP_REST_PASSWORD Password MCP_REST_LOGIN_ENDPOINT Login endpoint path MCP_REST_TOKEN_FIELD Token field name in login response MCP_REST_TIMEOUT Request timeout in milliseconds MCP_REST_RETRIES Number of retries for failed requests Examples: # Token authentication via command line node dist/index.js --base-url https://api.example.com --auth-type token --token your-token # Login authentication via environment variables MCP_REST_BASE_URL=https://api.example.com MCP_REST_AUTH_TYPE=login MCP_REST_USERNAME=user MCP_REST_PASSWORD=pass MCP_REST_LOGIN_ENDPOINT=/auth/login node dist/index.js # Using a configuration file node dist/index.js --config ./api-config.json `); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/gyuco/mcp-http-client'

If you have feedback or need assistance with the MCP directory API, please join our Discord server