Skip to main content
Glama
app.config.ts5.66 kB
import { z } from "zod"; /** * Application configuration object * Contains all configuration settings for the application */ export const AppConfigSchema = z.object({ /** Server Configuration */ PORT: z.coerce.number().default(4000), NODE_ENV: z.enum(["development", "production", "test"]).default("development"), /** Home Assistant Configuration */ HASS_HOST: z.string().default("http://homeassistant.local:8123"), HASS_TOKEN: z.string().optional(), /** Speech Features Configuration */ SPEECH: z .object({ ENABLED: z.boolean().default(false), WAKE_WORD_ENABLED: z.boolean().default(false), SPEECH_TO_TEXT_ENABLED: z.boolean().default(false), TEXT_TO_SPEECH_ENABLED: z.boolean().default(false), WHISPER_MODEL_PATH: z.string().default("/models"), WHISPER_MODEL_TYPE: z.string().default("base"), DEFAULT_LANGUAGE: z.string().default("en"), SUPPORTED_LANGUAGES: z.array(z.string()).default(["en", "de", "es", "fr"]), AUTO_DETECT_LANGUAGE: z.boolean().default(false), TTS_PROVIDER: z.string().default("google_translate"), TTS_CACHE_ENABLED: z.boolean().default(true), }) .default({ ENABLED: false, WAKE_WORD_ENABLED: false, SPEECH_TO_TEXT_ENABLED: false, TEXT_TO_SPEECH_ENABLED: false, WHISPER_MODEL_PATH: "/models", WHISPER_MODEL_TYPE: "base", DEFAULT_LANGUAGE: "en", SUPPORTED_LANGUAGES: ["en", "de", "es", "fr"], AUTO_DETECT_LANGUAGE: false, TTS_PROVIDER: "google_translate", TTS_CACHE_ENABLED: true, }), /** Security Configuration */ JWT_SECRET: z.string().default("your-secret-key-must-be-32-char-min"), RATE_LIMIT: z.object({ /** Time window for rate limiting in milliseconds */ windowMs: z.number().default(15 * 60 * 1000), // 15 minutes /** Maximum number of requests per window */ max: z.number().default(100), // limit each IP to 100 requests per windowMs }), /** Server-Sent Events Configuration */ SSE: z.object({ /** Maximum number of concurrent SSE clients */ MAX_CLIENTS: z.number().default(1000), /** Ping interval in milliseconds to keep connections alive */ PING_INTERVAL: z.number().default(30000), // 30 seconds }), /** Logging Configuration */ LOGGING: z.object({ /** Log level (error, warn, info, http, debug) */ LEVEL: z.enum(["error", "warn", "info", "debug", "trace"]).default("info"), /** Directory for log files */ DIR: z.string().default("logs"), /** Maximum log file size before rotation */ MAX_SIZE: z.string().default("20m"), /** Maximum number of days to keep log files */ MAX_DAYS: z.string().default("14d"), /** Whether to compress rotated logs */ COMPRESS: z.boolean().default(false), /** Format for timestamps in logs */ TIMESTAMP_FORMAT: z.string().default("YYYY-MM-DD HH:mm:ss:ms"), /** Whether to include request logging */ LOG_REQUESTS: z.boolean().default(false), }), /** Application Version */ VERSION: z.string().default("0.1.0"), }); /** Type definition for the configuration object */ export type AppConfig = z.infer<typeof AppConfigSchema>; /** Required environment variables that must be set for normal operation */ const requiredEnvVars = ["HASS_TOKEN"] as const; /** * Validate that all required environment variables are set * Throws an error if any required variable is missing * * Skip validation in the following cases: * 1. SMITHERY_SCAN=true (Smithery is scanning for tool capabilities) * 2. HASS_TOKEN is explicitly empty (user intends to run without credentials for discovery) * * This allows Smithery and other MCP clients to discover available tools * before user credentials are configured. Tool execution will still fail * gracefully if credentials are missing. */ const isSmitheryScan = process.env.SMITHERY_SCAN === "true"; const isDiscoveryMode = !process.env.HASS_TOKEN || process.env.HASS_TOKEN === ""; // Only validate in production mode when credentials are expected if (!isSmitheryScan && !isDiscoveryMode) { for (const envVar of requiredEnvVars) { if (!process.env[envVar]) { throw new Error(`Missing required environment variable: ${envVar}`); } } } // Fix NODE_ENV if it's set to "1" if (process.env.NODE_ENV === "1") { console.log('Fixing NODE_ENV from "1" to "development"'); process.env.NODE_ENV = "development"; } // Load and validate configuration export const APP_CONFIG = AppConfigSchema.parse({ PORT: process.env.PORT || 4000, NODE_ENV: process.env.NODE_ENV, HASS_HOST: process.env.HASS_HOST || "http://192.168.178.63:8123", HASS_TOKEN: process.env.HASS_TOKEN, JWT_SECRET: process.env.JWT_SECRET || "your-secret-key", RATE_LIMIT: { windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // limit each IP to 100 requests per windowMs }, SSE: { MAX_CLIENTS: 1000, PING_INTERVAL: 30000, // 30 seconds }, LOGGING: { LEVEL: process.env.LOG_LEVEL || "info", DIR: process.env.LOG_DIR || "logs", MAX_SIZE: process.env.LOG_MAX_SIZE || "20m", MAX_DAYS: process.env.LOG_MAX_DAYS || "14d", COMPRESS: process.env.LOG_COMPRESS === "true", TIMESTAMP_FORMAT: "YYYY-MM-DD HH:mm:ss:ms", LOG_REQUESTS: process.env.LOG_REQUESTS === "true", }, VERSION: "0.1.0", SPEECH: { ENABLED: process.env.ENABLE_SPEECH_FEATURES === "true", WAKE_WORD_ENABLED: process.env.ENABLE_WAKE_WORD === "true", SPEECH_TO_TEXT_ENABLED: process.env.ENABLE_SPEECH_TO_TEXT === "true", WHISPER_MODEL_PATH: process.env.WHISPER_MODEL_PATH || "/models", WHISPER_MODEL_TYPE: process.env.WHISPER_MODEL_TYPE || "base", }, });

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/jango-blockchained/advanced-homeassistant-mcp'

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