@supernova123/docker-mcp-server 0.2.0 → 0.2.1
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/monitoring.js +7 -7
- package/dist/types.d.ts +3 -3
- package/dist/types.js +3 -3
- package/package.json +16 -4
- package/src/tools/monitoring.ts +16 -16
- package/src/types.ts +4 -4
- package/tests/monitoring.test.ts +14 -14
package/dist/tools/monitoring.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
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("
|
|
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) => {
|
|
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("
|
|
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) => {
|
|
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", "
|
|
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) => {
|
|
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 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 timestamp.", SearchLogsSchema.shape, 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("
|
|
171
|
+
server.tool("resource_alert_check", "Alert when Docker containers exceed resource thresholds (CPU%, memory%, restart count). Returns violations with specific metrics that triggered alerts.", ResourceAlertCheckSchema.shape, 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", "
|
|
226
|
+
server.tool("monitor_dashboard", "Comprehensive Docker fleet dashboard in a single API call. Returns health status, top resource consumers, recent events, and threshold violations.", MonitorDashboardSchema.shape, async (params) => {
|
|
227
227
|
try {
|
|
228
228
|
const containers = await docker.listContainers({ all: false });
|
|
229
229
|
// Fleet health
|
package/dist/types.d.ts
CHANGED
|
@@ -306,8 +306,8 @@ export declare const ListVolumesSchema: z.ZodObject<{
|
|
|
306
306
|
}, {
|
|
307
307
|
filter?: string | undefined;
|
|
308
308
|
}>;
|
|
309
|
-
export declare const
|
|
310
|
-
export declare const
|
|
309
|
+
export declare const ContainerHealthStatusSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
310
|
+
export declare const ContainerResourceUsageSchema: z.ZodObject<{
|
|
311
311
|
sort_by: z.ZodOptional<z.ZodEnum<["cpu", "memory", "network"]>>;
|
|
312
312
|
}, "strip", z.ZodTypeAny, {
|
|
313
313
|
sort_by?: "cpu" | "memory" | "network" | undefined;
|
|
@@ -349,7 +349,7 @@ export declare const SearchLogsSchema: z.ZodObject<{
|
|
|
349
349
|
containers?: string[] | undefined;
|
|
350
350
|
ignore_case?: boolean | undefined;
|
|
351
351
|
}>;
|
|
352
|
-
export declare const
|
|
352
|
+
export declare const ResourceAlertCheckSchema: z.ZodObject<{
|
|
353
353
|
cpu_percent: z.ZodOptional<z.ZodNumber>;
|
|
354
354
|
memory_percent: z.ZodOptional<z.ZodNumber>;
|
|
355
355
|
restart_count: z.ZodOptional<z.ZodNumber>;
|
package/dist/types.js
CHANGED
|
@@ -126,8 +126,8 @@ export const ListVolumesSchema = z.object({
|
|
|
126
126
|
filter: z.string().optional().describe("Filter by name or driver"),
|
|
127
127
|
});
|
|
128
128
|
// Monitoring schemas (v0.2.0)
|
|
129
|
-
export const
|
|
130
|
-
export const
|
|
129
|
+
export const ContainerHealthStatusSchema = z.object({});
|
|
130
|
+
export const ContainerResourceUsageSchema = z.object({
|
|
131
131
|
sort_by: z.enum(["cpu", "memory", "network"]).optional().describe("Sort results by metric (default: cpu)"),
|
|
132
132
|
});
|
|
133
133
|
export const WatchEventsSchema = z.object({
|
|
@@ -143,7 +143,7 @@ export const SearchLogsSchema = z.object({
|
|
|
143
143
|
since: z.string().optional().describe("Only search logs since timestamp"),
|
|
144
144
|
ignore_case: z.boolean().optional().describe("Case-insensitive search (default: false)"),
|
|
145
145
|
});
|
|
146
|
-
export const
|
|
146
|
+
export const ResourceAlertCheckSchema = z.object({
|
|
147
147
|
cpu_percent: z.number().optional().describe("Alert if CPU usage exceeds this % (default: 80)"),
|
|
148
148
|
memory_percent: z.number().optional().describe("Alert if memory usage exceeds this % (default: 80)"),
|
|
149
149
|
restart_count: z.number().optional().describe("Alert if restart count exceeds this (default: 5)"),
|
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.1",
|
|
4
4
|
"mcpName": "io.github.friendlygeorge/docker-mcp-server",
|
|
5
5
|
"description": "MCP server for Docker \u2014 container management, health checks, auto-restart, Compose lifecycle, and log streaming for Claude, Cursor, and AI agents",
|
|
6
6
|
"type": "module",
|
|
@@ -18,19 +18,31 @@
|
|
|
18
18
|
"keywords": [
|
|
19
19
|
"mcp",
|
|
20
20
|
"mcp-server",
|
|
21
|
+
"model-context-protocol",
|
|
21
22
|
"docker",
|
|
22
23
|
"docker-mcp",
|
|
23
24
|
"container",
|
|
25
|
+
"containers",
|
|
24
26
|
"compose",
|
|
27
|
+
"docker-compose",
|
|
25
28
|
"health-check",
|
|
29
|
+
"health-monitoring",
|
|
30
|
+
"container-health",
|
|
26
31
|
"devops",
|
|
32
|
+
"infrastructure",
|
|
33
|
+
"orchestration",
|
|
27
34
|
"ai-agent",
|
|
28
|
-
"
|
|
35
|
+
"ai-agents",
|
|
29
36
|
"claude",
|
|
30
37
|
"cursor",
|
|
31
38
|
"chatgpt",
|
|
32
39
|
"claude-desktop",
|
|
33
|
-
"
|
|
40
|
+
"monitoring",
|
|
41
|
+
"resource-monitoring",
|
|
42
|
+
"log-search",
|
|
43
|
+
"container-logs",
|
|
44
|
+
"docker-events",
|
|
45
|
+
"fleet-management"
|
|
34
46
|
],
|
|
35
47
|
"author": "Nova",
|
|
36
48
|
"license": "MIT",
|
|
@@ -53,4 +65,4 @@
|
|
|
53
65
|
"typescript": "^5.7.0",
|
|
54
66
|
"vitest": "^3.1.0"
|
|
55
67
|
}
|
|
56
|
-
}
|
|
68
|
+
}
|
package/src/tools/monitoring.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import Dockerode from "dockerode";
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
ContainerHealthStatusSchema,
|
|
5
|
+
ContainerResourceUsageSchema,
|
|
6
6
|
WatchEventsSchema,
|
|
7
7
|
SearchLogsSchema,
|
|
8
|
-
|
|
8
|
+
ResourceAlertCheckSchema,
|
|
9
9
|
MonitorDashboardSchema,
|
|
10
10
|
} from "../types.js";
|
|
11
11
|
|
|
12
12
|
export function registerMonitoringTools(server: McpServer, docker: Dockerode): void {
|
|
13
13
|
// 1. fleet_status — health status of all running containers
|
|
14
14
|
server.tool(
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
|
|
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.",
|
|
17
|
+
ContainerHealthStatusSchema.shape,
|
|
18
18
|
async (params) => {
|
|
19
19
|
try {
|
|
20
20
|
const containers = await docker.listContainers({ all: false });
|
|
@@ -47,9 +47,9 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
47
47
|
|
|
48
48
|
// 2. fleet_stats — resource usage for all running containers
|
|
49
49
|
server.tool(
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
50
|
+
"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
|
+
ContainerResourceUsageSchema.shape,
|
|
53
53
|
async (params) => {
|
|
54
54
|
try {
|
|
55
55
|
const containers = await docker.listContainers({ all: false });
|
|
@@ -100,7 +100,7 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
100
100
|
// 3. watch_events — stream Docker events (simplified: collect events for a duration)
|
|
101
101
|
server.tool(
|
|
102
102
|
"watch_events",
|
|
103
|
-
"
|
|
103
|
+
"Stream Docker container events (start, stop, die, restart, health_status) over a configurable time window. Filter by specific container or event type.",
|
|
104
104
|
WatchEventsSchema.shape,
|
|
105
105
|
async (params) => {
|
|
106
106
|
try {
|
|
@@ -156,7 +156,7 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
156
156
|
// 4. search_logs — search logs across multiple containers
|
|
157
157
|
server.tool(
|
|
158
158
|
"search_logs",
|
|
159
|
-
"Search logs across multiple containers
|
|
159
|
+
"Search Docker container logs across multiple containers using regex pattern matching. Returns matching log lines with container name and timestamp.",
|
|
160
160
|
SearchLogsSchema.shape,
|
|
161
161
|
async (params) => {
|
|
162
162
|
try {
|
|
@@ -210,9 +210,9 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
210
210
|
|
|
211
211
|
// 5. check_thresholds — check all containers against thresholds
|
|
212
212
|
server.tool(
|
|
213
|
-
"
|
|
214
|
-
"
|
|
215
|
-
|
|
213
|
+
"resource_alert_check",
|
|
214
|
+
"Alert when Docker containers exceed resource thresholds (CPU%, memory%, restart count). Returns violations with specific metrics that triggered alerts.",
|
|
215
|
+
ResourceAlertCheckSchema.shape,
|
|
216
216
|
async (params) => {
|
|
217
217
|
try {
|
|
218
218
|
const cpuThreshold = params.cpu_percent ?? 80;
|
|
@@ -274,7 +274,7 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
274
274
|
// 6. monitor_dashboard — single-call fleet summary
|
|
275
275
|
server.tool(
|
|
276
276
|
"monitor_dashboard",
|
|
277
|
-
"
|
|
277
|
+
"Comprehensive Docker fleet dashboard in a single API call. Returns health status, top resource consumers, recent events, and threshold violations.",
|
|
278
278
|
MonitorDashboardSchema.shape,
|
|
279
279
|
async (params) => {
|
|
280
280
|
try {
|
|
@@ -366,4 +366,4 @@ export function registerMonitoringTools(server: McpServer, docker: Dockerode): v
|
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
368
|
);
|
|
369
|
-
}
|
|
369
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -153,9 +153,9 @@ export const ListVolumesSchema = z.object({
|
|
|
153
153
|
|
|
154
154
|
|
|
155
155
|
// Monitoring schemas (v0.2.0)
|
|
156
|
-
export const
|
|
156
|
+
export const ContainerHealthStatusSchema = z.object({});
|
|
157
157
|
|
|
158
|
-
export const
|
|
158
|
+
export const ContainerResourceUsageSchema = z.object({
|
|
159
159
|
sort_by: z.enum(["cpu", "memory", "network"]).optional().describe("Sort results by metric (default: cpu)"),
|
|
160
160
|
});
|
|
161
161
|
|
|
@@ -174,10 +174,10 @@ export const SearchLogsSchema = z.object({
|
|
|
174
174
|
ignore_case: z.boolean().optional().describe("Case-insensitive search (default: false)"),
|
|
175
175
|
});
|
|
176
176
|
|
|
177
|
-
export const
|
|
177
|
+
export const ResourceAlertCheckSchema = z.object({
|
|
178
178
|
cpu_percent: z.number().optional().describe("Alert if CPU usage exceeds this % (default: 80)"),
|
|
179
179
|
memory_percent: z.number().optional().describe("Alert if memory usage exceeds this % (default: 80)"),
|
|
180
180
|
restart_count: z.number().optional().describe("Alert if restart count exceeds this (default: 5)"),
|
|
181
181
|
});
|
|
182
182
|
|
|
183
|
-
export const MonitorDashboardSchema = z.object({});
|
|
183
|
+
export const MonitorDashboardSchema = z.object({});
|
package/tests/monitoring.test.ts
CHANGED
|
@@ -104,14 +104,14 @@ describe("Monitoring Tools", () => {
|
|
|
104
104
|
registerMonitoringTools(server, docker);
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
describe("
|
|
107
|
+
describe("container_health_status", () => {
|
|
108
108
|
it("returns health status for all running containers", async () => {
|
|
109
109
|
mockContainers(["abc123", "def456"], ["web", "db"]);
|
|
110
110
|
mockInspect
|
|
111
111
|
.mockResolvedValueOnce(mockInspectResult({ RestartCount: 2 }))
|
|
112
112
|
.mockResolvedValueOnce(mockInspectResult({ RestartCount: 0, State: { Running: true, StartedAt: "2026-06-15T11:00:00Z", Health: { Status: "unhealthy" } } }));
|
|
113
113
|
|
|
114
|
-
const result = await server.tools["
|
|
114
|
+
const result = await server.tools["container_health_status"].handler({});
|
|
115
115
|
const data = JSON.parse(result.content[0].text);
|
|
116
116
|
|
|
117
117
|
expect(data).toHaveLength(2);
|
|
@@ -128,7 +128,7 @@ describe("Monitoring Tools", () => {
|
|
|
128
128
|
State: { Running: true, StartedAt: "2026-06-15T10:00:00Z" },
|
|
129
129
|
}));
|
|
130
130
|
|
|
131
|
-
const result = await server.tools["
|
|
131
|
+
const result = await server.tools["container_health_status"].handler({});
|
|
132
132
|
const data = JSON.parse(result.content[0].text);
|
|
133
133
|
|
|
134
134
|
expect(data[0].health).toBe("no-healthcheck");
|
|
@@ -136,14 +136,14 @@ describe("Monitoring Tools", () => {
|
|
|
136
136
|
|
|
137
137
|
it("returns error on Docker failure", async () => {
|
|
138
138
|
mockListContainers.mockRejectedValue(new Error("Docker daemon not running"));
|
|
139
|
-
const result = await server.tools["
|
|
139
|
+
const result = await server.tools["container_health_status"].handler({});
|
|
140
140
|
|
|
141
141
|
expect(result.isError).toBe(true);
|
|
142
142
|
expect(result.content[0].text).toContain("Docker daemon not running");
|
|
143
143
|
});
|
|
144
144
|
});
|
|
145
145
|
|
|
146
|
-
describe("
|
|
146
|
+
describe("container_resource_usage", () => {
|
|
147
147
|
it("returns resource usage sorted by CPU by default", async () => {
|
|
148
148
|
mockContainers(["abc123", "def456"], ["low-cpu", "high-cpu"]);
|
|
149
149
|
mockStats
|
|
@@ -156,7 +156,7 @@ describe("Monitoring Tools", () => {
|
|
|
156
156
|
precpu_stats: { cpu_usage: { total_usage: 100000 }, system_cpu_usage: 9500000 },
|
|
157
157
|
}));
|
|
158
158
|
|
|
159
|
-
const result = await server.tools["
|
|
159
|
+
const result = await server.tools["container_resource_usage"].handler({});
|
|
160
160
|
const data = JSON.parse(result.content[0].text);
|
|
161
161
|
|
|
162
162
|
expect(data).toHaveLength(2);
|
|
@@ -177,7 +177,7 @@ describe("Monitoring Tools", () => {
|
|
|
177
177
|
memory_stats: { usage: 900 * 1024 * 1024, limit: 1024 * 1024 * 1024 },
|
|
178
178
|
}));
|
|
179
179
|
|
|
180
|
-
const result = await server.tools["
|
|
180
|
+
const result = await server.tools["container_resource_usage"].handler({ sort_by: "memory" });
|
|
181
181
|
const data = JSON.parse(result.content[0].text);
|
|
182
182
|
|
|
183
183
|
expect(data[0].name).toBe("high-mem");
|
|
@@ -186,7 +186,7 @@ describe("Monitoring Tools", () => {
|
|
|
186
186
|
|
|
187
187
|
it("returns error on Docker failure", async () => {
|
|
188
188
|
mockListContainers.mockRejectedValue(new Error("Cannot connect"));
|
|
189
|
-
const result = await server.tools["
|
|
189
|
+
const result = await server.tools["container_resource_usage"].handler({});
|
|
190
190
|
|
|
191
191
|
expect(result.isError).toBe(true);
|
|
192
192
|
expect(result.content[0].text).toContain("Cannot connect");
|
|
@@ -296,7 +296,7 @@ describe("Monitoring Tools", () => {
|
|
|
296
296
|
});
|
|
297
297
|
});
|
|
298
298
|
|
|
299
|
-
describe("
|
|
299
|
+
describe("resource_alert_check", () => {
|
|
300
300
|
it("returns violations when containers exceed thresholds", async () => {
|
|
301
301
|
mockContainers(["abc123"], ["high-cpu"]);
|
|
302
302
|
mockInspect.mockResolvedValue(mockInspectResult({ RestartCount: 10 }));
|
|
@@ -305,7 +305,7 @@ describe("Monitoring Tools", () => {
|
|
|
305
305
|
precpu_stats: { cpu_usage: { total_usage: 1000000 }, system_cpu_usage: 9500000 },
|
|
306
306
|
}));
|
|
307
307
|
|
|
308
|
-
const result = await server.tools["
|
|
308
|
+
const result = await server.tools["resource_alert_check"].handler({ cpu_percent: 80, restart_count: 5 });
|
|
309
309
|
const data = JSON.parse(result.content[0].text);
|
|
310
310
|
|
|
311
311
|
expect(data.violations).toHaveLength(1);
|
|
@@ -323,7 +323,7 @@ describe("Monitoring Tools", () => {
|
|
|
323
323
|
precpu_stats: { cpu_usage: { total_usage: 90000 }, system_cpu_usage: 9500000 },
|
|
324
324
|
}));
|
|
325
325
|
|
|
326
|
-
const result = await server.tools["
|
|
326
|
+
const result = await server.tools["resource_alert_check"].handler({});
|
|
327
327
|
const data = JSON.parse(result.content[0].text);
|
|
328
328
|
|
|
329
329
|
expect(data.message).toContain("All containers within thresholds");
|
|
@@ -338,7 +338,7 @@ describe("Monitoring Tools", () => {
|
|
|
338
338
|
precpu_stats: { cpu_usage: { total_usage: 90000 }, system_cpu_usage: 9500000 },
|
|
339
339
|
}));
|
|
340
340
|
|
|
341
|
-
const result = await server.tools["
|
|
341
|
+
const result = await server.tools["resource_alert_check"].handler({});
|
|
342
342
|
const data = JSON.parse(result.content[0].text);
|
|
343
343
|
|
|
344
344
|
expect(data.message).toContain("All containers within thresholds");
|
|
@@ -346,7 +346,7 @@ describe("Monitoring Tools", () => {
|
|
|
346
346
|
|
|
347
347
|
it("returns error on Docker failure", async () => {
|
|
348
348
|
mockListContainers.mockRejectedValue(new Error("Daemon down"));
|
|
349
|
-
const result = await server.tools["
|
|
349
|
+
const result = await server.tools["resource_alert_check"].handler({});
|
|
350
350
|
|
|
351
351
|
expect(result.isError).toBe(true);
|
|
352
352
|
expect(result.content[0].text).toContain("Daemon down");
|
|
@@ -408,4 +408,4 @@ describe("Monitoring Tools", () => {
|
|
|
408
408
|
expect(result.content[0].text).toContain("Connection refused");
|
|
409
409
|
});
|
|
410
410
|
});
|
|
411
|
-
});
|
|
411
|
+
});
|