import { ComposeManager } from '../managers/compose.js';
import { z } from 'zod';
export function getComposeTools() {
return [
{
name: 'docker_compose_up',
description: 'Start Docker Compose services',
inputSchema: {
type: 'object',
properties: {
projectDir: {
type: 'string',
description: 'Path to the directory containing docker-compose.yml',
},
build: {
type: 'boolean',
description: 'Build images before starting containers',
},
detach: {
type: 'boolean',
description: 'Run containers in the background',
},
forceRecreate: {
type: 'boolean',
description: 'Recreate containers even if their configuration and image haven\'t changed',
},
noBuild: {
type: 'boolean',
description: 'Don\'t build an image, even if it\'s missing',
},
noDeps: {
type: 'boolean',
description: 'Don\'t start linked services',
},
pull: {
type: 'string',
enum: ['always', 'missing', 'never'],
description: 'Pull image before running (always|missing|never)',
},
removeOrphans: {
type: 'boolean',
description: 'Remove containers for services not defined in the compose file',
},
scale: {
type: 'object',
description: 'Scale services (e.g., {"web": 2, "db": 1})',
additionalProperties: { type: 'number' },
},
services: {
type: 'array',
items: { type: 'string' },
description: 'Specific services to start',
},
},
required: ['projectDir'],
},
},
{
name: 'docker_compose_down',
description: 'Stop and remove Docker Compose services',
inputSchema: {
type: 'object',
properties: {
projectDir: {
type: 'string',
description: 'Path to the directory containing docker-compose.yml',
},
removeOrphans: {
type: 'boolean',
description: 'Remove containers for services not defined in the compose file',
},
volumes: {
type: 'boolean',
description: 'Remove named volumes declared in the volumes section',
},
images: {
type: 'string',
enum: ['all', 'local'],
description: 'Remove images used by services (all|local)',
},
timeout: {
type: 'number',
description: 'Specify a shutdown timeout in seconds',
},
},
required: ['projectDir'],
},
},
{
name: 'docker_compose_ps',
description: 'List Docker Compose services',
inputSchema: {
type: 'object',
properties: {
projectDir: {
type: 'string',
description: 'Path to the directory containing docker-compose.yml',
},
all: {
type: 'boolean',
description: 'Show all stopped containers',
},
services: {
type: 'array',
items: { type: 'string' },
description: 'Specific services to list',
},
},
required: ['projectDir'],
},
},
{
name: 'docker_compose_logs',
description: 'View output from Docker Compose services',
inputSchema: {
type: 'object',
properties: {
projectDir: {
type: 'string',
description: 'Path to the directory containing docker-compose.yml',
},
follow: {
type: 'boolean',
description: 'Follow log output',
},
tail: {
type: 'number',
description: 'Number of lines to show from the end of the logs',
},
since: {
type: 'string',
description: 'Show logs since timestamp (e.g., "2023-01-01T00:00:00")',
},
until: {
type: 'string',
description: 'Show logs before timestamp',
},
timestamps: {
type: 'boolean',
description: 'Show timestamps',
},
services: {
type: 'array',
items: { type: 'string' },
description: 'Specific services to show logs for',
},
},
required: ['projectDir'],
},
},
{
name: 'docker_compose_config',
description: 'Parse and validate docker-compose.yml file',
inputSchema: {
type: 'object',
properties: {
projectDir: {
type: 'string',
description: 'Path to the directory containing docker-compose.yml',
},
},
required: ['projectDir'],
},
},
{
name: 'docker_compose_build',
description: 'Build Docker Compose services',
inputSchema: {
type: 'object',
properties: {
projectDir: {
type: 'string',
description: 'Path to the directory containing docker-compose.yml',
},
services: {
type: 'array',
items: { type: 'string' },
description: 'Specific services to build',
},
noCache: {
type: 'boolean',
description: 'Do not use cache when building the image',
},
pull: {
type: 'boolean',
description: 'Always attempt to pull a newer version of the image',
},
},
required: ['projectDir'],
},
},
{
name: 'docker_compose_restart',
description: 'Restart Docker Compose services',
inputSchema: {
type: 'object',
properties: {
projectDir: {
type: 'string',
description: 'Path to the directory containing docker-compose.yml',
},
services: {
type: 'array',
items: { type: 'string' },
description: 'Specific services to restart',
},
timeout: {
type: 'number',
description: 'Specify a shutdown timeout in seconds',
},
},
required: ['projectDir'],
},
},
{
name: 'docker_compose_stop',
description: 'Stop Docker Compose services',
inputSchema: {
type: 'object',
properties: {
projectDir: {
type: 'string',
description: 'Path to the directory containing docker-compose.yml',
},
services: {
type: 'array',
items: { type: 'string' },
description: 'Specific services to stop',
},
timeout: {
type: 'number',
description: 'Specify a shutdown timeout in seconds',
},
},
required: ['projectDir'],
},
},
{
name: 'docker_compose_start',
description: 'Start Docker Compose services',
inputSchema: {
type: 'object',
properties: {
projectDir: {
type: 'string',
description: 'Path to the directory containing docker-compose.yml',
},
services: {
type: 'array',
items: { type: 'string' },
description: 'Specific services to start',
},
},
required: ['projectDir'],
},
},
];
}
export async function handleComposeTool(
name: string,
args: any,
composeManager: ComposeManager
): Promise<any> {
try {
switch (name) {
case 'docker_compose_up': {
const parsed = z
.object({
projectDir: z.string(),
build: z.boolean().optional(),
detach: z.boolean().optional(),
forceRecreate: z.boolean().optional(),
noBuild: z.boolean().optional(),
noDeps: z.boolean().optional(),
pull: z.enum(['always', 'missing', 'never']).optional(),
removeOrphans: z.boolean().optional(),
scale: z.record(z.number()).optional(),
services: z.array(z.string()).optional(),
})
.parse(args);
const result = await composeManager.composeUp(parsed.projectDir, {
build: parsed.build,
detach: parsed.detach,
forceRecreate: parsed.forceRecreate,
noBuild: parsed.noBuild,
noDeps: parsed.noDeps,
pull: parsed.pull,
removeOrphans: parsed.removeOrphans,
scale: parsed.scale,
services: parsed.services,
});
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
case 'docker_compose_down': {
const parsed = z
.object({
projectDir: z.string(),
removeOrphans: z.boolean().optional(),
volumes: z.boolean().optional(),
images: z.enum(['all', 'local']).optional(),
timeout: z.number().optional(),
})
.parse(args);
const result = await composeManager.composeDown(parsed.projectDir, {
removeOrphans: parsed.removeOrphans,
volumes: parsed.volumes,
images: parsed.images,
timeout: parsed.timeout,
});
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
case 'docker_compose_ps': {
const parsed = z
.object({
projectDir: z.string(),
all: z.boolean().optional(),
services: z.array(z.string()).optional(),
})
.parse(args);
const result = await composeManager.composePs(parsed.projectDir, {
all: parsed.all,
services: parsed.services,
});
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
case 'docker_compose_logs': {
const parsed = z
.object({
projectDir: z.string(),
follow: z.boolean().optional(),
tail: z.number().optional(),
since: z.string().optional(),
until: z.string().optional(),
timestamps: z.boolean().optional(),
services: z.array(z.string()).optional(),
})
.parse(args);
const result = await composeManager.composeLogs(parsed.projectDir, {
follow: parsed.follow,
tail: parsed.tail,
since: parsed.since,
until: parsed.until,
timestamps: parsed.timestamps,
services: parsed.services,
});
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
case 'docker_compose_config': {
const parsed = z
.object({
projectDir: z.string(),
})
.parse(args);
const result = await composeManager.composeConfig(parsed.projectDir);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}
case 'docker_compose_build': {
const parsed = z
.object({
projectDir: z.string(),
services: z.array(z.string()).optional(),
noCache: z.boolean().optional(),
pull: z.boolean().optional(),
})
.parse(args);
const result = await composeManager.composeBuild(parsed.projectDir, {
services: parsed.services,
noCache: parsed.noCache,
pull: parsed.pull,
});
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
case 'docker_compose_restart': {
const parsed = z
.object({
projectDir: z.string(),
services: z.array(z.string()).optional(),
timeout: z.number().optional(),
})
.parse(args);
const result = await composeManager.composeRestart(parsed.projectDir, {
services: parsed.services,
timeout: parsed.timeout,
});
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
case 'docker_compose_stop': {
const parsed = z
.object({
projectDir: z.string(),
services: z.array(z.string()).optional(),
timeout: z.number().optional(),
})
.parse(args);
const result = await composeManager.composeStop(parsed.projectDir, {
services: parsed.services,
timeout: parsed.timeout,
});
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
case 'docker_compose_start': {
const parsed = z
.object({
projectDir: z.string(),
services: z.array(z.string()).optional(),
})
.parse(args);
const result = await composeManager.composeStart(parsed.projectDir, {
services: parsed.services,
});
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
default:
return null;
}
} catch (error: any) {
if (error.message?.includes('Unknown tool')) {
return null;
}
throw error;
}
}