Files
python-mcp/tools/docker.py
AuroraCrimsonRose e471f9bc54 Added many tools
2026-06-03 06:01:06 -05:00

225 lines
6.4 KiB
Python

from __future__ import annotations
from typing import Any
from core.tools.base import BaseTool, ToolContext
from core.tools.registry import registry
from core.events import bus
from core.subprocess import run_command
class DockerTool(BaseTool):
name = "docker"
description = "Docker container and image management"
# =========================================================
# EXECUTE ROUTER
# =========================================================
def execute(self, payload: dict[str, Any], ctx: ToolContext):
action = str(payload.get("action", "")).strip()
bus.log(
"DOCKER",
"docker_execute",
"INFO",
{"action": action}
)
match action:
case "ps":
return self.ps(payload)
case "run":
return self.run_container(payload, ctx)
case "stop":
return self.stop_container(payload)
case "start":
return self.start_container(payload)
case "restart":
return self.restart_container(payload)
case "logs":
return self.logs(payload)
case "images":
return self.images(payload)
case "build":
return self.build_image(payload, ctx)
case _:
raise ValueError(f"Unknown docker action: {action}")
# =========================================================
# CONTAINERS LIST
# =========================================================
def ps(self, payload: dict[str, Any]):
all_containers = payload.get("all", False)
cmd = ["docker", "ps"]
if all_containers:
cmd.append("-a")
result = run_command(cmd=cmd)
return {
"action": "ps",
"status": "ok" if result.get("return_code") == 0 else "error",
"output": result.get("stdout", ""),
"error": result.get("stderr", "")
}
# =========================================================
# RUN CONTAINER
# =========================================================
def run_container(self, payload: dict[str, Any], ctx: ToolContext):
image = payload.get("image")
name = payload.get("name")
args = payload.get("args", [])
if not isinstance(image, str):
raise ValueError("image must be string")
if not isinstance(args, list):
raise ValueError("args must be list")
cmd = ["docker", "run"]
if name:
if not isinstance(name, str):
raise ValueError("name must be string")
cmd += ["--name", name]
cmd += args
cmd.append(image)
if ctx.dry_run:
return {
"dry_run": True,
"command": cmd
}
result = run_command(cmd=cmd)
return {
"action": "run",
"image": image,
"status": "ok" if result.get("return_code") == 0 else "error",
"stdout": result.get("stdout", ""),
"stderr": result.get("stderr", "")
}
# =========================================================
# STOP / START / RESTART
# =========================================================
def stop_container(self, payload: dict[str, Any]):
return self._simple_container_action("stop", payload)
def start_container(self, payload: dict[str, Any]):
return self._simple_container_action("start", payload)
def restart_container(self, payload: dict[str, Any]):
return self._simple_container_action("restart", payload)
def _simple_container_action(self, action: str, payload: dict[str, Any]):
container = payload.get("container")
if not isinstance(container, str):
raise ValueError("container must be string")
result = run_command(
cmd=["docker", action, container]
)
return {
"action": action,
"container": container,
"status": "ok" if result.get("return_code") == 0 else "error",
"stdout": result.get("stdout", ""),
"stderr": result.get("stderr", "")
}
# =========================================================
# LOGS
# =========================================================
def logs(self, payload: dict[str, Any]):
container = payload.get("container")
tail = payload.get("tail", 100)
if not isinstance(container, str):
raise ValueError("container must be string")
cmd = ["docker", "logs", "--tail", str(tail), container]
result = run_command(cmd=cmd)
return {
"action": "logs",
"container": container,
"output": result.get("stdout", ""),
"error": result.get("stderr", "")
}
# =========================================================
# IMAGES
# =========================================================
def images(self, payload: dict[str, Any]):
result = run_command(cmd=["docker", "images"])
return {
"action": "images",
"output": result.get("stdout", ""),
"error": result.get("stderr", "")
}
# =========================================================
# BUILD IMAGE
# =========================================================
def build_image(self, payload: dict[str, Any], ctx: ToolContext):
path = payload.get("path", ".")
tag = payload.get("tag")
if not isinstance(path, str):
raise ValueError("path must be string")
cmd = ["docker", "build", "-t"]
if isinstance(tag, str):
cmd.append(tag)
else:
cmd.append("untagged-image")
cmd.append(path)
if ctx.dry_run:
return {
"dry_run": True,
"command": cmd
}
result = run_command(cmd=cmd)
return {
"action": "build",
"path": path,
"status": "ok" if result.get("return_code") == 0 else "error",
"stdout": result.get("stdout", ""),
"stderr": result.get("stderr", "")
}
# =========================================================
# REGISTER TOOL
# =========================================================
registry.register(DockerTool())