Skip to main content
Glama

Google Drive MCP Server

by ducla5
config-manager.ts8.82 kB
/** * Configuration Manager * Handles loading configuration from files and environment variables */ import { readFileSync, writeFileSync, existsSync } from 'fs'; import { join } from 'path'; import { ServerConfig, EnvironmentConfig, ConfigValidationResult } from '../types/config.js'; export class ConfigManager { private config: ServerConfig | null = null; private configPath: string; constructor(configPath?: string) { this.configPath = configPath || join(process.cwd(), 'config.json'); } /** * Load configuration from file and environment variables */ public async loadConfig(): Promise<ServerConfig> { let fileConfig: Partial<ServerConfig> = {}; // Try to load from config file if (existsSync(this.configPath)) { try { const configContent = readFileSync(this.configPath, 'utf-8'); fileConfig = JSON.parse(configContent); } catch (error) { throw new Error(`Failed to parse config file: ${error instanceof Error ? error.message : 'Unknown error'}`); } } else { // Generate default config if file doesn't exist await this.generateDefaultConfig(); fileConfig = this.getDefaultConfig(); } // Merge with environment variables const envConfig = this.loadEnvironmentConfig(); this.config = this.mergeConfigs(fileConfig, envConfig); // Validate configuration const validation = this.validateConfig(this.config); if (!validation.isValid) { throw new Error(`Configuration validation failed: ${validation.errors.join(', ')}`); } return this.config; } /** * Get current configuration */ public getConfig(): ServerConfig { if (!this.config) { throw new Error('Configuration not loaded. Call loadConfig() first.'); } return this.config; } /** * Generate default configuration file */ public async generateDefaultConfig(): Promise<void> { const defaultConfig = this.getDefaultConfig(); try { writeFileSync(this.configPath, JSON.stringify(defaultConfig, null, 2)); console.log(`Default configuration generated at: ${this.configPath}`); } catch (error) { throw new Error(`Failed to generate default config: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Load configuration from environment variables */ private loadEnvironmentConfig(): Partial<ServerConfig> { const env = process.env as EnvironmentConfig; const envConfig: Partial<ServerConfig> = {}; // Google configuration if (env.GOOGLE_CLIENT_ID || env.GOOGLE_CLIENT_SECRET || env.GOOGLE_REDIRECT_URI) { envConfig.google = { clientId: env.GOOGLE_CLIENT_ID || '', clientSecret: env.GOOGLE_CLIENT_SECRET || '', redirectUri: env.GOOGLE_REDIRECT_URI || 'http://localhost:8080/callback', scopes: ['https://www.googleapis.com/auth/drive.readonly'], applicationName: 'Google Drive MCP Server' }; } // Cache configuration if (env.CACHE_DIR || env.CACHE_MAX_SIZE || env.CACHE_TTL) { envConfig.cache = { directory: env.CACHE_DIR || './cache', maxSize: env.CACHE_MAX_SIZE || '1GB', defaultTTL: env.CACHE_TTL ? parseInt(env.CACHE_TTL) : 3600, cleanupInterval: 300, enableCompression: true }; } // Processing configuration if (env.MAX_FILE_SIZE) { envConfig.processing = { maxFileSize: env.MAX_FILE_SIZE, supportedMimeTypes: [ 'application/vnd.google-apps.document', 'application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'text/plain', 'text/markdown' ], chunkSize: 4000, summaryLength: 500 }; } // Server configuration if (env.LOG_LEVEL || env.SERVER_PORT) { envConfig.server = { port: env.SERVER_PORT ? parseInt(env.SERVER_PORT) : 3000, logLevel: (env.LOG_LEVEL as any) || 'info', requestTimeout: 30000, maxConcurrentRequests: 10, enableMetrics: true }; } return envConfig; } /** * Get default configuration */ private getDefaultConfig(): ServerConfig { return { google: { clientId: process.env.GOOGLE_CLIENT_ID || '', clientSecret: process.env.GOOGLE_CLIENT_SECRET || '', redirectUri: process.env.GOOGLE_REDIRECT_URI || 'http://localhost:8080/callback', scopes: ['https://www.googleapis.com/auth/drive.readonly'], applicationName: 'Google Drive MCP Server' }, cache: { directory: './cache', maxSize: '1GB', defaultTTL: 3600, cleanupInterval: 300, enableCompression: true }, processing: { maxFileSize: '100MB', supportedMimeTypes: [ 'application/vnd.google-apps.document', 'application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'text/plain', 'text/markdown', 'text/html' ], chunkSize: 4000, summaryLength: 500, enableOCR: false, ocrLanguages: ['en'] }, server: { port: 3000, logLevel: 'info', requestTimeout: 30000, maxConcurrentRequests: 10, enableMetrics: true } }; } /** * Merge file config with environment config */ private mergeConfigs(fileConfig: Partial<ServerConfig>, envConfig: Partial<ServerConfig>): ServerConfig { const defaultConfig = this.getDefaultConfig(); return { google: { ...defaultConfig.google, ...fileConfig.google, ...envConfig.google }, cache: { ...defaultConfig.cache, ...fileConfig.cache, ...envConfig.cache }, processing: { ...defaultConfig.processing, ...fileConfig.processing, ...envConfig.processing }, server: { ...defaultConfig.server, ...fileConfig.server, ...envConfig.server } }; } /** * Validate configuration */ private validateConfig(config: ServerConfig): ConfigValidationResult { const errors: string[] = []; const warnings: string[] = []; // Validate Google configuration if (!config.google.clientId) { errors.push('Google Client ID is required'); } if (!config.google.clientSecret) { errors.push('Google Client Secret is required'); } if (!config.google.redirectUri) { errors.push('Google Redirect URI is required'); } // Validate server configuration if (config.server.port < 1 || config.server.port > 65535) { errors.push('Server port must be between 1 and 65535'); } if (!['debug', 'info', 'warn', 'error'].includes(config.server.logLevel)) { errors.push('Log level must be one of: debug, info, warn, error'); } // Validate processing configuration if (config.processing.chunkSize < 100) { warnings.push('Chunk size is very small, may impact performance'); } if (config.processing.summaryLength < 50) { warnings.push('Summary length is very short'); } // Validate cache configuration if (config.cache.defaultTTL < 60) { warnings.push('Cache TTL is very short, may impact performance'); } return { isValid: errors.length === 0, errors, warnings }; } /** * Update configuration and save to file */ public async updateConfig(updates: Partial<ServerConfig>): Promise<void> { if (!this.config) { throw new Error('Configuration not loaded. Call loadConfig() first.'); } // Merge updates with current config this.config = this.mergeConfigs(this.config, updates); // Validate updated configuration const validation = this.validateConfig(this.config); if (!validation.isValid) { throw new Error(`Configuration validation failed: ${validation.errors.join(', ')}`); } // Save to file try { writeFileSync(this.configPath, JSON.stringify(this.config, null, 2)); } catch (error) { throw new Error(`Failed to save config: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Get configuration value by path */ public getConfigValue<T>(path: string): T | undefined { if (!this.config) { return undefined; } const keys = path.split('.'); let current: any = this.config; for (const key of keys) { if (current && typeof current === 'object' && key in current) { current = current[key]; } else { return undefined; } } return current as T; } } // Export singleton instance export const configManager = new ConfigManager();

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/ducla5/gdriver-mcp'

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