docker_run
Execute Docker containers with specified image, command, ports, volumes, and environment settings. Configure detach, remove, interactive, TTY, network, working directory, user, memory, CPU, and restart policy.
Instructions
Run a Docker container
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| image | Yes | Docker image to run | |
| name | No | Container name | |
| command | No | Command to run in container | |
| args | No | Command arguments | |
| ports | No | Port mappings (e.g., ["8080:80", "3000:3000"]) | |
| volumes | No | Volume mounts (e.g., ["/host/path:/container/path"]) | |
| env | No | Environment variables as key-value pairs | |
| detach | No | Run container in background | |
| remove | No | Remove container when it exits | |
| interactive | No | Keep STDIN open | |
| tty | No | Allocate a pseudo-TTY | |
| network | No | Network to connect container to | |
| working_dir | No | Working directory inside container | |
| user | No | Username or UID (format: <name|uid>[:<group|gid>]) | |
| memory | No | Memory limit (e.g., "512m", "2g") | |
| cpus | No | CPU limit (e.g., "0.5", "2") | |
| restart | No | Restart policy (no, on-failure, always, unless-stopped) |
Implementation Reference
- src/services/DockerService.ts:371-496 (handler)The runContainer method is the main handler for the docker_run tool. It constructs a 'docker run' command from the provided DockerRunArgs, executes it via executeDockerCommand, and tracks detached containers by name.
async runContainer(args: DockerRunArgs): Promise<ToolResult> { const { image, name, command: cmd, args: cmdArgs = [], ports = [], volumes = [], env, detach, remove, interactive, tty, network, working_dir, user, memory, cpus, restart, privileged, read_only, security_opt = [], tmpfs = [], ulimit = [], cap_add = [], cap_drop = [], device = [], entrypoint, hostname, init, label, log_driver, log_opt, mac_address, shm_size, stop_signal, stop_timeout } = args; ValidationUtils.validateRequired({ image }, ['image']); let command = 'docker run'; if (detach) command += ' -d'; if (remove) command += ' --rm'; if (interactive) command += ' -i'; if (tty) command += ' -t'; if (name) command += ` --name ${name}`; if (network) command += ` --network ${network}`; if (working_dir) command += ` -w ${working_dir}`; if (user) command += ` -u ${user}`; if (memory) command += ` -m ${memory}`; if (cpus) command += ` --cpus ${cpus}`; if (restart) command += ` --restart ${restart}`; if (privileged) command += ' --privileged'; if (read_only) command += ' --read-only'; if (entrypoint) command += ` --entrypoint ${entrypoint}`; if (hostname) command += ` --hostname ${hostname}`; if (init) command += ' --init'; if (mac_address) command += ` --mac-address ${mac_address}`; if (shm_size) command += ` --shm-size ${shm_size}`; if (stop_signal) command += ` --stop-signal ${stop_signal}`; if (stop_timeout) command += ` --stop-timeout ${stop_timeout}`; if (log_driver) command += ` --log-driver ${log_driver}`; // Add ports ports.forEach(port => command += ` -p ${port}`); // Add volumes volumes.forEach(volume => command += ` -v ${volume}`); // Add environment variables if (env) { for (const [key, value] of Object.entries(env)) { command += ` -e ${key}=${value}`; } } // Add security options security_opt.forEach(opt => command += ` --security-opt ${opt}`); // Add tmpfs mounts tmpfs.forEach(mount => command += ` --tmpfs ${mount}`); // Add ulimits ulimit.forEach(limit => command += ` --ulimit ${limit}`); // Add capabilities cap_add.forEach(cap => command += ` --cap-add ${cap}`); cap_drop.forEach(cap => command += ` --cap-drop ${cap}`); // Add devices device.forEach(dev => command += ` --device ${dev}`); // Add labels if (label) { for (const [key, value] of Object.entries(label)) { command += ` --label ${key}=${value}`; } } // Add log options if (log_opt) { for (const [key, value] of Object.entries(log_opt)) { command += ` --log-opt ${key}=${value}`; } } command += ` ${image}`; if (cmd) command += ` ${cmd}`; if (cmdArgs.length > 0) command += ` ${cmdArgs.join(' ')}`; try { const result = await this.executeDockerCommand(command, { cwd: this.getCurrentWorkspace() }); // Track running containers if detached if (detach && name) { this.runningContainers.set(name, { image, started: new Date() }); } return result; } catch (error: any) { throw new Error(`Docker run failed: ${error.message}`); } } - src/services/DockerService.ts:29-65 (schema)The DockerRunArgs interface defines the input schema/type for the docker_run tool, including image, name, command, ports, volumes, env, detach, remove, and many other Docker run options.
export interface DockerRunArgs { image: string; name?: string; command?: string; args?: string[]; ports?: string[]; volumes?: string[]; env?: Record<string, string>; detach?: boolean; remove?: boolean; interactive?: boolean; tty?: boolean; network?: string; working_dir?: string; user?: string; memory?: string; cpus?: string; restart?: string; privileged?: boolean; read_only?: boolean; security_opt?: string[]; tmpfs?: string[]; ulimit?: string[]; cap_add?: string[]; cap_drop?: string[]; device?: string[]; entrypoint?: string; hostname?: string; init?: boolean; label?: Record<string, string>; log_driver?: string; log_opt?: Record<string, string>; mac_address?: string; shm_size?: string; stop_signal?: string; stop_timeout?: number; } - src/index.ts:207-208 (registration)The tool registration point: when 'docker_run' is called, it routes to dockerService.runContainer() in the executeToolCommand switch statement.
case 'docker_run': return await this.dockerService.runContainer(args as DockerRunArgs); - src/toolDefinitions.ts:438-463 (registration)The tool definition (inputSchema) for docker_run, registering it as an MCP tool with all input properties (image, name, ports, volumes, env, etc.) and marking 'image' as required.
name: 'docker_run', description: 'Run a Docker container', inputSchema: { type: 'object', properties: { image: { type: 'string', description: 'Docker image to run' }, name: { type: 'string', description: 'Container name' }, command: { type: 'string', description: 'Command to run in container' }, args: { type: 'array', items: { type: 'string' }, description: 'Command arguments' }, ports: { type: 'array', items: { type: 'string' }, description: 'Port mappings (e.g., ["8080:80", "3000:3000"])' }, volumes: { type: 'array', items: { type: 'string' }, description: 'Volume mounts (e.g., ["/host/path:/container/path"])' }, env: { type: 'object', description: 'Environment variables as key-value pairs' }, detach: { type: 'boolean', description: 'Run container in background' }, remove: { type: 'boolean', description: 'Remove container when it exits' }, interactive: { type: 'boolean', description: 'Keep STDIN open' }, tty: { type: 'boolean', description: 'Allocate a pseudo-TTY' }, network: { type: 'string', description: 'Network to connect container to' }, working_dir: { type: 'string', description: 'Working directory inside container' }, user: { type: 'string', description: 'Username or UID (format: <name|uid>[:<group|gid>])' }, memory: { type: 'string', description: 'Memory limit (e.g., "512m", "2g")' }, cpus: { type: 'string', description: 'CPU limit (e.g., "0.5", "2")' }, restart: { type: 'string', description: 'Restart policy (no, on-failure, always, unless-stopped)' }, }, required: ['image'], }, }, - The executeDockerCommand helper method that spawns a shell process, captures stdout/stderr, enforces timeouts, and returns a ToolResult. Called by runContainer to execute the constructed docker run command.
private async executeDockerCommand( command: string, options: any = {}, timeout: number = this.defaultTimeout ): Promise<ToolResult> { return new Promise((resolve, reject) => { const child = spawn(command, [], { shell: true, cwd: options.cwd || this.getCurrentWorkspace(), env: options.env || process.env, stdio: ['pipe', 'pipe', 'pipe'] }); let stdout = ''; let stderr = ''; let isResolved = false; let timeoutId: NodeJS.Timeout | null = null; // Set timeout if (timeout > 0) { timeoutId = setTimeout(() => { if (!isResolved) { isResolved = true; child.kill('SIGTERM'); setTimeout(() => { if (!child.killed) { child.kill('SIGKILL'); } }, 5000); reject(new Error(`Docker command timed out after ${timeout}ms: ${command}`)); } }, timeout); } // Capture output with size limits child.stdout?.on('data', (data) => { const chunk = data.toString(); stdout += chunk; if (stdout.length > 2 * 1024 * 1024) { // 2MB limit stdout = stdout.slice(-1024 * 1024) + '\n...[output truncated]...'; } }); child.stderr?.on('data', (data) => { const chunk = data.toString(); stderr += chunk; if (stderr.length > 1024 * 1024) { // 1MB limit stderr = stderr.slice(-512 * 1024) + '\n...[error output truncated]...'; } }); child.on('error', (error) => { if (!isResolved) { isResolved = true; if (timeoutId) clearTimeout(timeoutId); reject(new Error(`Failed to execute Docker command: ${error.message}`)); } }); child.on('exit', (code, signal) => { if (!isResolved) { isResolved = true; if (timeoutId) clearTimeout(timeoutId); if (code === 0 || (code === null && signal === 'SIGTERM')) { resolve({ content: [{ type: 'text', text: `${stdout}${stderr ? `\nWarnings/Errors:\n${stderr}` : ''}`.trim(), }], }); } else { const errorMsg = stderr || stdout || `Process exited with code ${code}`; reject(new Error(`Docker command failed: ${command}\n${errorMsg}`)); } } }); }); }