Skip to main content
Glama

Google Drive MCP Server

by ducla5
cli.ts10.1 kB
#!/usr/bin/env node /** * Google Drive MCP Server CLI * Command-line interface for server management and configuration */ import { Command } from 'commander'; import chalk from 'chalk'; import { ConfigManager } from './config/config-manager.js'; import { AuthService } from './auth/auth-service.js'; import { AuthSetupWizard } from './cli/auth-wizard.js'; import { ConfigValidator } from './cli/config-validator.js'; import { ServerManager } from './cli/server-manager.js'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; import { readFileSync } from 'fs'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Read package.json for version const packagePath = join(__dirname, '../package.json'); const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8')); const program = new Command(); program .name('google-drive-mcp') .description('Google Drive MCP Server - CLI for managing the server') .version(packageJson.version); /** * Start command - Start the MCP server */ program .command('start') .description('Start the Google Drive MCP server') .option('-c, --config <path>', 'Path to configuration file') .option('-p, --port <number>', 'Server port (overrides config)') .option('-l, --log-level <level>', 'Log level (debug, info, warn, error)') .option('--stdio', 'Use stdio transport (default for MCP)', true) .option('--http', 'Use HTTP transport instead of stdio') .action(async (options: any) => { try { const serverManager = new ServerManager(options.config); await serverManager.start({ port: options.port ? parseInt(options.port) : undefined, logLevel: options.logLevel, useStdio: !options.http }); } catch (error) { console.error(chalk.red('Failed to start server:'), error instanceof Error ? error.message : error); process.exit(1); } }); /** * Config command group */ const configCmd = program .command('config') .description('Configuration management commands'); configCmd .command('init') .description('Initialize configuration with default values') .option('-f, --force', 'Overwrite existing configuration') .option('-c, --config <path>', 'Path to configuration file') .action(async (options: any) => { try { const configManager = new ConfigManager(options.config); await configManager.generateDefaultConfig(); console.log(chalk.green('✓ Configuration initialized successfully')); console.log(chalk.yellow('Please update the configuration with your Google OAuth credentials')); } catch (error) { console.error(chalk.red('Failed to initialize configuration:'), error instanceof Error ? error.message : error); process.exit(1); } }); configCmd .command('validate') .description('Validate current configuration') .option('-c, --config <path>', 'Path to configuration file') .action(async (options: any) => { try { const validator = new ConfigValidator(options.config); const result = await validator.validate(); if (result.isValid) { console.log(chalk.green('✓ Configuration is valid')); if (result.warnings.length > 0) { console.log(chalk.yellow('\nWarnings:')); result.warnings.forEach(warning => console.log(chalk.yellow(` • ${warning}`))); } } else { console.log(chalk.red('✗ Configuration validation failed')); console.log(chalk.red('\nErrors:')); result.errors.forEach(error => console.log(chalk.red(` • ${error}`))); if (result.warnings.length > 0) { console.log(chalk.yellow('\nWarnings:')); result.warnings.forEach(warning => console.log(chalk.yellow(` • ${warning}`))); } process.exit(1); } } catch (error) { console.error(chalk.red('Failed to validate configuration:'), error instanceof Error ? error.message : error); process.exit(1); } }); configCmd .command('show') .description('Show current configuration') .option('-c, --config <path>', 'Path to configuration file') .option('--secrets', 'Show sensitive values (use with caution)') .action(async (options: any) => { try { const configManager = new ConfigManager(options.config); const config = await configManager.loadConfig(); // Mask sensitive values unless --secrets is used const displayConfig = options.secrets ? config : maskSensitiveValues(config); console.log(chalk.blue('Current Configuration:')); console.log(JSON.stringify(displayConfig, null, 2)); } catch (error) { console.error(chalk.red('Failed to show configuration:'), error instanceof Error ? error.message : error); process.exit(1); } }); /** * Auth command group */ const authCmd = program .command('auth') .description('Authentication management commands'); authCmd .command('setup') .description('Interactive authentication setup wizard') .option('-c, --config <path>', 'Path to configuration file') .action(async (options: any) => { try { const wizard = new AuthSetupWizard(options.config); await wizard.run(); } catch (error) { console.error(chalk.red('Authentication setup failed:'), error instanceof Error ? error.message : error); process.exit(1); } }); authCmd .command('status') .description('Check authentication status') .option('-c, --config <path>', 'Path to configuration file') .action(async (options: any) => { try { const configManager = new ConfigManager(options.config); await configManager.loadConfig(); const authService = new AuthService(); await authService.initialize(); const status = await authService.validateAuthentication(); if (status.isValid) { console.log(chalk.green('✓ Authentication is valid')); console.log(chalk.blue(' Access token is active and valid')); } else { console.log(chalk.red('✗ 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) { console.error(chalk.red('Failed to check authentication status:'), error instanceof Error ? error.message : error); process.exit(1); } }); authCmd .command('refresh') .description('Refresh authentication tokens') .option('-c, --config <path>', 'Path to configuration file') .action(async (options: any) => { try { const configManager = new ConfigManager(options.config); await configManager.loadConfig(); const authService = new AuthService(); await authService.initialize(); const success = await authService.refreshToken(); if (success) { console.log(chalk.green('✓ Authentication tokens refreshed successfully')); } else { console.log(chalk.red('✗ Failed to refresh tokens')); console.log(chalk.yellow(' You may need to re-authenticate using "google-drive-mcp auth setup"')); } } catch (error) { console.error(chalk.red('Failed to refresh tokens:'), error instanceof Error ? error.message : error); process.exit(1); } }); authCmd .command('logout') .description('Clear stored authentication tokens') .option('-c, --config <path>', 'Path to configuration file') .action(async (options: any) => { try { const configManager = new ConfigManager(options.config); await configManager.loadConfig(); const authService = new AuthService(); await authService.initialize(); await authService.logout(); console.log(chalk.green('✓ Logged out successfully')); } catch (error) { console.error(chalk.red('Failed to logout:'), error instanceof Error ? error.message : error); process.exit(1); } }); /** * Test command */ program .command('test') .description('Test server functionality') .option('-c, --config <path>', 'Path to configuration file') .option('--auth-only', 'Test authentication only') .option('--drive-only', 'Test Google Drive API only') .action(async (options: any) => { try { const serverManager = new ServerManager(options.config); await serverManager.test({ authOnly: options.authOnly, driveOnly: options.driveOnly }); } catch (error) { console.error(chalk.red('Test failed:'), error instanceof Error ? error.message : error); process.exit(1); } }); /** * Doctor command - Diagnose common issues */ program .command('doctor') .description('Diagnose common configuration and setup issues') .option('-c, --config <path>', 'Path to configuration file') .action(async (options: any) => { try { const validator = new ConfigValidator(options.config); await validator.diagnose(); } catch (error) { console.error(chalk.red('Diagnosis failed:'), error instanceof Error ? error.message : error); process.exit(1); } }); /** * Utility function to mask sensitive configuration values */ function maskSensitiveValues(config: any): any { const masked = JSON.parse(JSON.stringify(config)); if (masked.google) { if (masked.google.clientSecret) { masked.google.clientSecret = '***MASKED***'; } } return masked; } /** * Handle uncaught errors */ process.on('uncaughtException', (error) => { console.error(chalk.red('Uncaught Exception:'), error); process.exit(1); }); process.on('unhandledRejection', (reason, promise) => { console.error(chalk.red('Unhandled Rejection at:'), promise, chalk.red('reason:'), reason); process.exit(1); }); // Parse command line arguments program.parse();

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