Skip to main content
Glama

complete_deployment

Finalize verified deployments in Optimizely DXP by transitioning them from AwaitingVerification to completion, with automatic progress monitoring and real-time event notifications.

Instructions

✅ Finalize deployment after verification. ASYNC: 2-15min. For AI Agents: Subscribe to deployment://{deploymentId} resource for real-time completion events (preferred method). Alternatively, set monitor=true (default) for background polling fallback. Deployment transitions: AwaitingVerification → Completing → Succeeded/Failed. After completing, monitor automatically tracks progress and emits events. Production deployments take 2-15min, other environments <1min. Required: deploymentId. Optional: monitor (default true).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
deploymentIdYes
monitorNo
projectNameNo
projectIdNo
apiKeyNo
apiSecretNo

Implementation Reference

  • Primary handler function for the 'complete_deployment' tool. Validates args, checks deployment state, calls DXP REST API to complete deployment, emits events, starts monitoring, and formats response.
    static async handleCompleteDeployment(args: CompleteDeploymentArgs): Promise<any> { // Check if this is a self-hosted project if (args.isSelfHosted || args.connectionString) { return ResponseBuilder.invalidParams('Deployment completion is not available for self-hosted projects. Self-hosted projects can only download existing backups and blobs.'); } if (!args.apiKey || !args.apiSecret || !args.projectId || !args.deploymentId) { return ResponseBuilder.invalidParams('Missing required parameters'); } try { const result = await this.completeDeployment(args); // Check if result is already a structured response with data and message if (result && typeof result === 'object' && 'data' in result && 'message' in result) { // DXP-68: If result contains an error field, return as error response if (result.data.error) { return { error: result.message, data: result.data }; } return ResponseBuilder.successWithStructuredData(result.data, result.message); } // Fallback for legacy string responses return ResponseBuilder.success(result); } catch (error: any) { console.error('Complete deployment error:', error); return ResponseBuilder.internalError('Failed to complete deployment', error.message); } } static async completeDeployment(args: CompleteDeploymentArgs): Promise<any> { const { apiKey, apiSecret, projectId, deploymentId } = args; console.error(`Completing deployment ${deploymentId} for project ${projectId}`); // DXP-68: Validate deployment state before attempting completion console.error('Checking deployment state before completion...'); const DeploymentListOperations = require('./deployment-list'); try { const statusResult = await DeploymentListOperations.getDeploymentStatus({ apiKey, apiSecret, projectId, deploymentId }); // Extract current status from the response let currentStatus = 'Unknown'; // Check if this is a structured response (new format from DXP-66) if (statusResult && typeof statusResult === 'object' && 'data' in statusResult && 'message' in statusResult) { currentStatus = statusResult.data.status || 'Unknown'; } else if (typeof statusResult === 'string' && statusResult.includes('Status:')) { const statusMatch = statusResult.match(/Status:\s*\*\*([^*]+)\*\*/); if (statusMatch) { currentStatus = statusMatch[1].trim(); } } console.error(`Current deployment status: ${currentStatus}`); // Check if deployment is in the correct state for completion (DXP-69: Use status constants) if (!isAwaitingVerification(currentStatus)) { // Return structured error response const errorMessage = `❌ **Cannot Complete Deployment**\n\n` + `Deployment must be in **${DEPLOYMENT_STATUS.AWAITING_VERIFICATION}** state to complete.\n\n` + `**Current State**: ${currentStatus}\n` + `**Deployment ID**: ${deploymentId}\n\n` + `**Next Steps:**\n` + (isInProgress(currentStatus) ? `• Wait for deployment to reach verification state\n` + `• Use \`get_deployment_status\` to check progress\n` + `• Use \`monitor_deployment\` for continuous updates` : isSucceeded(currentStatus) ? `• Deployment is already completed - no action needed` : isFailed(currentStatus) ? `• Deployment has failed - use \`reset_deployment\` to rollback` : `• Check deployment status with \`get_deployment_status\`` ); return { data: { error: 'INVALID_STATE', deploymentId: deploymentId, currentStatus: currentStatus, requiredStatus: DEPLOYMENT_STATUS.AWAITING_VERIFICATION, canComplete: false }, message: ResponseBuilder.addFooter(errorMessage) }; } console.error('✓ Deployment is in valid state for completion'); } catch (statusError: any) { console.error('Warning: Could not check deployment status before completion:', statusError.message); // Continue with completion attempt even if status check fails // The REST API itself will fail if state is wrong } // DXP-101: Use REST API instead of PowerShell (3-10x faster, no PowerShell dependency) try { const result: DeploymentResult = await DXPRestClient.completeDeployment( projectId!, apiKey!, apiSecret!, deploymentId!, { apiUrl: args.apiUrl } // Support custom API URLs ); // DXP-47: The completion API returns immediately with status "Completing" (transitional), // not "Succeeded" (final). Format the response with the ACTUAL current status. if (result) { // DXP-136: Emit deployment completing event try { if (result.status === 'Completing') { DeploymentResourceHandler.emitCompleting(deploymentId!, { project: args.projectName, status: result.status, slotUrl: result.deploymentSlotUrl || result.DeploymentSlotUrl }); } else if (result.status === 'Succeeded') { DeploymentResourceHandler.emitSucceeded(deploymentId!, { project: args.projectName, status: result.status, slotUrl: result.deploymentSlotUrl || result.DeploymentSlotUrl }); } } catch (eventError: any) { console.error(`Failed to emit deployment completion event: ${eventError.message}`); // Don't fail the operation if event emission fails } // DXP-121: Auto-start background monitoring if enabled (default true) if (args.monitor !== false && result && result.id) { try { const monitor = getGlobalMonitor(); monitor.startMonitoring({ deploymentId: result.id || deploymentId!, projectId: args.projectId!, apiKey: args.apiKey!, apiSecret: args.apiSecret!, interval: 30 * 1000 // 30 seconds (faster polling for completion phase) }); const logger = new StructuredLogger({ context: { tool: 'complete_deployment', deployment_id: result.id || deploymentId! } }); logger.info('Auto-monitoring started for deployment completion', { deployment_id: result.id || deploymentId!, interval_ms: 30 * 1000 }); console.log('🔄 Auto-monitoring started for deployment completion'); } catch (monitorError: any) { console.error(`Failed to start monitoring: ${monitorError.message}`); // Don't fail the operation if monitoring fails } } return DeploymentFormatters.formatDeploymentCompleted(result, args.projectName, projectId); } else { // Fallback if no result returned return { data: { deploymentId: deploymentId, status: 'Unknown' }, message: ResponseBuilder.addFooter('Deployment completion initiated but status unavailable') }; } } catch (error: any) { // Handle REST API errors const errorDetails = { operation: 'Complete Deployment', projectId, projectName: args.projectName, deploymentId, apiKey }; // Check if this is an access denied error if (error.statusCode === 401 || error.statusCode === 403) { return ErrorHandler.formatError({ type: 'ACCESS_DENIED', message: 'Access denied to deployment API', statusCode: error.statusCode } as any, errorDetails); } // Generic error handling return ErrorHandler.formatError({ type: 'API_ERROR', message: error.message, statusCode: error.statusCode } as any, errorDetails); } }
  • DeploymentTools aggregator entry point that delegates 'complete_deployment' handling to DeploymentActionOperations.
    static async handleCompleteDeployment(args: any): Promise<any> { return DeploymentActionOperations.handleCompleteDeployment(args); } static async handleResetDeployment(args: any): Promise<any> { return DeploymentActionOperations.handleResetDeployment(args); } static async handleMonitorDeployment(args: any): Promise<any> { return DeploymentActionOperations.handleMonitorDeployment(args); } }
  • Low-level REST API client method that performs the actual POST request to complete the deployment via Optimizely DXP API.
    static async completeDeployment( projectId: string, clientKey: string, clientSecret: string, deploymentId: string, options: RequestOptions = {} ): Promise<any> { const uriEnding = `projects/${projectId}/deployments/${deploymentId}/complete`; return await this.makeRequest(clientKey, clientSecret, uriEnding, 'POST', {}, options); }
  • Tool registration/definition in availability matrix, specifying it's for DXP PaaS, category, description, and restriction message.
    'complete_deployment': { hostingTypes: ['dxp-paas'], category: 'Deployments', description: 'Complete an in-progress deployment', restrictedMessage: 'Completing deployments is only available for DXP PaaS hosting.'

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