Skip to main content
Glama
coolify-tools.ts35.2 kB
import { z } from 'zod'; import { CoolifyClient } from '../services/coolify-client.js'; import type { CoolifyApiError } from '../types/coolify.js'; // Input validation schemas const TeamIdSchema = z.object({ teamId: z.number().describe('The team ID'), }); const ServerUuidSchema = z.object({ uuid: z.string().describe('The server UUID'), }); const ProjectIdSchema = z.object({ projectId: z.number().describe('The project ID'), }); const ApplicationUuidSchema = z.object({ uuid: z.string().describe('The application UUID'), }); const DatabaseUuidSchema = z.object({ uuid: z.string().describe('The database UUID'), }); const ServiceUuidSchema = z.object({ uuid: z.string().describe('The service UUID'), }); const DeploymentUuidSchema = z.object({ uuid: z.string().describe('The deployment UUID'), }); const PrivateKeyUuidSchema = z.object({ uuid: z.string().describe('The private key UUID'), }); const CreateServerSchema = z.object({ name: z.string().describe('Server name'), description: z.string().optional().describe('Server description'), ip: z.string().describe('Server IP address'), port: z.number().default(22).describe('SSH port'), user: z.string().default('root').describe('SSH user'), private_key_uuid: z.string().describe('UUID of the private key to use for SSH'), is_build_server: z.boolean().optional().describe('Whether this is a build server'), instant_validate: z.boolean().optional().describe('Validate server immediately after creation'), }); const CreateApplicationSchema = z.object({ project_uuid: z.string().describe('Project UUID'), environment_name: z.string().optional().describe('Environment name'), server_uuid: z.string().describe('Server UUID'), type: z.enum(['public', 'private']).describe('Application type'), name: z.string().describe('Application name'), description: z.string().optional().describe('Application description'), git_repository: z.string().optional().describe('Git repository URL'), git_branch: z.string().optional().describe('Git branch'), git_commit_sha: z.string().optional().describe('Git commit SHA'), ports_exposes: z.string().optional().describe('Exposed ports'), ports_mappings: z.string().optional().describe('Port mappings'), build_pack: z.string().optional().describe('Build pack to use'), install_command: z.string().optional().describe('Install command'), build_command: z.string().optional().describe('Build command'), start_command: z.string().optional().describe('Start command'), base_directory: z.string().optional().describe('Base directory'), publish_directory: z.string().optional().describe('Publish directory'), health_check_enabled: z.boolean().optional().describe('Enable health check'), health_check_path: z.string().optional().describe('Health check path'), limits_memory: z.string().optional().describe('Memory limit'), limits_cpus: z.string().optional().describe('CPU limit'), instant_deploy: z.boolean().optional().describe('Deploy immediately after creation'), }); const CreateDatabaseSchema = z.object({ project_uuid: z.string().describe('Project UUID'), environment_name: z.string().optional().describe('Environment name'), server_uuid: z.string().describe('Server UUID'), type: z.enum(['postgresql', 'mysql', 'mariadb', 'mongodb', 'redis']).describe('Database type'), name: z.string().describe('Database name'), description: z.string().optional().describe('Database description'), version: z.string().optional().describe('Database version'), public_port: z.number().optional().describe('Public port'), limits_memory: z.string().optional().describe('Memory limit'), limits_cpus: z.string().optional().describe('CPU limit'), postgres_user: z.string().optional().describe('PostgreSQL user'), postgres_password: z.string().optional().describe('PostgreSQL password'), postgres_db: z.string().optional().describe('PostgreSQL database name'), mysql_user: z.string().optional().describe('MySQL user'), mysql_password: z.string().optional().describe('MySQL password'), mysql_database: z.string().optional().describe('MySQL database name'), mysql_root_password: z.string().optional().describe('MySQL root password'), mariadb_user: z.string().optional().describe('MariaDB user'), mariadb_password: z.string().optional().describe('MariaDB password'), mariadb_database: z.string().optional().describe('MariaDB database name'), mariadb_root_password: z.string().optional().describe('MariaDB root password'), mongo_initdb_root_username: z.string().optional().describe('MongoDB root username'), mongo_initdb_root_password: z.string().optional().describe('MongoDB root password'), mongo_initdb_database: z.string().optional().describe('MongoDB database name'), redis_password: z.string().optional().describe('Redis password'), instant_deploy: z.boolean().optional().describe('Deploy immediately after creation'), }); const CreateServiceSchema = z.object({ project_uuid: z.string().describe('Project UUID'), environment_name: z.string().optional().describe('Environment name'), server_uuid: z.string().describe('Server UUID'), type: z.string().describe('Service type (e.g., plausible, umami, etc.)'), name: z.string().describe('Service name'), description: z.string().optional().describe('Service description'), instant_deploy: z.boolean().optional().describe('Deploy immediately after creation'), }); const CreateProjectSchema = z.object({ name: z.string().describe('Project name'), description: z.string().optional().describe('Project description'), }); const EnvironmentVariableSchema = z.object({ resourceType: z.enum(['application', 'service', 'database']).describe('Resource type'), resourceUuid: z.string().describe('Resource UUID'), key: z.string().describe('Environment variable key'), value: z.string().describe('Environment variable value'), is_build_time: z.boolean().optional().describe('Available at build time'), is_preview: z.boolean().optional().describe('Available in preview deployments'), is_shared: z.boolean().optional().describe('Shared across environments'), }); const ExecuteCommandSchema = z.object({ uuid: z.string().describe('Application UUID'), command: z.string().describe('Command to execute'), workDir: z.string().optional().describe('Working directory'), }); const DeployWebhookSchema = z.object({ uuid: z.string().describe('Application or service UUID'), tag: z.string().optional().describe('Docker image tag'), }); const CreatePrivateKeySchema = z.object({ name: z.string().describe('Private key name'), description: z.string().optional().describe('Private key description'), private_key: z.string().describe('Private key content'), }); export class CoolifyTools { constructor(private client: CoolifyClient) {} private formatError(error: unknown): { isError: true; content: Array<{ type: 'text'; text: string }> } { let message = 'An unexpected error occurred'; if (error && typeof error === 'object' && 'message' in error) { const apiError = error as CoolifyApiError; message = apiError.message; if (apiError.errors) { const errorDetails = Object.entries(apiError.errors) .map(([field, messages]) => { const messageList = Array.isArray(messages) ? messages : [String(messages)]; return `${field}: ${messageList.join(', ')}`; }) .join('\n'); message = `${message}\n${errorDetails}`; } if (apiError.status) { message = `[${apiError.status}] ${message}`; } } return { isError: true, content: [{ type: 'text', text: message }], }; } // Version & Health Tools async getVersion() { try { const version = await this.client.getVersion(); return { content: [{ type: 'text', text: `Coolify Version: ${version.version}${version.build_date ? `\nBuild Date: ${version.build_date}` : ''}${version.commit_hash ? `\nCommit: ${version.commit_hash}` : ''}`, }], }; } catch (error) { return this.formatError(error); } } async checkHealth() { try { const health = await this.client.checkHealth(); let text = `Status: ${health.status}\nTimestamp: ${health.timestamp}`; if (health.services) { text += '\n\nServices:'; text += `\n- Database: ${health.services.database ? '✅' : '❌'}`; text += `\n- Redis: ${health.services.redis ? '✅' : '❌'}`; text += `\n- Docker: ${health.services.docker ? '✅' : '❌'}`; } return { content: [{ type: 'text', text }] }; } catch (error) { return this.formatError(error); } } // Team Tools async listTeams() { try { const teams = await this.client.listTeams(); const text = teams.map(team => `ID: ${team.id}\n` + `Name: ${team.name}\n` + `Personal: ${team.personal_team ? 'Yes' : 'No'}` + (team.description ? `\nDescription: ${team.description}` : '') ).join('\n\n'); return { content: [{ type: 'text', text: text || 'No teams found', }], }; } catch (error) { return this.formatError(error); } } async getTeam(input: unknown) { try { const { teamId } = TeamIdSchema.parse(input); const team = await this.client.getTeam(teamId); return { content: [{ type: 'text', text: `ID: ${team.id}\nName: ${team.name}\nPersonal: ${team.personal_team ? 'Yes' : 'No'}${team.description ? `\nDescription: ${team.description}` : ''}\nCreated: ${team.created_at}\nUpdated: ${team.updated_at}`, }], }; } catch (error) { return this.formatError(error); } } async getCurrentTeam() { try { const team = await this.client.getCurrentTeam(); return { content: [{ type: 'text', text: `Current Team:\nID: ${team.id}\nName: ${team.name}\nPersonal: ${team.personal_team ? 'Yes' : 'No'}${team.description ? `\nDescription: ${team.description}` : ''}`, }], }; } catch (error) { return this.formatError(error); } } async getCurrentTeamMembers() { try { const members = await this.client.getCurrentTeamMembers(); const text = members.map(member => `ID: ${member.id}\n` + `Name: ${member.name}\n` + `Email: ${member.email}\n` + `Role: ${member.role}\n` + `Joined: ${member.joined_at}` ).join('\n\n'); return { content: [{ type: 'text', text: text || 'No team members found', }], }; } catch (error) { return this.formatError(error); } } // Server Tools async listServers() { try { const servers = await this.client.listServers(); const text = servers.map(server => `UUID: ${server.uuid}\n` + `Name: ${server.name}\n` + `IP: ${server.ip}:${server.port}\n` + `User: ${server.user}` + (server.proxy ? `\nProxy: ${server.proxy.type} (${server.proxy.status})` : '') + (server.description ? `\nDescription: ${server.description}` : '') ).join('\n\n'); return { content: [{ type: 'text', text: text || 'No servers found', }], }; } catch (error) { return this.formatError(error); } } async createServer(input: unknown) { try { const data = CreateServerSchema.parse(input); const server = await this.client.createServer(data); return { content: [{ type: 'text', text: `Server created successfully!\nUUID: ${server.uuid}\nName: ${server.name}\nIP: ${server.ip}:${server.port}`, }], }; } catch (error) { return this.formatError(error); } } async validateServer(input: unknown) { try { const { uuid } = ServerUuidSchema.parse(input); const validation = await this.client.validateServer(uuid); let text = `Server: ${validation.server}\nStatus: ${validation.status}`; if (validation.message) { text += `\nMessage: ${validation.message}`; } if (validation.errors && validation.errors.length > 0) { text += `\nErrors:\n${validation.errors.map(e => `- ${e}`).join('\n')}`; } return { content: [{ type: 'text', text }] }; } catch (error) { return this.formatError(error); } } async getServerResources(input: unknown) { try { const { uuid } = ServerUuidSchema.parse(input); const resources = await this.client.getServerResources(uuid); const text = resources.map(resource => `UUID: ${resource.uuid}\n` + `Name: ${resource.name}\n` + `Type: ${resource.type}\n` + `Status: ${resource.status}` + (resource.fqdn ? `\nURL: ${resource.fqdn}` : '') ).join('\n\n'); return { content: [{ type: 'text', text: text || 'No resources found on this server', }], }; } catch (error) { return this.formatError(error); } } async getServerDomains(input: unknown) { try { const { uuid } = ServerUuidSchema.parse(input); const domains = await this.client.getServerDomains(uuid); const text = domains.map(domain => `Domain: ${domain.domain}\n` + `Resource Type: ${domain.resource_type}\n` + `Resource ID: ${domain.resource_id}` ).join('\n\n'); return { content: [{ type: 'text', text: text || 'No domains found on this server', }], }; } catch (error) { return this.formatError(error); } } // Project Tools async listProjects() { try { const projects = await this.client.listProjects(); const text = projects.map(project => `UUID: ${project.uuid}\n` + `Name: ${project.name}` + (project.description ? `\nDescription: ${project.description}` : '') ).join('\n\n'); return { content: [{ type: 'text', text: text || 'No projects found', }], }; } catch (error) { return this.formatError(error); } } async getProject(input: unknown) { try { const { projectId } = ProjectIdSchema.parse(input); const project = await this.client.getProject(projectId); return { content: [{ type: 'text', text: `UUID: ${project.uuid}\nName: ${project.name}${project.description ? `\nDescription: ${project.description}` : ''}\nTeam ID: ${project.team_id}\nCreated: ${project.created_at}\nUpdated: ${project.updated_at}`, }], }; } catch (error) { return this.formatError(error); } } async createProject(input: unknown) { try { const data = CreateProjectSchema.parse(input); const project = await this.client.createProject(data); return { content: [{ type: 'text', text: `Project created successfully!\nUUID: ${project.uuid}\nName: ${project.name}`, }], }; } catch (error) { return this.formatError(error); } } async updateProject(input: unknown) { try { const parsed = ProjectIdSchema.merge(CreateProjectSchema.partial()).parse(input); const { projectId, ...data } = parsed; const project = await this.client.updateProject(projectId, data); return { content: [{ type: 'text', text: `Project updated successfully!\nUUID: ${project.uuid}\nName: ${project.name}`, }], }; } catch (error) { return this.formatError(error); } } async deleteProject(input: unknown) { try { const { projectId } = ProjectIdSchema.parse(input); await this.client.deleteProject(projectId); return { content: [{ type: 'text', text: 'Project deleted successfully', }], }; } catch (error) { return this.formatError(error); } } // Application Tools async listApplications() { try { const applications = await this.client.listApplications(); const text = applications.map(app => `UUID: ${app.uuid}\n` + `Name: ${app.name}\n` + `Status: ${app.status}\n` + `Build Pack: ${app.build_pack}` + (app.fqdn ? `\nURL: ${app.fqdn}` : '') + (app.git_repository ? `\nRepository: ${app.git_repository}` : '') + (app.git_branch ? `\nBranch: ${app.git_branch}` : '') ).join('\n\n'); return { content: [{ type: 'text', text: text || 'No applications found', }], }; } catch (error) { return this.formatError(error); } } async getApplication(input: unknown) { try { const { uuid } = ApplicationUuidSchema.parse(input); const app = await this.client.getApplication(uuid); let text = `UUID: ${app.uuid}\nName: ${app.name}\nStatus: ${app.status}\nBuild Pack: ${app.build_pack}`; if (app.description) text += `\nDescription: ${app.description}`; if (app.fqdn) text += `\nURL: ${app.fqdn}`; if (app.git_repository) text += `\nRepository: ${app.git_repository}`; if (app.git_branch) text += `\nBranch: ${app.git_branch}`; if (app.git_commit_sha) text += `\nCommit: ${app.git_commit_sha}`; if (app.port_mappings) text += `\nPort Mappings: ${app.port_mappings}`; if (app.port_exposes) text += `\nExposed Ports: ${app.port_exposes}`; return { content: [{ type: 'text', text }] }; } catch (error) { return this.formatError(error); } } async createApplication(input: unknown) { try { const data = CreateApplicationSchema.parse(input); const app = await this.client.createApplication(data); return { content: [{ type: 'text', text: `Application created successfully!\nUUID: ${app.uuid}\nName: ${app.name}\nStatus: ${app.status}`, }], }; } catch (error) { return this.formatError(error); } } async updateApplication(input: unknown) { try { const parsed = ApplicationUuidSchema.merge(CreateApplicationSchema.partial()).parse(input); const { uuid, ...data } = parsed; const app = await this.client.updateApplication(uuid, data); return { content: [{ type: 'text', text: `Application updated successfully!\nUUID: ${app.uuid}\nName: ${app.name}`, }], }; } catch (error) { return this.formatError(error); } } async deleteApplication(input: unknown) { try { const { uuid } = ApplicationUuidSchema.parse(input); await this.client.deleteApplication(uuid); return { content: [{ type: 'text', text: 'Application deleted successfully', }], }; } catch (error) { return this.formatError(error); } } async startApplication(input: unknown) { try { const { uuid } = ApplicationUuidSchema.parse(input); const result = await this.client.startApplication(uuid); return { content: [{ type: 'text', text: result.message, }], }; } catch (error) { return this.formatError(error); } } async stopApplication(input: unknown) { try { const { uuid } = ApplicationUuidSchema.parse(input); const result = await this.client.stopApplication(uuid); return { content: [{ type: 'text', text: result.message, }], }; } catch (error) { return this.formatError(error); } } async restartApplication(input: unknown) { try { const { uuid } = ApplicationUuidSchema.parse(input); const result = await this.client.restartApplication(uuid); return { content: [{ type: 'text', text: result.message, }], }; } catch (error) { return this.formatError(error); } } async executeCommand(input: unknown) { try { const { uuid, command, workDir } = ExecuteCommandSchema.parse(input); const result = await this.client.executeCommand(uuid, { command, workDir }); let text = `Exit Code: ${result.exitCode}`; if (result.stdout) text += `\n\nStdout:\n${result.stdout}`; if (result.stderr) text += `\n\nStderr:\n${result.stderr}`; return { content: [{ type: 'text', text }] }; } catch (error) { return this.formatError(error); } } async getApplicationLogs(input: unknown) { try { const parsed = ApplicationUuidSchema.merge(z.object({ since: z.number().optional().describe('Unix timestamp to get logs since'), })).parse(input); const logs = await this.client.getApplicationLogs(parsed.uuid, parsed.since); return { content: [{ type: 'text', text: logs || 'No logs available', }], }; } catch (error) { return this.formatError(error); } } // Database Tools async listDatabases() { try { const databases = await this.client.listDatabases(); const text = databases.map(db => `UUID: ${db.uuid}\n` + `Name: ${db.name}\n` + `Type: ${db.type} v${db.version}\n` + `Status: ${db.status}` + (db.public_port ? `\nPublic Port: ${db.public_port}` : '') ).join('\n\n'); return { content: [{ type: 'text', text: text || 'No databases found', }], }; } catch (error) { return this.formatError(error); } } async getDatabase(input: unknown) { try { const { uuid } = DatabaseUuidSchema.parse(input); const db = await this.client.getDatabase(uuid); let text = `UUID: ${db.uuid}\nName: ${db.name}\nType: ${db.type} v${db.version}\nStatus: ${db.status}`; if (db.description) text += `\nDescription: ${db.description}`; if (db.public_port) text += `\nPublic Port: ${db.public_port}`; text += `\nEnvironment ID: ${db.environment_id}`; text += `\nDestination ID: ${db.destination_id}`; return { content: [{ type: 'text', text }] }; } catch (error) { return this.formatError(error); } } async createDatabase(input: unknown) { try { const data = CreateDatabaseSchema.parse(input); const db = await this.client.createDatabase(data); return { content: [{ type: 'text', text: `Database created successfully!\nUUID: ${db.uuid}\nName: ${db.name}\nType: ${db.type} v${db.version}`, }], }; } catch (error) { return this.formatError(error); } } async updateDatabase(input: unknown) { try { const parsed = DatabaseUuidSchema.merge(CreateDatabaseSchema.partial()).parse(input); const { uuid, ...data } = parsed; const db = await this.client.updateDatabase(uuid, data); return { content: [{ type: 'text', text: `Database updated successfully!\nUUID: ${db.uuid}\nName: ${db.name}`, }], }; } catch (error) { return this.formatError(error); } } async deleteDatabase(input: unknown) { try { const { uuid } = DatabaseUuidSchema.parse(input); await this.client.deleteDatabase(uuid); return { content: [{ type: 'text', text: 'Database deleted successfully', }], }; } catch (error) { return this.formatError(error); } } async startDatabase(input: unknown) { try { const { uuid } = DatabaseUuidSchema.parse(input); const result = await this.client.startDatabase(uuid); return { content: [{ type: 'text', text: result.message, }], }; } catch (error) { return this.formatError(error); } } async stopDatabase(input: unknown) { try { const { uuid } = DatabaseUuidSchema.parse(input); const result = await this.client.stopDatabase(uuid); return { content: [{ type: 'text', text: result.message, }], }; } catch (error) { return this.formatError(error); } } async restartDatabase(input: unknown) { try { const { uuid } = DatabaseUuidSchema.parse(input); const result = await this.client.restartDatabase(uuid); return { content: [{ type: 'text', text: result.message, }], }; } catch (error) { return this.formatError(error); } } // Service Tools async listServices() { try { const services = await this.client.listServices(); const text = services.map(service => `UUID: ${service.uuid}\n` + `Name: ${service.name}\n` + `Type: ${service.type}${service.version ? ` v${service.version}` : ''}\n` + `Status: ${service.status}` + (service.fqdn ? `\nURL: ${service.fqdn}` : '') ).join('\n\n'); return { content: [{ type: 'text', text: text || 'No services found', }], }; } catch (error) { return this.formatError(error); } } async getService(input: unknown) { try { const { uuid } = ServiceUuidSchema.parse(input); const service = await this.client.getService(uuid); let text = `UUID: ${service.uuid}\nName: ${service.name}\nType: ${service.type}${service.version ? ` v${service.version}` : ''}\nStatus: ${service.status}`; if (service.description) text += `\nDescription: ${service.description}`; if (service.fqdn) text += `\nURL: ${service.fqdn}`; text += `\nEnvironment ID: ${service.environment_id}`; text += `\nServer ID: ${service.server_id}`; return { content: [{ type: 'text', text }] }; } catch (error) { return this.formatError(error); } } async createService(input: unknown) { try { const data = CreateServiceSchema.parse(input); const service = await this.client.createService(data); return { content: [{ type: 'text', text: `Service created successfully!\nUUID: ${service.uuid}\nName: ${service.name}\nType: ${service.type}`, }], }; } catch (error) { return this.formatError(error); } } async updateService(input: unknown) { try { const parsed = ServiceUuidSchema.merge(CreateServiceSchema.partial()).parse(input); const { uuid, ...data } = parsed; const service = await this.client.updateService(uuid, data); return { content: [{ type: 'text', text: `Service updated successfully!\nUUID: ${service.uuid}\nName: ${service.name}`, }], }; } catch (error) { return this.formatError(error); } } async deleteService(input: unknown) { try { const { uuid } = ServiceUuidSchema.parse(input); await this.client.deleteService(uuid); return { content: [{ type: 'text', text: 'Service deleted successfully', }], }; } catch (error) { return this.formatError(error); } } async startService(input: unknown) { try { const { uuid } = ServiceUuidSchema.parse(input); const result = await this.client.startService(uuid); return { content: [{ type: 'text', text: result.message, }], }; } catch (error) { return this.formatError(error); } } async stopService(input: unknown) { try { const { uuid } = ServiceUuidSchema.parse(input); const result = await this.client.stopService(uuid); return { content: [{ type: 'text', text: result.message, }], }; } catch (error) { return this.formatError(error); } } async restartService(input: unknown) { try { const { uuid } = ServiceUuidSchema.parse(input); const result = await this.client.restartService(uuid); return { content: [{ type: 'text', text: result.message, }], }; } catch (error) { return this.formatError(error); } } // Environment Variable Tools async listEnvironmentVariables(input: unknown) { try { const parsed = z.object({ resourceType: z.enum(['application', 'service', 'database']).describe('Resource type'), resourceUuid: z.string().describe('Resource UUID'), }).parse(input); const envVars = await this.client.listEnvironmentVariables(parsed.resourceType, parsed.resourceUuid); const text = envVars.map(env => `${env.key}=${env.value}` + (env.is_build_time ? ' (build-time)' : '') + (env.is_preview ? ' (preview)' : '') ).join('\n'); return { content: [{ type: 'text', text: text || 'No environment variables found', }], }; } catch (error) { return this.formatError(error); } } async createEnvironmentVariable(input: unknown) { try { const { resourceType, resourceUuid, ...data } = EnvironmentVariableSchema.parse(input); const envVar = await this.client.createEnvironmentVariable(resourceType, resourceUuid, data); return { content: [{ type: 'text', text: `Environment variable created: ${envVar.key}=${envVar.value}`, }], }; } catch (error) { return this.formatError(error); } } async updateEnvironmentVariable(input: unknown) { try { const parsed = EnvironmentVariableSchema.partial().merge(z.object({ envId: z.number().describe('Environment variable ID'), })).parse(input); const { resourceType, resourceUuid, envId, ...data } = parsed; if (!resourceType || !resourceUuid) { throw new Error('resourceType and resourceUuid are required'); } const envVar = await this.client.updateEnvironmentVariable(resourceType, resourceUuid, envId, data); return { content: [{ type: 'text', text: `Environment variable updated: ${envVar.key}=${envVar.value}`, }], }; } catch (error) { return this.formatError(error); } } async deleteEnvironmentVariable(input: unknown) { try { const parsed = z.object({ resourceType: z.enum(['application', 'service', 'database']).describe('Resource type'), resourceUuid: z.string().describe('Resource UUID'), envId: z.number().describe('Environment variable ID'), }).parse(input); await this.client.deleteEnvironmentVariable(parsed.resourceType, parsed.resourceUuid, parsed.envId); return { content: [{ type: 'text', text: 'Environment variable deleted successfully', }], }; } catch (error) { return this.formatError(error); } } // Deployment Tools async listDeployments() { try { const deployments = await this.client.listDeployments(); const text = deployments.map(deployment => `UUID: ${deployment.uuid}\n` + `Status: ${deployment.status}\n` + `Application ID: ${deployment.application_id}` + (deployment.commit ? `\nCommit: ${deployment.commit}` : '') + (deployment.pull_request_id ? `\nPR #${deployment.pull_request_id}` : '') + `\nCreated: ${deployment.created_at}` ).join('\n\n'); return { content: [{ type: 'text', text: text || 'No deployments found', }], }; } catch (error) { return this.formatError(error); } } async getDeployment(input: unknown) { try { const { uuid } = DeploymentUuidSchema.parse(input); const deployment = await this.client.getDeployment(uuid); let text = `UUID: ${deployment.uuid}\nStatus: ${deployment.status}\nApplication ID: ${deployment.application_id}`; if (deployment.commit) text += `\nCommit: ${deployment.commit}`; if (deployment.pull_request_id) text += `\nPR #${deployment.pull_request_id}`; text += `\nWebhook: ${deployment.is_webhook ? 'Yes' : 'No'}`; text += `\nForce Rebuild: ${deployment.force_rebuild ? 'Yes' : 'No'}`; text += `\nCreated: ${deployment.created_at}`; if (deployment.logs) text += `\n\nLogs:\n${deployment.logs}`; return { content: [{ type: 'text', text }] }; } catch (error) { return this.formatError(error); } } async deployByWebhook(input: unknown) { try { const { uuid, tag } = DeployWebhookSchema.parse(input); const result = await this.client.deployByWebhook(uuid, tag); return { content: [{ type: 'text', text: `${result.message}\nDeployment UUID: ${result.deployment_uuid}`, }], }; } catch (error) { return this.formatError(error); } } // Private Key Tools async listPrivateKeys() { try { const keys = await this.client.listPrivateKeys(); const text = keys.map(key => `UUID: ${key.uuid}\n` + `Name: ${key.name}` + (key.description ? `\nDescription: ${key.description}` : '') ).join('\n\n'); return { content: [{ type: 'text', text: text || 'No private keys found', }], }; } catch (error) { return this.formatError(error); } } async createPrivateKey(input: unknown) { try { const data = CreatePrivateKeySchema.parse(input); const key = await this.client.createPrivateKey(data); return { content: [{ type: 'text', text: `Private key created successfully!\nUUID: ${key.uuid}\nName: ${key.name}`, }], }; } catch (error) { return this.formatError(error); } } async updatePrivateKey(input: unknown) { try { const parsed = PrivateKeyUuidSchema.merge(CreatePrivateKeySchema.partial()).parse(input); const { uuid, ...data } = parsed; const key = await this.client.updatePrivateKey(uuid, data); return { content: [{ type: 'text', text: `Private key updated successfully!\nUUID: ${key.uuid}\nName: ${key.name}`, }], }; } catch (error) { return this.formatError(error); } } async deletePrivateKey(input: unknown) { try { const { uuid } = PrivateKeyUuidSchema.parse(input); await this.client.deletePrivateKey(uuid); return { content: [{ type: 'text', text: 'Private key deleted successfully', }], }; } catch (error) { return this.formatError(error); } } }

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/pavelsukhachev/mcp-server-coolify'

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