synapse-mcp 1.0.0

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.
Files changed (138) hide show
  1. package/README.md +607 -0
  2. package/dist/constants.d.ts +23 -0
  3. package/dist/constants.d.ts.map +1 -0
  4. package/dist/constants.js +58 -0
  5. package/dist/constants.js.map +1 -0
  6. package/dist/formatters/index.d.ts +275 -0
  7. package/dist/formatters/index.d.ts.map +1 -0
  8. package/dist/formatters/index.js +461 -0
  9. package/dist/formatters/index.js.map +1 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +178 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/schemas/common.d.ts +48 -0
  15. package/dist/schemas/common.d.ts.map +1 -0
  16. package/dist/schemas/common.js +69 -0
  17. package/dist/schemas/common.js.map +1 -0
  18. package/dist/schemas/discriminator.d.ts +20 -0
  19. package/dist/schemas/discriminator.d.ts.map +1 -0
  20. package/dist/schemas/discriminator.js +25 -0
  21. package/dist/schemas/discriminator.js.map +1 -0
  22. package/dist/schemas/flux/compose.d.ts +93 -0
  23. package/dist/schemas/flux/compose.d.ts.map +1 -0
  24. package/dist/schemas/flux/compose.js +112 -0
  25. package/dist/schemas/flux/compose.js.map +1 -0
  26. package/dist/schemas/flux/container.d.ts +144 -0
  27. package/dist/schemas/flux/container.d.ts.map +1 -0
  28. package/dist/schemas/flux/container.js +163 -0
  29. package/dist/schemas/flux/container.js.map +1 -0
  30. package/dist/schemas/flux/docker.d.ts +91 -0
  31. package/dist/schemas/flux/docker.d.ts.map +1 -0
  32. package/dist/schemas/flux/docker.js +101 -0
  33. package/dist/schemas/flux/docker.js.map +1 -0
  34. package/dist/schemas/flux/host.d.ts +61 -0
  35. package/dist/schemas/flux/host.d.ts.map +1 -0
  36. package/dist/schemas/flux/host.js +72 -0
  37. package/dist/schemas/flux/host.js.map +1 -0
  38. package/dist/schemas/flux/index.d.ts +20 -0
  39. package/dist/schemas/flux/index.d.ts.map +1 -0
  40. package/dist/schemas/flux/index.js +88 -0
  41. package/dist/schemas/flux/index.js.map +1 -0
  42. package/dist/schemas/index.d.ts +11 -0
  43. package/dist/schemas/index.d.ts.map +1 -0
  44. package/dist/schemas/index.js +11 -0
  45. package/dist/schemas/index.js.map +1 -0
  46. package/dist/schemas/scout/index.d.ts +151 -0
  47. package/dist/schemas/scout/index.d.ts.map +1 -0
  48. package/dist/schemas/scout/index.js +41 -0
  49. package/dist/schemas/scout/index.js.map +1 -0
  50. package/dist/schemas/scout/logs.d.ts +48 -0
  51. package/dist/schemas/scout/logs.d.ts.map +1 -0
  52. package/dist/schemas/scout/logs.js +47 -0
  53. package/dist/schemas/scout/logs.js.map +1 -0
  54. package/dist/schemas/scout/simple.d.ts +68 -0
  55. package/dist/schemas/scout/simple.d.ts.map +1 -0
  56. package/dist/schemas/scout/simple.js +75 -0
  57. package/dist/schemas/scout/simple.js.map +1 -0
  58. package/dist/schemas/scout/zfs.d.ts +37 -0
  59. package/dist/schemas/scout/zfs.d.ts.map +1 -0
  60. package/dist/schemas/scout/zfs.js +36 -0
  61. package/dist/schemas/scout/zfs.js.map +1 -0
  62. package/dist/schemas/unified.d.ts +674 -0
  63. package/dist/schemas/unified.d.ts.map +1 -0
  64. package/dist/schemas/unified.js +453 -0
  65. package/dist/schemas/unified.js.map +1 -0
  66. package/dist/services/compose.d.ts +107 -0
  67. package/dist/services/compose.d.ts.map +1 -0
  68. package/dist/services/compose.js +308 -0
  69. package/dist/services/compose.js.map +1 -0
  70. package/dist/services/container.d.ts +69 -0
  71. package/dist/services/container.d.ts.map +1 -0
  72. package/dist/services/container.js +111 -0
  73. package/dist/services/container.js.map +1 -0
  74. package/dist/services/docker.d.ts +243 -0
  75. package/dist/services/docker.d.ts.map +1 -0
  76. package/dist/services/docker.js +812 -0
  77. package/dist/services/docker.js.map +1 -0
  78. package/dist/services/file-service.d.ts +79 -0
  79. package/dist/services/file-service.d.ts.map +1 -0
  80. package/dist/services/file-service.js +226 -0
  81. package/dist/services/file-service.js.map +1 -0
  82. package/dist/services/interfaces.d.ts +537 -0
  83. package/dist/services/interfaces.d.ts.map +1 -0
  84. package/dist/services/interfaces.js +2 -0
  85. package/dist/services/interfaces.js.map +1 -0
  86. package/dist/services/ssh-pool-exec.d.ts +10 -0
  87. package/dist/services/ssh-pool-exec.d.ts.map +1 -0
  88. package/dist/services/ssh-pool-exec.js +10 -0
  89. package/dist/services/ssh-pool-exec.js.map +1 -0
  90. package/dist/services/ssh-pool.d.ts +66 -0
  91. package/dist/services/ssh-pool.d.ts.map +1 -0
  92. package/dist/services/ssh-pool.js +253 -0
  93. package/dist/services/ssh-pool.js.map +1 -0
  94. package/dist/services/ssh-service.d.ts +39 -0
  95. package/dist/services/ssh-service.d.ts.map +1 -0
  96. package/dist/services/ssh-service.js +143 -0
  97. package/dist/services/ssh-service.js.map +1 -0
  98. package/dist/services/ssh.d.ts +37 -0
  99. package/dist/services/ssh.d.ts.map +1 -0
  100. package/dist/services/ssh.js +50 -0
  101. package/dist/services/ssh.js.map +1 -0
  102. package/dist/tools/flux.d.ts +14 -0
  103. package/dist/tools/flux.d.ts.map +1 -0
  104. package/dist/tools/flux.js +86 -0
  105. package/dist/tools/flux.js.map +1 -0
  106. package/dist/tools/index.d.ts +7 -0
  107. package/dist/tools/index.d.ts.map +1 -0
  108. package/dist/tools/index.js +43 -0
  109. package/dist/tools/index.js.map +1 -0
  110. package/dist/tools/scout.d.ts +14 -0
  111. package/dist/tools/scout.d.ts.map +1 -0
  112. package/dist/tools/scout.js +96 -0
  113. package/dist/tools/scout.js.map +1 -0
  114. package/dist/tools/unified.d.ts +7 -0
  115. package/dist/tools/unified.d.ts.map +1 -0
  116. package/dist/tools/unified.js +827 -0
  117. package/dist/tools/unified.js.map +1 -0
  118. package/dist/types.d.ts +93 -0
  119. package/dist/types.d.ts.map +1 -0
  120. package/dist/types.js +7 -0
  121. package/dist/types.js.map +1 -0
  122. package/dist/utils/errors.d.ts +60 -0
  123. package/dist/utils/errors.d.ts.map +1 -0
  124. package/dist/utils/errors.js +131 -0
  125. package/dist/utils/errors.js.map +1 -0
  126. package/dist/utils/help.d.ts +69 -0
  127. package/dist/utils/help.d.ts.map +1 -0
  128. package/dist/utils/help.js +259 -0
  129. package/dist/utils/help.js.map +1 -0
  130. package/dist/utils/index.d.ts +4 -0
  131. package/dist/utils/index.d.ts.map +1 -0
  132. package/dist/utils/index.js +4 -0
  133. package/dist/utils/index.js.map +1 -0
  134. package/dist/utils/path-security.d.ts +64 -0
  135. package/dist/utils/path-security.d.ts.map +1 -0
  136. package/dist/utils/path-security.js +138 -0
  137. package/dist/utils/path-security.js.map +1 -0
  138. package/package.json +85 -0
