Skip to main content
Glama

Industrial MCP Server

by intecrel
secrets-manager.ts5.59 kB
/** * Secrets management utility for secure credential handling */ export interface SecureCredential { value: string masked: string lastAccessed?: Date source: 'environment' | 'file' | 'external' } export class SecretsManager { private static instance: SecretsManager private credentials = new Map<string, SecureCredential>() private constructor() {} static getInstance(): SecretsManager { if (!SecretsManager.instance) { SecretsManager.instance = new SecretsManager() } return SecretsManager.instance } /** * Get a credential value securely */ getSecret(key: string): string | undefined { const credential = this.credentials.get(key) if (credential) { credential.lastAccessed = new Date() return credential.value } // Fallback to environment variable const envValue = process.env[key] if (envValue) { this.credentials.set(key, { value: envValue, masked: this.maskValue(envValue), lastAccessed: new Date(), source: 'environment' }) return envValue } return undefined } /** * Set a credential securely */ setSecret(key: string, value: string, source: 'environment' | 'file' | 'external' = 'external'): void { if (!key || !value) { throw new Error('Key and value are required') } this.credentials.set(key, { value, masked: this.maskValue(value), lastAccessed: new Date(), source }) } /** * Get masked credential for logging */ getMaskedSecret(key: string): string | undefined { const credential = this.credentials.get(key) if (credential) { return credential.masked } const envValue = process.env[key] if (envValue) { return this.maskValue(envValue) } return undefined } /** * Validate that required secrets are available */ validateRequiredSecrets(requiredKeys: string[]): { valid: boolean; missing: string[] } { const missing: string[] = [] for (const key of requiredKeys) { if (!this.getSecret(key)) { missing.push(key) } } return { valid: missing.length === 0, missing } } /** * Get connection string with masked credentials */ getMaskedConnectionString(connectionString: string): string { // Pattern: protocol://username:password@host:port/database return connectionString.replace( /:([^:@]+)@/g, ':***@' ) } /** * Clear all cached credentials (for cleanup) */ clearCache(): void { this.credentials.clear() } /** * Get security audit information */ getSecurityAudit(): { totalSecrets: number secretsBySource: Record<string, number> lastAccessed: Record<string, Date> } { const secretsBySource: Record<string, number> = { environment: 0, file: 0, external: 0 } const lastAccessed: Record<string, Date> = {} Array.from(this.credentials.entries()).forEach(([key, credential]) => { secretsBySource[credential.source]++ if (credential.lastAccessed) { lastAccessed[key] = credential.lastAccessed } }) return { totalSecrets: this.credentials.size, secretsBySource, lastAccessed } } private maskValue(value: string): string { if (!value || value.length <= 4) { return '***' } // For connection strings or URLs if (value.includes('://')) { return this.getMaskedConnectionString(value) } // For API keys or tokens if (value.length > 20) { return value.substring(0, 8) + '...' + value.substring(value.length - 4) } // For passwords return value.substring(0, 2) + '*'.repeat(Math.min(value.length - 4, 6)) + value.substring(value.length - 2) } } /** * Utility function to get secrets manager instance */ export const getSecretsManager = () => SecretsManager.getInstance() /** * Database configuration helper with secure credential handling */ export interface SecureDatabaseConfig { type: 'mysql' | 'neo4j' host?: string port?: number database?: string uri?: string username?: string password?: string ssl?: boolean | object maxConnections?: number timeout?: number } export function createSecureDatabaseConfig( type: 'mysql' | 'neo4j', envPrefix: string ): SecureDatabaseConfig { const secrets = getSecretsManager() const config: SecureDatabaseConfig = { type, host: secrets.getSecret(`${envPrefix}_HOST`), port: parseInt(secrets.getSecret(`${envPrefix}_PORT`) || '0') || undefined, database: secrets.getSecret(`${envPrefix}_DATABASE`), uri: secrets.getSecret(`${envPrefix}_URI`), username: secrets.getSecret(`${envPrefix}_USERNAME`), password: secrets.getSecret(`${envPrefix}_PASSWORD`), maxConnections: parseInt(secrets.getSecret(`${envPrefix}_MAX_CONNECTIONS`) || '10'), timeout: parseInt(secrets.getSecret(`${envPrefix}_TIMEOUT`) || '60000') } // Validate required credentials const requiredKeys = [`${envPrefix}_USERNAME`, `${envPrefix}_PASSWORD`] const validation = secrets.validateRequiredSecrets(requiredKeys) if (!validation.valid) { throw new Error(`Missing required database credentials: ${validation.missing.join(', ')}`) } // Security logging const maskedUri = config.uri ? secrets.getMaskedConnectionString(config.uri) : undefined const maskedHost = config.host ? `${config.host}:***` : undefined console.log(`🔧 Database config created for ${type}: ${maskedUri || maskedHost}`) return config }

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/intecrel/industrial-mcp'

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