Skip to main content
Glama
sondt2709

Docker MCP

by sondt2709
ComposeService.ts6.55 kB
import Docker from "dockerode"; import path from "path"; import fs from "fs"; import { DockerComposeProject } from "../types/docker.js"; export class ComposeService { private docker: Docker; constructor(dockerInstance?: Docker) { this.docker = dockerInstance || new Docker({ socketPath: '/var/run/docker.sock' }); } async up(composePath: string, projectName?: string, services?: string[]): Promise<any> { try { return { success: true, message: `Docker Compose up functionality will be implemented with docker-compose CLI integration`, details: { composePath, projectName, services } }; } catch (error) { throw new Error(`Failed to start compose services: ${error instanceof Error ? error.message : String(error)}`); } } async down(composePath: string, projectName?: string, options: { removeVolumes?: boolean; removeImages?: boolean } = {}): Promise<any> { try { return { success: true, message: "Docker Compose down functionality will be implemented with docker-compose CLI integration", details: { composePath, projectName, options } }; } catch (error) { throw new Error(`Failed to stop compose services: ${error instanceof Error ? error.message : String(error)}`); } } async pull(composePath: string, projectName?: string, services?: string[]): Promise<any> { try { return { success: true, message: `Docker Compose pull functionality will be implemented with docker-compose CLI integration`, details: { composePath, projectName, services } }; } catch (error) { throw new Error(`Failed to pull compose images: ${error instanceof Error ? error.message : String(error)}`); } } async logs(composePath: string, projectName?: string, options: { services?: string[]; tail?: number; follow?: boolean; timestamps?: boolean; } = {}): Promise<string> { try { // For now, we'll get logs from individual containers const project = await this.getProjectInfo(composePath, projectName); const containerLogs: string[] = []; // Get all containers for this project const containers = await this.docker.listContainers({ all: true, filters: JSON.stringify({ label: [`com.docker.compose.project=${project.name}`] }) }); for (const containerInfo of containers) { const container = this.docker.getContainer(containerInfo.Id); const serviceName = containerInfo.Labels['com.docker.compose.service']; // Filter by services if specified if (options.services && !options.services.includes(serviceName)) { continue; } try { // Use the same pattern as DockerService const logs = await new Promise<string>((resolve, reject) => { const logOptions: any = { stdout: true, stderr: true, timestamps: options.timestamps || false, tail: options.tail || 100 }; container.logs(logOptions, (err: any, stream: any) => { if (err) { reject(err); return; } let output = ''; if (stream) { stream.on('data', (chunk: Buffer) => { output += chunk.toString(); }); stream.on('end', () => { resolve(output); }); stream.on('error', reject); } else { resolve(''); } }); }); containerLogs.push(`=== ${serviceName} (${containerInfo.Id.substring(0, 12)}) ===\n${logs}`); } catch (logError) { containerLogs.push(`=== ${serviceName} (${containerInfo.Id.substring(0, 12)}) ===\nError fetching logs: ${logError}`); } } return containerLogs.join('\n\n'); } catch (error) { throw new Error(`Failed to get compose logs: ${error instanceof Error ? error.message : String(error)}`); } } async getProjectInfo(composePath: string, projectName?: string): Promise<DockerComposeProject> { try { const absolutePath = path.resolve(composePath); const defaultProjectName = projectName || path.basename(path.dirname(absolutePath)); if (!fs.existsSync(absolutePath)) { throw new Error(`Docker compose file not found: ${absolutePath}`); } // For now, return basic project info // In a full implementation, you might parse the compose file return { name: defaultProjectName, services: [], // Would be parsed from compose file networks: [], volumes: [], configFiles: [absolutePath] }; } catch (error) { throw new Error(`Failed to get project info: ${error instanceof Error ? error.message : String(error)}`); } } async restart(composePath: string, projectName?: string, services?: string[]): Promise<any> { try { // Stop and then start services await this.down(composePath, projectName); const result = await this.up(composePath, projectName, services); return { success: true, message: `Successfully restarted services${services ? ` for: ${services.join(', ')}` : ''}`, details: result }; } catch (error) { throw new Error(`Failed to restart compose services: ${error instanceof Error ? error.message : String(error)}`); } } async ps(composePath: string, projectName?: string): Promise<any> { try { const project = await this.getProjectInfo(composePath, projectName); // Get all containers for this project const containers = await this.docker.listContainers({ all: true, filters: JSON.stringify({ label: [`com.docker.compose.project=${project.name}`] }) }); return containers.map(container => ({ id: container.Id, name: container.Names[0], service: container.Labels['com.docker.compose.service'], state: container.State, status: container.Status, ports: container.Ports, image: container.Image })); } catch (error) { throw new Error(`Failed to get compose project status: ${error instanceof Error ? error.message : String(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/sondt2709/docker-mcp'

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