Skip to main content
Glama

Claude Desktop Commander MCP

config-manager.tsโ€ข6.89 kB
import fs from 'fs/promises'; import path from 'path'; import { existsSync } from 'fs'; import { mkdir } from 'fs/promises'; import os from 'os'; import { VERSION } from './version.js'; import { CONFIG_FILE } from './config.js'; export interface ServerConfig { blockedCommands?: string[]; defaultShell?: string; allowedDirectories?: string[]; telemetryEnabled?: boolean; // New field for telemetry control fileWriteLineLimit?: number; // Line limit for file write operations fileReadLineLimit?: number; // Default line limit for file read operations (changed from character-based) clientId?: string; // Unique client identifier for analytics currentClient?: ClientInfo; // Current connected client information [key: string]: any; // Allow for arbitrary configuration keys } export interface ClientInfo { name: string; version: string; } /** * Singleton config manager for the server */ class ConfigManager { private configPath: string; private config: ServerConfig = {}; private initialized = false; constructor() { // Get user's home directory // Define config directory and file paths this.configPath = CONFIG_FILE; } /** * Initialize configuration - load from disk or create default */ async init() { if (this.initialized) return; try { // Ensure config directory exists const configDir = path.dirname(this.configPath); if (!existsSync(configDir)) { await mkdir(configDir, { recursive: true }); } // Check if config file exists try { await fs.access(this.configPath); // Load existing config const configData = await fs.readFile(this.configPath, 'utf8'); this.config = JSON.parse(configData); } catch (error) { // Config file doesn't exist, create default this.config = this.getDefaultConfig(); await this.saveConfig(); } this.config['version'] = VERSION; this.initialized = true; } catch (error) { console.error('Failed to initialize config:', error); // Fall back to default config in memory this.config = this.getDefaultConfig(); this.initialized = true; } } /** * Alias for init() to maintain backward compatibility */ async loadConfig() { return this.init(); } /** * Create default configuration */ private getDefaultConfig(): ServerConfig { return { blockedCommands: [ // Disk and partition management "mkfs", // Create a filesystem on a device "format", // Format a storage device (cross-platform) "mount", // Mount a filesystem "umount", // Unmount a filesystem "fdisk", // Manipulate disk partition tables "dd", // Convert and copy files, can write directly to disks "parted", // Disk partition manipulator "diskpart", // Windows disk partitioning utility // System administration and user management "sudo", // Execute command as superuser "su", // Substitute user identity "passwd", // Change user password "adduser", // Add a user to the system "useradd", // Create a new user "usermod", // Modify user account "groupadd", // Create a new group "chsh", // Change login shell "visudo", // Edit the sudoers file // System control "shutdown", // Shutdown the system "reboot", // Restart the system "halt", // Stop the system "poweroff", // Power off the system "init", // Change system runlevel // Network and security "iptables", // Linux firewall administration "firewall", // Generic firewall command "netsh", // Windows network configuration // Windows system commands "sfc", // System File Checker "bcdedit", // Boot Configuration Data editor "reg", // Windows registry editor "net", // Network/user/service management "sc", // Service Control manager "runas", // Execute command as another user "cipher", // Encrypt/decrypt files or wipe data "takeown" // Take ownership of files ], defaultShell: os.platform() === 'win32' ? 'powershell.exe' : '/bin/sh', allowedDirectories: [], telemetryEnabled: true, // Default to opt-out approach (telemetry on by default) fileWriteLineLimit: 50, // Default line limit for file write operations (changed from 100) fileReadLineLimit: 1000 // Default line limit for file read operations (changed from character-based) }; } /** * Save config to disk */ private async saveConfig() { try { await fs.writeFile(this.configPath, JSON.stringify(this.config, null, 2), 'utf8'); } catch (error) { console.error('Failed to save config:', error); throw error; } } /** * Get the entire config */ async getConfig(): Promise<ServerConfig> { await this.init(); return { ...this.config }; } /** * Get a specific configuration value */ async getValue(key: string): Promise<any> { await this.init(); return this.config[key]; } /** * Set a specific configuration value */ async setValue(key: string, value: any): Promise<void> { await this.init(); // Special handling for telemetry opt-out if (key === 'telemetryEnabled' && value === false) { // Get the current value before changing it const currentValue = this.config[key]; // Only capture the opt-out event if telemetry was previously enabled if (currentValue !== false) { // Import the capture function dynamically to avoid circular dependencies const { capture } = await import('./utils/capture.js'); // Send a final telemetry event noting that the user has opted out // This helps us track opt-out rates while respecting the user's choice await capture('server_telemetry_opt_out', { reason: 'user_disabled', prev_value: currentValue }); } } // Update the value this.config[key] = value; await this.saveConfig(); } /** * Update multiple configuration values at once */ async updateConfig(updates: Partial<ServerConfig>): Promise<ServerConfig> { await this.init(); this.config = { ...this.config, ...updates }; await this.saveConfig(); return { ...this.config }; } /** * Reset configuration to defaults */ async resetConfig(): Promise<ServerConfig> { this.config = this.getDefaultConfig(); await this.saveConfig(); return { ...this.config }; } } // 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/wonderwhy-er/DesktopCommanderMCP'

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