Skip to main content
Glama
deployment-task-integration.ts16.8 kB
/** * MCP Tasks Integration for Deployment Readiness Tool * * This module provides standardized task tracking for the deployment readiness tool, * implementing ADR-020: MCP Tasks Integration Strategy. * * Key features: * - Creates MCP Tasks for deployment validation operations * - Tracks progress through validation phases (tests, history, code quality, ADR compliance) * - Supports cancellation between phases * - Provides memory integration for deployment assessment tracking * * @see ADR-020: MCP Tasks Integration Strategy * @see https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/tasks */ import { getTaskManager, type AdrTask, type TaskResult, type TaskManager } from './task-manager.js'; import { createComponentLogger, type ComponentLogger } from './enhanced-logging.js'; const logger: ComponentLogger = createComponentLogger('DeploymentTaskIntegration'); /** * Deployment validation phases that map to MCP Task phases */ export const DEPLOYMENT_PHASES = [ 'initialization', 'test_validation', 'code_quality_analysis', 'deployment_history_analysis', 'adr_compliance_check', 'environment_research', 'blocker_assessment', 'final_report', ] as const; export type DeploymentPhase = (typeof DEPLOYMENT_PHASES)[number]; /** * Deployment task context for tracking state across validation steps */ export interface DeploymentTaskContext { taskId: string; currentPhase: DeploymentPhase; operation: string; targetEnvironment: string; cancelled: boolean; testValidationResult?: { passed: boolean; failureCount: number; coveragePercentage: number; }; codeQualityResult?: { score: number; securityIssues: number; complexity: number; }; historyAnalysisResult?: { successRate: number; rollbackRate: number; recommendedAction: string; }; adrComplianceResult?: { score: number; compliantAdrs: number; totalAdrs: number; }; blockerCount?: number; } /** * Options for creating a deployment task */ export interface CreateDeploymentTaskOptions { projectPath: string; targetEnvironment: string; operation: string; strictMode?: boolean; enableMemoryIntegration?: boolean; enableTreeSitterAnalysis?: boolean; enableResearchIntegration?: boolean; } /** * Result from deployment task execution */ export interface DeploymentTaskResult extends TaskResult { data?: { isDeploymentReady: boolean; overallScore: number; confidence: number; blockerCount: number; testsPassed: boolean; gitPushStatus: 'allowed' | 'blocked' | 'conditional'; memoryEntityId?: string; }; } /** * Deployment Task Manager - Provides MCP Tasks integration for deployment readiness * * This class wraps the TaskManager to provide deployment-specific functionality: * - Creates tasks with deployment validation phases * - Tracks validation progress through multiple checks * - Supports cancellation between phases * - Integrates with memory for assessment tracking */ export class DeploymentTaskManager { private taskManager: TaskManager; private activeContexts: Map<string, DeploymentTaskContext> = new Map(); constructor(taskManager?: TaskManager) { this.taskManager = taskManager ?? getTaskManager(); } /** * Initialize the deployment task manager */ async initialize(): Promise<void> { await this.taskManager.initialize(); logger.info('DeploymentTaskManager initialized'); } /** * Create a new deployment task * * @returns The created task and context */ async createDeploymentTask(options: CreateDeploymentTaskOptions): Promise<{ task: AdrTask; context: DeploymentTaskContext; }> { const { projectPath, targetEnvironment, operation } = options; const task = await this.taskManager.createTask({ type: 'deployment', tool: 'deployment_readiness', phases: [...DEPLOYMENT_PHASES], projectPath, ttl: 600000, // 10 minute TTL for deployment checks pollInterval: 1000, // 1 second poll interval }); const context: DeploymentTaskContext = { taskId: task.taskId, currentPhase: 'initialization', operation, targetEnvironment, cancelled: false, }; this.activeContexts.set(task.taskId, context); logger.info('Deployment task created', { taskId: task.taskId, projectPath, targetEnvironment, operation, }); return { task, context }; } /** * Get deployment task context */ getContext(taskId: string): DeploymentTaskContext | undefined { return this.activeContexts.get(taskId); } /** * Start a deployment phase */ async startPhase(taskId: string, phase: DeploymentPhase, message?: string): Promise<void> { const context = this.activeContexts.get(taskId); if (!context) { logger.warn('No context found for task', { taskId }); return; } // Check for cancellation if (context.cancelled) { throw new Error('Task was cancelled'); } context.currentPhase = phase; await this.taskManager.startPhase(taskId, phase); // Calculate overall progress based on phase const phaseIndex = DEPLOYMENT_PHASES.indexOf(phase); const phaseProgress = phaseIndex >= 0 ? Math.floor((phaseIndex / DEPLOYMENT_PHASES.length) * 100) : 0; await this.taskManager.updateProgress({ taskId, progress: phaseProgress, phase, phaseProgress: 0, message: message ?? `Starting phase: ${phase}`, }); logger.info('Deployment phase started', { taskId, phase, progress: phaseProgress }); } /** * Update phase progress */ async updatePhaseProgress( taskId: string, phase: DeploymentPhase, phaseProgress: number, message?: string ): Promise<void> { const context = this.activeContexts.get(taskId); if (!context) { return; } // Calculate overall progress const phaseIndex = DEPLOYMENT_PHASES.indexOf(phase); const phaseFraction = 100 / DEPLOYMENT_PHASES.length; const baseProgress = phaseIndex * phaseFraction; const overallProgress = Math.floor(baseProgress + (phaseProgress / 100) * phaseFraction); await this.taskManager.updateProgress({ taskId, progress: overallProgress, phase, phaseProgress, ...(message !== undefined && { message }), }); } /** * Complete a deployment phase */ async completePhase(taskId: string, phase: DeploymentPhase, _message?: string): Promise<void> { const context = this.activeContexts.get(taskId); if (!context) { return; } await this.taskManager.completePhase(taskId, phase); logger.info('Deployment phase completed', { taskId, phase }); } /** * Fail a deployment phase */ async failPhase(taskId: string, phase: DeploymentPhase, error: string): Promise<void> { const context = this.activeContexts.get(taskId); if (!context) { return; } await this.taskManager.failPhase(taskId, phase, error); logger.warn('Deployment phase failed', { taskId, phase, error }); } /** * Store test validation result */ async storeTestValidationResult( taskId: string, result: { passed: boolean; failureCount: number; coveragePercentage: number } ): Promise<void> { const context = this.activeContexts.get(taskId); if (!context) { return; } context.testValidationResult = result; const statusMessage = result.passed ? `Tests passed (${result.failureCount} failures, ${result.coveragePercentage}% coverage)` : `Tests failed (${result.failureCount} failures, ${result.coveragePercentage}% coverage)`; await this.taskManager.updateProgress({ taskId, progress: 25, message: statusMessage, }); logger.info('Test validation result stored', { taskId, ...result }); } /** * Store code quality result */ async storeCodeQualityResult( taskId: string, result: { score: number; securityIssues: number; complexity: number } ): Promise<void> { const context = this.activeContexts.get(taskId); if (!context) { return; } context.codeQualityResult = result; await this.taskManager.updateProgress({ taskId, progress: 40, message: `Code quality score: ${result.score}% (${result.securityIssues} security issues)`, }); logger.info('Code quality result stored', { taskId, ...result }); } /** * Store deployment history analysis result */ async storeHistoryAnalysisResult( taskId: string, result: { successRate: number; rollbackRate: number; recommendedAction: string } ): Promise<void> { const context = this.activeContexts.get(taskId); if (!context) { return; } context.historyAnalysisResult = result; await this.taskManager.updateProgress({ taskId, progress: 55, message: `Deployment history: ${result.successRate}% success, ${result.rollbackRate}% rollback`, }); logger.info('History analysis result stored', { taskId, ...result }); } /** * Store ADR compliance result */ async storeAdrComplianceResult( taskId: string, result: { score: number; compliantAdrs: number; totalAdrs: number } ): Promise<void> { const context = this.activeContexts.get(taskId); if (!context) { return; } context.adrComplianceResult = result; await this.taskManager.updateProgress({ taskId, progress: 70, message: `ADR compliance: ${result.score}% (${result.compliantAdrs}/${result.totalAdrs} ADRs)`, }); logger.info('ADR compliance result stored', { taskId, ...result }); } /** * Store blocker count */ async storeBlockerCount(taskId: string, blockerCount: number): Promise<void> { const context = this.activeContexts.get(taskId); if (!context) { return; } context.blockerCount = blockerCount; const statusMessage = blockerCount === 0 ? 'No deployment blockers found' : `${blockerCount} deployment blocker(s) found`; await this.taskManager.updateProgress({ taskId, progress: 85, message: statusMessage, }); logger.info('Blocker count stored', { taskId, blockerCount }); } /** * Check if task is cancelled */ async isCancelled(taskId: string): Promise<boolean> { const context = this.activeContexts.get(taskId); if (!context) { return false; } // Check if task was cancelled externally const task = await this.taskManager.getTask(taskId); if (task?.status === 'cancelled') { context.cancelled = true; } return context.cancelled; } /** * Cancel a deployment task */ async cancelTask(taskId: string, reason?: string): Promise<void> { const context = this.activeContexts.get(taskId); if (context) { context.cancelled = true; } await this.taskManager.cancelTask(taskId, reason ?? 'Deployment validation cancelled by user'); this.activeContexts.delete(taskId); logger.info('Deployment task cancelled', { taskId, reason }); } /** * Complete a deployment task successfully */ async completeTask(taskId: string, result: DeploymentTaskResult): Promise<void> { await this.taskManager.completeTask(taskId, result); this.activeContexts.delete(taskId); logger.info('Deployment task completed', { taskId, success: result.success }); } /** * Fail a deployment task */ async failTask(taskId: string, error: string): Promise<void> { await this.taskManager.failTask(taskId, error); this.activeContexts.delete(taskId); logger.error('Deployment task failed', undefined, { taskId, error }); } /** * Get task status */ async getTaskStatus(taskId: string): Promise<{ task: AdrTask | null; context: DeploymentTaskContext | undefined; }> { const task = await this.taskManager.getTask(taskId); const context = this.activeContexts.get(taskId); return { task, context }; } } /** * Get the global DeploymentTaskManager instance */ let globalDeploymentTaskManager: DeploymentTaskManager | null = null; export function getDeploymentTaskManager(): DeploymentTaskManager { if (!globalDeploymentTaskManager) { globalDeploymentTaskManager = new DeploymentTaskManager(); } return globalDeploymentTaskManager; } /** * Reset the global DeploymentTaskManager (for testing) */ export async function resetDeploymentTaskManager(): Promise<void> { globalDeploymentTaskManager = null; } /** * Helper function to wrap deployment execution with task tracking * * This can be used by the deployment_readiness tool to automatically * track progress through MCP Tasks. * * @example * ```typescript * const result = await executeDeploymentWithTaskTracking( * { * projectPath: '/path/to/project', * targetEnvironment: 'production', * operation: 'full_audit', * }, * async (tracker) => { * // Test validation phase * await tracker.startPhase('test_validation'); * const testResult = await runTests(); * await tracker.storeTestValidationResult(testResult); * await tracker.completePhase('test_validation'); * * // Code quality phase * await tracker.startPhase('code_quality_analysis'); * const qualityResult = await analyzeCodeQuality(); * await tracker.storeCodeQualityResult(qualityResult); * await tracker.completePhase('code_quality_analysis'); * * // Return final result * return { isDeploymentReady: true, overallScore: 95 }; * } * ); * ``` */ export async function executeDeploymentWithTaskTracking<T extends DeploymentTaskResult>( options: CreateDeploymentTaskOptions, executor: (tracker: DeploymentTaskTracker) => Promise<T['data']> ): Promise<{ taskId: string; result: T }> { const dtm = getDeploymentTaskManager(); await dtm.initialize(); const { task, context } = await dtm.createDeploymentTask(options); const taskId = task.taskId; // Create a tracker interface for the executor const tracker: DeploymentTaskTracker = { taskId, startPhase: (phase, message) => dtm.startPhase(taskId, phase, message), updatePhaseProgress: (phase, progress, message) => dtm.updatePhaseProgress(taskId, phase, progress, message), completePhase: (phase, message) => dtm.completePhase(taskId, phase, message), failPhase: (phase, error) => dtm.failPhase(taskId, phase, error), storeTestValidationResult: result => dtm.storeTestValidationResult(taskId, result), storeCodeQualityResult: result => dtm.storeCodeQualityResult(taskId, result), storeHistoryAnalysisResult: result => dtm.storeHistoryAnalysisResult(taskId, result), storeAdrComplianceResult: result => dtm.storeAdrComplianceResult(taskId, result), storeBlockerCount: count => dtm.storeBlockerCount(taskId, count), isCancelled: () => dtm.isCancelled(taskId), getContext: () => context, }; try { const resultData = await executor(tracker); const result = { success: resultData?.isDeploymentReady ?? false, data: resultData, } as T; await dtm.completeTask(taskId, result); return { taskId, result }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); await dtm.failTask(taskId, errorMessage); return { taskId, result: { success: false, error: { code: 'DEPLOYMENT_READINESS_ERROR', message: errorMessage, recoverable: false, }, } as T, }; } } /** * Task tracker interface provided to deployment executor */ export interface DeploymentTaskTracker { taskId: string; startPhase: (phase: DeploymentPhase, message?: string) => Promise<void>; updatePhaseProgress: ( phase: DeploymentPhase, progress: number, message?: string ) => Promise<void>; completePhase: (phase: DeploymentPhase, message?: string) => Promise<void>; failPhase: (phase: DeploymentPhase, error: string) => Promise<void>; storeTestValidationResult: (result: { passed: boolean; failureCount: number; coveragePercentage: number; }) => Promise<void>; storeCodeQualityResult: (result: { score: number; securityIssues: number; complexity: number; }) => Promise<void>; storeHistoryAnalysisResult: (result: { successRate: number; rollbackRate: number; recommendedAction: string; }) => Promise<void>; storeAdrComplianceResult: (result: { score: number; compliantAdrs: number; totalAdrs: number; }) => Promise<void>; storeBlockerCount: (count: number) => Promise<void>; isCancelled: () => Promise<boolean>; getContext: () => DeploymentTaskContext; }

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/tosin2013/mcp-adr-analysis-server'

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