import { Tool } from '@modelcontextprotocol/sdk/types.js';
import { CoolifyApiClient } from '../client/coolify-api';
import {
DeployAppSchema,
GetDeploymentStatusSchema,
GetDeploymentLogsSchema,
} from '../schemas';
import { logger, logToolInvocation, logDeploymentAction } from '../utils/logger';
export const deployAppTool: Tool = {
name: 'coolify.deploy_app',
description: 'Deploy an application and wait for it to complete',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'string',
description: 'Application ID to deploy',
},
force: {
type: 'boolean',
description: 'Force redeployment even if no changes',
default: false,
},
},
required: ['id'],
},
};
export const getDeploymentStatusTool: Tool = {
name: 'coolify.get_deployment_status',
description: 'Get the status of a deployment',
inputSchema: {
type: 'object',
properties: {
deploymentId: {
type: 'string',
description: 'Deployment ID to check',
},
},
required: ['deploymentId'],
},
};
export const getDeploymentLogsTool: Tool = {
name: 'coolify.get_deployment_logs',
description: 'Get logs from a deployment',
inputSchema: {
type: 'object',
properties: {
deploymentId: {
type: 'string',
description: 'Deployment ID to get logs from',
},
lines: {
type: 'integer',
description: 'Number of log lines to retrieve (max 1000)',
minimum: 1,
maximum: 1000,
default: 100,
},
},
required: ['deploymentId'],
},
};
export async function handleDeployApp(args: any, apiClient: CoolifyApiClient) {
logToolInvocation('coolify.deploy_app', args);
try {
const validated = DeployAppSchema.parse(args);
logDeploymentAction('deploy_start', validated.id);
const deployment = await apiClient.deployApplication(validated.id, validated.force);
logger.info(`Started deployment ${deployment.id} for application ${validated.id}`);
// Poll for deployment completion
const maxPolls = 60; // 10 minutes with 10-second intervals
let polls = 0;
let completedDeployment = deployment;
while (polls < maxPolls && ['pending', 'running'].includes(completedDeployment.status)) {
await new Promise(resolve => setTimeout(resolve, 10000));
completedDeployment = await apiClient.getDeploymentStatus(deployment.id);
polls++;
logger.debug(`Deployment ${deployment.id} status: ${completedDeployment.status}`);
}
if (completedDeployment.status === 'success') {
logDeploymentAction('deploy_success', validated.id, deployment.id);
return {
success: true,
deployment: completedDeployment,
message: 'Deployment completed successfully',
};
} else if (completedDeployment.status === 'failed') {
logDeploymentAction('deploy_failed', validated.id, deployment.id);
const logs = await apiClient.getDeploymentLogs(deployment.id);
return {
success: false,
deployment: completedDeployment,
logs: logs.slice(-20), // Return last 20 lines for debugging
message: 'Deployment failed',
};
} else {
logDeploymentAction('deploy_timeout', validated.id, deployment.id);
return {
success: false,
deployment: completedDeployment,
message: 'Deployment timed out. Please check status manually.',
};
}
} catch (error: any) {
logger.error('Failed to deploy application', { error: error.message });
return {
success: false,
error: {
code: error.code || 'UNKNOWN_ERROR',
message: error.message,
},
};
}
}
export async function handleGetDeploymentStatus(args: any, apiClient: CoolifyApiClient) {
logToolInvocation('coolify.get_deployment_status', args);
try {
const validated = GetDeploymentStatusSchema.parse(args);
const deployment = await apiClient.getDeploymentStatus(validated.deploymentId);
logger.info(`Retrieved deployment status: ${deployment.status} for ${validated.deploymentId}`);
return {
success: true,
deployment,
};
} catch (error: any) {
logger.error('Failed to get deployment status', { error: error.message });
return {
success: false,
error: {
code: error.code || 'UNKNOWN_ERROR',
message: error.message,
},
};
}
}
export async function handleGetDeploymentLogs(args: any, apiClient: CoolifyApiClient) {
logToolInvocation('coolify.get_deployment_logs', args);
try {
const validated = GetDeploymentLogsSchema.parse(args);
const logs = await apiClient.getDeploymentLogs(validated.deploymentId);
// Return requested number of lines from the end
const linesToReturn = logs.slice(-validated.lines);
logger.info(`Retrieved ${linesToReturn.length} log lines for deployment ${validated.deploymentId}`);
return {
success: true,
logs: linesToReturn,
totalLines: logs.length,
requestedLines: validated.lines,
};
} catch (error: any) {
logger.error('Failed to get deployment logs', { error: error.message });
return {
success: false,
error: {
code: error.code || 'UNKNOWN_ERROR',
message: error.message,
},
};
}
}