Skip to main content
Glama

db_export_download

Download Optimizely DXP database exports to local storage. Initiates background downloads for large files and provides tracking IDs to monitor progress and retrieve file paths upon completion.

Instructions

📥 Download completed database export to local storage. BACKGROUND: returns immediately with download ID, actual download continues in background. Large files (>1GB) may take 5-20min. Use download_status() to monitor download progress and get local file path when complete. Required: downloadUrl. Optional: downloadPath, background (default true). Returns downloadId for tracking.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
exportIdNoExport ID to download (not required if downloadUrl provided)
environmentNoEnvironment where export was created (not required if downloadUrl provided)
downloadUrlNoDirect SAS URL to download from (skips API authentication - useful for downloaded URLs from db_export_status)
downloadPathNoDirectory to save downloaded export
backgroundNoDownload in background vs wait for completion (default: true)
skipConfirmationNoSkip file overwrite confirmation prompts
monitorNoEnable download monitoring - instructs AI to poll check_download_status until complete
projectNoProject name (default: current project)
projectNameNoAlternative to project parameter
projectIdNoProject UUID (if providing inline credentials)
apiKeyNoAPI key (if providing inline credentials)
apiSecretNoAPI secret (if providing inline credentials)

Implementation Reference

  • Main handler function executing the db_export_download tool logic. Supports both blocking and background downloads of database export files using the provided download URL.
    static async handleDownloadDatabaseExport(args: DownloadDatabaseExportArgs): Promise<any> { if (!args.downloadUrl) { return ResponseBuilder.invalidParams('Missing required parameter: downloadUrl'); } // DXP-81: Support new 'database' parameter const databaseName = args.database || args.databaseName; try { // DXP-183: Honor background parameter (defaults to true per schema) const useBackground = args.background !== false; // Default to true if not specified if (useBackground) { // Start background download, return immediately with downloadId const downloadId = await this.startBackgroundDatabaseDownload( args.downloadUrl, args.downloadPath, args.projectName, args.environment, databaseName ); const fileSize = await this.getRemoteFileSize(args.downloadUrl).catch(() => 0); const estimatedTime = this.estimateDownloadTime(fileSize); const message = `📥 **Background Database Download Started**\n\n` + `**Download Details:**\n` + `• Download ID: \`${downloadId}\`\n` + `• Project: ${args.projectName || 'Unknown'}\n` + `• Environment: ${args.environment || 'Production'}\n` + `• Database: ${databaseName || 'epicms'}\n` + `• Size: ${this.formatBytes(fileSize)}\n` + `• Estimated Time: ${estimatedTime}\n\n` + `**Monitor Progress:**\n` + `Use \`download_list()\` to check download status.\n` + `Use \`download_status({ downloadId: "${downloadId}", monitor: true })\` for live updates.\n\n` + `⚠️ **Note**: Background downloads skip confirmation and start immediately.`; return ResponseBuilder.success(message); } else { // Blocking download (background=false explicitly set) const result = await this.downloadFromUrl( args.downloadUrl, args.downloadPath, args.projectName, args.environment, databaseName, args.skipConfirmation, args.incremental, args.timeoutMinutes ); return ResponseBuilder.success(result); } } catch (error: any) { console.error('Download database export error:', error); return ResponseBuilder.internalError('Failed to download database export', error.message); } }
  • TypeScript interface defining the input parameters (schema) for the db_export_download tool handler.
    interface DownloadDatabaseExportArgs { downloadUrl?: string; downloadPath?: string; projectName?: string; environment?: string; databaseName?: string; database?: string; skipConfirmation?: boolean; incremental?: boolean; timeoutMinutes?: number; }
  • Tool availability matrix entry registering 'db_export_download' with hosting restrictions, category, and description.
    'db_export_download': { hostingTypes: ['dxp-paas'], category: 'Database', description: 'Download completed export (background or synchronous)', restrictedMessage: 'Database export download is only available for DXP PaaS hosting.'
  • Key helper function performing the synchronous file download from Azure Blob URL with progress monitoring, timeout handling, and state persistence.
    static async downloadFromUrl( downloadUrl: string, downloadPath: string | undefined, projectName: string | undefined, environment: string | undefined, databaseName: string | undefined, skipConfirmation?: boolean, incremental?: boolean, timeoutMinutes?: number ): Promise<string> { // DXP-186: Use DownloadConfig to respect dbPath configuration const basePath = await DownloadConfig.getDownloadPath( 'database', projectName || 'Unknown', downloadPath || null ); const safeProjectName = (projectName || 'project').replace(/[^a-zA-Z0-9-_]/g, '_'); const safeEnvironment = (environment || 'production').toLowerCase(); const safeDatabaseName = (databaseName || 'epicms').replace(/[^a-zA-Z0-9-_]/g, '_'); const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5); const filename = `${safeProjectName}-${safeEnvironment}-${safeDatabaseName}-${timestamp}.bacpac`; const filepath = path.join(basePath, filename); // Create download ID for tracking const downloadId = `${safeProjectName}-db-${safeEnvironment}-${safeDatabaseName}-${Date.now()}`; // Check if we should use incremental download if (incremental) { const existingBackups = await this.checkForExistingBackups( basePath, projectName || 'project', environment || 'Production', databaseName || 'epicms' ); if (existingBackups.length > 0) { const latest = existingBackups[0]; OutputLogger.info(`Found existing backup: ${latest.fileName} (${this.formatBytes(latest.fileSize)})`); OutputLogger.info('Incremental mode: Checking if download is needed...'); // For database exports, we can't do true incremental (they're full backups) // But we can check if we already have a recent backup if (latest.ageHours < 24) { return `Using existing backup: ${latest.fileName}\\n` + `Location: ${latest.filePath}\\n` + `Size: ${this.formatBytes(latest.fileSize)}\\n` + `Age: ${latest.formattedAge}\\n\\n` + `Backup is less than 24 hours old. Skipping download.`; } } } // Get remote file size for progress tracking const fileSize = await this.getRemoteFileSize(downloadUrl); const estimatedTime = this.estimateDownloadTime(fileSize); if (!skipConfirmation) { OutputLogger.info(`About to download database backup:`); OutputLogger.info(` File: ${filename}`); OutputLogger.info(` Size: ${this.formatBytes(fileSize)}`); OutputLogger.info(` Estimated time: ${estimatedTime}`); OutputLogger.info(` Destination: ${filepath}`); } // Register download with DownloadManager DownloadManager.registerDownload({ projectName: downloadId, containerName: databaseName || 'epicms', environment: environment || 'Production', dateRange: 'export', type: 'database', totalFiles: 1, totalSize: fileSize }); // Save download state const downloadState: DownloadState = { downloadId, projectName: projectName || 'Unknown', environment: environment || 'Production', databaseName: databaseName || 'epicms', downloadUrl, downloadPath: filepath, status: 'active', startedAt: new Date().toISOString(), fileSize }; await this.saveDownloadState(downloadState); try { // Download file with timeout protection const timeoutMs = (timeoutMinutes || 30) * 60 * 1000; // Default 30 minutes await this.downloadFile(downloadUrl, filepath, timeoutMs, downloadId); // Mark download complete DownloadManager.completeDownload(downloadId, { success: true }); downloadState.status = 'completed'; downloadState.completedAt = new Date().toISOString(); await this.saveDownloadState(downloadState); // Save backup info const backupInfo: BackupInfo = { projectName: projectName || 'Unknown', environment: environment || 'Production', databaseName: databaseName || 'epicms', exportId: downloadUrl.split('/').pop() || 'unknown', downloadUrl, downloadedAt: new Date().toISOString(), filePath: filepath, fileSize }; await this.storeBackupInfo(projectName || 'Unknown', backupInfo); return `✅ Database backup downloaded successfully\\n` + `File: ${filename}\\n` + `Size: ${this.formatBytes(fileSize)}\\n` + `Location: ${filepath}`; } catch (error: any) { // Mark download failed DownloadManager.failDownload(downloadId, error.message); downloadState.status = 'failed'; downloadState.error = error.message; downloadState.completedAt = new Date().toISOString(); await this.saveDownloadState(downloadState); throw error; } }
  • Helper for initiating background (non-blocking) database downloads to avoid MCP timeouts, integrates with download management system.
    static async startBackgroundDatabaseDownload( downloadUrl: string, downloadPath: string | undefined, projectName: string | undefined, environment: string | undefined, databaseName: string | undefined ): Promise<string> { // DXP-186: Use DownloadConfig to respect dbPath configuration const basePath = await DownloadConfig.getDownloadPath( 'database', projectName || 'Unknown', downloadPath || null ); const safeProjectName = (projectName || 'project').replace(/[^a-zA-Z0-9-_]/g, '_'); const safeEnvironment = (environment || 'production').toLowerCase(); const safeDatabaseName = (databaseName || 'epicms').replace(/[^a-zA-Z0-9-_]/g, '_'); // Create download ID for tracking const downloadId = `${safeProjectName}-db-${safeEnvironment}-${safeDatabaseName}-${Date.now()}`; // Get remote file size for preview let fileSize = 0; try { fileSize = await this.getRemoteFileSize(downloadUrl); } catch (error: any) { OutputLogger.warn(`⚠️ Could not get file size: ${error.message}`); } // Register download with DownloadManager DownloadManager.registerDownload({ projectName: downloadId, containerName: databaseName || 'epicms', environment: environment || 'Production', dateRange: 'export', type: 'database', totalFiles: 1, totalSize: fileSize }); // Start download in background (don't await!) this.runDatabaseDownloadInBackground( downloadId, downloadUrl, downloadPath, projectName, environment, databaseName, fileSize ).catch(error => { OutputLogger.error(`Background database download ${downloadId} failed: ${error.message}`); DownloadManager.failDownload(downloadId, error.message); }); return downloadId;

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/JaxonDigital/optimizely-dxp-mcp'

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