Skip to main content
Glama
setup-tools.ts21.9 kB
/** * @fileoverview Setup & Configuration Tools for MCP Mobile Server * * This module provides automated environment setup and configuration tools for mobile * development, handling Flutter SDK installation, Android SDK setup, and complete * environment configuration across different platforms (macOS, Linux, Windows). * * @module tools/setup-tools * @category Setup & Configuration * * Key Features: * - Automated Flutter SDK installation and configuration * - Android SDK setup with environment variable configuration * - Cross-platform support (macOS, Linux, Windows) * - Automatic shell environment configuration (.zshrc, .bashrc) * - Environment validation and health checks * - Smart recommendations for missing components * - Path detection and automatic PATH updates * * Platform Support: * - macOS: Homebrew integration, .zshrc configuration * - Linux: APT/DNF package managers, .bashrc configuration * - Windows: System environment variables, PowerShell support * * @example * ```typescript * const setupTools = createSetupTools(globalProcessMap); * const flutterSetup = setupTools.get('flutter_setup_environment'); * const result = await flutterSetup.handler({ * action: 'full', * channel: 'stable', * autoConfig: true * }); * ``` */ import { z } from 'zod'; import { processExecutor } from '../utils/process.js'; import * as fs from 'fs/promises'; import * as path from 'path'; import * as os from 'os'; /** * Creates and configures all Setup & Configuration tools for the MCP Mobile Server. * * This factory function initializes environment setup tools that automate the * installation and configuration of mobile development dependencies across * different platforms. These tools reduce setup time from hours to minutes. * * **Setup Tools Created:** * * 1. **flutter_setup_environment** * - Complete Flutter SDK installation and configuration * - Actions: check, install, configure, full * - Automatic PATH configuration * - Channel selection (stable, beta, dev, master) * - Cross-platform support * - Shell environment updates (.zshrc, .bashrc) * - Environment validation with recommendations * * 2. **android_sdk_setup** * - Android SDK installation and configuration * - SDK component installation (platform-tools, build-tools, etc.) * - Environment variable setup (ANDROID_HOME, ANDROID_SDK_ROOT) * - SDK Manager integration * - AVD (Android Virtual Device) setup * - System image installation * - Build tools and platform tools configuration * * **Setup Workflow:** * 1. Check current environment status * 2. Identify missing components * 3. Install required SDKs and tools * 4. Configure environment variables * 5. Update shell configuration files * 6. Validate installation * 7. Provide recommendations for manual steps * * **Features:** * - Idempotent operations (safe to re-run) * - Comprehensive error handling * - Progress reporting for long operations * - Platform-specific optimizations * - Automatic dependency detection * - Smart path resolution * * @param {Map<string, number>} processMap - Global map tracking all active processes * @returns {Map<string, any>} Map of setup tool names to tool configurations * * @example * ```typescript * const globalProcesses = new Map(); * const tools = createSetupTools(globalProcesses); * * // Check environment status * const setupTool = tools.get('flutter_setup_environment'); * const checkResult = await setupTool.handler({ action: 'check' }); * console.log('Flutter installed:', checkResult.data.checks.flutter.installed); * console.log('Android SDK installed:', checkResult.data.checks.android.sdkInstalled); * * // Full Flutter setup * const fullSetup = await setupTool.handler({ * action: 'full', * channel: 'stable', * installPath: '/opt/flutter', * autoConfig: true * }); * console.log('Setup complete:', fullSetup.success); * console.log('Recommendations:', fullSetup.data.recommendations); * * // Android SDK setup * const androidSetup = tools.get('android_sdk_setup'); * const androidResult = await androidSetup.handler({ * action: 'install', * components: ['platform-tools', 'build-tools;33.0.0', 'platforms;android-33'] * }); * ``` * * @throws {Error} If platform is not supported * @throws {Error} If required permissions are missing (e.g., write access to install directory) * @throws {Error} If validation schemas fail for any setup parameters * * @see {@link https://docs.flutter.dev/get-started/install|Flutter Installation Guide} * @see {@link https://developer.android.com/studio/command-line/sdkmanager|Android SDK Manager} */ export function createSetupTools(processMap: Map<string, number>): Map<string, any> { const tools = new Map(); // Flutter Setup Environment Tool tools.set('flutter_setup_environment', { name: 'flutter_setup_environment', description: 'Complete Flutter SDK installation and environment setup with automatic path configuration', inputSchema: { type: 'object', properties: { action: { type: 'string', enum: ['check', 'install', 'configure', 'full'], description: 'Action to perform (check status, install Flutter, configure paths, or full setup)', default: 'check' }, channel: { type: 'string', enum: ['stable', 'beta', 'dev', 'master'], description: 'Flutter channel to install', default: 'stable' }, installPath: { type: 'string', description: 'Custom installation path (default: ~/development/flutter)', }, autoConfig: { type: 'boolean', description: 'Automatically configure shell environment', default: true } } }, handler: async (args: any) => { const homeDir = os.homedir(); const platform = process.platform as 'darwin' | 'linux' | 'win32'; const results = { platform, checks: {} as any, installation: null as any, configuration: null as any, recommendations: [] as string[] }; // Determine default paths based on OS const platformPaths = { darwin: { flutter: path.join(homeDir, 'development', 'flutter'), androidSdk: path.join(homeDir, 'Library', 'Android', 'sdk'), shellConfig: path.join(homeDir, '.zshrc') }, linux: { flutter: path.join(homeDir, 'development', 'flutter'), androidSdk: path.join(homeDir, 'Android', 'Sdk'), shellConfig: path.join(homeDir, '.bashrc') }, win32: { flutter: 'C:\\src\\flutter', androidSdk: path.join(homeDir, 'AppData', 'Local', 'Android', 'Sdk'), shellConfig: null as string | null // Windows uses system environment variables } }; const defaultPaths = platformPaths[platform] || platformPaths.linux; const installPath = args.installPath || defaultPaths.flutter; // Action: CHECK - Check current environment status if (args.action === 'check' || args.action === 'full') { results.checks = { flutter: { installed: false, version: null, path: null, inPath: false }, android: { sdkInstalled: false, sdkPath: null, adbAvailable: false, platformTools: false, cmdlineTools: false, emulator: false, envVars: { ANDROID_HOME: process.env.ANDROID_HOME || null, ANDROID_SDK_ROOT: process.env.ANDROID_SDK_ROOT || null } }, java: { installed: false, version: null, path: null }, environment: { PATH: process.env.PATH?.includes('flutter'), shellConfig: null as string | null } }; // Check Flutter installation try { const { stdout: flutterPath } = await processExecutor.execute('which', ['flutter'], {}); if (flutterPath) { results.checks.flutter.installed = true; results.checks.flutter.path = flutterPath.trim(); results.checks.flutter.inPath = true; // Get Flutter version try { const { stdout: version } = await processExecutor.execute('flutter', ['--version'], {}); const versionMatch = version.match(/Flutter (\d+\.\d+\.\d+)/); if (versionMatch) { results.checks.flutter.version = versionMatch[1]; } } catch (e) { // Version check failed } } } catch (e) { // Flutter not in PATH, check common locations try { await fs.access(installPath); const flutterBin = path.join(installPath, 'bin', 'flutter'); await fs.access(flutterBin); results.checks.flutter.installed = true; results.checks.flutter.path = installPath; results.checks.flutter.inPath = false; results.recommendations.push('Flutter is installed but not in PATH. Run with action="configure" to fix.'); } catch (e) { results.recommendations.push('Flutter is not installed. Run with action="install" to install.'); } } // Check Android SDK const androidHome = process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT || defaultPaths.androidSdk; try { await fs.access(androidHome); results.checks.android.sdkInstalled = true; results.checks.android.sdkPath = androidHome; // Check specific Android tools const toolsToCheck = [ { name: 'adb', path: path.join(androidHome, 'platform-tools', 'adb'), key: 'adbAvailable' }, { name: 'platform-tools', path: path.join(androidHome, 'platform-tools'), key: 'platformTools' }, { name: 'cmdline-tools', path: path.join(androidHome, 'cmdline-tools'), key: 'cmdlineTools' }, { name: 'emulator', path: path.join(androidHome, 'emulator'), key: 'emulator' } ]; for (const tool of toolsToCheck) { try { await fs.access(tool.path); results.checks.android[tool.key] = true; } catch (e) { results.checks.android[tool.key] = false; results.recommendations.push(`Android ${tool.name} not found. Install Android SDK components.`); } } } catch (e) { results.recommendations.push('Android SDK not found. Install Android Studio or command-line tools.'); } // Check Java try { const { stdout: javaVersion } = await processExecutor.execute('java', ['-version'], {}); results.checks.java.installed = true; const versionMatch = javaVersion.match(/version "?(\d+)/); if (versionMatch) { results.checks.java.version = versionMatch[1]; } } catch (e) { results.recommendations.push('Java not found. Install JDK 11 or higher.'); } // Check shell configuration if (defaultPaths.shellConfig) { try { const shellContent = await fs.readFile(defaultPaths.shellConfig, 'utf-8'); results.checks.environment.shellConfig = defaultPaths.shellConfig; const hasFlutterPath = shellContent.includes('flutter/bin'); const hasAndroidHome = shellContent.includes('ANDROID_HOME'); if (!hasFlutterPath) { results.recommendations.push('Flutter not configured in shell. Run with action="configure".'); } if (!hasAndroidHome) { results.recommendations.push('Android SDK not configured in shell. Run with action="configure".'); } } catch (e) { results.recommendations.push('Shell configuration file not found.'); } } } // Action: INSTALL - Install Flutter SDK if (args.action === 'install' || args.action === 'full') { if (!results.checks?.flutter?.installed || args.action === 'install') { results.installation = { status: 'starting', path: installPath, channel: args.channel || 'stable' }; try { // Create installation directory await fs.mkdir(path.dirname(installPath), { recursive: true }); // Download Flutter based on platform const downloadUrls: Record<string, string> = { darwin: `https://storage.googleapis.com/flutter_infra_release/releases/${args.channel}/macos/flutter_macos_arm64-${args.channel}.zip`, linux: `https://storage.googleapis.com/flutter_infra_release/releases/${args.channel}/linux/flutter_linux_${args.channel}.tar.xz`, win32: `https://storage.googleapis.com/flutter_infra_release/releases/${args.channel}/windows/flutter_windows_${args.channel}.zip` }; const downloadUrl = downloadUrls[platform as string]; if (!downloadUrl) { throw new Error(`Unsupported platform: ${platform}`); } // Check if git is available for cloning try { await processExecutor.execute('git', ['--version'], {}); // Clone Flutter repository results.installation.method = 'git'; results.installation.status = 'cloning'; await processExecutor.execute('git', [ 'clone', 'https://github.com/flutter/flutter.git', '-b', args.channel || 'stable', installPath ], { timeout: 300000 }); // 5 minute timeout for clone results.installation.status = 'success'; results.installation.message = `Flutter installed successfully at ${installPath}`; } catch (gitError) { // Fallback to download method results.installation.method = 'download'; results.installation.status = 'downloading'; results.installation.error = 'Git not available, manual download required'; results.installation.downloadUrl = downloadUrl; results.recommendations.push(`Download Flutter manually from: ${downloadUrl}`); } } catch (error) { results.installation.status = 'failed'; results.installation.error = error instanceof Error ? error.message : String(error); } } } // Action: CONFIGURE - Configure environment variables if ((args.action === 'configure' || args.action === 'full') && args.autoConfig !== false) { results.configuration = { status: 'starting', shellConfig: defaultPaths.shellConfig, changes: [] as string[] }; if (platform === 'win32') { results.configuration.status = 'manual'; results.configuration.instructions = [ 'Add Flutter to Windows PATH:', `1. Add "${installPath}\\bin" to your PATH`, '2. Set ANDROID_HOME environment variable', '3. Restart your terminal' ]; } else if (defaultPaths.shellConfig) { try { const shellPath = defaultPaths.shellConfig; let shellContent = ''; try { shellContent = await fs.readFile(shellPath, 'utf-8'); } catch (e) { // File doesn't exist, create it shellContent = ''; } const additions = []; // Add Flutter configuration if not present if (!shellContent.includes('flutter/bin')) { const flutterPath = results.checks?.flutter?.path || installPath; additions.push(` # Flutter SDK Configuration export PATH="$PATH:${flutterPath}/bin" export PATH="$PATH:${flutterPath}/bin/cache/dart-sdk/bin" export PATH="$PATH:$HOME/.pub-cache/bin"`); results.configuration.changes.push('Added Flutter to PATH'); } // Add Android SDK configuration if not present if (!shellContent.includes('ANDROID_HOME') && results.checks?.android?.sdkPath) { additions.push(` # Android SDK Configuration export ANDROID_HOME="${results.checks.android.sdkPath}" export ANDROID_SDK_ROOT="${results.checks.android.sdkPath}" export PATH="$PATH:$ANDROID_HOME/platform-tools" export PATH="$PATH:$ANDROID_HOME/tools" export PATH="$PATH:$ANDROID_HOME/tools/bin" export PATH="$PATH:$ANDROID_HOME/emulator" export PATH="$PATH:$ANDROID_HOME/cmdline-tools/latest/bin"`); results.configuration.changes.push('Added Android SDK configuration'); } // Add Chrome executable for web development (macOS) if (platform === 'darwin' && !shellContent.includes('CHROME_EXECUTABLE')) { additions.push(` # Chrome for Flutter Web Development export CHROME_EXECUTABLE="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"`); results.configuration.changes.push('Added Chrome executable for web development'); } if (additions.length > 0) { await fs.appendFile(shellPath, additions.join('\n') + '\n'); results.configuration.status = 'success'; results.configuration.message = `Updated ${shellPath}. Run 'source ${shellPath}' to apply changes.`; } else { results.configuration.status = 'unchanged'; results.configuration.message = 'Environment already configured correctly.'; } } catch (error) { results.configuration.status = 'failed'; results.configuration.error = error instanceof Error ? error.message : String(error); } } } // Final recommendations if (results.checks?.flutter?.installed && results.checks?.flutter?.inPath) { results.recommendations.push('Run "flutter doctor" to verify your setup.'); } return { success: true, data: results }; } }); // Android SDK Setup Tool tools.set('android_sdk_setup', { name: 'android_sdk_setup', description: 'Setup Android SDK and configure environment for Android development', inputSchema: { type: 'object', properties: { action: { type: 'string', enum: ['check', 'install', 'configure'], description: 'Action to perform', default: 'check' }, components: { type: 'array', items: { type: 'string' }, description: 'SDK components to install (platform-tools, build-tools, platforms, etc.)', default: ['platform-tools', 'build-tools;34.0.0', 'platforms;android-34'] } } }, handler: async (args: any) => { const homeDir = os.homedir(); const platform = process.platform; const androidPath = platform === 'darwin' ? path.join(homeDir, 'Library', 'Android', 'sdk') : platform === 'win32' ? path.join(homeDir, 'AppData', 'Local', 'Android', 'Sdk') : path.join(homeDir, 'Android', 'Sdk'); const results = { platform, androidPath, status: {} as any, installation: null as any, configuration: null as any }; // Check current status if (args.action === 'check' || args.action === 'install') { try { await fs.access(androidPath); results.status.sdkFound = true; // Check for sdkmanager const sdkManagerPaths = [ path.join(androidPath, 'cmdline-tools', 'latest', 'bin', 'sdkmanager'), path.join(androidPath, 'cmdline-tools', '17.0', 'bin', 'sdkmanager'), path.join(androidPath, 'tools', 'bin', 'sdkmanager') ]; let sdkManagerPath = null; for (const path of sdkManagerPaths) { try { await fs.access(path); sdkManagerPath = path; break; } catch (e) { // Continue checking } } results.status.sdkManager = sdkManagerPath; if (sdkManagerPath && args.action === 'install') { // Install requested components results.installation = { components: args.components || [], results: [] }; for (const component of args.components || []) { try { await processExecutor.execute(sdkManagerPath, [ '--install', component, '--sdk_root=' + androidPath ], { timeout: 300000 }); results.installation.results.push({ component, status: 'success' }); } catch (error) { results.installation.results.push({ component, status: 'failed', error: error instanceof Error ? error.message : String(error) }); } } } } catch (e) { results.status.sdkFound = false; results.status.message = 'Android SDK not found. Install Android Studio or command-line tools.'; } } return { success: true, data: results }; } }); return tools; }

Implementation Reference

Latest Blog Posts

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/cristianoaredes/mcp-mobile-server'

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