Skip to main content
Glama
Akdag94

vps-ops-mcp

by Akdag94
README.md
# vps-ops-mcp

**Don't give your AI raw root SSH.** A safe, structured [MCP](https://modelcontextprotocol.io) server that lets Claude (or any MCP client) inspect and operate your VPS — nginx, PM2, SSL, UFW, fail2ban — through **typed, allowlisted tools** instead of free-form shell access.

**Read-only by default.** Mutating actions don't even exist unless you opt in with an environment variable.

```
You: "Is everything OK on my server? Any cert expiring soon?"

Claude → server_health(myvps)     → load 0.08, disk 61%, RAM fine
       → ssl_status(myvps)        → b2fest.com expires in 71 days ✓
       → security_audit(myvps)    → ufw active, root login disabled ✓
```

## Why not just an SSH MCP server?

Generic SSH MCP servers hand the model a root shell and hope for the best. This server takes the opposite approach:

| | Raw SSH MCP | vps-ops-mcp |
|---|---|---|
| Command surface | anything | fixed command templates only |
| User input in commands | interpolated | strict allowlist regex, rejected otherwise |
| Credentials | often stored in config | **never touched** — delegates to your `ssh` client, `~/.ssh/config`, ssh-agent |
| Password prompts | can hang | `BatchMode=yes`, fails fast |
| Writes/restarts | always on | **off by default**, opt-in via env var |
| `pm2 restart all` | sure, why not | refused by design |

## Quickstart

Requires Node 18+ and a working `ssh <your-host>` from your terminal (key-based auth).

**Claude Code**

```bash
claude mcp add vps-ops -- npx -y vps-ops-mcp
```

**Claude Desktop / Cursor / any MCP client** — add to your MCP config:

```json
{
  "mcpServers": {
    "vps-ops": {
      "command": "npx",
      "args": ["-y", "vps-ops-mcp"]
    }
  }
}
```

Then just ask: *"Check the health of `myvps`"* (any alias from your `~/.ssh/config`, or `user@host`).

### Enabling mutations (optional)

By default the server is strictly read-only. To enable the two mutating tools (`nginx_check_and_reload`, `pm2_restart`):

```json
{
  "mcpServers": {
    "vps-ops": {
      "command": "npx",
      "args": ["-y", "vps-ops-mcp"],
      "env": { "VPS_OPS_ALLOW_MUTATIONS": "true" }
    }
  }
}
```

Even then: no free-form commands, `nginx -t` always runs before a reload, and `pm2 restart all` is refused.

## Tools

| Tool | What it does | Needs |
|---|---|---|
| `list_hosts` | Lists aliases from your local `~/.ssh/config` | nothing (local) |
| `server_health` | Uptime, load, memory, disk, top processes | ssh |
| `list_sites` | Enabled nginx sites, PM2 process list, running web services | ssh |
| `ssl_status` | Cert expiry for every domain found in nginx configs (or one domain) | ssh |
| `read_logs` | Tail nginx access/error, PM2 app, or journald unit logs | ssh (some logs: sudo) |
| `security_audit` | Listening ports, UFW, fail2ban, sshd hardening, pending security updates, recent logins | ssh (richer with sudo) |
| `nginx_check_and_reload` 🔒 | `nginx -t`, then graceful reload only if the test passes | opt-in + sudo |
| `pm2_restart` 🔒 | Restart one named PM2 app (never `all`) | opt-in |

🔒 = only registered when `VPS_OPS_ALLOW_MUTATIONS=true`.

### About sudo

Some checks (ufw, fail2ban, `sshd -T`) need root. The server always uses `sudo -n` (non-interactive): if passwordless sudo isn't configured for those commands, the check degrades gracefully and tells you, instead of hanging on a password prompt. You choose how much to allow in `/etc/sudoers.d/`.

## Safety model

1. **No credential handling.** We spawn your system `ssh` binary. Keys, agents, `ProxyJump`, `known_hosts` — all yours, all untouched.
2. **Fixed command templates.** Remote commands are string constants. There is no `run_command` tool and there never will be one in read-only mode.
3. **Allowlist validation.** Every user-supplied value (host, app name, domain, unit) must match a strict regex before it goes anywhere near a command line. No escaping heuristics — invalid input is simply rejected.
4. **Bounded output.** Every call has a timeout and an output cap, so a runaway `tail` can't flood your context window.
5. **Mutations are opt-in and minimal.** Two tools, both narrow, both guarded.

## Roadmap

- [ ] `site_provision` — nginx vhost + certbot + PM2 registration in one guarded flow
- [ ] Docker container inventory & log tools
- [ ] Caddy support
- [ ] Multi-server fleet summary (`health across all hosts`)
- [ ] Scheduled-check examples (cron + Claude Code headless)

PRs welcome — especially real-world ops workflows this doesn't cover yet.

## License

MIT © Azat Akdağ

TDQS

A4.1/5.0

Scored across 6 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: listing SSH hosts, inventorying sites, reading logs, security auditing, health checks, and SSL status. There is no overlap in functionality.

Naming Consistency4/5

All tool names use snake_case and follow a predictable pattern, though not all are verb_noun (e.g., security_audit, server_health, ssl_status are noun_noun). Overall consistent and readable.

Tool Count5/5

Six tools is a well-scoped set for a VPS monitoring server, covering essential inspection operations without unnecessary bloat.

Completeness4/5

The tool set covers major inspection needs for a VPS (hosts, sites, logs, security, health, SSL). Missing action-oriented tools (e.g., restart, deploy), but the read-only focus is intentional and well-covered.

Maintenance

ActivityStale
ResponsivenessNo issues