Homelab MCP Server
This server provides unified Docker management and SSH remote operations for homelab infrastructure through two main tools: Flux for Docker operations and Scout for SSH operations.
Docker Management (Flux Tool)
Container lifecycle: Start, stop, restart, pause/resume, pull, recreate, and exec into containers
Docker Compose: Full project management (up, down, restart, logs, build, pull, recreate) with auto-discovery and caching
Image operations: List, pull, build, and remove Docker images
System operations: Docker daemon info, disk usage, prune unused resources (images, containers, volumes, cache)
Monitoring: Real-time resource statistics (CPU, memory, network, I/O), detailed container inspection
Logs: Advanced filtering with time ranges and safe grep patterns
Host operations: Check connectivity, monitor resources, view systemd services, network info, and mounted filesystems
Smart search: Find containers by name, image, or labels across all hosts
Remote Operations (Scout Tool)
File operations: Read files, list directory trees, find by glob patterns, compare files (delta), and transfer between hosts (beam)
Command execution: Execute allowlist-validated commands on single or multiple hosts
Process monitoring: List and filter processes by user, CPU, or memory usage
System logs: Access syslog, journald, dmesg, and auth logs with filtering
ZFS management: Monitor pools, datasets, and snapshots with health status
Disk monitoring: Filesystem usage across all mounts
Infrastructure Features
Multi-host support: Manage Unraid, Proxmox, and bare metal systems
Auto-discovery: Local Docker socket and SSH hosts from
~/.ssh/configSSH connection pooling: 50× faster repeated operations
Dual transport: stdio for Claude Code and HTTP for remote access
Security: Path traversal protection, command allowlists, and safe execution patterns
Performance: O(1) schema validation (<0.005ms), pagination support, and configurable resource limits
Manages Docker containers across multiple homelab hosts, providing tools for container lifecycle management (start, stop, restart, pause/unpause), log retrieval, resource monitoring (CPU, memory, network, I/O), container search and inspection, and Docker system operations including disk usage analysis and resource pruning.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Homelab MCP Servershow me running containers on my unraid server"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Synapse MCP
MCP server for homelab infrastructure. Provides two tools: flux for Docker/Compose/host management and scout for SSH remote operations.
Version: 2.2.3 | Node.js ≥ 24 | MIT
Overview
Synapse MCP exposes Docker infrastructure and SSH operations as MCP tools. Connect it to any MCP client (Claude Code, Cursor, Gemini) and manage containers, inspect remote files, read logs, and run diagnostics across multiple hosts.
What it includes:
src/— TypeScript implementation (tools, schemas, services, transport)config/— Config examples and JSON Schemaskills/synapse/— Client-facing skill docstests/— Vitest test suite.claude-plugin/,.codex-plugin/,gemini-extension.json— Client manifests
Tools
flux — Docker infrastructure management
Routes by action, then subaction. Total: 43 subactions.
container (14 subactions)
Subaction | Description | Destructive |
| List containers. Filter by | — |
| Detailed container info. | — |
| Container logs. Supports | — |
| CPU/memory resource usage. Omit | — |
| Running processes inside a container | — |
| Full-text search across containers | — |
| Start a stopped container | — |
| Stop a running container | Yes |
| Stop then start a container | — |
| Freeze container processes via cgroups | — |
| Unfreeze a paused container | — |
| Pull the latest image for a container | — |
| Delete and recreate container. | Yes |
| Execute a command inside a running container | Yes |
All subactions accept an optional host field. Destructive subactions require confirmation via MCP elicitation (or SYNAPSE_MCP_ALLOW_DESTRUCTIVE=true).
container:exec parameters: container_id, command, user (optional), workdir (optional), timeout (1000–300000 ms, default 30000).
container:logs parameters: lines (1–500, default 50), since/until (ISO 8601 or relative like "1h"), grep, stream (stdout/stderr/both).
compose (10 subactions)
Subaction | Description | Destructive |
| List all Compose projects. Filter with | — |
| Project service status. Filter with | — |
| Project logs. Supports | — |
| Pull images for a project or specific service | — |
| Build project images. | — |
| Start project. | — |
| Stop and remove containers. | Yes |
| Restart all project services | Yes |
| Recreate all project containers. Requires | Yes |
| Rescan filesystem to refresh Compose project cache | — |
compose:down note: remove_volumes=true AND force=true are both required to delete volumes. This prevents accidental data loss.
compose:logs time filter: Accepts durations (30s, 5m, 1.5h, 100ms), dates (2024-01-01), RFC3339 timestamps, or Unix timestamps.
Default Compose search paths (Unraid-centric defaults, override per host):
/compose/mnt/cache/compose/mnt/cache/code
docker (9 subactions)
Subaction | Description | Destructive |
| Docker daemon information | — |
| Docker disk usage | — |
| List images. | — |
| List Docker networks | — |
| List Docker volumes | — |
| Pull an image by name | — |
| Build an image. | — |
| Remove an image. Requires | Yes |
| Remove unused resources. | Yes |
docker:prune targets: containers, images, volumes, networks, buildcache, all.
docker:build parameters: context (absolute path, no ..), tag, dockerfile (relative to context, optional), no_cache.
host (9 subactions)
Subaction | Description |
| Docker connectivity check |
| OS, kernel, architecture, hostname |
| System uptime |
| CPU, memory, disk usage via SSH |
| Systemd service status. Filter by |
| Network interfaces and IP addresses |
| Mounted filesystems |
| All port mappings for containers. Filter by |
| Diagnostic checks. Optional |
help
{ "action": "help", "topic": "container:list", "format": "markdown" }Returns auto-generated documentation. topic is optional.
scout — SSH remote operations
Routes by action. Total: 16 operations.
Simple actions (9)
Action | Description | Destructive |
| List all configured SSH hosts | — |
| Read file or directory on a remote host. | — |
| Find files by glob pattern. Parameters: | — |
| List processes. Sort by | — |
| Disk usage for a remote host. Optional | — |
| Compare files between two remote locations, or a remote file against inline | — |
| Run an allowlisted command on a remote host | Yes |
| Run a command on multiple hosts simultaneously | Yes |
| Transfer a file from one remote path to another | Yes |
peek parameters: host, path (safe chars only, no ..), tree (boolean), depth (1–10, default 3).
exec and emit — command allowlist: Commands are validated at runtime. Only these commands are permitted: cat, head, tail, grep, rg, find, ls, tree, wc, sort, uniq, diff, stat, file, du, df, pwd, hostname, uptime, whoami, git. Write commands (rm, mkdir, cp) are blocked.
exec parameters: host, path (absolute, working directory), command, timeout (ms, default 30000, max 300000).
emit parameters: targets (array of { host, path } objects), command, timeout.
beam parameters: source and destination as { host, path } objects.
delta parameters: source ({ host, path }), then either target ({ host, path }) or content (inline string up to 1 MB).
zfs (3 subactions)
Subaction | Description |
| List ZFS pools. Filter by |
| List datasets. Filter by |
| List snapshots. Filter by |
All zfs subactions require host.
logs (4 subactions)
Subaction | Description |
| Read |
| Systemd journal. Supports |
| Kernel ring buffer. Requires root or |
| Authentication logs ( |
journal priority levels: emerg, alert, crit, err, warning, notice, info, debug.
journal time formats: ISO 8601 timestamps or relative strings like "2h ago", "yesterday".
All logs subactions accept host, lines (1–500, default 50), and grep.
Installation
Marketplace (Claude Code)
/plugin marketplace add jmagar/claude-homelab
/plugin install synapse-mcp @jmagar-claude-homelabLocal build
npm install
npm run build
npm startThe published binary:
synapse-mcp # stdio transport (default)
synapse-mcp --http # HTTP transportDocker
docker compose up -dSee the full docker-compose.yaml example below.
Configuration
Host configuration
Synapse MCP loads hosts in this priority order:
SYNAPSE_CONFIG_FILEenv var (explicit path)./synapse.config.json(current directory)~/.config/synapse-mcp/config.json(XDG)~/.synapse-mcp.json(home directory)SYNAPSE_HOSTS_CONFIGenv var (JSON array)~/.ssh/config(auto-discovery)/var/run/docker.sock(local Docker fallback)
You do not need a config file. If ~/.ssh/config lists hosts with HostName and User, they are discovered automatically.
synapse.config.json
Full example:
{
"$schema": "./config/config.schema.json",
"hosts": [
{
"name": "local",
"host": "localhost",
"protocol": "ssh",
"dockerSocketPath": "/var/run/docker.sock",
"tags": ["local", "development"]
},
{
"name": "nas",
"host": "192.168.1.100",
"port": 22,
"protocol": "ssh",
"sshUser": "admin",
"sshKeyPath": "~/.ssh/id_ed25519",
"dockerSocketPath": "/var/run/docker.sock",
"composeSearchPaths": ["/opt/stacks", "/srv/docker"],
"tags": ["production", "storage"]
},
{
"name": "api-only-host",
"host": "docker.local",
"port": 2375,
"protocol": "http",
"tags": ["api-only"]
}
]
}Host fields:
Field | Required | Description |
| Yes | Unique identifier. Alphanumeric, |
| Yes | Hostname, IP, or |
| Yes |
|
| If | SSH username |
| No | SSH port (default 22) or Docker API port (default 2375/2376) |
| No | Path to SSH private key. Defaults to SSH agent |
| No | Docker socket path (default |
| No | Dirs to search for Compose projects. Overrides Unraid defaults |
| No | String array for grouping and filtering |
Security warning: protocol: "http" exposes Docker over TCP without authentication. Use ssh for all real deployments.
SSH config auto-discovery
Any entry in ~/.ssh/config with HostName and User is loaded automatically:
Host nas
HostName 192.168.1.100
User admin
IdentityFile ~/.ssh/id_ed25519
Host pi
HostName 192.168.1.50
User pi
IdentityFile ~/.ssh/id_rsaManual synapse.config.json entries override SSH config entries with the same name.
SSH key setup
Generate a key (if needed):
ssh-keygen -t ed25519 -C "synapse-mcp"Copy the public key to each host:
ssh-copy-id admin@192.168.1.100Test connectivity:
ssh admin@192.168.1.100 "echo ok"
When running in Docker, mount your SSH directory read-only:
volumes:
- ${HOME}/.ssh:/home/node/.ssh:roThe container runs as the node user, so keys must be readable by that user. The mount path /home/node/.ssh is used by the container.
Environment variables
Variable | Required | Default | Description |
| No | — | Explicit path to |
| No | — | JSON array of host configs as a fallback |
| No | — | Default host when none is specified in a request |
| No | — | Comma-separated host names to skip during discovery |
| No |
| Allow SSH as root without elicitation prompt |
| No |
| Skip elicitation prompts for destructive operations |
| No |
| Bypass ALL elicitation confirmation gates (strict |
| No |
| Include full error details in responses (do not use in production) |
| No |
| Set to |
| No |
| HTTP server listen port |
| No |
| HTTP server bind address. Set |
| If HTTP | — | Bearer token for HTTP transport. Generate with |
| No | — | Set |
| No |
| Session idle timeout in ms (30 minutes) |
| No | — | Comma-separated allowed |
| No |
| Docker-over-SSH connection timeout in ms |
| No |
| Compose project host auto-resolution timeout in ms |
| No |
| User ID for Docker container process |
| No |
| Group ID for Docker container process |
| No |
| Docker network name for Compose |
SYNAPSE_ALLOW_ROOT_LOGIN: When false, SSH operations that would run as root require confirmation via MCP elicitation. If your client does not support elicitation, the operation is blocked.
SYNAPSE_MCP_ALLOW_DESTRUCTIVE: When false, these operations require MCP elicitation confirmation: container:stop, container:recreate, container:exec, compose:down, compose:restart, compose:recreate, docker:rmi, docker:prune, scout:exec, scout:emit, scout:beam. When your client does not support elicitation, the operation is blocked entirely.
SYNAPSE_MCP_ALLOW_YOLO: When true, bypasses ALL elicitation confirmation gates — both confirmDestructiveAction and confirmRootLogin return immediately without prompting. Only the exact string "true" activates this; 1, yes, and TRUE do not. YOLO fires before SYNAPSE_MCP_ALLOW_DESTRUCTIVE when both are set. Does NOT bypass schema-level force: true fields — callers must still supply those explicitly. A startup warning is logged whenever this is active.
SYNAPSE_DEBUG_ERRORS: When true, full stack traces and internal error details appear in tool responses. Do not enable in production — this may expose sensitive host information.
SSH connection pooling
Synapse MCP maintains a per-host SSH connection pool. This avoids repeated handshakes when executing many operations against the same host.
Default pool behavior:
Max 3 connections per host
Idle timeout: 60 seconds
Connection timeout: 5 seconds
Health checks every 30 seconds
Pool configuration is not currently exposed via environment variables. To change defaults, edit src/services/ssh-pool.ts.
Docker socket
The container needs access to the Docker socket to manage local Docker resources:
volumes:
- /var/run/docker.sock:/var/run/docker.sockThe container runs as user 1000:1000 by default. Add the container to the Docker socket group so it can read the socket without running as root:
group_add:
- "${DOCKER_SOCKET_GID:-981}"Find your Docker socket GID:
stat -c '%g' /var/run/docker.sockDeployment
Full docker-compose.yaml example
networks:
mcp-net:
name: ${DOCKER_NETWORK:-mcp-net}
external: true
services:
synapse-mcp:
image: ghcr.io/jmagar/synapse-mcp:latest
container_name: synapse-mcp
restart: unless-stopped
user: "${PUID:-1000}:${PGID:-1000}"
group_add:
- "${DOCKER_SOCKET_GID:-981}"
environment:
SYNAPSE_MCP_TRANSPORT: http
SYNAPSE_MCP_PORT: 3000
SYNAPSE_MCP_TOKEN: "${SYNAPSE_MCP_TOKEN}"
SYNAPSE_DEFAULT_HOST: nas
ports:
- "${SYNAPSE_MCP_PORT:-3000}:${SYNAPSE_MCP_PORT:-3000}"
volumes:
- ./config/synapse.config.json:/config/synapse.config.json:ro
- ${HOME}/.ssh:/home/node/.ssh:ro
- /var/run/docker.sock:/var/run/docker.sock
networks:
- mcp-net
deploy:
resources:
limits:
memory: 1024M
cpus: "1"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:${SYNAPSE_MCP_PORT:-3000}/health || exit 1"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30sHTTP transport endpoints
When running with --http or SYNAPSE_MCP_TRANSPORT=http:
Endpoint | Method | Description |
| POST | Client-to-server (new session or route existing) |
| GET | Server-to-client SSE stream (requires |
| DELETE | Terminate a session |
| GET | Liveness check (no auth required) |
| GET | Readiness check (no auth required) |
MCP client configuration (Claude Code)
For HTTP transport, configure the MCP server in your client:
{
"mcpServers": {
"synapse": {
"type": "http",
"url": "http://synapse-mcp:3000/mcp",
"headers": {
"Authorization": "Bearer <your-token>"
}
}
}
}For stdio transport:
{
"mcpServers": {
"synapse": {
"command": "node",
"args": ["/path/to/synapse-mcp/dist/index.js"]
}
}
}Usage examples
List containers across hosts
{ "action": "container", "subaction": "list", "state": "running" }Target a specific host:
{ "action": "container", "subaction": "list", "host": "nas", "state": "all" }Get container logs
{
"action": "container",
"subaction": "logs",
"container_id": "nginx",
"host": "nas",
"lines": 100,
"since": "1h",
"grep": "error"
}Restart a container
{ "action": "container", "subaction": "restart", "container_id": "nginx", "host": "nas" }Pull and recreate a container
{ "action": "container", "subaction": "pull", "container_id": "nginx", "host": "nas" }{ "action": "container", "subaction": "recreate", "container_id": "nginx", "host": "nas", "pull": false }Update a Compose project
{ "action": "compose", "subaction": "pull", "project": "media-stack", "host": "nas" }{ "action": "compose", "subaction": "recreate", "project": "media-stack", "host": "nas", "force": true }Check host resources
{ "action": "host", "subaction": "resources", "host": "nas" }Run diagnostics
{
"action": "host",
"subaction": "doctor",
"host": "nas",
"checks": ["resources", "containers", "docker"]
}List all configured hosts (scout)
{ "action": "nodes" }Read a remote file
{ "action": "peek", "host": "nas", "path": "/etc/docker/daemon.json" }Read a remote directory as a tree
{ "action": "peek", "host": "nas", "path": "/opt/stacks", "tree": true, "depth": 2 }Find files by pattern
{ "action": "find", "host": "nas", "path": "/opt/stacks", "pattern": "*.yaml", "depth": 3 }Check disk usage
{ "action": "df", "host": "nas" }View systemd journal with filters
{
"action": "logs",
"subaction": "journal",
"host": "nas",
"unit": "docker.service",
"priority": "err",
"since": "2h ago",
"lines": 100
}List ZFS pools
{ "action": "zfs", "subaction": "pools", "host": "nas" }List ZFS datasets with health filter
{ "action": "zfs", "subaction": "datasets", "host": "nas", "pool": "tank", "recursive": true }Run a command on multiple hosts
{
"action": "emit",
"targets": [
{ "host": "nas", "path": "/home" },
{ "host": "pi", "path": "/home" }
],
"command": "df -h"
}Security
Path validation
All remote paths are validated against a safe character set ([a-zA-Z0-9._\-/]) and checked for path traversal (.. as a path component). Shell metacharacters are rejected to prevent command injection (CWE-78).
Command allowlist
scout:exec and scout:emit run commands through ALLOWED_READ_COMMANDS — a static read-only allowlist (see the full list under exec above). mkdir, rm, and all other write commands are blocked. cp is write-capable and intentionally excluded from the public surface; it is only available to internal services (e.g., scout:beam file transfer).
SSH username validation
SSH usernames and key paths are validated before shell interpolation. Non-alphanumeric characters (with limited exceptions) are rejected.
HTTP authentication
HTTP transport requires a Bearer token set via SYNAPSE_MCP_TOKEN. To generate one:
openssl rand -hex 32If neither SYNAPSE_MCP_TOKEN nor SYNAPSE_MCP_NO_AUTH=true is set, the server refuses to start.
DNS rebinding protection
Set SYNAPSE_MCP_ALLOWED_HOSTS to a comma-separated list of allowed Host header values. Requests with other Host values are rejected.
Development
npm run build # compile TypeScript
npm run typecheck # type-check without emitting
npm test # run unit tests
npm run test:coverage # run tests with coverage report
npm run test:integration # run integration tests
npm run lint # lint with Biome
npm run format # format with BiomeVia Justfile:
just build
just test
just lint
just up # docker compose up -d
just down # docker compose down
just logs # docker compose logs -f
just health # curl /health endpoint
just gen-token # generate a new bearer tokenVerification
npm run typecheck
npm test
npm run lintIntegration tests require live SSH/Docker access to configured hosts:
npm run test:integrationHealth check (HTTP transport):
curl -sf http://localhost:3000/health | jq .Related plugins
Plugin | Category | Description |
core | Core agents, commands, skills, and setup/health workflows for homelab management. | |
media | Search movies and TV shows, submit requests, and monitor failed requests via Overseerr. | |
infrastructure | Query, monitor, and manage Unraid servers: Docker, VMs, array, parity, and live telemetry. | |
infrastructure | Monitor and manage UniFi devices, clients, firewall rules, and network health. | |
utilities | Send and manage push notifications via a self-hosted Gotify server. | |
infrastructure | Create, edit, and manage SWAG nginx reverse proxy configurations. | |
infrastructure | Manage Docker environments, containers, images, volumes, networks, and GitOps via Arcane. | |
infrastructure | Receive, index, and search syslog streams from all homelab hosts via SQLite FTS5. | |
dev-tools | Scaffold, review, align, and deploy homelab MCP plugins with agents and canonical templates. |
License
MIT
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Tools
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jmagar/synapse-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server