@supernova123/docker-mcp-server 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tools/compose.js +4 -4
- package/dist/tools/container.js +7 -7
- package/dist/tools/exec.js +1 -1
- package/dist/tools/health.js +3 -3
- package/dist/tools/image.js +4 -4
- package/dist/tools/logs.js +1 -1
- package/dist/tools/monitoring.js +6 -6
- package/dist/tools/network.js +2 -2
- package/package.json +1 -1
- package/src/tools/compose.ts +5 -1
- package/src/tools/container.ts +8 -1
- package/src/tools/exec.ts +2 -1
- package/src/tools/health.ts +4 -1
- package/src/tools/image.ts +5 -1
- package/src/tools/logs.ts +2 -1
- package/src/tools/monitoring.ts +12 -6
- package/src/tools/network.ts +3 -1
package/dist/tools/compose.js
CHANGED
|
@@ -38,7 +38,7 @@ function runCompose(path, args) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
export function registerComposeTools(server) {
|
|
41
|
-
server.tool("compose_up", "Bring up Docker Compose services from a docker-compose.yml file. Optionally build images first.", ComposeUpSchema.shape, async (params) => {
|
|
41
|
+
server.tool("compose_up", "Bring up Docker Compose services from a docker-compose.yml file. Optionally build images first.", ComposeUpSchema.shape, { idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
42
42
|
try {
|
|
43
43
|
const args = ["up", "-d"];
|
|
44
44
|
if (params.build)
|
|
@@ -52,7 +52,7 @@ export function registerComposeTools(server) {
|
|
|
52
52
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
|
-
server.tool("compose_down", "Tear down Docker Compose services. Optionally remove named volumes.", ComposeDownSchema.shape, async (params) => {
|
|
55
|
+
server.tool("compose_down", "Tear down Docker Compose services. Optionally remove named volumes.", ComposeDownSchema.shape, { destructiveHint: true, openWorldHint: false }, async (params) => {
|
|
56
56
|
try {
|
|
57
57
|
const args = ["down"];
|
|
58
58
|
if (params.volumes)
|
|
@@ -66,7 +66,7 @@ export function registerComposeTools(server) {
|
|
|
66
66
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
67
67
|
}
|
|
68
68
|
});
|
|
69
|
-
server.tool("compose_ps", "List service states across a Docker Compose stack.", ComposePsSchema.shape, async (params) => {
|
|
69
|
+
server.tool("compose_ps", "List service states across a Docker Compose stack.", ComposePsSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
70
70
|
try {
|
|
71
71
|
const output = runCompose(params.path, ["ps", "--format", "json"]);
|
|
72
72
|
const lines = output.split("\n").filter(Boolean);
|
|
@@ -98,7 +98,7 @@ export function registerComposeTools(server) {
|
|
|
98
98
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
99
99
|
}
|
|
100
100
|
});
|
|
101
|
-
server.tool("compose_restart", "Restart Docker Compose services. Restart specific services or the entire stack.", ComposeRestartSchema.shape, async (params) => {
|
|
101
|
+
server.tool("compose_restart", "Restart Docker Compose services. Restart specific services or the entire stack.", ComposeRestartSchema.shape, { destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
102
102
|
try {
|
|
103
103
|
const args = ["restart"];
|
|
104
104
|
if (params.timeout)
|
package/dist/tools/container.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ListContainersSchema, InspectContainerSchema, StartContainerSchema, StopContainerSchema, RestartContainerSchema, RemoveContainerSchema, RecreateContainerSchema, RunContainerSchema, } from "../types.js";
|
|
2
2
|
import { formatContainer, formatError } from "../docker.js";
|
|
3
3
|
export function registerContainerTools(server, docker) {
|
|
4
|
-
server.tool("list_containers", "List Docker containers with optional filters (state, label, name). Returns container IDs, names, images, states, ports, and labels.", ListContainersSchema.shape, async (params) => {
|
|
4
|
+
server.tool("list_containers", "List Docker containers with optional filters (state, label, name). Returns container IDs, names, images, states, ports, and labels.", ListContainersSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
5
5
|
try {
|
|
6
6
|
const containers = await docker.listContainers({
|
|
7
7
|
all: params.all ?? false,
|
|
@@ -18,7 +18,7 @@ export function registerContainerTools(server, docker) {
|
|
|
18
18
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
|
-
server.tool("inspect_container", "Get detailed configuration and state of a Docker container by ID or name.", InspectContainerSchema.shape, async (params) => {
|
|
21
|
+
server.tool("inspect_container", "Get detailed configuration and state of a Docker container by ID or name.", InspectContainerSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
22
22
|
try {
|
|
23
23
|
const container = docker.getContainer(params.container_id);
|
|
24
24
|
const info = await container.inspect();
|
|
@@ -28,7 +28,7 @@ export function registerContainerTools(server, docker) {
|
|
|
28
28
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
|
-
server.tool("start_container", "Start a stopped Docker container by ID or name.", StartContainerSchema.shape, async (params) => {
|
|
31
|
+
server.tool("start_container", "Start a stopped Docker container by ID or name.", StartContainerSchema.shape, { idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
32
32
|
try {
|
|
33
33
|
const container = docker.getContainer(params.container_id);
|
|
34
34
|
await container.start();
|
|
@@ -38,7 +38,7 @@ export function registerContainerTools(server, docker) {
|
|
|
38
38
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
39
39
|
}
|
|
40
40
|
});
|
|
41
|
-
server.tool("stop_container", "Stop a running Docker container by ID or name with optional timeout.", StopContainerSchema.shape, async (params) => {
|
|
41
|
+
server.tool("stop_container", "Stop a running Docker container by ID or name with optional timeout.", StopContainerSchema.shape, { destructiveHint: true, openWorldHint: false }, async (params) => {
|
|
42
42
|
try {
|
|
43
43
|
const container = docker.getContainer(params.container_id);
|
|
44
44
|
await container.stop({ t: params.timeout ?? 10 });
|
|
@@ -62,7 +62,7 @@ export function registerContainerTools(server, docker) {
|
|
|
62
62
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
|
-
server.tool("remove_container", "Remove a Docker container by ID or name. Use force to remove running containers.", RemoveContainerSchema.shape, async (params) => {
|
|
65
|
+
server.tool("remove_container", "Remove a Docker container by ID or name. Use force to remove running containers.", RemoveContainerSchema.shape, { destructiveHint: true, openWorldHint: false }, async (params) => {
|
|
66
66
|
try {
|
|
67
67
|
const container = docker.getContainer(params.container_id);
|
|
68
68
|
await container.remove({ force: params.force ?? false });
|
|
@@ -72,7 +72,7 @@ export function registerContainerTools(server, docker) {
|
|
|
72
72
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
|
-
server.tool("recreate_container", "Recreate a container with the same configuration (stop, remove, re-create). Useful for applying config changes.", RecreateContainerSchema.shape, async (params) => {
|
|
75
|
+
server.tool("recreate_container", "Recreate a container with the same configuration (stop, remove, re-create). Useful for applying config changes.", RecreateContainerSchema.shape, { destructiveHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
76
76
|
try {
|
|
77
77
|
const container = docker.getContainer(params.container_id);
|
|
78
78
|
const info = await container.inspect();
|
|
@@ -107,7 +107,7 @@ export function registerContainerTools(server, docker) {
|
|
|
107
107
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
|
-
server.tool("run_container", "Create and start a new Docker container with one command. Supports image, env, ports, volumes, restart policy, and command override. Auto-pulls missing images.", RunContainerSchema.shape, async (params) => {
|
|
110
|
+
server.tool("run_container", "Create and start a new Docker container with one command. Supports image, env, ports, volumes, restart policy, and command override. Auto-pulls missing images.", RunContainerSchema.shape, { openWorldHint: false }, async (params) => {
|
|
111
111
|
try {
|
|
112
112
|
const createOpts = {
|
|
113
113
|
Image: params.image,
|
package/dist/tools/exec.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ExecInContainerSchema } from "../types.js";
|
|
2
2
|
import { formatError } from "../docker.js";
|
|
3
3
|
export function registerExecTools(server, docker) {
|
|
4
|
-
server.tool("exec_in_container", "Execute a command inside a running Docker container. Returns stdout, stderr, and exit code.", ExecInContainerSchema.shape, async (params) => {
|
|
4
|
+
server.tool("exec_in_container", "Execute a command inside a running Docker container. Returns stdout, stderr, and exit code.", ExecInContainerSchema.shape, { openWorldHint: false }, async (params) => {
|
|
5
5
|
try {
|
|
6
6
|
const container = docker.getContainer(params.container_id);
|
|
7
7
|
const exec = await container.exec({
|
package/dist/tools/health.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CheckHealthSchema, WatchHealthSchema, SetRestartPolicySchema } from "../types.js";
|
|
2
2
|
import { formatError } from "../docker.js";
|
|
3
3
|
export function registerHealthTools(server, docker) {
|
|
4
|
-
server.tool("check_health", "Run a health probe against a container. Supports HTTP, TCP, and exec probes. Auto-detects from container HEALTHCHECK if available.", CheckHealthSchema.shape, async (params) => {
|
|
4
|
+
server.tool("check_health", "Run a health probe against a container. Supports HTTP, TCP, and exec probes. Auto-detects from container HEALTHCHECK if available.", CheckHealthSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
5
5
|
try {
|
|
6
6
|
const container = docker.getContainer(params.container_id);
|
|
7
7
|
const info = await container.inspect();
|
|
@@ -62,7 +62,7 @@ export function registerHealthTools(server, docker) {
|
|
|
62
62
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
|
-
server.tool("watch_health", "Poll a container's health status until it becomes healthy or times out. Useful for waiting on service startup.", WatchHealthSchema.shape, async (params) => {
|
|
65
|
+
server.tool("watch_health", "Poll a container's health status until it becomes healthy or times out. Useful for waiting on service startup.", WatchHealthSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
66
66
|
try {
|
|
67
67
|
const container = docker.getContainer(params.container_id);
|
|
68
68
|
const timeout = (params.timeout ?? 60) * 1000;
|
|
@@ -108,7 +108,7 @@ export function registerHealthTools(server, docker) {
|
|
|
108
108
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
109
109
|
}
|
|
110
110
|
});
|
|
111
|
-
server.tool("set_restart_policy", "Change the restart policy of a running container without recreating it.", SetRestartPolicySchema.shape, async (params) => {
|
|
111
|
+
server.tool("set_restart_policy", "Change the restart policy of a running container without recreating it.", SetRestartPolicySchema.shape, { idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
112
112
|
try {
|
|
113
113
|
const container = docker.getContainer(params.container_id);
|
|
114
114
|
await container.update({
|
package/dist/tools/image.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ListImagesSchema, PullImageSchema, BuildImageSchema, RemoveImageSchema, } from "../types.js";
|
|
2
2
|
import { formatImage, formatError } from "../docker.js";
|
|
3
3
|
export function registerImageTools(server, docker) {
|
|
4
|
-
server.tool("list_images", "List Docker images with optional filters. Returns image IDs, tags, sizes, and creation dates.", ListImagesSchema.shape, async (params) => {
|
|
4
|
+
server.tool("list_images", "List Docker images with optional filters. Returns image IDs, tags, sizes, and creation dates.", ListImagesSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
5
5
|
try {
|
|
6
6
|
const images = await docker.listImages({
|
|
7
7
|
all: params.all ?? false,
|
|
@@ -14,7 +14,7 @@ export function registerImageTools(server, docker) {
|
|
|
14
14
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
15
15
|
}
|
|
16
16
|
});
|
|
17
|
-
server.tool("pull_image", "Pull a Docker image from a registry. Returns pull progress events.", PullImageSchema.shape, async (params) => {
|
|
17
|
+
server.tool("pull_image", "Pull a Docker image from a registry. Returns pull progress events.", PullImageSchema.shape, { idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
18
18
|
try {
|
|
19
19
|
const imageRef = params.tag ? `${params.image}:${params.tag}` : params.image;
|
|
20
20
|
const stream = await docker.pull(imageRef);
|
|
@@ -33,7 +33,7 @@ export function registerImageTools(server, docker) {
|
|
|
33
33
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
|
-
server.tool("build_image", "Build a Docker image from a Dockerfile or build context path.", BuildImageSchema.shape, async (params) => {
|
|
36
|
+
server.tool("build_image", "Build a Docker image from a Dockerfile or build context path.", BuildImageSchema.shape, { idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
37
37
|
try {
|
|
38
38
|
const stream = await docker.buildImage({
|
|
39
39
|
context: params.context,
|
|
@@ -53,7 +53,7 @@ export function registerImageTools(server, docker) {
|
|
|
53
53
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
|
-
server.tool("remove_image", "Remove a Docker image by name or ID. Use force to remove even if tagged.", RemoveImageSchema.shape, async (params) => {
|
|
56
|
+
server.tool("remove_image", "Remove a Docker image by name or ID. Use force to remove even if tagged.", RemoveImageSchema.shape, { destructiveHint: true, openWorldHint: false }, async (params) => {
|
|
57
57
|
try {
|
|
58
58
|
const image = docker.getImage(params.image);
|
|
59
59
|
await image.remove({ force: params.force ?? false });
|
package/dist/tools/logs.js
CHANGED
|
@@ -19,7 +19,7 @@ export function registerLogsTools(server, docker) {
|
|
|
19
19
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
20
20
|
}
|
|
21
21
|
});
|
|
22
|
-
server.tool("container_stats", "Get real-time resource usage statistics for a Docker container (CPU, memory, network, I/O).", ContainerStatsSchema.shape, async (params) => {
|
|
22
|
+
server.tool("container_stats", "Get real-time resource usage statistics for a Docker container (CPU, memory, network, I/O).", ContainerStatsSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
23
23
|
try {
|
|
24
24
|
const container = docker.getContainer(params.container_id);
|
|
25
25
|
const stats = await container.stats({ stream: false });
|
package/dist/tools/monitoring.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ContainerHealthStatusSchema, ContainerResourceUsageSchema, WatchEventsSchema, SearchLogsSchema, ResourceAlertCheckSchema, MonitorDashboardSchema, } from "../types.js";
|
|
2
2
|
export function registerMonitoringTools(server, docker) {
|
|
3
3
|
// 1. fleet_status — health status of all running containers
|
|
4
|
-
server.tool("container_health_status", "Check health status, uptime, and restart count for all running Docker containers. Returns JSON with container name, state, health probe status, and restart count.", ContainerHealthStatusSchema.shape, async (params) => {
|
|
4
|
+
server.tool("container_health_status", "Check health status, uptime, and restart count for all running Docker containers. Returns JSON with container name, state, health probe status (healthy/unhealthy/no-healthcheck), and restart count. Use this for a quick fleet health overview; for resource metrics use container_resource_usage instead. Returns an array of objects with name, id, state, status, health, uptime, restartCount, and image fields. Read-only and safe to call repeatedly.", ContainerHealthStatusSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
5
5
|
try {
|
|
6
6
|
const containers = await docker.listContainers({ all: false });
|
|
7
7
|
const results = await Promise.all(containers.map(async (c) => {
|
|
@@ -29,7 +29,7 @@ export function registerMonitoringTools(server, docker) {
|
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
31
|
// 2. fleet_stats — resource usage for all running containers
|
|
32
|
-
server.tool("container_resource_usage", "Monitor CPU, memory, and network I/O across all running Docker containers. Returns sorted resource usage metrics with percentage breakdowns.", ContainerResourceUsageSchema.shape, async (params) => {
|
|
32
|
+
server.tool("container_resource_usage", "Monitor CPU, memory, and network I/O across all running Docker containers. Returns sorted resource usage metrics with percentage breakdowns for each container. Use container_health_status for health probes; use resource_alert_check for threshold violations. Supports sort by cpu, memory, or network. Returns array of objects with name, id, cpu_percent, memory_usage_mb, memory_percent, network_rx_mb, network_tx_mb. Read-only and safe to call repeatedly.", ContainerResourceUsageSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
33
33
|
try {
|
|
34
34
|
const containers = await docker.listContainers({ all: false });
|
|
35
35
|
const results = await Promise.all(containers.map(async (c) => {
|
|
@@ -73,7 +73,7 @@ export function registerMonitoringTools(server, docker) {
|
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
75
|
// 3. watch_events — stream Docker events (simplified: collect events for a duration)
|
|
76
|
-
server.tool("watch_events", "Stream Docker container events (start, stop, die, restart, health_status) over a configurable time window. Filter by specific container or event type.", WatchEventsSchema.shape, async (params) => {
|
|
76
|
+
server.tool("watch_events", "Stream Docker container events (start, stop, die, restart, health_status) over a configurable time window. Filter by specific container or event type. Use container_health_status for current state; use this tool to watch for changes over time. Returns array of event objects with type, action, container, and time fields. Returns 'No events captured in the time window.' when no events occur. Read-only and safe to call repeatedly.", WatchEventsSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
77
77
|
try {
|
|
78
78
|
const durationMs = (params.duration || 30) * 1000;
|
|
79
79
|
const filter = {};
|
|
@@ -122,7 +122,7 @@ export function registerMonitoringTools(server, docker) {
|
|
|
122
122
|
}
|
|
123
123
|
});
|
|
124
124
|
// 4. search_logs — search logs across multiple containers
|
|
125
|
-
server.tool("search_logs", "Search Docker container logs across multiple containers using regex pattern matching. Returns matching log lines with container name and
|
|
125
|
+
server.tool("search_logs", "Search Docker container logs across multiple containers using regex pattern matching. Use stream_logs for single-container log tailing; use this tool to search across multiple containers at once. Returns matching log lines with container name and line content. The pattern parameter accepts any valid regex; set ignore_case for case-insensitive matching. Returns 'No matches found.' when no lines match. Read-only and safe to call repeatedly.", SearchLogsSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
126
126
|
try {
|
|
127
127
|
const targetContainers = params.containers || [];
|
|
128
128
|
let containers;
|
|
@@ -168,7 +168,7 @@ export function registerMonitoringTools(server, docker) {
|
|
|
168
168
|
}
|
|
169
169
|
});
|
|
170
170
|
// 5. check_thresholds — check all containers against thresholds
|
|
171
|
-
server.tool("resource_alert_check", "
|
|
171
|
+
server.tool("resource_alert_check", "Check all running Docker containers against configurable CPU%, memory%, and restart count thresholds. Returns containers that violate thresholds with specific metrics that triggered alerts. Use container_resource_usage for raw metrics; use this tool for automated alerting. Default thresholds: 80% CPU, 80% memory, 5 restarts. Returns { violations: [...], checked: N } or { message: 'All containers within thresholds.', checked: N }. Read-only and safe to call repeatedly.", ResourceAlertCheckSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
172
172
|
try {
|
|
173
173
|
const cpuThreshold = params.cpu_percent ?? 80;
|
|
174
174
|
const memThreshold = params.memory_percent ?? 80;
|
|
@@ -223,7 +223,7 @@ export function registerMonitoringTools(server, docker) {
|
|
|
223
223
|
}
|
|
224
224
|
});
|
|
225
225
|
// 6. monitor_dashboard — single-call fleet summary
|
|
226
|
-
server.tool("monitor_dashboard", "Comprehensive Docker fleet dashboard in a single API call.
|
|
226
|
+
server.tool("monitor_dashboard", "Comprehensive Docker fleet dashboard in a single API call. Aggregates health status of all containers, top 5 CPU consumers, recent events (last 5 minutes), and threshold violations into one response. Use individual tools (container_health_status, container_resource_usage, watch_events) for targeted queries; use this for a complete fleet overview. Returns object with summary (total, running, healthy, unhealthy), top_consumers, recent_events, and violations. Read-only and safe to call repeatedly.", MonitorDashboardSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
227
227
|
try {
|
|
228
228
|
const containers = await docker.listContainers({ all: false });
|
|
229
229
|
// Fleet health
|
package/dist/tools/network.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ListNetworksSchema, ListVolumesSchema } from "../types.js";
|
|
2
2
|
import { formatError } from "../docker.js";
|
|
3
3
|
export function registerNetworkTools(server, docker) {
|
|
4
|
-
server.tool("list_networks", "List Docker networks with optional filter. Returns network IDs, names, drivers, and scopes.", ListNetworksSchema.shape, async (params) => {
|
|
4
|
+
server.tool("list_networks", "List Docker networks with optional filter. Returns network IDs, names, drivers, and scopes.", ListNetworksSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
5
5
|
try {
|
|
6
6
|
const networks = await docker.listNetworks({
|
|
7
7
|
filters: params.filter ? JSON.stringify({ name: [params.filter] }) : undefined,
|
|
@@ -25,7 +25,7 @@ export function registerNetworkTools(server, docker) {
|
|
|
25
25
|
return { content: [{ type: "text", text: `Error: ${formatError(error)}` }], isError: true };
|
|
26
26
|
}
|
|
27
27
|
});
|
|
28
|
-
server.tool("list_volumes", "List Docker volumes with optional filter. Returns volume names, drivers, mount points, and labels.", ListVolumesSchema.shape, async (params) => {
|
|
28
|
+
server.tool("list_volumes", "List Docker volumes with optional filter. Returns volume names, drivers, mount points, and labels.", ListVolumesSchema.shape, { readOnlyHint: true, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
29
29
|
try {
|
|
30
30
|
const result = await docker.listVolumes({
|
|
31
31
|
filters: params.filter ? JSON.stringify({ name: [params.filter] }) : undefined,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supernova123/docker-mcp-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"mcpName": "io.github.friendlygeorge/docker-mcp-server",
|
|
5
5
|
"description": "MCP server for Docker — container management, health checks, auto-restart, Compose lifecycle, and log streaming for Claude, Cursor, and AI agents",
|
|
6
6
|
"type": "module",
|
package/src/tools/compose.ts
CHANGED
|
@@ -52,6 +52,7 @@ export function registerComposeTools(server: McpServer): void {
|
|
|
52
52
|
"compose_up",
|
|
53
53
|
"Bring up Docker Compose services from a docker-compose.yml file. Optionally build images first.",
|
|
54
54
|
ComposeUpSchema.shape,
|
|
55
|
+
{ idempotentHint: true, openWorldHint: false },
|
|
55
56
|
async (params) => {
|
|
56
57
|
try {
|
|
57
58
|
const args = ["up", "-d"];
|
|
@@ -69,6 +70,7 @@ export function registerComposeTools(server: McpServer): void {
|
|
|
69
70
|
"compose_down",
|
|
70
71
|
"Tear down Docker Compose services. Optionally remove named volumes.",
|
|
71
72
|
ComposeDownSchema.shape,
|
|
73
|
+
{ destructiveHint: true, openWorldHint: false },
|
|
72
74
|
async (params) => {
|
|
73
75
|
try {
|
|
74
76
|
const args = ["down"];
|
|
@@ -86,6 +88,7 @@ export function registerComposeTools(server: McpServer): void {
|
|
|
86
88
|
"compose_ps",
|
|
87
89
|
"List service states across a Docker Compose stack.",
|
|
88
90
|
ComposePsSchema.shape,
|
|
91
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
89
92
|
async (params) => {
|
|
90
93
|
try {
|
|
91
94
|
const output = runCompose(params.path, ["ps", "--format", "json"]);
|
|
@@ -122,6 +125,7 @@ export function registerComposeTools(server: McpServer): void {
|
|
|
122
125
|
"compose_restart",
|
|
123
126
|
"Restart Docker Compose services. Restart specific services or the entire stack.",
|
|
124
127
|
ComposeRestartSchema.shape,
|
|
128
|
+
{ destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
125
129
|
async (params) => {
|
|
126
130
|
try {
|
|
127
131
|
const args = ["restart"];
|
|
@@ -134,4 +138,4 @@ export function registerComposeTools(server: McpServer): void {
|
|
|
134
138
|
}
|
|
135
139
|
}
|
|
136
140
|
);
|
|
137
|
-
}
|
|
141
|
+
}
|
package/src/tools/container.ts
CHANGED
|
@@ -17,6 +17,7 @@ export function registerContainerTools(server: McpServer, docker: Dockerode): vo
|
|
|
17
17
|
"list_containers",
|
|
18
18
|
"List Docker containers with optional filters (state, label, name). Returns container IDs, names, images, states, ports, and labels.",
|
|
19
19
|
ListContainersSchema.shape,
|
|
20
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
20
21
|
async (params) => {
|
|
21
22
|
try {
|
|
22
23
|
const containers = await docker.listContainers({
|
|
@@ -39,6 +40,7 @@ export function registerContainerTools(server: McpServer, docker: Dockerode): vo
|
|
|
39
40
|
"inspect_container",
|
|
40
41
|
"Get detailed configuration and state of a Docker container by ID or name.",
|
|
41
42
|
InspectContainerSchema.shape,
|
|
43
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
42
44
|
async (params) => {
|
|
43
45
|
try {
|
|
44
46
|
const container = docker.getContainer(params.container_id);
|
|
@@ -54,6 +56,7 @@ export function registerContainerTools(server: McpServer, docker: Dockerode): vo
|
|
|
54
56
|
"start_container",
|
|
55
57
|
"Start a stopped Docker container by ID or name.",
|
|
56
58
|
StartContainerSchema.shape,
|
|
59
|
+
{ idempotentHint: true, openWorldHint: false },
|
|
57
60
|
async (params) => {
|
|
58
61
|
try {
|
|
59
62
|
const container = docker.getContainer(params.container_id);
|
|
@@ -69,6 +72,7 @@ export function registerContainerTools(server: McpServer, docker: Dockerode): vo
|
|
|
69
72
|
"stop_container",
|
|
70
73
|
"Stop a running Docker container by ID or name with optional timeout.",
|
|
71
74
|
StopContainerSchema.shape,
|
|
75
|
+
{ destructiveHint: true, openWorldHint: false },
|
|
72
76
|
async (params) => {
|
|
73
77
|
try {
|
|
74
78
|
const container = docker.getContainer(params.container_id);
|
|
@@ -104,6 +108,7 @@ export function registerContainerTools(server: McpServer, docker: Dockerode): vo
|
|
|
104
108
|
"remove_container",
|
|
105
109
|
"Remove a Docker container by ID or name. Use force to remove running containers.",
|
|
106
110
|
RemoveContainerSchema.shape,
|
|
111
|
+
{ destructiveHint: true, openWorldHint: false },
|
|
107
112
|
async (params) => {
|
|
108
113
|
try {
|
|
109
114
|
const container = docker.getContainer(params.container_id);
|
|
@@ -119,6 +124,7 @@ export function registerContainerTools(server: McpServer, docker: Dockerode): vo
|
|
|
119
124
|
"recreate_container",
|
|
120
125
|
"Recreate a container with the same configuration (stop, remove, re-create). Useful for applying config changes.",
|
|
121
126
|
RecreateContainerSchema.shape,
|
|
127
|
+
{ destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
122
128
|
async (params) => {
|
|
123
129
|
try {
|
|
124
130
|
const container = docker.getContainer(params.container_id);
|
|
@@ -159,6 +165,7 @@ export function registerContainerTools(server: McpServer, docker: Dockerode): vo
|
|
|
159
165
|
"run_container",
|
|
160
166
|
"Create and start a new Docker container with one command. Supports image, env, ports, volumes, restart policy, and command override. Auto-pulls missing images.",
|
|
161
167
|
RunContainerSchema.shape,
|
|
168
|
+
{ openWorldHint: false },
|
|
162
169
|
async (params) => {
|
|
163
170
|
try {
|
|
164
171
|
const createOpts: Dockerode.ContainerCreateOptions = {
|
|
@@ -213,4 +220,4 @@ export function registerContainerTools(server: McpServer, docker: Dockerode): vo
|
|
|
213
220
|
}
|
|
214
221
|
}
|
|
215
222
|
);
|
|
216
|
-
}
|
|
223
|
+
}
|
package/src/tools/exec.ts
CHANGED
|
@@ -8,6 +8,7 @@ export function registerExecTools(server: McpServer, docker: Dockerode): void {
|
|
|
8
8
|
"exec_in_container",
|
|
9
9
|
"Execute a command inside a running Docker container. Returns stdout, stderr, and exit code.",
|
|
10
10
|
ExecInContainerSchema.shape,
|
|
11
|
+
{ openWorldHint: false },
|
|
11
12
|
async (params) => {
|
|
12
13
|
try {
|
|
13
14
|
const container = docker.getContainer(params.container_id);
|
|
@@ -45,4 +46,4 @@ export function registerExecTools(server: McpServer, docker: Dockerode): void {
|
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
);
|
|
48
|
-
}
|
|
49
|
+
}
|
package/src/tools/health.ts
CHANGED
|
@@ -8,6 +8,7 @@ export function registerHealthTools(server: McpServer, docker: Dockerode): void
|
|
|
8
8
|
"check_health",
|
|
9
9
|
"Run a health probe against a container. Supports HTTP, TCP, and exec probes. Auto-detects from container HEALTHCHECK if available.",
|
|
10
10
|
CheckHealthSchema.shape,
|
|
11
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
11
12
|
async (params) => {
|
|
12
13
|
try {
|
|
13
14
|
const container = docker.getContainer(params.container_id);
|
|
@@ -77,6 +78,7 @@ export function registerHealthTools(server: McpServer, docker: Dockerode): void
|
|
|
77
78
|
"watch_health",
|
|
78
79
|
"Poll a container's health status until it becomes healthy or times out. Useful for waiting on service startup.",
|
|
79
80
|
WatchHealthSchema.shape,
|
|
81
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
80
82
|
async (params) => {
|
|
81
83
|
try {
|
|
82
84
|
const container = docker.getContainer(params.container_id);
|
|
@@ -130,6 +132,7 @@ export function registerHealthTools(server: McpServer, docker: Dockerode): void
|
|
|
130
132
|
"set_restart_policy",
|
|
131
133
|
"Change the restart policy of a running container without recreating it.",
|
|
132
134
|
SetRestartPolicySchema.shape,
|
|
135
|
+
{ idempotentHint: true, openWorldHint: false },
|
|
133
136
|
async (params) => {
|
|
134
137
|
try {
|
|
135
138
|
const container = docker.getContainer(params.container_id);
|
|
@@ -147,4 +150,4 @@ export function registerHealthTools(server: McpServer, docker: Dockerode): void
|
|
|
147
150
|
}
|
|
148
151
|
}
|
|
149
152
|
);
|
|
150
|
-
}
|
|
153
|
+
}
|
package/src/tools/image.ts
CHANGED
|
@@ -13,6 +13,7 @@ export function registerImageTools(server: McpServer, docker: Dockerode): void {
|
|
|
13
13
|
"list_images",
|
|
14
14
|
"List Docker images with optional filters. Returns image IDs, tags, sizes, and creation dates.",
|
|
15
15
|
ListImagesSchema.shape,
|
|
16
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
16
17
|
async (params) => {
|
|
17
18
|
try {
|
|
18
19
|
const images = await docker.listImages({
|
|
@@ -31,6 +32,7 @@ export function registerImageTools(server: McpServer, docker: Dockerode): void {
|
|
|
31
32
|
"pull_image",
|
|
32
33
|
"Pull a Docker image from a registry. Returns pull progress events.",
|
|
33
34
|
PullImageSchema.shape,
|
|
35
|
+
{ idempotentHint: true, openWorldHint: false },
|
|
34
36
|
async (params) => {
|
|
35
37
|
try {
|
|
36
38
|
const imageRef = params.tag ? `${params.image}:${params.tag}` : params.image;
|
|
@@ -53,6 +55,7 @@ export function registerImageTools(server: McpServer, docker: Dockerode): void {
|
|
|
53
55
|
"build_image",
|
|
54
56
|
"Build a Docker image from a Dockerfile or build context path.",
|
|
55
57
|
BuildImageSchema.shape,
|
|
58
|
+
{ idempotentHint: true, openWorldHint: false },
|
|
56
59
|
async (params) => {
|
|
57
60
|
try {
|
|
58
61
|
const stream = await docker.buildImage(
|
|
@@ -79,6 +82,7 @@ export function registerImageTools(server: McpServer, docker: Dockerode): void {
|
|
|
79
82
|
"remove_image",
|
|
80
83
|
"Remove a Docker image by name or ID. Use force to remove even if tagged.",
|
|
81
84
|
RemoveImageSchema.shape,
|
|
85
|
+
{ destructiveHint: true, openWorldHint: false },
|
|
82
86
|
async (params) => {
|
|
83
87
|
try {
|
|
84
88
|
const image = docker.getImage(params.image);
|
|
@@ -89,4 +93,4 @@ export function registerImageTools(server: McpServer, docker: Dockerode): void {
|
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
95
|
);
|
|
92
|
-
}
|
|
96
|
+
}
|
package/src/tools/logs.ts
CHANGED
|
@@ -32,6 +32,7 @@ export function registerLogsTools(server: McpServer, docker: Dockerode): void {
|
|
|
32
32
|
"container_stats",
|
|
33
33
|
"Get real-time resource usage statistics for a Docker container (CPU, memory, network, I/O).",
|
|
34
34
|
ContainerStatsSchema.shape,
|
|
35
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
35
36
|
async (params) => {
|
|
36
37
|
try {
|
|
37
38
|
const container = docker.getContainer(params.container_id);
|
|
@@ -83,4 +84,4 @@ export function registerLogsTools(server: McpServer, docker: Dockerode): void {
|
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
);
|
|
86
|
-
}
|
|
87
|
+
}
|
package/src/tools/monitoring.ts
CHANGED
|
@@ -13,8 +13,9 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
13
13
|
// 1. fleet_status — health status of all running containers
|
|
14
14
|
server.tool(
|
|
15
15
|
"container_health_status",
|
|
16
|
-
"Check health status, uptime, and restart count for all running Docker containers. Returns JSON with container name, state, health probe status, and restart count.",
|
|
16
|
+
"Check health status, uptime, and restart count for all running Docker containers. Returns JSON with container name, state, health probe status (healthy/unhealthy/no-healthcheck), and restart count. Use this for a quick fleet health overview; for resource metrics use container_resource_usage instead. Returns an array of objects with name, id, state, status, health, uptime, restartCount, and image fields. Read-only and safe to call repeatedly.",
|
|
17
17
|
ContainerHealthStatusSchema.shape,
|
|
18
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
18
19
|
async (params) => {
|
|
19
20
|
try {
|
|
20
21
|
const containers = await docker.listContainers({ all: false });
|
|
@@ -48,8 +49,9 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
48
49
|
// 2. fleet_stats — resource usage for all running containers
|
|
49
50
|
server.tool(
|
|
50
51
|
"container_resource_usage",
|
|
51
|
-
"Monitor CPU, memory, and network I/O across all running Docker containers. Returns sorted resource usage metrics with percentage breakdowns.",
|
|
52
|
+
"Monitor CPU, memory, and network I/O across all running Docker containers. Returns sorted resource usage metrics with percentage breakdowns for each container. Use container_health_status for health probes; use resource_alert_check for threshold violations. Supports sort by cpu, memory, or network. Returns array of objects with name, id, cpu_percent, memory_usage_mb, memory_percent, network_rx_mb, network_tx_mb. Read-only and safe to call repeatedly.",
|
|
52
53
|
ContainerResourceUsageSchema.shape,
|
|
54
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
53
55
|
async (params) => {
|
|
54
56
|
try {
|
|
55
57
|
const containers = await docker.listContainers({ all: false });
|
|
@@ -100,8 +102,9 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
100
102
|
// 3. watch_events — stream Docker events (simplified: collect events for a duration)
|
|
101
103
|
server.tool(
|
|
102
104
|
"watch_events",
|
|
103
|
-
"Stream Docker container events (start, stop, die, restart, health_status) over a configurable time window. Filter by specific container or event type.",
|
|
105
|
+
"Stream Docker container events (start, stop, die, restart, health_status) over a configurable time window. Filter by specific container or event type. Use container_health_status for current state; use this tool to watch for changes over time. Returns array of event objects with type, action, container, and time fields. Returns 'No events captured in the time window.' when no events occur. Read-only and safe to call repeatedly.",
|
|
104
106
|
WatchEventsSchema.shape,
|
|
107
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
105
108
|
async (params) => {
|
|
106
109
|
try {
|
|
107
110
|
const durationMs = (params.duration || 30) * 1000;
|
|
@@ -156,8 +159,9 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
156
159
|
// 4. search_logs — search logs across multiple containers
|
|
157
160
|
server.tool(
|
|
158
161
|
"search_logs",
|
|
159
|
-
"Search Docker container logs across multiple containers using regex pattern matching. Returns matching log lines with container name and
|
|
162
|
+
"Search Docker container logs across multiple containers using regex pattern matching. Use stream_logs for single-container log tailing; use this tool to search across multiple containers at once. Returns matching log lines with container name and line content. The pattern parameter accepts any valid regex; set ignore_case for case-insensitive matching. Returns 'No matches found.' when no lines match. Read-only and safe to call repeatedly.",
|
|
160
163
|
SearchLogsSchema.shape,
|
|
164
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
161
165
|
async (params) => {
|
|
162
166
|
try {
|
|
163
167
|
const targetContainers = params.containers || [];
|
|
@@ -211,8 +215,9 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
211
215
|
// 5. check_thresholds — check all containers against thresholds
|
|
212
216
|
server.tool(
|
|
213
217
|
"resource_alert_check",
|
|
214
|
-
"
|
|
218
|
+
"Check all running Docker containers against configurable CPU%, memory%, and restart count thresholds. Returns containers that violate thresholds with specific metrics that triggered alerts. Use container_resource_usage for raw metrics; use this tool for automated alerting. Default thresholds: 80% CPU, 80% memory, 5 restarts. Returns { violations: [...], checked: N } or { message: 'All containers within thresholds.', checked: N }. Read-only and safe to call repeatedly.",
|
|
215
219
|
ResourceAlertCheckSchema.shape,
|
|
220
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
216
221
|
async (params) => {
|
|
217
222
|
try {
|
|
218
223
|
const cpuThreshold = params.cpu_percent ?? 80;
|
|
@@ -274,8 +279,9 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
274
279
|
// 6. monitor_dashboard — single-call fleet summary
|
|
275
280
|
server.tool(
|
|
276
281
|
"monitor_dashboard",
|
|
277
|
-
"Comprehensive Docker fleet dashboard in a single API call.
|
|
282
|
+
"Comprehensive Docker fleet dashboard in a single API call. Aggregates health status of all containers, top 5 CPU consumers, recent events (last 5 minutes), and threshold violations into one response. Use individual tools (container_health_status, container_resource_usage, watch_events) for targeted queries; use this for a complete fleet overview. Returns object with summary (total, running, healthy, unhealthy), top_consumers, recent_events, and violations. Read-only and safe to call repeatedly.",
|
|
278
283
|
MonitorDashboardSchema.shape,
|
|
284
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
279
285
|
async (params) => {
|
|
280
286
|
try {
|
|
281
287
|
const containers = await docker.listContainers({ all: false });
|
package/src/tools/network.ts
CHANGED
|
@@ -8,6 +8,7 @@ export function registerNetworkTools(server: McpServer, docker: Dockerode): void
|
|
|
8
8
|
"list_networks",
|
|
9
9
|
"List Docker networks with optional filter. Returns network IDs, names, drivers, and scopes.",
|
|
10
10
|
ListNetworksSchema.shape,
|
|
11
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
11
12
|
async (params) => {
|
|
12
13
|
try {
|
|
13
14
|
const networks = await docker.listNetworks({
|
|
@@ -39,6 +40,7 @@ export function registerNetworkTools(server: McpServer, docker: Dockerode): void
|
|
|
39
40
|
"list_volumes",
|
|
40
41
|
"List Docker volumes with optional filter. Returns volume names, drivers, mount points, and labels.",
|
|
41
42
|
ListVolumesSchema.shape,
|
|
43
|
+
{ readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
42
44
|
async (params) => {
|
|
43
45
|
try {
|
|
44
46
|
const result = await docker.listVolumes({
|
|
@@ -57,4 +59,4 @@ export function registerNetworkTools(server: McpServer, docker: Dockerode): void
|
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
);
|
|
60
|
-
}
|
|
62
|
+
}
|