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
package/README.md ADDED
@@ -0,0 +1,607 @@
1
+ # Synapse MCP
2
+
3
+ MCP (Model Context Protocol) server providing **Flux** (Docker management) and **Scout** (SSH operations) tools for homelab infrastructure. The neural connection point for your distributed systems.
4
+
5
+ Designed for use with Claude Code and other MCP-compatible clients.
6
+
7
+ ## Features
8
+
9
+ ### Flux Tool (Docker Infrastructure Management)
10
+ - **Container lifecycle**: Start, stop, restart, pause/resume, pull, recreate, exec
11
+ - **Docker Compose**: Full project management (up, down, restart, logs, build, pull, recreate)
12
+ - **Image operations**: List, pull, build, remove Docker images
13
+ - **Host operations**: Status checks, resource monitoring, systemd services, network info
14
+ - **Log retrieval**: Advanced filtering with time ranges, grep, stream selection
15
+ - **Resource monitoring**: Real-time CPU, memory, network, I/O statistics
16
+ - **Smart search**: Find containers by name, image, or labels across all hosts
17
+ - **Pagination & filtering**: All list operations support limits, offsets, and filtering
18
+
19
+ ### Scout Tool (SSH Remote Operations)
20
+ - **File operations**: Read files, directory trees, file transfer (beam), diff comparison
21
+ - **Remote execution**: Execute commands with allowlist security
22
+ - **Process monitoring**: List and filter processes by user, CPU, memory
23
+ - **ZFS management**: Pools, datasets, snapshots with health monitoring
24
+ - **System logs**: Access syslog, journald, dmesg, auth logs with filtering
25
+ - **Disk monitoring**: Filesystem usage across all mounts
26
+ - **Multi-host operations**: Execute commands or read files across multiple hosts (emit)
27
+
28
+ ### Infrastructure
29
+ - **Multi-host support**: Manage Docker and SSH across Unraid, Proxmox, bare metal
30
+ - **Auto-detect local Docker**: Automatically adds local Docker socket if available
31
+ - **Dual transport**: stdio for Claude Code, HTTP for remote access
32
+ - **O(1) validation**: Discriminated union pattern for instant schema validation
33
+ - **SSH connection pooling**: 50× faster repeated operations
34
+
35
+ ## Tools
36
+
37
+ The server provides two powerful tools with discriminated union schemas for O(1) validation:
38
+
39
+ ### Tool 1: `flux` - Docker Infrastructure Management
40
+
41
+ **4 actions, 39 subactions** - State changes, lifecycle control, destructive operations.
42
+
43
+ #### Container Operations (`action: "container"`) - 14 subactions
44
+
45
+ | Subaction | Description |
46
+ | ---------|-------------|
47
+ | `list` | List containers with filtering by state, name, image, labels |
48
+ | `start` | Start a stopped container |
49
+ | `stop` | Stop a running container |
50
+ | `restart` | Restart a container |
51
+ | `pause` | Pause a running container |
52
+ | `resume` | Resume a paused container (was `unpause`) |
53
+ | `logs` | Retrieve container logs with time and grep filters |
54
+ | `stats` | Get real-time CPU, memory, network, I/O statistics |
55
+ | `inspect` | Detailed container configuration and state (with summary mode) |
56
+ | `search` | Search containers by name, image, or labels |
57
+ | `pull` | Pull latest image for a container |
58
+ | `recreate` | Recreate container with latest image |
59
+ | `exec` | Execute command inside a container (allowlist validated) |
60
+ | `top` | Show running processes in a container |
61
+
62
+ #### Docker Compose Operations (`action: "compose"`) - 9 subactions
63
+
64
+ | Subaction | Description |
65
+ | ---------|-------------|
66
+ | `list` | List Docker Compose projects on a host |
67
+ | `status` | Get status of services in a project |
68
+ | `up` | Start a compose project |
69
+ | `down` | Stop a compose project |
70
+ | `restart` | Restart a compose project |
71
+ | `logs` | Get logs from compose project services |
72
+ | `build` | Build images for a compose project |
73
+ | `pull` | Pull images for a compose project |
74
+ | `recreate` | Force recreate containers in a project |
75
+
76
+ #### Docker System Operations (`action: "docker"`) - 9 subactions
77
+
78
+ | Subaction | Description |
79
+ | ---------|-------------|
80
+ | `info` | Get Docker daemon information |
81
+ | `df` | Get Docker disk usage (images, containers, volumes, cache) |
82
+ | `prune` | Remove unused Docker resources (requires `force: true`) |
83
+ | `images` | List Docker images on a host |
84
+ | `pull` | Pull a Docker image |
85
+ | `build` | Build a Docker image from Dockerfile |
86
+ | `rmi` | Remove a Docker image |
87
+ | `networks` | List Docker networks |
88
+ | `volumes` | List Docker volumes |
89
+
90
+ #### Host Operations (`action: "host"`) - 7 subactions
91
+
92
+ | Subaction | Description |
93
+ | ---------|-------------|
94
+ | `status` | Check Docker connectivity to host |
95
+ | `resources` | Get CPU, memory, disk usage via SSH |
96
+ | `info` | Get OS, kernel, architecture, hostname |
97
+ | `uptime` | Get system uptime |
98
+ | `services` | Get systemd service status |
99
+ | `network` | Get network interfaces and IP addresses |
100
+ | `mounts` | Get mounted filesystems |
101
+
102
+ ---
103
+
104
+ ### Tool 2: `scout` - SSH Remote Operations
105
+
106
+ **11 actions, 16 operations** - Read-mostly remote file and system operations.
107
+
108
+ #### Simple Actions (9)
109
+
110
+ | Action | Description |
111
+ | ------|-------------|
112
+ | `nodes` | List all configured SSH hosts |
113
+ | `peek` | Read file or directory contents (with tree mode) |
114
+ | `exec` | Execute command on remote host (allowlist validated) |
115
+ | `find` | Find files by glob pattern |
116
+ | `delta` | Compare files or content between locations |
117
+ | `emit` | Multi-host operations (read files or execute commands) |
118
+ | `beam` | File transfer between local/remote or remote/remote |
119
+ | `ps` | List and search processes with filtering |
120
+ | `df` | Disk usage information |
121
+
122
+ #### ZFS Operations (`action: "zfs"`) - 3 subactions
123
+
124
+ | Subaction | Description |
125
+ | ---------|-------------|
126
+ | `pools` | List ZFS storage pools with health status |
127
+ | `datasets` | List ZFS datasets (filesystems and volumes) |
128
+ | `snapshots` | List ZFS snapshots |
129
+
130
+ #### Log Operations (`action: "logs"`) - 4 subactions
131
+
132
+ | Subaction | Description |
133
+ | ---------|-------------|
134
+ | `syslog` | Access system log files (/var/log) |
135
+ | `journal` | Access systemd journal logs with unit filtering |
136
+ | `dmesg` | Access kernel ring buffer logs |
137
+ | `auth` | Access authentication logs |
138
+
139
+ ---
140
+
141
+ ## Example Usage
142
+
143
+ ### Flux Tool Examples
144
+
145
+ ```json
146
+ // List running containers
147
+ { "tool": "flux", "action": "container", "subaction": "list", "state": "running" }
148
+
149
+ // Restart a container
150
+ { "tool": "flux", "action": "container", "subaction": "restart", "container_id": "plex", "host": "tootie" }
151
+
152
+ // Start a compose project
153
+ { "tool": "flux", "action": "compose", "subaction": "up", "host": "tootie", "project": "media-stack" }
154
+
155
+ // Get host resources
156
+ { "tool": "flux", "action": "host", "subaction": "resources", "host": "tootie" }
157
+
158
+ // Pull an image
159
+ { "tool": "flux", "action": "docker", "subaction": "pull", "host": "tootie", "image": "nginx:latest" }
160
+
161
+ // Execute command in container
162
+ { "tool": "flux", "action": "container", "subaction": "exec", "container_id": "nginx", "command": "nginx -t" }
163
+ ```
164
+
165
+ ### Scout Tool Examples
166
+
167
+ ```json
168
+ // List configured SSH hosts
169
+ { "tool": "scout", "action": "nodes" }
170
+
171
+ // Read a remote file
172
+ { "tool": "scout", "action": "peek", "target": "tootie:/etc/nginx/nginx.conf" }
173
+
174
+ // Show directory tree
175
+ { "tool": "scout", "action": "peek", "target": "dookie:/var/log", "tree": true }
176
+
177
+ // Execute remote command
178
+ { "tool": "scout", "action": "exec", "target": "tootie:/var/www", "command": "du -sh *" }
179
+
180
+ // Transfer file between hosts
181
+ { "tool": "scout", "action": "beam", "source": "tootie:/tmp/backup.tar.gz", "destination": "dookie:/backup/" }
182
+
183
+ // Check ZFS pool health
184
+ { "tool": "scout", "action": "zfs", "subaction": "pools", "host": "dookie" }
185
+
186
+ // View systemd journal
187
+ { "tool": "scout", "action": "logs", "subaction": "journal", "host": "tootie", "unit": "docker.service" }
188
+
189
+ // Multi-host command execution
190
+ { "tool": "scout", "action": "emit", "targets": ["tootie:/tmp", "dookie:/tmp"], "command": "df -h" }
191
+ ```
192
+
193
+ ## Installation
194
+
195
+ ```bash
196
+ # Clone or copy the server files
197
+ cd synapse-mcp
198
+
199
+ # Install dependencies
200
+ pnpm install
201
+
202
+ # Build
203
+ pnpm run build
204
+ ```
205
+
206
+ ## Configuration
207
+
208
+ Create a config file at one of these locations (checked in order):
209
+
210
+ 1. Path in `SYNAPSE_CONFIG_FILE` env var
211
+ 2. `./synapse.config.json` (current directory)
212
+ 3. `~/.config/synapse-mcp/config.json`
213
+ 4. `~/.synapse-mcp.json`
214
+
215
+ ### Example Config
216
+
217
+ ```json
218
+ {
219
+ "hosts": [
220
+ {
221
+ "name": "unraid",
222
+ "host": "unraid.local",
223
+ "port": 2375,
224
+ "protocol": "http",
225
+ "tags": ["media", "storage"]
226
+ },
227
+ {
228
+ "name": "proxmox-docker",
229
+ "host": "192.168.1.100",
230
+ "port": 2375,
231
+ "protocol": "http",
232
+ "tags": ["vms"]
233
+ },
234
+ {
235
+ "name": "local",
236
+ "host": "localhost",
237
+ "protocol": "http",
238
+ "dockerSocketPath": "/var/run/docker.sock"
239
+ }
240
+ ]
241
+ }
242
+ ```
243
+
244
+ Copy `synapse.config.example.json` as a starting point:
245
+ ```bash
246
+ cp synapse.config.example.json ~/.config/synapse-mcp/config.json
247
+ # or
248
+ cp synapse.config.example.json ~/.synapse-mcp.json
249
+ ```
250
+
251
+ > **Note:** If `/var/run/docker.sock` exists and isn't already in your config, it will be automatically added as a host using your machine's hostname. This means the server works out-of-the-box for local Docker without any configuration.
252
+
253
+ ### Host Configuration Options
254
+
255
+ | Field | Type | Description |
256
+ | ----- | ---- | ----------- |
257
+ | `name` | `string` | Unique identifier for the host |
258
+ | `host` | `string` | Hostname or IP address |
259
+ | `port` | `number` | Docker API port (default: 2375) |
260
+ | `protocol` | `"http"` / `"https"` / `"ssh"` | Connection protocol |
261
+ | `dockerSocketPath` | `string` | Path to Docker socket (for local connections) |
262
+ | `sshUser` | `string` | SSH username for remote connections (protocol: "ssh") |
263
+ | `sshKeyPath` | `string` | Path to SSH private key for authentication |
264
+ | `tags` | `string[]` | Optional tags for filtering |
265
+
266
+ ### Resource Limits & Defaults
267
+
268
+ | Setting | Value | Description |
269
+ | -------|-------|-------------|
270
+ | `CHARACTER_LIMIT` | 40,000 | Maximum response size (~12.5k tokens) |
271
+ | `DEFAULT_LIMIT` | 20 | Default pagination limit for list operations |
272
+ | `MAX_LIMIT` | 100 | Maximum pagination limit |
273
+ | `DEFAULT_LOG_LINES` | 50 | Default number of log lines to fetch |
274
+ | `MAX_LOG_LINES` | 500 | Maximum log lines allowed |
275
+ | `API_TIMEOUT` | 30s | Docker API operation timeout |
276
+ | `STATS_TIMEOUT` | 5s | Stats collection timeout |
277
+
278
+ ### Enabling Docker API on Hosts
279
+
280
+ #### Unraid
281
+ Docker API is typically available at port 2375 by default.
282
+
283
+ #### Standard Docker (systemd)
284
+ Edit `/etc/docker/daemon.json`:
285
+ ```json
286
+ {
287
+ "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"]
288
+ }
289
+ ```
290
+
291
+ Or override the systemd service:
292
+ ```bash
293
+ sudo systemctl edit docker.service
294
+ ```
295
+ ```ini
296
+ [Service]
297
+ ExecStart=
298
+ ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375
299
+ ```
300
+
301
+ ⚠️ **Security Note**: Exposing Docker API without TLS is insecure. Use on trusted networks only, or set up TLS certificates.
302
+
303
+ ## Usage
304
+
305
+ ### With Claude Code
306
+
307
+ Add to `~/.claude/claude_code_config.json`:
308
+
309
+ ```json
310
+ {
311
+ "mcpServers": {
312
+ "synapse": {
313
+ "command": "node",
314
+ "args": ["/absolute/path/to/synapse-mcp/dist/index.js"],
315
+ "env": {
316
+ "SYNAPSE_CONFIG_FILE": "/home/youruser/.config/synapse-mcp/config.json"
317
+ }
318
+ }
319
+ }
320
+ }
321
+ ```
322
+
323
+ Or if your config is in one of the default locations, you can skip the env entirely:
324
+
325
+ ```json
326
+ {
327
+ "mcpServers": {
328
+ "synapse": {
329
+ "command": "node",
330
+ "args": ["/absolute/path/to/synapse-mcp/dist/index.js"]
331
+ }
332
+ }
333
+ }
334
+ ```
335
+
336
+ Then in Claude Code:
337
+ ```
338
+ > List all running containers on tootie (uses flux tool)
339
+ > Restart the plex container (uses flux tool)
340
+ > Show me the logs from sonarr with errors in the last hour (uses flux tool)
341
+ > Which containers are using the most memory? (uses flux tool)
342
+ > Read the nginx config on tootie (uses scout tool)
343
+ > Check ZFS pool health on dookie (uses scout tool)
344
+ > Show me systemd journal errors from the last hour (uses scout tool)
345
+ ```
346
+
347
+ ### HTTP Mode
348
+
349
+ For remote access or multi-client scenarios:
350
+
351
+ ```bash
352
+ # Start HTTP server
353
+ node dist/index.js --http
354
+
355
+ # Server runs on http://127.0.0.1:3000/mcp
356
+ # Health check: http://127.0.0.1:3000/health
357
+ ```
358
+
359
+ Environment variables for HTTP mode:
360
+ - `PORT`: Server port (default: 3000)
361
+ - `HOST`: Bind address (default: 127.0.0.1)
362
+
363
+ ### CLI Help
364
+
365
+ ```bash
366
+ node dist/index.js --help
367
+ ```
368
+
369
+ ## Example Interactions
370
+
371
+ ### Flux Tool - Container Management
372
+ ```
373
+ User: What containers are running on tootie?
374
+
375
+ Claude: [calls flux with action="container", subaction="list", host="tootie", state="running"]
376
+
377
+ I found 23 running containers on tootie:
378
+
379
+ 🟢 plex (tootie) - Image: linuxserver/plex | Up 3 days
380
+ 🟢 sonarr (tootie) - Image: linuxserver/sonarr | Up 3 days
381
+ 🟢 radarr (tootie) - Image: linuxserver/radarr | Up 3 days
382
+ ...
383
+ ```
384
+
385
+ ### Flux Tool - Log Analysis
386
+ ```
387
+ User: Show me any errors from nginx in the last hour
388
+
389
+ Claude: [calls flux with action="container", subaction="logs",
390
+ container_id="nginx", since="1h", grep="error"]
391
+
392
+ Found 3 error entries in nginx logs:
393
+ [14:23:15] 2024/12/15 14:23:15 [error] connect() failed...
394
+ ```
395
+
396
+ ### Scout Tool - Remote File Access
397
+ ```
398
+ User: Read the nginx config on tootie
399
+
400
+ Claude: [calls scout with action="peek", target="tootie:/etc/nginx/nginx.conf"]
401
+
402
+ Here's the nginx configuration from tootie:
403
+
404
+ user nginx;
405
+ worker_processes auto;
406
+ ...
407
+ ```
408
+
409
+ ### Scout Tool - ZFS Health Check
410
+ ```
411
+ User: Check ZFS pool health on dookie
412
+
413
+ Claude: [calls scout with action="zfs", subaction="pools", host="dookie"]
414
+
415
+ ZFS Pools on dookie:
416
+
417
+ tank - ONLINE | Size: 24TB | Free: 8.2TB | Health: 100%
418
+ backup - ONLINE | Size: 12TB | Free: 5.1TB | Health: 100%
419
+ ```
420
+
421
+ ### Scout Tool - System Logs
422
+ ```
423
+ User: Show me Docker service errors from systemd journal
424
+
425
+ Claude: [calls scout with action="logs", subaction="journal",
426
+ host="tootie", unit="docker.service", priority="err"]
427
+
428
+ Recent errors from docker.service:
429
+
430
+ [15:42:10] Failed to allocate directory watch: Too many open files
431
+ [15:42:15] containerd: connection error: desc = "transport: error while dialing"
432
+ ```
433
+
434
+ ## Security
435
+
436
+ ### Path Traversal Protection (CWE-22)
437
+
438
+ The `image_build` tool implements strict path validation to prevent directory traversal attacks:
439
+
440
+ - **Absolute paths required**: All paths (context, dockerfile) must start with `/`
441
+ - **Traversal blocked**: Paths containing `..` or `.` components are rejected
442
+ - **Character validation**: Only alphanumeric, dots (in filenames), hyphens, underscores, and forward slashes allowed
443
+ - **Pre-execution validation**: Paths validated before SSH commands are executed
444
+
445
+ Example of rejected paths:
446
+ ```bash
447
+ # Rejected: Directory traversal
448
+ ../../../etc/passwd
449
+ /app/../../../etc/passwd
450
+
451
+ # Rejected: Relative paths
452
+ ./build
453
+ relative/path
454
+
455
+ # Accepted: Absolute paths without traversal
456
+ /home/user/docker/build
457
+ /opt/myapp/Dockerfile.prod
458
+ ```
459
+
460
+ ### General Security Notes
461
+
462
+ - Docker API on port 2375 is insecure without TLS
463
+ - Always use execFile for shell commands (prevents injection)
464
+ - Validate host config fields with regex
465
+ - Require force=true for destructive operations
466
+
467
+ ## Development
468
+
469
+ ```bash
470
+ # Watch mode for development
471
+ pnpm run dev
472
+
473
+ # Build
474
+ pnpm run build
475
+
476
+ # Run tests
477
+ pnpm test
478
+
479
+ # Run tests with coverage
480
+ pnpm run test:coverage
481
+
482
+ # Test with MCP Inspector
483
+ npx @modelcontextprotocol/inspector node dist/index.js
484
+ ```
485
+
486
+ ## Architecture
487
+
488
+ ```
489
+ synapse-mcp/
490
+ ├── src/
491
+ │ ├── index.ts # Entry point, transport setup
492
+ │ ├── types.ts # TypeScript interfaces
493
+ │ ├── constants.ts # Configuration constants
494
+ │ ├── config/
495
+ │ │ └── command-allowlist.json # Allowed commands for scout:exec
496
+ │ ├── formatters/
497
+ │ │ ├── index.ts # Response formatting utilities
498
+ │ │ └── formatters.test.ts # Formatter tests
499
+ │ ├── tools/
500
+ │ │ ├── index.ts # Tool registration router
501
+ │ │ ├── flux.ts # Flux tool handler + routing
502
+ │ │ ├── scout.ts # Scout tool handler + routing
503
+ │ │ ├── container.ts # handleContainerAction()
504
+ │ │ ├── compose.ts # handleComposeAction()
505
+ │ │ ├── docker.ts # handleDockerAction()
506
+ │ │ └── host.ts # handleHostAction()
507
+ │ ├── services/
508
+ │ │ ├── docker.ts # DockerService
509
+ │ │ ├── compose.ts # ComposeService
510
+ │ │ ├── ssh.ts # SSHService
511
+ │ │ └── scout/ # Scout-specific services
512
+ │ │ ├── pool.ts # SSH connection pool
513
+ │ │ ├── executors.ts # Command execution
514
+ │ │ └── transfer.ts # File transfer (beam)
515
+ │ ├── schemas/
516
+ │ │ ├── index.ts # FluxSchema + ScoutSchema exports
517
+ │ │ ├── common.ts # Shared schemas (pagination, response_format)
518
+ │ │ ├── container.ts # Container subaction schemas
519
+ │ │ ├── compose.ts # Compose subaction schemas
520
+ │ │ ├── docker.ts # Docker subaction schemas
521
+ │ │ ├── host.ts # Host subaction schemas
522
+ │ │ └── scout.ts # Scout action schemas
523
+ │ └── lint.test.ts # Linting tests
524
+ ├── dist/ # Compiled JavaScript
525
+ ├── package.json
526
+ ├── tsconfig.json
527
+ └── README.md
528
+ ```
529
+
530
+ ### Key Architectural Decisions
531
+
532
+ **V3 Schema Refactor - Two Tools Pattern**:
533
+ - **Flux**: 4 actions (container, compose, docker, host) with 39 total subactions
534
+ - **Scout**: 11 actions (9 simple + 2 with subactions) for 16 total operations
535
+ - Clean separation: Flux = Docker/state changes, Scout = SSH/read operations
536
+ - Total: 55 discriminator keys across both tools
537
+
538
+ **Discriminated Union for O(1) Validation**:
539
+ - **Flux**: Composite `action_subaction` discriminator (`container:list`, `compose:up`, etc.)
540
+ - **Scout**: Primary `action` discriminator with nested discriminators for `zfs` and `logs`
541
+ - Validation latency: <0.005ms average across all operations
542
+ - Zero performance degradation regardless of which operation is called
543
+
544
+ **Help System**:
545
+ - Auto-generated help handlers for both tools
546
+ - Introspects Zod schemas using `.describe()` metadata
547
+ - Supports topic-specific help (e.g., `flux help container:logs`)
548
+ - Available in markdown or JSON format
549
+
550
+ **SSH Connection Pooling**:
551
+ - 50× faster for repeated operations
552
+ - Automatic idle timeout and health checks
553
+ - Configurable pool size and connection reuse
554
+ - Transparent integration (no code changes required)
555
+
556
+ **Test Coverage**:
557
+ - Unit tests for all services, schemas, and tools
558
+ - Integration tests for end-to-end workflows
559
+ - Performance benchmarks for schema validation
560
+ - TDD approach for all new features
561
+
562
+ ## Performance
563
+
564
+ ### Schema Validation
565
+
566
+ Both Flux and Scout tools use Zod discriminated union for O(1) constant-time schema validation:
567
+
568
+ - **Validation latency**: <0.005ms average across all 55 operations
569
+ - **Flux optimization**: Composite `action_subaction` discriminator with preprocessor
570
+ - **Scout optimization**: Primary `action` discriminator with nested discriminators for zfs/logs
571
+ - **Consistency**: All operations perform identically fast (no worst-case scenarios)
572
+
573
+ Flux inputs are automatically preprocessed to inject the `action_subaction` discriminator key.
574
+
575
+ ### SSH Connection Pooling
576
+
577
+ All SSH operations use connection pooling for optimal performance:
578
+
579
+ - **50× faster** for repeated operations
580
+ - Connections reused across compose operations
581
+ - Automatic idle timeout and health checks
582
+ - Configurable via environment variables
583
+
584
+ See [docs/ssh-connection-pooling.md](docs/ssh-connection-pooling.md) for details.
585
+
586
+ **Key Benefits:**
587
+ - Eliminate 250ms connection overhead per operation
588
+ - Support high-concurrency scenarios (configurable pool size)
589
+ - Automatic connection cleanup and health monitoring
590
+ - Zero code changes required (transparent integration)
591
+
592
+ ### Benchmarks
593
+
594
+ Run performance benchmarks:
595
+
596
+ ```bash
597
+ npm run test:bench
598
+ ```
599
+
600
+ Expected results:
601
+ - Worst-case validation: <0.005ms (0.003ms typical)
602
+ - Average-case validation: <0.005ms (0.003ms typical)
603
+ - Performance variance: <0.001ms (proves O(1) consistency)
604
+
605
+ ## License
606
+
607
+ MIT
@@ -0,0 +1,23 @@
1
+ export declare const CHARACTER_LIMIT = 40000;
2
+ export declare const DEFAULT_LIMIT = 20;
3
+ export declare const MAX_LIMIT = 100;
4
+ export declare const DEFAULT_LOG_LINES = 50;
5
+ export declare const MAX_LOG_LINES = 500;
6
+ export declare const API_TIMEOUT = 30000;
7
+ export declare const STATS_TIMEOUT = 5000;
8
+ export declare const DEFAULT_DOCKER_SOCKET = "/var/run/docker.sock";
9
+ export declare const ENV_HOSTS_CONFIG = "HOMELAB_HOSTS_CONFIG";
10
+ export declare const ENV_DEFAULT_HOST = "HOMELAB_DEFAULT_HOST";
11
+ export declare const DEFAULT_MAX_FILE_SIZE = 1048576;
12
+ export declare const MAX_FILE_SIZE_LIMIT = 10485760;
13
+ export declare const DEFAULT_COMMAND_TIMEOUT = 30000;
14
+ export declare const MAX_COMMAND_TIMEOUT = 300000;
15
+ export declare const DEFAULT_TREE_DEPTH = 3;
16
+ export declare const MAX_TREE_DEPTH = 10;
17
+ export declare const DEFAULT_FIND_LIMIT = 100;
18
+ export declare const MAX_FIND_LIMIT = 1000;
19
+ export declare const DEFAULT_DIFF_CONTEXT_LINES = 3;
20
+ export declare const MAX_DIFF_CONTEXT_LINES = 50;
21
+ export declare const ALLOWED_COMMANDS: Set<string>;
22
+ export declare const ENV_ALLOW_ANY_COMMAND = "HOMELAB_ALLOW_ANY_COMMAND";
23
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,eAAe,QAAQ,CAAC;AAGrC,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,SAAS,MAAM,CAAC;AAG7B,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,aAAa,MAAM,CAAC;AAGjC,eAAO,MAAM,WAAW,QAAQ,CAAC;AACjC,eAAO,MAAM,aAAa,OAAO,CAAC;AAGlC,eAAO,MAAM,qBAAqB,yBAAyB,CAAC;AAG5D,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AACvD,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AAKvD,eAAO,MAAM,qBAAqB,UAAU,CAAC;AAC7C,eAAO,MAAM,mBAAmB,WAAW,CAAC;AAG5C,eAAO,MAAM,uBAAuB,QAAQ,CAAC;AAC7C,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAG1C,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,cAAc,KAAK,CAAC;AAGjC,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,cAAc,OAAO,CAAC;AAGnC,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAC5C,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAGzC,eAAO,MAAM,gBAAgB,aAqB3B,CAAC;AAGH,eAAO,MAAM,qBAAqB,8BAA8B,CAAC"}
@@ -0,0 +1,58 @@
1
+ // Character limit for responses to prevent context overflow (~12.5k tokens)
2
+ export const CHARACTER_LIMIT = 40000;
3
+ // Default pagination settings
4
+ export const DEFAULT_LIMIT = 20;
5
+ export const MAX_LIMIT = 100;
6
+ // Log retrieval defaults
7
+ export const DEFAULT_LOG_LINES = 50;
8
+ export const MAX_LOG_LINES = 500;
9
+ // Timeout settings (ms)
10
+ export const API_TIMEOUT = 30000;
11
+ export const STATS_TIMEOUT = 5000;
12
+ // Default Docker socket path
13
+ export const DEFAULT_DOCKER_SOCKET = "/var/run/docker.sock";
14
+ // Environment variable names for config
15
+ export const ENV_HOSTS_CONFIG = "HOMELAB_HOSTS_CONFIG";
16
+ export const ENV_DEFAULT_HOST = "HOMELAB_DEFAULT_HOST";
17
+ // ===== Scout File Operations Constants =====
18
+ // File size limits (bytes)
19
+ export const DEFAULT_MAX_FILE_SIZE = 1048576; // 1MB
20
+ export const MAX_FILE_SIZE_LIMIT = 10485760; // 10MB
21
+ // Command timeout limits (milliseconds)
22
+ export const DEFAULT_COMMAND_TIMEOUT = 30000; // 30s
23
+ export const MAX_COMMAND_TIMEOUT = 300000; // 300s (5 min)
24
+ // Tree depth limits
25
+ export const DEFAULT_TREE_DEPTH = 3;
26
+ export const MAX_TREE_DEPTH = 10;
27
+ // Find result limits
28
+ export const DEFAULT_FIND_LIMIT = 100;
29
+ export const MAX_FIND_LIMIT = 1000;
30
+ // Diff context lines limits
31
+ export const DEFAULT_DIFF_CONTEXT_LINES = 3;
32
+ export const MAX_DIFF_CONTEXT_LINES = 50;
33
+ // Allowed commands for exec subaction (read-only operations)
34
+ export const ALLOWED_COMMANDS = new Set([
35
+ "cat",
36
+ "head",
37
+ "tail",
38
+ "grep",
39
+ "rg",
40
+ "find",
41
+ "ls",
42
+ "tree",
43
+ "wc",
44
+ "sort",
45
+ "uniq",
46
+ "diff",
47
+ "stat",
48
+ "file",
49
+ "du",
50
+ "df",
51
+ "pwd",
52
+ "hostname",
53
+ "uptime",
54
+ "whoami"
55
+ ]);
56
+ // Environment variable to disable command allowlist
57
+ export const ENV_ALLOW_ANY_COMMAND = "HOMELAB_ALLOW_ANY_COMMAND";
58
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC;AAErC,8BAA8B;AAC9B,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAChC,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,CAAC;AAE7B,yBAAyB;AACzB,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AACpC,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AAEjC,wBAAwB;AACxB,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC;AACjC,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAElC,6BAA6B;AAC7B,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAE5D,wCAAwC;AACxC,MAAM,CAAC,MAAM,gBAAgB,GAAG,sBAAsB,CAAC;AACvD,MAAM,CAAC,MAAM,gBAAgB,GAAG,sBAAsB,CAAC;AAEvD,8CAA8C;AAE9C,2BAA2B;AAC3B,MAAM,CAAC,MAAM,qBAAqB,GAAG,OAAO,CAAC,CAAC,MAAM;AACpD,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CAAC,CAAC,OAAO;AAEpD,wCAAwC;AACxC,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,CAAC,CAAC,MAAM;AACpD,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,CAAC,eAAe;AAE1D,oBAAoB;AACpB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AAEjC,qBAAqB;AACrB,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AAEnC,4BAA4B;AAC5B,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC;AAC5C,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAEzC,6DAA6D;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IACtC,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,IAAI;IACJ,MAAM;IACN,IAAI;IACJ,MAAM;IACN,IAAI;IACJ,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,UAAU;IACV,QAAQ;IACR,QAAQ;CACT,CAAC,CAAC;AAEH,oDAAoD;AACpD,MAAM,CAAC,MAAM,qBAAqB,GAAG,2BAA2B,CAAC"}