Skip to main content
Glama

download_status

Check real-time progress of Optimizely DXP downloads by tracking percentage, speed, ETA, and file path. Poll every 5-10 seconds to monitor ongoing transfers.

Instructions

šŸ“Š Get real-time status of specific download. REAL-TIME: <1s. Returns current progress percentage, download speed (MB/s), estimated time remaining, and local file path when download completes. Poll this every 5-10s to track long-running downloads. Download completes when status="completed" and file path is provided. Required: downloadId. Returns progress, speed, ETA, file path.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
downloadIdYesDownload ID to check (from download_list)
monitorNoDXP-3: Auto-monitor download - polls every 10s and shows live progress updates until complete. Returns combined progress report. Default: false (single status check)

Implementation Reference

  • Main handler function executing the download_status tool. Handles both log and database downloads, supports live progress display, structured data output, and optional monitoring mode.
    static async handleDownloadStatus(args: DownloadStatusArgs): Promise<any> { if (!args.downloadId) { return ResponseBuilder.invalidParams('downloadId is required.'); } // DXP-3: Check if auto-monitoring is enabled const shouldMonitor = args.monitor === true; try { // DXP-3: If monitoring enabled, poll until complete if (shouldMonitor) { return await this.monitorDownloadProgress(args.downloadId); } // First check log download system (active + history) let download = downloadManager.getDownloadOrHistory(args.downloadId); // If not found, check database export system if (!download) { const DatabaseSimpleTools = require('./database-simple-tools'); // DXP-178 FIX: Use .backgroundDownloads.get() instead of non-existent .getDownloadStatus() download = DatabaseSimpleTools.backgroundDownloads.get(args.downloadId); // If found in database system, return database-specific status if (download) { return this._formatDatabaseStatusResponse(download, args.downloadId); } // Not found in either system return ResponseBuilder.error( `Download ${args.downloadId} not found.\n\n` + `**View active downloads:** \`download_list({ status: "active" })\`\n` + `**View recent history:** \`download_list({ status: "all" })\`` ); } // DXP-3: Get live progress from ProgressMonitor if available const liveProgress: LiveProgress | null = downloadManager.getLiveProgress(args.downloadId) as LiveProgress | null; // Format log download status const elapsed = Date.now() - download.startTime; const elapsedMinutes = Math.floor(elapsed / 60000); const elapsedSeconds = Math.floor((elapsed % 60000) / 1000); let message = `# šŸ“Š Download Status\n\n`; message += `**ID**: ${download.key}\n`; message += `**Type**: ${download.containerName} logs\n`; message += `**Project**: ${download.projectName} (${download.environment})\n`; message += `**Status**: ${download.status}\n`; // DXP-3: Show detailed progress if ProgressMonitor is available if (liveProgress && liveProgress.totalFiles) { message += `**Progress**: ${liveProgress.percentage}% (${liveProgress.filesDownloaded}/${liveProgress.totalFiles} files)\n`; if (liveProgress.bytesDownloaded > 0) { const formatBytes = (bytes: number): string => { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; message += `**Downloaded**: ${formatBytes(liveProgress.bytesDownloaded)}`; if (liveProgress.totalBytes > 0) { message += ` / ${formatBytes(liveProgress.totalBytes)}`; } message += `\n`; if (liveProgress.speed > 0) { message += `**Speed**: ${formatBytes(liveProgress.speed)}/s\n`; if (liveProgress.eta && liveProgress.eta > 0) { const etaMinutes = Math.floor(liveProgress.eta / 60); const etaSeconds = Math.round(liveProgress.eta % 60); message += `**ETA**: ${etaMinutes}m ${etaSeconds}s\n`; } } } if (liveProgress.currentFile) { const displayFile = liveProgress.currentFile.length > 60 ? '...' + liveProgress.currentFile.substring(liveProgress.currentFile.length - 57) : liveProgress.currentFile; message += `**Current File**: ${displayFile}\n`; } } else { message += `**Progress**: ${download.progress}%\n`; } message += `**Runtime**: ${elapsedMinutes}m ${elapsedSeconds}s\n`; if (download.dateRange && download.dateRange !== 'all-time') { message += `**Date Range**: ${download.dateRange}\n`; } if (download.pid) { message += `**Process ID**: ${download.pid}\n`; } // DXP-190: Show download path if completed if (download.status === 'completed' && download.result && download.result.downloadPath) { message += `\nšŸ“ **Files Location:**\n`; message += `\`\`\`\n${download.result.downloadPath}\n\`\`\`\n`; if (download.result.actualFilesOnDisk !== undefined) { message += `āœ… Verified ${download.result.actualFilesOnDisk} files on disk\n`; } } // Show error if download failed if (download.error) { message += `\n**āŒ Error**: ${download.error}\n`; } message += `\n**Actions**:\n`; if (download.status === 'failed') { message += `• Retry: Start a new download with same parameters\n`; message += `• Debug: Set DEBUG=true environment variable for detailed logs\n`; } else { message += `• Cancel: \`download_cancel({ downloadId: "${download.key}" })\`\n`; } message += `• View all: \`download_list({ status: "active" })\`\n`; // DXP-3: Add structured data with live progress const structuredData: any = { downloadId: download.key, type: 'logs', containerName: download.containerName, projectName: download.projectName, environment: download.environment, status: download.status, progress: download.progress, dateRange: download.dateRange || 'all-time', elapsedMs: elapsed, pid: download.pid || null }; // DXP-190: Include download path and verified file count if completed if (download.status === 'completed' && download.result) { if (download.result.downloadPath) { structuredData.downloadPath = download.result.downloadPath; } if (download.result.actualFilesOnDisk !== undefined) { structuredData.actualFilesOnDisk = download.result.actualFilesOnDisk; } } // Include live progress data if available if (liveProgress && liveProgress.totalFiles) { structuredData.liveProgress = liveProgress; } return ResponseBuilder.successWithStructuredData(structuredData, message); } catch (error: any) { OutputLogger.error(`Get download status error: ${error}`); return ResponseBuilder.internalError('Failed to get download status', error.message); } }
  • Input schema defining required downloadId and optional monitor flag for the download_status tool.
    interface DownloadStatusArgs { downloadId: string; monitor?: boolean; }
  • Helper function for monitoring download progress when monitor=true. Polls every 10s for up to 30min, providing live updates.
    static async monitorDownloadProgress(downloadId: string): Promise<any> { const updates: string[] = []; const startTime = Date.now(); let pollCount = 0; const MAX_POLLS = 180; // 30 minutes max (180 * 10s) OutputLogger.info(`šŸ“Š Monitoring download: ${downloadId}`); OutputLogger.info(`Will poll every 10 seconds until complete...`); // Wait 2 seconds before first poll to give download time to start if (process.env.DEBUG === 'true') { console.error('[DEBUG] Waiting 2 seconds before first poll...'); } await new Promise(resolve => setTimeout(resolve, 2000)); while (pollCount < MAX_POLLS) { pollCount++; // Get current status (check active and history) const download = downloadManager.getDownloadOrHistory(downloadId); // Check if download no longer exists if (!download) { return ResponseBuilder.error(`Download ${downloadId} not found`); } // Check if download is in final state (completed/failed) if (download.status === 'completed' || download.status === 'failed' || download.status === 'cancelled') { updates.push(`\nāœ… **Download Complete**`); if (download.status === 'completed') { updates.push(`Final status: Completed successfully`); } else if (download.status === 'failed') { updates.push(`Final status: Failed - ${download.error || 'Unknown error'}`); } else { updates.push(`Final status: ${download.status}`); } break; } // Get live progress const liveProgress: LiveProgress | null = downloadManager.getLiveProgress(downloadId) as LiveProgress | null; // Format update let update = `\nšŸ“„ **Progress Update #${pollCount}** (${Math.floor((Date.now() - startTime) / 1000)}s elapsed)`; if (liveProgress && liveProgress.totalFiles) { update += `\n ${liveProgress.percentage}% - ${liveProgress.filesDownloaded}/${liveProgress.totalFiles} files`; if (liveProgress.bytesDownloaded > 0) { const formatBytes = (bytes: number): string => { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; update += ` (${formatBytes(liveProgress.bytesDownloaded)}`; if (liveProgress.totalBytes > 0) { update += ` / ${formatBytes(liveProgress.totalBytes)}`; } update += `)`; if (liveProgress.speed > 0) { update += ` - ${formatBytes(liveProgress.speed)}/s`; if (liveProgress.eta && liveProgress.eta > 0) { const etaMin = Math.floor(liveProgress.eta / 60); const etaSec = Math.round(liveProgress.eta % 60); update += ` - ETA: ${etaMin}m ${etaSec}s`; } } } } else { update += `\n ${download.progress}% complete`; } updates.push(update); // Check if download is complete const status = download.status as string; if (status === 'completed' || status === 'failed' || status === 'cancelled') { updates.push(`\nāœ… **Download ${status}**`); break; } // Wait 10 seconds before next poll await new Promise(resolve => setTimeout(resolve, 10000)); } if (pollCount >= MAX_POLLS) { updates.push(`\nāš ļø **Monitoring timeout** - download still running after 30 minutes`); updates.push(`Check status manually: \`download_status({ downloadId: "${downloadId}" })\``); } const message = `# šŸ“Š Download Monitoring Complete\n\n` + `**Download ID**: ${downloadId}\n` + `**Total monitoring time**: ${Math.floor((Date.now() - startTime) / 1000)}s\n` + `**Updates**: ${pollCount}\n` + updates.join('\n'); return ResponseBuilder.success(message); }
  • Tool availability registration defining download_status as available across all hosting types in the Download Management category.
    'download_status': { hostingTypes: ['dxp-paas', 'dxp-saas', 'self-hosted'], category: 'Download Management', description: 'Get download status with optional auto-monitoring' },
  • Private helper formatting status response specifically for database export downloads.
    static _formatDatabaseStatusResponse(download: any, downloadId: string): any { const elapsed = Date.now() - download.startTime; const elapsedMinutes = Math.floor(elapsed / 60000); const elapsedSeconds = Math.floor((elapsed % 60000) / 1000); let message = `# šŸ“Š Database Export Download Status\n\n`; message += `**ID**: ${downloadId}\n`; message += `**Type**: Database Export\n`; message += `**Status**: ${download.status}\n`; if (download.percent !== undefined) { message += `**Progress**: ${download.percent}%\n`; } if (download.bytesDownloaded && download.totalBytes) { const downloadedMB = (download.bytesDownloaded / (1024 * 1024)).toFixed(2); const totalMB = (download.totalBytes / (1024 * 1024)).toFixed(2); message += `**Downloaded**: ${downloadedMB} MB / ${totalMB} MB\n`; } message += `**Runtime**: ${elapsedMinutes}m ${elapsedSeconds}s\n`; if (download.filePath) { message += `**File Path**: ${download.filePath}\n`; } if (download.error) { message += `**Error**: ${download.error}\n`; } message += `\n**Actions**:\n`; message += `• Check again: \`download_status({ downloadId: "${downloadId}" })\`\n`; message += `• View all: \`download_list({ status: "active" })\`\n`; return ResponseBuilder.successWithStructuredData({ downloadId: downloadId, type: 'database_export', status: download.status, progress: download.percent || 0, bytesDownloaded: download.bytesDownloaded || 0, totalBytes: download.totalBytes || 0, filePath: download.filePath || null, elapsedMs: elapsed, error: download.error || null }, message); }

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