Skip to main content
Glama

Google Drive MCP Server

by ducla5
config-validator.ts•11.7 kB
/** * Configuration Validator * Validates configuration and diagnoses common issues */ import chalk from 'chalk'; import ora from 'ora'; import { existsSync, accessSync, constants } from 'fs'; import { ConfigManager } from '../config/config-manager.js'; import { AuthService } from '../auth/auth-service.js'; import { ServerConfig } from '../types/config.js'; export interface ValidationResult { isValid: boolean; errors: string[]; warnings: string[]; } export class ConfigValidator { private configManager: ConfigManager; constructor(configPath?: string) { this.configManager = new ConfigManager(configPath); } /** * Validate configuration */ async validate(): Promise<ValidationResult> { const errors: string[] = []; const warnings: string[] = []; try { const config = await this.configManager.loadConfig(); // Validate Google OAuth configuration this.validateGoogleConfig(config, errors, warnings); // Validate cache configuration this.validateCacheConfig(config, errors, warnings); // Validate processing configuration this.validateProcessingConfig(config, errors, warnings); // Validate server configuration this.validateServerConfig(config, errors, warnings); return { isValid: errors.length === 0, errors, warnings }; } catch (error) { errors.push(`Failed to load configuration: ${error instanceof Error ? error.message : 'Unknown error'}`); return { isValid: false, errors, warnings }; } } /** * Comprehensive diagnosis of common issues */ async diagnose(): Promise<void> { console.log(chalk.blue.bold('\nšŸ” Google Drive MCP Server - System Diagnosis\n')); // Check 1: Configuration file await this.checkConfigurationFile(); // Check 2: Google OAuth setup await this.checkGoogleOAuthSetup(); // Check 3: Authentication status await this.checkAuthenticationStatus(); // Check 4: File system permissions await this.checkFileSystemPermissions(); // Check 5: Network connectivity await this.checkNetworkConnectivity(); // Check 6: Dependencies await this.checkDependencies(); console.log(chalk.blue('\nšŸ“‹ Diagnosis complete!')); } /** * Validate Google OAuth configuration */ private validateGoogleConfig(config: ServerConfig, errors: string[], warnings: string[]): void { if (!config.google.clientId) { errors.push('Google Client ID is required'); } else if (!config.google.clientId.includes('.googleusercontent.com')) { warnings.push('Google Client ID should end with .googleusercontent.com'); } if (!config.google.clientSecret) { errors.push('Google Client Secret is required'); } if (!config.google.redirectUri) { errors.push('Google Redirect URI is required'); } else { try { new URL(config.google.redirectUri); } catch { errors.push('Google Redirect URI must be a valid URL'); } } if (!config.google.scopes || config.google.scopes.length === 0) { errors.push('Google OAuth scopes are required'); } else if (!config.google.scopes.includes('https://www.googleapis.com/auth/drive.readonly')) { warnings.push('Drive readonly scope is recommended for basic functionality'); } } /** * Validate cache configuration */ private validateCacheConfig(config: ServerConfig, errors: string[], warnings: string[]): void { if (!config.cache.directory) { errors.push('Cache directory is required'); } if (config.cache.defaultTTL < 60) { warnings.push('Cache TTL is very short, may impact performance'); } if (config.cache.defaultTTL > 86400) { warnings.push('Cache TTL is very long, files may become stale'); } // Parse max size const maxSize = config.cache.maxSize; if (maxSize) { const sizeMatch = maxSize.match(/^(\d+(?:\.\d+)?)\s*(GB|MB|KB|B)?$/i); if (!sizeMatch) { errors.push('Cache max size format is invalid (e.g., "1GB", "500MB")'); } } } /** * Validate processing configuration */ private validateProcessingConfig(config: ServerConfig, errors: string[], warnings: string[]): void { if (config.processing.chunkSize < 100) { warnings.push('Chunk size is very small, may impact performance'); } if (config.processing.chunkSize > 10000) { warnings.push('Chunk size is very large, may cause memory issues'); } if (config.processing.summaryLength < 50) { warnings.push('Summary length is very short'); } // Parse max file size const maxFileSize = config.processing.maxFileSize; if (maxFileSize) { const sizeMatch = maxFileSize.match(/^(\d+(?:\.\d+)?)\s*(GB|MB|KB|B)?$/i); if (!sizeMatch) { errors.push('Processing max file size format is invalid (e.g., "100MB", "1GB")'); } } } /** * Validate server configuration */ private validateServerConfig(config: ServerConfig, errors: string[], warnings: string[]): void { 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'); } if (config.server.requestTimeout < 1000) { warnings.push('Request timeout is very short, may cause timeouts'); } if (config.server.maxConcurrentRequests && config.server.maxConcurrentRequests < 1) { errors.push('Max concurrent requests must be at least 1'); } } /** * Check configuration file */ private async checkConfigurationFile(): Promise<void> { const spinner = ora('Checking configuration file...').start(); try { await this.configManager.loadConfig(); spinner.succeed('Configuration file loaded successfully'); // Validate configuration const validation = await this.validate(); if (!validation.isValid) { console.log(chalk.red(' āœ— Configuration validation failed:')); validation.errors.forEach(error => console.log(chalk.red(` • ${error}`))); } if (validation.warnings.length > 0) { console.log(chalk.yellow(' ⚠ Configuration warnings:')); validation.warnings.forEach(warning => console.log(chalk.yellow(` • ${warning}`))); } } catch (error) { spinner.fail('Configuration file check failed'); console.log(chalk.red(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`)); } } /** * Check Google OAuth setup */ private async checkGoogleOAuthSetup(): Promise<void> { const spinner = ora('Checking Google OAuth setup...').start(); try { const config = await this.configManager.loadConfig(); if (!config.google.clientId || !config.google.clientSecret) { spinner.fail('Google OAuth credentials not configured'); console.log(chalk.yellow(' Run "google-drive-mcp auth setup" to configure OAuth')); return; } spinner.succeed('Google OAuth credentials configured'); } catch (error) { spinner.fail('Failed to check Google OAuth setup'); console.log(chalk.red(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`)); } } /** * Check authentication status */ private async checkAuthenticationStatus(): Promise<void> { const spinner = ora('Checking authentication status...').start(); try { const authService = new AuthService(); await authService.initialize(); const status = await authService.validateAuthentication(); if (status.isValid) { spinner.succeed('Authentication is valid'); } else { spinner.fail('Authentication failed'); console.log(chalk.red(` Error: ${status.error}`)); if (status.needsSetup) { console.log(chalk.yellow(' Run "google-drive-mcp auth setup" to configure authentication')); } else if (status.needsReauth) { console.log(chalk.yellow(' Run "google-drive-mcp auth refresh" to refresh tokens')); } } } catch (error) { spinner.fail('Failed to check authentication'); console.log(chalk.red(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`)); } } /** * Check file system permissions */ private async checkFileSystemPermissions(): Promise<void> { const spinner = ora('Checking file system permissions...').start(); try { const config = await this.configManager.loadConfig(); const cacheDir = config.cache.directory; // Check if cache directory exists and is writable if (existsSync(cacheDir)) { try { accessSync(cacheDir, constants.R_OK | constants.W_OK); spinner.succeed('File system permissions OK'); } catch { spinner.fail('Cache directory is not writable'); console.log(chalk.red(` Directory: ${cacheDir}`)); } } else { spinner.warn('Cache directory does not exist (will be created on first use)'); console.log(chalk.yellow(` Directory: ${cacheDir}`)); } } catch (error) { spinner.fail('Failed to check file system permissions'); console.log(chalk.red(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`)); } } /** * Check network connectivity */ private async checkNetworkConnectivity(): Promise<void> { const spinner = ora('Checking network connectivity...').start(); try { // Test Google APIs endpoint const response = await fetch('https://www.googleapis.com/drive/v3/', { method: 'HEAD', signal: AbortSignal.timeout(5000) }); if (response.ok || response.status === 401) { // 401 is expected without authentication spinner.succeed('Network connectivity OK'); } else { spinner.fail('Network connectivity issues'); console.log(chalk.red(` HTTP Status: ${response.status}`)); } } catch (error) { spinner.fail('Network connectivity failed'); if (error instanceof Error) { if (error.name === 'AbortError') { console.log(chalk.red(' Timeout connecting to Google APIs')); } else { console.log(chalk.red(` Error: ${error.message}`)); } } } } /** * Check dependencies */ private async checkDependencies(): Promise<void> { const spinner = ora('Checking dependencies...').start(); try { // Check required modules const requiredModules = [ '@modelcontextprotocol/sdk', 'googleapis', 'pdf-parse', 'mammoth', 'node-cache' ]; const missingModules: string[] = []; for (const module of requiredModules) { try { await import(module); } catch { missingModules.push(module); } } if (missingModules.length === 0) { spinner.succeed('All dependencies available'); } else { spinner.fail('Missing dependencies'); console.log(chalk.red(' Missing modules:')); missingModules.forEach(module => console.log(chalk.red(` • ${module}`))); console.log(chalk.yellow(' Run "npm install" to install missing dependencies')); } } catch (error) { spinner.fail('Failed to check dependencies'); console.log(chalk.red(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`)); } } }

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