Skip to main content
Glama

Agent MCP

envManager.ts7.96 kB
// Environment Variable Management for Agent-MCP // Handles reading, writing, and managing .env file through TUI import { existsSync, readFileSync, writeFileSync, appendFileSync } from 'fs'; import { join } from 'path'; import { getProjectDir } from './config.js'; export interface EnvVariable { key: string; value: string | undefined; required: boolean; description: string; category: 'embedding' | 'cli' | 'system' | 'optional'; } export const MANAGED_ENV_VARS: EnvVariable[] = [ // Embedding Provider Keys { key: 'OPENAI_API_KEY', value: undefined, required: false, description: 'OpenAI API key for embeddings and chat completion', category: 'embedding' }, { key: 'HUGGINGFACE_API_KEY', value: undefined, required: false, description: 'HuggingFace API key for embedding models', category: 'embedding' }, { key: 'GEMINI_API_KEY', value: undefined, required: false, description: 'Google Gemini API key for embeddings', category: 'embedding' }, { key: 'ANTHROPIC_API_KEY', value: undefined, required: false, description: 'Anthropic Claude API key for CLI agents', category: 'cli' }, // System Configuration { key: 'EMBEDDING_PROVIDER', value: undefined, required: false, description: 'Default embedding provider (openai, ollama, huggingface, gemini)', category: 'system' }, { key: 'MCP_DEBUG', value: undefined, required: false, description: 'Enable debug logging (true/false)', category: 'system' }, // Optional Services { key: 'OLLAMA_HOST', value: undefined, required: false, description: 'Ollama service host URL (default: http://localhost:11434)', category: 'optional' }, { key: 'LOCAL_SERVER_URL', value: undefined, required: false, description: 'Local embedding server URL', category: 'optional' } ]; function getEnvFilePath(): string { return join(getProjectDir(), '.env'); } export function loadEnvFile(): Map<string, string> { const envPath = getEnvFilePath(); const envVars = new Map<string, string>(); if (!existsSync(envPath)) { return envVars; } try { const content = readFileSync(envPath, 'utf-8'); const lines = content.split('\n'); for (const line of lines) { const trimmed = line.trim(); if (trimmed && !trimmed.startsWith('#')) { const equalIndex = trimmed.indexOf('='); if (equalIndex > 0) { const key = trimmed.substring(0, equalIndex).trim(); const value = trimmed.substring(equalIndex + 1).trim() .replace(/^["']/, '') // Remove leading quote .replace(/["']$/, ''); // Remove trailing quote envVars.set(key, value); } } } } catch (error) { console.warn(`Warning: Could not read .env file: ${error}`); } return envVars; } export function saveEnvFile(envVars: Map<string, string>): void { const envPath = getEnvFilePath(); const lines: string[] = []; // Add header comment lines.push('# Agent-MCP Environment Configuration'); lines.push('# Generated by Agent-MCP TUI Configuration'); lines.push('# ' + new Date().toISOString()); lines.push(''); // Group by category const categories = ['embedding', 'cli', 'system', 'optional'] as const; for (const category of categories) { const categoryVars = MANAGED_ENV_VARS.filter(v => v.category === category); if (categoryVars.length === 0) continue; // Category header const categoryName = category.charAt(0).toUpperCase() + category.slice(1); lines.push(`# ${categoryName} Configuration`); for (const envVar of categoryVars) { const value = envVars.get(envVar.key); if (value !== undefined && value !== '') { lines.push(`${envVar.key}="${value}"`); } else { lines.push(`# ${envVar.key}= # ${envVar.description}`); } } lines.push(''); } // Add any other existing vars that aren't managed const existingVars = loadEnvFile(); const otherVars: string[] = []; for (const [key, value] of existingVars) { if (!MANAGED_ENV_VARS.find(v => v.key === key)) { otherVars.push(`${key}="${value}"`); } } if (otherVars.length > 0) { lines.push('# Other Configuration'); lines.push(...otherVars); lines.push(''); } try { writeFileSync(envPath, lines.join('\n')); } catch (error) { console.error(`Error writing .env file: ${error}`); throw error; } } export function getCurrentEnvValues(): Map<string, string> { const current = new Map<string, string>(); const fileVars = loadEnvFile(); for (const envVar of MANAGED_ENV_VARS) { // Priority: process.env > .env file const processValue = process.env[envVar.key]; const fileValue = fileVars.get(envVar.key); if (processValue) { current.set(envVar.key, processValue); } else if (fileValue) { current.set(envVar.key, fileValue); } } return current; } export function setEnvVariable(key: string, value: string): void { const envVars = loadEnvFile(); envVars.set(key, value); saveEnvFile(envVars); // Also update the current process environment process.env[key] = value; } export function removeEnvVariable(key: string): void { const envVars = loadEnvFile(); envVars.delete(key); saveEnvFile(envVars); // Also remove from current process environment delete process.env[key]; } export function validateApiKey(key: string, value: string): { valid: boolean; message?: string } { if (!value || value.trim() === '') { return { valid: false, message: 'API key cannot be empty' }; } // Basic validation patterns for different services switch (key) { case 'OPENAI_API_KEY': if (!value.startsWith('sk-') || value.length < 20) { return { valid: false, message: 'OpenAI API key should start with "sk-" and be at least 20 characters' }; } break; case 'ANTHROPIC_API_KEY': if (!value.startsWith('sk-ant-') || value.length < 20) { return { valid: false, message: 'Anthropic API key should start with "sk-ant-" and be at least 20 characters' }; } break; case 'HUGGINGFACE_API_KEY': if (!value.startsWith('hf_') || value.length < 10) { return { valid: false, message: 'HuggingFace API key should start with "hf_" and be at least 10 characters' }; } break; case 'GEMINI_API_KEY': if (value.length < 10) { return { valid: false, message: 'Gemini API key should be at least 10 characters' }; } break; } return { valid: true }; } export function maskApiKey(value: string): string { if (!value || value.length < 8) { return '***'; } const start = value.substring(0, 4); const end = value.substring(value.length - 4); const middle = '*'.repeat(Math.max(4, value.length - 8)); return `${start}${middle}${end}`; } export function getEnvVariablesByCategory(category: 'embedding' | 'cli' | 'system' | 'optional'): EnvVariable[] { return MANAGED_ENV_VARS.filter(v => v.category === category); } export function reloadEnvironmentVariables(): void { // Reload environment variables from .env file into process.env const envVars = loadEnvFile(); for (const [key, value] of envVars) { process.env[key] = value; } } export function isEnvVariableRequired(key: string, embeddingProvider?: string): boolean { const envVar = MANAGED_ENV_VARS.find(v => v.key === key); if (!envVar) return false; // Dynamic requirements based on selected embedding provider if (embeddingProvider) { switch (key) { case 'OPENAI_API_KEY': return embeddingProvider === 'openai'; case 'HUGGINGFACE_API_KEY': return embeddingProvider === 'huggingface'; case 'GEMINI_API_KEY': return embeddingProvider === 'gemini'; } } return envVar.required; }

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/rinadelph/Agent-MCP'

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