import { ExecManager } from '../managers/exec.js';
import { z } from 'zod';
export function getExecTools() {
return [
{
name: 'docker_exec',
description: 'Execute a command in a running container',
inputSchema: {
type: 'object',
properties: {
containerId: {
type: 'string',
description: 'Container ID or name',
},
cmd: {
type: 'array',
items: { type: 'string' },
description: 'Command to execute (e.g., ["ls", "-la"])',
},
env: {
type: 'array',
items: { type: 'string' },
description: 'Environment variables (e.g., ["KEY=value"])',
},
workingDir: {
type: 'string',
description: 'Working directory inside the container',
},
user: {
type: 'string',
description: 'User to run as (e.g., "root", "1000:1000")',
},
tty: {
type: 'boolean',
description: 'Allocate a pseudo-TTY',
},
privileged: {
type: 'boolean',
description: 'Run in privileged mode',
},
},
required: ['containerId', 'cmd'],
},
},
{
name: 'docker_inspect_exec',
description: 'Get information about an exec instance',
inputSchema: {
type: 'object',
properties: {
execId: {
type: 'string',
description: 'Exec instance ID',
},
},
required: ['execId'],
},
},
];
}
export async function handleExecTool(
name: string,
args: any,
execManager: ExecManager
): Promise<any> {
try {
switch (name) {
case 'docker_exec': {
const parsed = z
.object({
containerId: z.string(),
cmd: z.array(z.string()),
env: z.array(z.string()).optional(),
workingDir: z.string().optional(),
user: z.string().optional(),
tty: z.boolean().optional(),
privileged: z.boolean().optional(),
})
.parse(args);
const exec = await execManager.createExec(parsed.containerId, {
Cmd: parsed.cmd,
Env: parsed.env,
WorkingDir: parsed.workingDir,
User: parsed.user,
Tty: parsed.tty ?? false,
Privileged: parsed.privileged ?? false,
AttachStdout: true,
AttachStderr: true,
AttachStdin: false,
});
const stream = await execManager.startExec(exec.id, {
Detach: false,
Tty: parsed.tty ?? false,
});
// Read output from stream
const chunks: Buffer[] = [];
for await (const chunk of stream as any) {
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
}
const output = Buffer.concat(chunks).toString('utf-8');
return {
content: [
{
type: 'text',
text: output || JSON.stringify({ message: 'Command executed successfully' }, null, 2),
},
],
};
}
case 'docker_inspect_exec': {
const parsed = z.object({ execId: z.string() }).parse(args);
const info = await execManager.inspectExec(parsed.execId);
return {
content: [
{
type: 'text',
text: JSON.stringify(info, null, 2),
},
],
};
}
default:
return null;
}
} catch (error: any) {
if (error.message?.includes('Unknown tool')) {
return null;
}
throw error;
}
}