Skip to main content
Glama
by ghrud92
loki-auth.ts5.05 kB
import fs from "fs"; import path from "path"; import yaml from "js-yaml"; import os from "os"; import { z } from "zod"; import { createLogger } from "./logger.js"; import { LokiAuthError, JsonRpcErrorCode } from "./errors.js"; // Config validation using Zod schema const LokiAuthConfigSchema = z.object({ addr: z.string().url().optional(), username: z.string().optional(), password: z.string().optional(), tenant_id: z.string().optional(), bearer_token: z.string().optional(), bearer_token_file: z.string().optional(), ca_file: z.string().optional(), cert_file: z.string().optional(), key_file: z.string().optional(), org_id: z.string().optional(), tls_skip_verify: z.boolean().optional(), }); export type LokiAuthConfig = z.infer<typeof LokiAuthConfigSchema>; export class LokiAuth { private config: LokiAuthConfig = {}; private logger = createLogger("LokiAuth"); constructor() { try { // Load configuration from environment variables this.loadFromEnv(); // Load from config file (lower priority than environment variables) this.loadFromConfigFile(); // Validate configuration this.validateConfig(); this.logger.debug("Authentication configuration loaded", { addr: this.config.addr, }); } catch (error) { this.logger.error("Error loading authentication configuration", { error, }); // Structure error code and details const cause = error as Error; throw new LokiAuthError( "config_load_error", "An error occurred while loading authentication configuration", { cause: cause, details: { message: cause.message, name: cause.name, stack: cause.stack, // Add original error's jsonRpcCode if available errorCode: (cause as { jsonRpcCode?: JsonRpcErrorCode }).jsonRpcCode || JsonRpcErrorCode.ConfigError, }, } ); } } private loadFromEnv() { // Load configuration from environment variables if (process.env.LOKI_ADDR) this.config.addr = process.env.LOKI_ADDR; if (process.env.LOKI_USERNAME) this.config.username = process.env.LOKI_USERNAME; if (process.env.LOKI_PASSWORD) this.config.password = process.env.LOKI_PASSWORD; if (process.env.LOKI_TENANT_ID) this.config.tenant_id = process.env.LOKI_TENANT_ID; if (process.env.LOKI_BEARER_TOKEN) this.config.bearer_token = process.env.LOKI_BEARER_TOKEN; if (process.env.LOKI_BEARER_TOKEN_FILE) this.config.bearer_token_file = process.env.LOKI_BEARER_TOKEN_FILE; if (process.env.LOKI_CA_FILE) this.config.ca_file = process.env.LOKI_CA_FILE; if (process.env.LOKI_CERT_FILE) this.config.cert_file = process.env.LOKI_CERT_FILE; if (process.env.LOKI_KEY_FILE) this.config.key_file = process.env.LOKI_KEY_FILE; if (process.env.LOKI_ORG_ID) this.config.org_id = process.env.LOKI_ORG_ID; if (process.env.LOKI_TLS_SKIP_VERIFY) this.config.tls_skip_verify = process.env.LOKI_TLS_SKIP_VERIFY === "true"; this.logger.debug("Configuration loaded from environment variables"); } private loadFromConfigFile() { // Configuration file paths (in order of priority) const configPaths = [ process.env.LOKI_CONFIG_PATH, // Custom path path.join(process.cwd(), "logcli-config.yaml"), // Current directory path.join(os.homedir(), ".logcli-config.yaml"), // Home directory ].filter(Boolean) as string[]; for (const configPath of configPaths) { if (fs.existsSync(configPath)) { try { const configContent = fs.readFileSync(configPath, "utf8"); const parsedConfig = yaml.load(configContent) as LokiAuthConfig; // Only load values from config file that are not set in environment variables this.config = { ...parsedConfig, ...this.config }; this.logger.debug(`Configuration file loaded: ${configPath}`); break; } catch (error) { this.logger.warn(`Failed to load configuration file: ${configPath}`, { error, }); } } } } // Validate configuration private validateConfig() { try { LokiAuthConfigSchema.parse(this.config); } catch (error) { this.logger.warn("Loki configuration validation failed", { error }); // Only log a warning, don't treat as error (fields are optional) } if (!this.config.addr) { this.logger.warn("Loki server address (addr) is not configured"); } } // Return current configuration info (can be exposed as MCP resource) public getConfig(): Partial<LokiAuthConfig> { // Password and token are excluded // eslint-disable-next-line @typescript-eslint/no-unused-vars const { password, bearer_token, ...safeConfig } = this.config; return safeConfig; } // Check if configuration is valid public isConfigValid(): boolean { return !!this.config.addr; } }

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/ghrud92/loki-mcp'

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