@@ -0,0 +1,461 @@
1
+ /**
2
+ * Formatting utilities for homelab MCP responses
3
+ *
4
+ * Provides consistent markdown formatting for container, host, and Docker data.
5
+ */
6
+ import { CHARACTER_LIMIT } from "../constants.js";
7
+ import { formatBytes } from "../services/docker.js";
8
+ // Re-export formatBytes for convenience
9
+ export { formatBytes };
10
+ /**
11
+ * Truncate text if it exceeds CHARACTER_LIMIT
12
+ */
13
+ export function truncateIfNeeded(text) {
14
+ if (text.length <= CHARACTER_LIMIT)
15
+ return text;
16
+ return (text.slice(0, CHARACTER_LIMIT - 100) +
17
+ "\n\n... [Output truncated. Use pagination or filters to reduce results.]");
18
+ }
19
+ /**
20
+ * Format container list as markdown
21
+ */
22
+ export function formatContainersMarkdown(containers, total, offset, hasMore) {
23
+ if (containers.length === 0) {
24
+ return "No containers found matching the specified criteria.";
25
+ }
26
+ const lines = [`## Containers (${offset + 1}-${offset + containers.length} of ${total})`, ""];
27
+ for (const c of containers) {
28
+ const stateEmoji = c.state === "running" ? "🟢" : c.state === "paused" ? "🟡" : "🔴";
29
+ const ports = c.ports
30
+ .filter((p) => p.hostPort)
31
+ .map((p) => `${p.hostPort}→${p.containerPort}`)
32
+ .join(", ");
33
+ lines.push(`${stateEmoji} **${c.name}** (${c.hostName})`);
34
+ lines.push(` Image: ${c.image} | Status: ${c.status}`);
35
+ if (ports)
36
+ lines.push(` Ports: ${ports}`);
37
+ lines.push("");
38
+ }
39
+ if (hasMore) {
40
+ lines.push(`*More results available. Use offset=${offset + containers.length} to see next page.*`);
41
+ }
42
+ return lines.join("\n");
43
+ }
44
+ /**
45
+ * Format container logs as markdown
46
+ */
47
+ export function formatLogsMarkdown(logs, container, host) {
48
+ if (logs.length === 0) {
49
+ return `No logs found for container '${container}' on ${host}.`;
50
+ }
51
+ const lines = [`## Logs: ${container} (${host})`, "", "```"];
52
+ for (const log of logs) {
53
+ const ts = log.timestamp.slice(11, 19);
54
+ lines.push(`[${ts}] ${log.message}`);
55
+ }
56
+ lines.push("```");
57
+ return lines.join("\n");
58
+ }
59
+ /**
60
+ * Format single container stats as markdown
61
+ */
62
+ export function formatStatsMarkdown(stats, host) {
63
+ const s = stats[0];
64
+ return `## Stats: ${s.containerName} (${host})
65
+
66
+ | Metric | Value |
67
+ |--------|-------|
68
+ | CPU | ${s.cpuPercent.toFixed(1)}% |
69
+ | Memory | ${formatBytes(s.memoryUsage)} / ${formatBytes(s.memoryLimit)} (${s.memoryPercent.toFixed(1)}%) |
70
+ | Network RX | ${formatBytes(s.networkRx)} |
71
+ | Network TX | ${formatBytes(s.networkTx)} |
72
+ | Block Read | ${formatBytes(s.blockRead)} |
73
+ | Block Write | ${formatBytes(s.blockWrite)} |`;
74
+ }
75
+ /**
76
+ * Format multiple container stats as markdown table
77
+ */
78
+ export function formatMultiStatsMarkdown(allStats) {
79
+ if (allStats.length === 0)
80
+ return "No running containers found.";
81
+ const lines = [
82
+ "## Container Resource Usage",
83
+ "",
84
+ "| Container | Host | CPU% | Memory | Mem% |",
85
+ "|-----------|------|------|--------|------|"
86
+ ];
87
+ for (const { stats, host } of allStats) {
88
+ lines.push(`| ${stats.containerName} | ${host} | ${stats.cpuPercent.toFixed(1)}% | ${formatBytes(stats.memoryUsage)} | ${stats.memoryPercent.toFixed(1)}% |`);
89
+ }
90
+ return lines.join("\n");
91
+ }
92
+ /**
93
+ * Format container inspection as markdown
94
+ */
95
+ export function formatInspectMarkdown(info, host) {
96
+ const config = info.Config;
97
+ const state = info.State;
98
+ const mounts = info.Mounts || [];
99
+ const network = info.NetworkSettings;
100
+ const lines = [
101
+ `## Container: ${info.Name.replace(/^\//, "")} (${host})`,
102
+ "",
103
+ "### State",
104
+ `- Status: ${state.Status}`,
105
+ `- Running: ${state.Running}`,
106
+ `- Started: ${state.StartedAt}`,
107
+ `- Restart Count: ${info.RestartCount}`,
108
+ "",
109
+ "### Configuration",
110
+ `- Image: ${config.Image}`,
111
+ `- Command: ${(config.Cmd || []).join(" ")}`,
112
+ `- Working Dir: ${config.WorkingDir || "/"}`,
113
+ ""
114
+ ];
115
+ if (config.Env && config.Env.length > 0) {
116
+ lines.push("### Environment Variables");
117
+ for (const env of config.Env.slice(0, 20)) {
118
+ const [key] = env.split("=");
119
+ const isSensitive = /password|secret|key|token|api/i.test(key);
120
+ lines.push(`- ${isSensitive ? `${key}=****` : env}`);
121
+ }
122
+ if (config.Env.length > 20)
123
+ lines.push(`- ... and ${config.Env.length - 20} more`);
124
+ lines.push("");
125
+ }
126
+ if (mounts.length > 0) {
127
+ lines.push("### Mounts");
128
+ for (const m of mounts) {
129
+ lines.push(`- ${m.Source} → ${m.Destination} (${m.Mode || "rw"})`);
130
+ }
131
+ lines.push("");
132
+ }
133
+ if (network.Ports) {
134
+ lines.push("### Ports");
135
+ for (const [containerPort, bindings] of Object.entries(network.Ports)) {
136
+ if (bindings && bindings.length > 0) {
137
+ for (const b of bindings) {
138
+ lines.push(`- ${b.HostIp || "0.0.0.0"}:${b.HostPort} → ${containerPort}`);
139
+ }
140
+ }
141
+ }
142
+ lines.push("");
143
+ }
144
+ if (network.Networks && Object.keys(network.Networks).length > 0) {
145
+ lines.push("### Networks");
146
+ for (const networkName of Object.keys(network.Networks)) {
147
+ lines.push(`- ${networkName}`);
148
+ }
149
+ }
150
+ return lines.join("\n");
151
+ }
152
+ /**
153
+ * Format host status as markdown table
154
+ */
155
+ export function formatHostStatusMarkdown(status) {
156
+ const lines = [
157
+ "## Homelab Host Status",
158
+ "",
159
+ "| Host | Status | Containers | Running |",
160
+ "|------|--------|------------|---------|"
161
+ ];
162
+ for (const h of status) {
163
+ const statusEmoji = h.connected ? "🟢" : "🔴";
164
+ const statusText = h.connected ? "Online" : `Offline (${h.error || "Unknown"})`;
165
+ lines.push(`| ${h.name} | ${statusEmoji} ${statusText} | ${h.containerCount} | ${h.runningCount} |`);
166
+ }
167
+ return lines.join("\n");
168
+ }
169
+ /**
170
+ * Format search results as markdown
171
+ */
172
+ export function formatSearchResultsMarkdown(containers, query, total) {
173
+ if (containers.length === 0)
174
+ return `No containers found matching '${query}'.`;
175
+ const lines = [`## Search Results for '${query}' (${total} matches)`, ""];
176
+ for (const c of containers) {
177
+ const stateEmoji = c.state === "running" ? "🟢" : c.state === "paused" ? "🟡" : "🔴";
178
+ lines.push(`${stateEmoji} **${c.name}** (${c.hostName})`);
179
+ lines.push(` Image: ${c.image} | State: ${c.state}`);
180
+ lines.push("");
181
+ }
182
+ return lines.join("\n");
183
+ }
184
+ /**
185
+ * Format Docker info as markdown
186
+ */
187
+ export function formatDockerInfoMarkdown(results) {
188
+ const lines = ["## Docker System Info", ""];
189
+ for (const { host, info } of results) {
190
+ lines.push(`### ${host}`);
191
+ if (info.dockerVersion === "error") {
192
+ lines.push(`❌ Error: ${info.os}`);
193
+ }
194
+ else {
195
+ lines.push(`- Docker: ${info.dockerVersion} (API ${info.apiVersion})`);
196
+ lines.push(`- OS: ${info.os} (${info.arch})`);
197
+ lines.push(`- Kernel: ${info.kernelVersion}`);
198
+ lines.push(`- CPUs: ${info.cpus} | Memory: ${formatBytes(info.memoryBytes)}`);
199
+ lines.push(`- Storage: ${info.storageDriver} @ ${info.rootDir}`);
200
+ lines.push(`- Containers: ${info.containersRunning} running / ${info.containersTotal} total`);
201
+ lines.push(`- Images: ${info.images}`);
202
+ }
203
+ lines.push("");
204
+ }
205
+ return lines.join("\n");
206
+ }
207
+ /**
208
+ * Format Docker disk usage as markdown
209
+ */
210
+ export function formatDockerDfMarkdown(results) {
211
+ const lines = ["## Docker Disk Usage", ""];
212
+ for (const { host, usage } of results) {
213
+ lines.push(`### ${host}`, "", "| Type | Count | Size | Reclaimable |", "|------|-------|------|-------------|");
214
+ lines.push(`| Images | ${usage.images.total} (${usage.images.active} active) | ${formatBytes(usage.images.size)} | ${formatBytes(usage.images.reclaimable)} |`);
215
+ lines.push(`| Containers | ${usage.containers.total} (${usage.containers.running} running) | ${formatBytes(usage.containers.size)} | ${formatBytes(usage.containers.reclaimable)} |`);
216
+ lines.push(`| Volumes | ${usage.volumes.total} (${usage.volumes.active} active) | ${formatBytes(usage.volumes.size)} | ${formatBytes(usage.volumes.reclaimable)} |`);
217
+ lines.push(`| Build Cache | ${usage.buildCache.total} | ${formatBytes(usage.buildCache.size)} | ${formatBytes(usage.buildCache.reclaimable)} |`);
218
+ lines.push(`| **Total** | | **${formatBytes(usage.totalSize)}** | **${formatBytes(usage.totalReclaimable)}** |`);
219
+ lines.push("");
220
+ }
221
+ return lines.join("\n");
222
+ }
223
+ /**
224
+ * Format prune results as markdown
225
+ */
226
+ export function formatPruneMarkdown(allResults) {
227
+ const lines = ["## Prune Results", ""];
228
+ let totalReclaimed = 0;
229
+ let totalDeleted = 0;
230
+ for (const { host, results } of allResults) {
231
+ lines.push(`### ${host}`, "", "| Type | Items Deleted | Space Reclaimed |", "|------|---------------|-----------------|");
232
+ for (const r of results) {
233
+ lines.push(`| ${r.type} | ${r.itemsDeleted} | ${formatBytes(r.spaceReclaimed)} |`);
234
+ totalReclaimed += r.spaceReclaimed;
235
+ totalDeleted += r.itemsDeleted;
236
+ }
237
+ lines.push("");
238
+ }
239
+ lines.push(`**Total: ${totalDeleted} items deleted, ${formatBytes(totalReclaimed)} reclaimed**`);
240
+ return lines.join("\n");
241
+ }
242
+ /**
243
+ * Format host resources as markdown
244
+ */
245
+ export function formatHostResourcesMarkdown(results) {
246
+ const lines = ["## Host Resources", ""];
247
+ for (const { host, resources, error } of results) {
248
+ lines.push(`### ${host}`);
249
+ if (error || !resources) {
250
+ lines.push(`❌ ${error || "Unknown error"}`);
251
+ lines.push("");
252
+ continue;
253
+ }
254
+ lines.push(`- **Hostname:** ${resources.hostname}`);
255
+ lines.push(`- **Uptime:** ${resources.uptime}`);
256
+ lines.push(`- **Load:** ${resources.loadAverage.join(", ")}`);
257
+ lines.push(`- **CPU:** ${resources.cpu.cores} cores @ ${resources.cpu.usagePercent}%`);
258
+ lines.push(`- **Memory:** ${resources.memory.usedMB} MB / ${resources.memory.totalMB} MB (${resources.memory.usagePercent}%)`);
259
+ if (resources.disk.length > 0) {
260
+ lines.push("", "**Disks:**");
261
+ for (const d of resources.disk) {
262
+ lines.push(`- ${d.mount}: ${d.usedGB}G / ${d.totalGB}G (${d.usagePercent}%)`);
263
+ }
264
+ }
265
+ lines.push("");
266
+ }
267
+ return lines.join("\n");
268
+ }
269
+ /**
270
+ * Format images list as markdown table
271
+ */
272
+ export function formatImagesMarkdown(images, total, offset) {
273
+ if (images.length === 0)
274
+ return "No images found.";
275
+ const lines = [
276
+ "## Docker Images",
277
+ "",
278
+ `Showing ${images.length} of ${total} images (offset: ${offset})`,
279
+ "",
280
+ "| ID | Tags | Size | Host | Containers |",
281
+ "|-----|------|------|------|------------|"
282
+ ];
283
+ for (const img of images) {
284
+ const tags = img.tags.slice(0, 2).join(", ") + (img.tags.length > 2 ? "..." : "");
285
+ lines.push(`| ${img.id} | ${tags} | ${formatBytes(img.size)} | ${img.hostName} | ${img.containers} |`);
286
+ }
287
+ return lines.join("\n");
288
+ }
289
+ /**
290
+ * Format compose project list as markdown
291
+ */
292
+ export function formatComposeListMarkdown(projects, host, total, offset, hasMore) {
293
+ if (projects.length === 0)
294
+ return `No compose projects found on ${host}.`;
295
+ const header = total !== undefined
296
+ ? `## Compose Projects on ${host} (${(offset || 0) + 1}-${(offset || 0) + projects.length} of ${total})`
297
+ : `## Compose Projects on ${host}`;
298
+ const lines = [header, "", "| Project | Status | Services |", "|---------|--------|----------|"];
299
+ for (const p of projects) {
300
+ const statusEmoji = p.status === "running" ? "🟢" : p.status === "partial" ? "🟡" : "🔴";
301
+ lines.push(`| ${p.name} | ${statusEmoji} ${p.status} | ${p.services.length || "-"} |`);
302
+ }
303
+ if (hasMore) {
304
+ lines.push("");
305
+ lines.push(`*More results available. Use offset=${(offset || 0) + projects.length} to see next page.*`);
306
+ }
307
+ return lines.join("\n");
308
+ }
309
+ /**
310
+ * Format compose project status as markdown
311
+ */
312
+ export function formatComposeStatusMarkdown(project, totalServices, offset, hasMore) {
313
+ const statusEmoji = project.status === "running" ? "🟢" : project.status === "partial" ? "🟡" : "🔴";
314
+ const serviceInfo = totalServices !== undefined
315
+ ? ` - Services ${(offset || 0) + 1}-${(offset || 0) + project.services.length} of ${totalServices}`
316
+ : "";
317
+ const lines = [`## ${project.name} (${statusEmoji} ${project.status})${serviceInfo}`, ""];
318
+ if (project.services.length === 0) {
319
+ lines.push("No services found.");
320
+ }
321
+ else {
322
+ lines.push("| Service | Status | Health | Ports |", "|---------|--------|--------|-------|");
323
+ for (const svc of project.services) {
324
+ const health = svc.health || "-";
325
+ const ports = svc.publishers?.map((p) => `${p.publishedPort}→${p.targetPort}`).join(", ") || "-";
326
+ const svcEmoji = svc.status === "running" ? "🟢" : "🔴";
327
+ lines.push(`| ${svc.name} | ${svcEmoji} ${svc.status} | ${health} | ${ports} |`);
328
+ }
329
+ }
330
+ if (hasMore) {
331
+ lines.push("");
332
+ lines.push(`*More services available. Use offset=${(offset || 0) + project.services.length} to see next page.*`);
333
+ }
334
+ return lines.join("\n");
335
+ }
336
+ /**
337
+ * Format container inspect summary as markdown (condensed version)
338
+ */
339
+ export function formatInspectSummaryMarkdown(summary) {
340
+ const lines = [
341
+ `## ${summary.name} (${summary.host})`,
342
+ "",
343
+ "| Field | Value |",
344
+ "|-------|-------|",
345
+ `| ID | ${summary.id} |`,
346
+ `| Image | ${summary.image} |`,
347
+ `| State | ${summary.state} |`,
348
+ `| Started | ${summary.started?.slice(0, 19) || "-"} |`,
349
+ `| Restarts | ${summary.restartCount} |`,
350
+ `| Networks | ${summary.networks.join(", ") || "-"} |`,
351
+ `| Ports | ${summary.ports.join(", ") || "-"} |`,
352
+ `| Mounts | ${summary.mounts.length} |`,
353
+ `| Env Vars | ${summary.env_count} |`,
354
+ `| Labels | ${summary.labels_count} |`
355
+ ];
356
+ if (summary.mounts.length > 0 && summary.mounts.length <= 5) {
357
+ lines.push("", "**Mounts:**");
358
+ for (const m of summary.mounts) {
359
+ lines.push(`- ${m.src} → ${m.dst} (${m.type})`);
360
+ }
361
+ }
362
+ return lines.join("\n");
363
+ }
364
+ // ===== Scout Formatters =====
365
+ /**
366
+ * Format file read result as markdown
367
+ */
368
+ export function formatScoutReadMarkdown(host, path, content, size, truncated) {
369
+ const lines = [
370
+ `## 📄 ${host}:${path}`,
371
+ "",
372
+ `**Size:** ${formatBytes(size)}${truncated ? " (truncated)" : ""}`,
373
+ "",
374
+ "```",
375
+ content,
376
+ "```"
377
+ ];
378
+ if (truncated) {
379
+ lines.push("");
380
+ lines.push("⚠️ *File was truncated to fit size limit*");
381
+ }
382
+ return truncateIfNeeded(lines.join("\n"));
383
+ }
384
+ /**
385
+ * Format directory listing as markdown
386
+ */
387
+ export function formatScoutListMarkdown(host, path, listing) {
388
+ return truncateIfNeeded([`## 📁 ${host}:${path}`, "", "```", listing, "```"].join("\n"));
389
+ }
390
+ /**
391
+ * Format tree output as markdown
392
+ */
393
+ export function formatScoutTreeMarkdown(host, path, tree, depth) {
394
+ return truncateIfNeeded([`## 🌳 ${host}:${path} (depth: ${depth})`, "", "```", tree, "```"].join("\n"));
395
+ }
396
+ /**
397
+ * Format command execution result as markdown
398
+ */
399
+ export function formatScoutExecMarkdown(host, path, command, stdout, exitCode) {
400
+ const statusEmoji = exitCode === 0 ? "✅" : "❌";
401
+ return truncateIfNeeded([
402
+ `## ${statusEmoji} Command: ${host}:${path}`,
403
+ "",
404
+ `**Command:** \`${command}\``,
405
+ `**Exit:** ${exitCode}`,
406
+ "",
407
+ "**Output:**",
408
+ "```",
409
+ stdout,
410
+ "```"
411
+ ].join("\n"));
412
+ }
413
+ /**
414
+ * Format find results as markdown
415
+ */
416
+ export function formatScoutFindMarkdown(host, path, pattern, results) {
417
+ const lines = results.split("\n").filter((l) => l.trim());
418
+ return truncateIfNeeded([
419
+ `## 🔍 Find: ${host}:${path}`,
420
+ "",
421
+ `**Pattern:** \`${pattern}\``,
422
+ `**Results:** ${lines.length} files`,
423
+ "",
424
+ "```",
425
+ results,
426
+ "```"
427
+ ].join("\n"));
428
+ }
429
+ /**
430
+ * Format file transfer result as markdown
431
+ */
432
+ export function formatScoutTransferMarkdown(sourceHost, sourcePath, targetHost, targetPath, bytesTransferred, warning) {
433
+ const lines = [
434
+ `## 📦 Transfer Complete`,
435
+ "",
436
+ `**From:** ${sourceHost}:${sourcePath}`,
437
+ `**To:** ${targetHost}:${targetPath}`,
438
+ `**Size:** ${formatBytes(bytesTransferred)}`
439
+ ];
440
+ if (warning) {
441
+ lines.push("");
442
+ lines.push(`⚠️ ${warning}`);
443
+ }
444
+ return lines.join("\n");
445
+ }
446
+ /**
447
+ * Format file diff result as markdown
448
+ */
449
+ export function formatScoutDiffMarkdown(host1, path1, host2, path2, diff) {
450
+ return truncateIfNeeded([
451
+ `## 📊 Diff`,
452
+ "",
453
+ `**File 1:** ${host1}:${path1}`,
454
+ `**File 2:** ${host2}:${path2}`,
455
+ "",
456
+ "```diff",
457
+ diff,
458
+ "```"
459
+ ].join("\n"));
460
+ }
461
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
5
+ import express from "express";
6
+ import rateLimit from "express-rate-limit";
7
+ import { registerTools } from "./tools/index.js";
8
+ import { createDefaultContainer } from "./services/container.js";
9
+ // Server metadata
10
+ const SERVER_NAME = "homelab-mcp-server";
11
+ const SERVER_VERSION = "1.0.0";
12
+ // Global service container instance
13
+ let globalContainer;
14
+ /**
15
+ * Create and configure the MCP server
16
+ */
17
+ function createServer() {
18
+ const server = new McpServer({
19
+ name: SERVER_NAME,
20
+ version: SERVER_VERSION
21
+ });
22
+ // Create and register service container
23
+ globalContainer = createDefaultContainer();
24
+ // Register all homelab tools
25
+ registerTools(server, globalContainer);
26
+ return server;
27
+ }
28
+ /**
29
+ * Run server with stdio transport (for Claude Code, local integrations)
30
+ */
31
+ async function runStdio() {
32
+ const server = createServer();
33
+ const transport = new StdioServerTransport();
34
+ await server.connect(transport);
35
+ // Log to stderr (stdout is reserved for MCP protocol)
36
+ console.error(`${SERVER_NAME} v${SERVER_VERSION} running on stdio`);
37
+ }
38
+ /**
39
+ * Rate limiter for HTTP API
40
+ */
41
+ const limiter = rateLimit({
42
+ windowMs: 60 * 1000, // 1 minute
43
+ max: 100, // 100 requests per minute
44
+ standardHeaders: true,
45
+ legacyHeaders: false,
46
+ message: { error: "Too many requests, please try again later" }
47
+ });
48
+ /**
49
+ * Run server with HTTP transport (for remote access, multiple clients)
50
+ */
51
+ async function runHTTP() {
52
+ const server = createServer();
53
+ const app = express();
54
+ app.use(express.json());
55
+ // Request logging middleware
56
+ app.use((req, _res, next) => {
57
+ const timestamp = new Date().toISOString();
58
+ const forwarded = req.headers["x-forwarded-for"] || req.headers["x-real-ip"] || "";
59
+ console.error(`[${timestamp}] ${req.method} ${req.path} from ${req.ip} (fwd: ${forwarded})`);
60
+ next();
61
+ });
62
+ // Health check endpoint (no rate limiting)
63
+ app.get("/health", (_req, res) => {
64
+ res.json({ status: "ok", server: SERVER_NAME, version: SERVER_VERSION });
65
+ });
66
+ // MCP endpoint - stateless JSON mode with rate limiting
67
+ app.post("/mcp", limiter, async (req, res) => {
68
+ const transport = new StreamableHTTPServerTransport({
69
+ sessionIdGenerator: undefined,
70
+ enableJsonResponse: true
71
+ });
72
+ res.on("close", () => transport.close());
73
+ await server.connect(transport);
74
+ await transport.handleRequest(req, res, req.body);
75
+ });
76
+ const port = parseInt(process.env.HOMELAB_PORT || "3000", 10);
77
+ const host = process.env.HOMELAB_HOST || "127.0.0.1";
78
+ app.listen(port, host, () => {
79
+ console.error(`${SERVER_NAME} v${SERVER_VERSION} running on http://${host}:${port}/mcp`);
80
+ });
81
+ }
82
+ /**
83
+ * Print usage information
84
+ */
85
+ function printUsage() {
86
+ console.log(`
87
+ ${SERVER_NAME} v${SERVER_VERSION}
88
+
89
+ MCP server for managing homelab Docker infrastructure across multiple hosts.
90
+
91
+ USAGE:
92
+ node dist/index.js [--stdio | --http]
93
+
94
+ OPTIONS:
95
+ --stdio Run with stdio transport (default, for Claude Code)
96
+ --http Run with HTTP transport (for remote access)
97
+ --help Show this help message
98
+
99
+ CONFIGURATION:
100
+ Create a config file at one of these locations (checked in order):
101
+ 1. Path specified by HOMELAB_CONFIG_FILE env var
102
+ 2. ./homelab.config.json (current directory)
103
+ 3. ~/.config/homelab-mcp/config.json
104
+ 4. ~/.homelab-mcp.json
105
+
106
+ Example config file:
107
+ {
108
+ "hosts": [
109
+ {"name": "unraid", "host": "unraid.local", "port": 2375, "protocol": "http"},
110
+ {"name": "proxmox", "host": "proxmox.local", "port": 2375, "protocol": "http"},
111
+ {"name": "local", "host": "localhost", "dockerSocketPath": "/var/run/docker.sock"}
112
+ ]
113
+ }
114
+
115
+ ENVIRONMENT VARIABLES:
116
+ HOMELAB_CONFIG_FILE Path to config file (optional, overrides default paths)
117
+ HOMELAB_HOSTS_CONFIG JSON config as env var (fallback if no config file)
118
+ HOMELAB_PORT HTTP server port (default: 3000)
119
+ HOMELAB_HOST HTTP server bind address (default: 127.0.0.1)
120
+
121
+ CLAUDE CODE CONFIG (~/.claude/claude_code_config.json):
122
+ {
123
+ "mcpServers": {
124
+ "homelab": {
125
+ "command": "node",
126
+ "args": ["/path/to/homelab-mcp-server/dist/index.js"],
127
+ "env": {
128
+ "HOMELAB_CONFIG_FILE": "/path/to/your/homelab.config.json"
129
+ }
130
+ }
131
+ }
132
+ }
133
+ `);
134
+ }
135
+ /**
136
+ * Graceful shutdown handler
137
+ */
138
+ async function shutdown(signal) {
139
+ console.error(`\nReceived ${signal}, shutting down gracefully...`);
140
+ if (globalContainer) {
141
+ await globalContainer.cleanup();
142
+ }
143
+ console.error("Cleanup complete");
144
+ process.exit(0);
145
+ }
146
+ // Register signal handlers for graceful shutdown
147
+ process.on("SIGINT", () => {
148
+ shutdown("SIGINT").catch((error) => {
149
+ console.error("Error during shutdown:", error);
150
+ process.exit(1);
151
+ });
152
+ });
153
+ process.on("SIGTERM", () => {
154
+ shutdown("SIGTERM").catch((error) => {
155
+ console.error("Error during shutdown:", error);
156
+ process.exit(1);
157
+ });
158
+ });
159
+ // Main entry point
160
+ const args = process.argv.slice(2);
161
+ if (args.includes("--help") || args.includes("-h")) {
162
+ printUsage();
163
+ process.exit(0);
164
+ }
165
+ const transportMode = args.includes("--http") ? "http" : "stdio";
166
+ if (transportMode === "http") {
167
+ runHTTP().catch((error) => {
168
+ console.error("Server error:", error);
169
+ process.exit(1);
170
+ });
171
+ }
172
+ else {
173
+ runStdio().catch((error) => {
174
+ console.error("Server error:", error);
175
+ process.exit(1);
176
+ });
177
+ }
178
+ //# sourceMappingURL=index.js.map