list_storage_containers
Discover available Azure blob storage containers in Optimizely DXP environments to identify logs, blobs, and websitelogs before downloading or generating access links.
Instructions
📦 List Azure blob storage containers for environment. REAL-TIME: 1-3s. Returns container names, types (logs, blobs, websitelogs), and creation dates. Use this to discover available containers before download_blobs() or generate_storage_sas_link() calls. Containers vary by environment and project configuration. Required: environment. Optional: project. Returns array of container details.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| environment | Yes | ||
| limit | No | Max results to return (1-100) | |
| offset | No | Pagination offset | |
| projectName | No | ||
| projectId | No | ||
| apiKey | No | ||
| apiSecret | No |
Implementation Reference
- lib/tools/storage-tools.ts:105-154 (handler)Main handler function that executes the list_storage_containers tool logic. Handles argument resolution, self-hosted vs DXP, calls core listing function, and formats response.static async handleListStorageContainers(args: StorageArgs): Promise<any> { try { // Check if this is a self-hosted project if (args.connectionString || args.isSelfHosted) { const containers = await SelfHostedStorage.listContainers(args.connectionString!); return ResponseBuilder.success(this.formatSelfHostedContainers(containers)); } // Resolve project configuration if credentials not provided let resolvedArgs = args; if (!args.apiKey || !args.apiSecret || !args.projectId) { const resolved = ProjectTools.resolveCredentials(args); // Check if the resolved project is self-hosted if (resolved.project?.isSelfHosted) { const containers = await SelfHostedStorage.listContainers(resolved.project.connectionString as string); return ResponseBuilder.success(this.formatSelfHostedContainers(containers)); } if (!resolved.success || !resolved.credentials) { return ResponseBuilder.invalidParams('Missing required parameters. Either provide apiKey/apiSecret/projectId or configure a project.'); } resolvedArgs = { ...args, apiKey: resolved.credentials.apiKey || undefined, apiSecret: resolved.credentials.apiSecret || undefined, projectId: resolved.credentials.projectId || undefined, projectName: resolved.project?.name }; } // Default to Production if no environment specified if (!resolvedArgs.environment) { resolvedArgs.environment = 'Production'; } const result = await this.listStorageContainers(resolvedArgs); // DXP-66: Check if result is structured response with data and message if (result && typeof result === 'object' && 'data' in result && 'message' in result) { return ResponseBuilder.successWithStructuredData(result.data, result.message); } // Fallback for legacy string responses return ResponseBuilder.success(result); } catch (error: any) { // console.error('List storage containers error:', error); return ResponseBuilder.internalError('Failed to list storage containers', error.message); } }
- lib/tools/storage-tools.ts:156-223 (helper)Core listing function called by handler. Uses DXPRestClient to fetch containers with pagination support.static async listStorageContainers(args: StorageArgs): Promise<StorageContainersResult | string> { // DXP-76-4: Extract pagination parameters const { limit = 20, offset = 0 } = args; // Extract authentication parameters const apiKey = args.apiKey!; const apiSecret = args.apiSecret!; const projectId = args.projectId!; const environment = args.environment!; // console.error(`Listing storage containers for ${environment}`); // DXP-102: Use REST API instead of PowerShell (3-10x faster, no PowerShell dependency) try { const result: StorageContainersResponse | string[] = await DXPRestClient.getStorageContainers( projectId, apiKey, apiSecret, environment, false, // writable parameter { apiUrl: args.apiUrl } // Support custom API URLs ); // Get all containers let allContainers: string[]; if (Array.isArray(result)) { allContainers = result; } else if (result && (result as any).storageContainers) { allContainers = (result as any).storageContainers; } else { allContainers = []; } // DXP-76-4: Apply pagination const total = allContainers.length; const paginatedContainers = allContainers.slice(offset, offset + limit); // Format response - REST API returns array of container names directly if (paginatedContainers.length > 0) { return this.formatStorageContainers(paginatedContainers, environment, { total, limit, offset, hasMore: (offset + limit) < total }); } else if (allContainers.length === 0) { return this.formatStorageContainers([], environment, { total: 0, limit, offset, hasMore: false }); } else { return this.formatStorageContainers(paginatedContainers, environment, { total, limit, offset, hasMore: false }); } return ResponseBuilder.addFooter('No storage containers found'); } catch (error: any) { // Handle REST API errors throw new Error(`Failed to list storage containers: ${error.message}`); } }
- lib/tools/storage-tools.ts:66-80 (schema)Input schema defining parameters for storage tools, including list_storage_containers (projectId, environment, limit, offset, etc.).interface StorageArgs { apiKey?: string; apiSecret?: string; projectId?: string; projectName?: string; environment?: string; containerName?: string; permissions?: string; expiryHours?: number; connectionString?: string; isSelfHosted?: boolean; apiUrl?: string; limit?: number; offset?: number; }
- lib/tools/storage-tools.ts:38-41 (schema)Output schema for structured response from list_storage_containers.interface StorageContainersResult { data: StorageContainersData; message: string; }
- lib/tools/storage-tools.ts:265-316 (helper)Helper function to format the list of storage containers with pagination, tips, and structured data for the tool response.static formatStorageContainers(data: StorageContainersResponse | string[], environment: string, pagination?: { total: number; limit: number; offset: number; hasMore: boolean }): StorageContainersResult { const { FORMATTING: { STATUS_ICONS } } = Config; // DXP-76-4: Add pagination info to header if provided const paginationInfo = pagination && pagination.total > pagination.limit ? ` (showing ${pagination.offset + 1}-${Math.min(pagination.offset + pagination.limit, pagination.total)} of ${pagination.total})` : ''; let response = `${STATUS_ICONS.FOLDER} **Storage Containers - ${environment}**${paginationInfo}\n\n`; // DXP-66: Build structured data for automation tools let containers: string[] = []; if (data && typeof data === 'object' && 'storageContainers' in data && Array.isArray(data.storageContainers) && data.storageContainers.length > 0) { containers = data.storageContainers; response += '**Available Containers:**\n'; data.storageContainers.forEach((container, index) => { const actualIndex = pagination ? pagination.offset + index : index; response += `${actualIndex + 1}. 📦 ${container}\n`; }); } else if (Array.isArray(data) && data.length > 0) { containers = data; response += '**Available Containers:**\n'; data.forEach((container, index) => { const actualIndex = pagination ? pagination.offset + index : index; response += `${actualIndex + 1}. 📦 ${container}\n`; }); } else { response += 'No storage containers found.\n'; } const tips = [ 'Use generate_storage_sas_link to get access URLs', 'Containers store BLOBs and media files', 'Each environment has its own containers' ]; response += '\n' + ResponseBuilder.formatTips(tips); // DXP-66 + DXP-76-4: Return structured data with pagination metadata const structuredData: any = { environment: environment, containerCount: containers.length, containers: containers }; if (pagination) { structuredData.pagination = pagination; } return { data: structuredData, message: ResponseBuilder.addFooter(response) }; }