Skip to main content
Glama
toml-loader.ts7.26 kB
/** * TOML configuration loader for HybridHub * Handles loading and parsing of hybridhub.toml configuration files */ import fs from "fs"; import path from "path"; import TOML from "@iarna/toml"; import type { TomlConfig, DatabaseSourceConfig, StorageSourceConfig, DatabaseToolConfig, StorageToolConfig, } from "../types/config.js"; /** * Find configuration file in standard locations * @param customPath - Optional custom path from CLI argument * @returns Path to config file or null if not found */ export function findConfigFile(customPath?: string): string | null { // If custom path provided, use it directly if (customPath) { if (fs.existsSync(customPath)) { return customPath; } console.error(`Warning: Specified config file not found: ${customPath}`); return null; } // Standard locations to search for config file const searchPaths = [ path.join(process.cwd(), "hybridhub.toml"), path.join(process.cwd(), ".hybridhub.toml"), path.join(process.cwd(), "config", "hybridhub.toml"), ]; for (const configPath of searchPaths) { if (fs.existsSync(configPath)) { return configPath; } } return null; } /** * Parse TOML configuration file * @param configPath - Path to the configuration file * @returns Parsed configuration object */ export function parseTomlFile(configPath: string): TomlConfig { const content = fs.readFileSync(configPath, "utf-8"); const parsed = TOML.parse(content) as any; const config: TomlConfig = { databases: [], storages: [], database_tools: [], storage_tools: [], }; // Parse database sources if (parsed.databases && Array.isArray(parsed.databases)) { config.databases = parsed.databases.map((db: any) => ({ id: db.id, type: db.type, dsn: db.dsn, host: db.host, port: db.port, database: db.database, user: db.user, password: db.password, instanceName: db.instanceName, readonly: db.readonly, max_rows: db.max_rows, connection_timeout: db.connection_timeout, request_timeout: db.request_timeout, ssh_host: db.ssh_host, ssh_port: db.ssh_port, ssh_user: db.ssh_user, ssh_password: db.ssh_password, ssh_key: db.ssh_key, ssh_passphrase: db.ssh_passphrase, } as DatabaseSourceConfig)); } // Parse storage sources if (parsed.storages && Array.isArray(parsed.storages)) { config.storages = parsed.storages.map((storage: any) => ({ id: storage.id, type: storage.type, endpoint: storage.endpoint, access_key: storage.access_key, secret_key: storage.secret_key, region: storage.region, default_bucket: storage.default_bucket, connection_timeout: storage.connection_timeout, security_token: storage.security_token, ssl: storage.ssl, path_style: storage.path_style, } as StorageSourceConfig)); } // Parse database tools if (parsed.database_tools && Array.isArray(parsed.database_tools)) { config.database_tools = parsed.database_tools.map((tool: any) => ({ name: tool.name, description: tool.description, source: tool.source, statement: tool.statement, parameters: tool.parameters, } as DatabaseToolConfig)); } // Parse storage tools if (parsed.storage_tools && Array.isArray(parsed.storage_tools)) { config.storage_tools = parsed.storage_tools.map((tool: any) => ({ name: tool.name, source: tool.source, description: tool.description, operation: tool.operation, filter: tool.filter, parameters: tool.parameters, max_keys: tool.max_keys, max_size: tool.max_size, max_results: tool.max_results, } as StorageToolConfig)); } return config; } /** * Load TOML configuration from file * @param customPath - Optional custom path from CLI argument * @returns Configuration object or null if not found */ export function loadTomlConfig(customPath?: string): TomlConfig | null { const configPath = findConfigFile(customPath); if (!configPath) { return null; } console.error(`Loading configuration from: ${configPath}`); try { return parseTomlFile(configPath); } catch (error) { console.error(`Error parsing config file ${configPath}:`, error); throw error; } } /** * Validate TOML configuration * @param config - Configuration to validate * @returns True if valid, throws error otherwise */ export function validateTomlConfig(config: TomlConfig): boolean { const errors: string[] = []; const sourceIds = new Set<string>(); // Validate database sources if (config.databases) { for (const db of config.databases) { if (!db.id) { errors.push("Database source missing required 'id' field"); } else if (sourceIds.has(db.id)) { errors.push(`Duplicate source ID: ${db.id}`); } else { sourceIds.add(db.id); } // Must have either DSN or type + connection params if (!db.dsn && !db.type) { errors.push(`Database source '${db.id}' must have either 'dsn' or 'type' specified`); } } } // Validate storage sources if (config.storages) { for (const storage of config.storages) { if (!storage.id) { errors.push("Storage source missing required 'id' field"); } else if (sourceIds.has(storage.id)) { errors.push(`Duplicate source ID: ${storage.id}`); } else { sourceIds.add(storage.id); } if (!storage.type) { errors.push(`Storage source '${storage.id}' missing required 'type' field`); } if (!storage.endpoint) { errors.push(`Storage source '${storage.id}' missing required 'endpoint' field`); } if (!storage.access_key) { errors.push(`Storage source '${storage.id}' missing required 'access_key' field`); } if (!storage.secret_key) { errors.push(`Storage source '${storage.id}' missing required 'secret_key' field`); } } } // Validate database tools if (config.database_tools) { for (const tool of config.database_tools) { if (!tool.name) { errors.push("Database tool missing required 'name' field"); } if (!tool.source) { errors.push(`Database tool '${tool.name}' missing required 'source' field`); } else if (!sourceIds.has(tool.source)) { errors.push(`Database tool '${tool.name}' references non-existent source '${tool.source}'`); } if (!tool.statement) { errors.push(`Database tool '${tool.name}' missing required 'statement' field`); } } } // Validate storage tools if (config.storage_tools) { for (const tool of config.storage_tools) { if (!tool.name) { errors.push("Storage tool missing required 'name' field"); } if (!tool.source) { errors.push(`Storage tool '${tool.name}' missing required 'source' field`); } else if (!sourceIds.has(tool.source)) { errors.push(`Storage tool '${tool.name}' references non-existent source '${tool.source}'`); } } } if (errors.length > 0) { throw new Error(`Configuration validation failed:\n${errors.join("\n")}`); } return true; }

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/zq940222/hybrid-mcp'

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