Skip to main content
ClaudeWave

Stdio MCP server that inspects and (with confirmation) mutates one VPS over SSH.

MCP ServersOfficial Registry0 stars0 forksShellMITUpdated today
ClaudeWave Trust Score
87/100
Trusted
Passed
  • Open-source license (MIT)
  • Actively maintained (<30d)
  • Clear description
  • Documented (README)
Last scanned: 9/23/2026
Install in Claude Code / Claude Desktop
Method: Manual
Claude Code CLI
git clone https://github.com/koller-nexus/vps-ops-mcp
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
💡 Clone https://github.com/koller-nexus/vps-ops-mcp and follow its README for install instructions.
Detected environment variables
VPS_HOST
Use cases

MCP Servers overview

# vps-ops-mcp

A stdio [MCP](https://modelcontextprotocol.io) server that operates one VPS over SSH. Cursor and Codex start the process with `bun` and call read-only tools (host health, Unix debug, Docker, Compose, Swarm, firewall) plus mutation tools (restart, stop, start, prune). Mutations require an explicit confirmation.

Transport is stdio. Do not start the server as a long-lived process by hand: the client (Cursor or Codex) launches it.

## Contributing

See [CONTRIBUTING.md](./CONTRIBUTING.md) (branches, pull requests, verification) and [ISSUE.md](./ISSUE.md) (how to file an issue).

## Requirements

- [Bun](https://bun.sh)
- Python 3 (used by the registration scripts)
- OpenSSH client (`ssh` on `PATH`)
- A readable SSH private key with access to the remote user
- On the remote host: Docker (and passwordless `sudo -n` for `ufw`, `fail2ban`, `sshd -T`, `ss`, and `dmesg` if you use those tools)

## Configuration

```bash
cp .env.example .env
```

Edit `.env`. The file is gitignored.

| Variable | Required | Default | Purpose |
| --- | --- | --- | --- |
| `VPS_SSH_KEY_PATH` | yes | — | Absolute path to the private key. The process refuses to start if the file is missing or unreadable. |
| `VPS_HOST` | no | `vps.example.invalid` | SSH host (placeholder; set your own host). |
| `VPS_USER` | no | `ubuntu` | SSH user. |
| `VPS_PORT` | no | `22` | SSH port. |
| `VPS_COMPOSE_DIR` | no | — | Absolute Compose directory **on the VPS**. Without it, Compose tools require the `dir` argument. |
| `VPS_COMMAND_TIMEOUT_MS` | no | `30000` | Remote command timeout. Expiry returns `exit_code` 124. |
| `VPS_LOG_MAX_BYTES` | no | `200000` | Cap for `stdout`/`stderr`. Overflow is cut and `truncated` is `true`. |
| `VPS_ALLOW_MUTATIONS` | no | `true` | `false`, `0`, `no`, or `off` disables every mutation. |
| `VPS_SSH_KEY_PASSPHRASE` | no | — | Avoid. Prefer `ssh-agent`. Registration scripts **do not** copy this variable into the client. |

`VPS_COMPOSE_DIR` must be absolute and match `/^[a-zA-Z0-9/_.-]+$/` (it must start with `/`).

## Installation

```bash
bun install
```

npm package (requires [Bun](https://bun.sh); the MCP Registry points at this artifact):

```bash
bunx @koller-nexus/vps-ops-mcp
```

MCP Registry name: `io.github.koller-nexus/vps-ops-mcp`. The registry publishes metadata only after the package exists on public npm.

## Register with clients

The scripts write MCP config from variables **already exported in the shell**. They do not load `.env` themselves. If you skip the export, the scripts fall back to their defaults (host, user, port, and a local key path).

Do this once at the repository root before each script:

```bash
set -a
source .env
set +a
```

Each run backs up the destination file (`*.bak.YYYYMMDDHHMMSS`) and replaces only the `vps-ops` server. Other MCP servers stay in place.

Optional script variables:

| Variable | Default | Purpose |
| --- | --- | --- |
| `MCP_PROJECT_DIR` | this repository root | Source of the `src/index.ts` path. |
| `CURSOR_MCP_JSON` | `~/.cursor/mcp.json` | Cursor file to update. |
| `CODEX_CONFIG` | `~/.codex/config.toml` | Codex file to update. |

`VPS_COMPOSE_DIR` is written into the client config only when it is set and non-empty.

### Cursor

Global registration (applies in every workspace):

```bash
./scripts/register-cursor-mcp.sh
```

The script writes `~/.cursor/mcp.json` in this shape:

```json
{
  "mcpServers": {
    "vps-ops": {
      "command": "bun",
      "args": ["/absolute/path/vps-ops-mcp/src/index.ts"],
      "env": {
        "VPS_HOST": "your.host",
        "VPS_USER": "ubuntu",
        "VPS_PORT": "22",
        "VPS_SSH_KEY_PATH": "/absolute/path/to/key",
        "VPS_COMMAND_TIMEOUT_MS": "30000",
        "VPS_LOG_MAX_BYTES": "200000",
        "VPS_ALLOW_MUTATIONS": "true"
      }
    }
  }
}
```

To scope it to one project, point the script at that project's `mcp.json`:

```bash
CURSOR_MCP_JSON="/absolute/path/to/project/.cursor/mcp.json" ./scripts/register-cursor-mcp.sh
```

Then reload the Cursor window (Command Palette → **Developer: Reload Window**) or restart the server under **Settings → MCP**. The server appears as `vps-ops`.

### Codex

```bash
./scripts/register-codex-mcp.sh
```

The script writes `~/.codex/config.toml`:

```toml
[mcp_servers.vps-ops]
command = "bun"
args = ["/absolute/path/vps-ops-mcp/src/index.ts"]

[mcp_servers.vps-ops.env]
VPS_HOST = "your.host"
VPS_USER = "ubuntu"
VPS_PORT = "22"
VPS_SSH_KEY_PATH = "/absolute/path/to/key"
VPS_COMMAND_TIMEOUT_MS = "30000"
VPS_LOG_MAX_BYTES = "200000"
VPS_ALLOW_MUTATIONS = "true"
```

Close and reopen the Codex session so it rereads `config.toml`. If the CLI is on `PATH`, `codex mcp list` should show `vps-ops`.

## Verify

Test SSH outside MCP with the same flags the server uses:

```bash
ssh -i "$VPS_SSH_KEY_PATH" \
  -o BatchMode=yes \
  -o IdentitiesOnly=yes \
  -o StrictHostKeyChecking=accept-new \
  -p "${VPS_PORT:-22}" \
  "${VPS_USER}@${VPS_HOST}" \
  'uname -a'
```

In Cursor or Codex, ask the client to call `vps_ping`. The response is JSON:

```json
{
  "exit_code": 0,
  "stdout": "...",
  "stderr": "",
  "duration_ms": 0,
  "truncated": false
}
```

A non-zero `exit_code` is an MCP error. If the process exits immediately with `VPS_SSH_KEY_PATH is required` or `missing or unreadable`, the variable never reached the client `env` — rerun the registration script with `.env` exported.

## Tools

Every call returns `exit_code`, `stdout`, `stderr`, `duration_ms`, and `truncated`.

### Read-only

| Tool | Arguments | What it does |
| --- | --- | --- |
| `vps_ping` | — | `uname -a`, `uptime`, `hostname`. |
| `vps_resources` | — | `df -h`, `free -h`, load average. |
| `vps_journal` | `unit`, `n?` (1–500, default 100) | `journalctl -u`. Unit from the allowlist (`docker`, `sshd`, `fail2ban`, `ufw`, `cron`, with or without `.service`) or a safe name ending in `.service`. |
| `docker_ps` | — | `docker ps -a` as JSON lines. |
| `docker_inspect` | `name` | `docker inspect`. |
| `docker_logs` | `name`, `n?` (1–1000, default 200), `since?` | `docker logs --tail --timestamps`. |
| `docker_stats` | — | `docker stats --no-stream`. |
| `docker_service_ls` | — | `docker service ls` as JSON lines (Swarm). |
| `docker_node_ls` | — | `docker node ls` as JSON lines (Swarm). |
| `compose_ps` | `dir?` | `docker compose ps` in `dir` or `VPS_COMPOSE_DIR`. |
| `host_listen` | — | `ss -lntup` (`sudo -n`, otherwise without sudo). |
| `host_failed_units` | — | `systemctl --failed --no-pager --full`. |
| `host_top` | — | Top 30 processes by memory (`ps aux --sort=-%mem`). |
| `host_dmesg` | `n?` (1–200, default 100) | `dmesg -T` + `tail` (`sudo -n`, otherwise without sudo). |
| `host_firewall` | — | `ufw status verbose` (`sudo -n`, otherwise without sudo). |
| `host_fail2ban` | `jail?` | `fail2ban-client status` (`sudo -n`). |
| `ssh_hardening_check` | — | Filtered `sshd -T`: port, password, root login, pubkey. |

Container, service, image, and jail names must match `^[a-zA-Z0-9][a-zA-Z0-9_.-]*$`.

### Mutation

These require `confirm: true`. With `VPS_ALLOW_MUTATIONS=false`, all of them are rejected.

| Tool | Extra arguments | Remote command |
| --- | --- | --- |
| `docker_restart` | `name` | `docker restart` |
| `docker_stop` | `name` | `docker stop` |
| `docker_start` | `name` | `docker start` |
| `compose_up` | `dir?`, `services?` | `docker compose up -d` |
| `compose_restart` | `dir?`, `services?` | `docker compose restart` |
| `compose_pull_up` | `dir?`, `services?` | `docker compose pull` then `up -d` |
| `docker_rm` | `name`, `force_name` | `docker rm -f`. `force_name` must equal `name`. |
| `disk_cleanup_docker` | `confirm_volumes?` | `docker system prune -f`. Volumes only with `confirm_volumes: true`. |

## Security

- Remote commands are fixed. There is no free-form shell tool.
- Name and path arguments go through an allowlist and are quoted in the shell.
- SSH uses `BatchMode=yes`, `IdentitiesOnly=yes`, and `StrictHostKeyChecking=accept-new`.
- A mutation without `confirm: true` is rejected. `docker_rm` asks for the name twice. Volume prune requires `confirm_volumes: true`.
- For a read-only client, register with `VPS_ALLOW_MUTATIONS=false`.

What people ask about vps-ops-mcp

What is koller-nexus/vps-ops-mcp?

+

koller-nexus/vps-ops-mcp is mcp servers for the Claude AI ecosystem. Stdio MCP server that inspects and (with confirmation) mutates one VPS over SSH. It has 0 GitHub stars and its last recorded update is dated 2026-09-22.

How do I install vps-ops-mcp?

+

You can install vps-ops-mcp by cloning the repository (https://github.com/koller-nexus/vps-ops-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.

Is koller-nexus/vps-ops-mcp safe to use?

+

Our security agent has analyzed koller-nexus/vps-ops-mcp and assigned a Trust Score of 87/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.

Who maintains koller-nexus/vps-ops-mcp?

+

koller-nexus/vps-ops-mcp is maintained by koller-nexus. The last recorded GitHub activity is dated 2026-09-22, with 0 open issues.

Are there alternatives to vps-ops-mcp?

+

Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.

Deploy vps-ops-mcp to your cloud

Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.

Maintain this repo? Add a badge to your README

Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.

Featured on ClaudeWave: koller-nexus/vps-ops-mcp
[![Featured on ClaudeWave](https://claudewave.com/api/badge/koller-nexus-vps-ops-mcp)](https://claudewave.com/repo/koller-nexus-vps-ops-mcp)
<a href="https://claudewave.com/repo/koller-nexus-vps-ops-mcp"><img src="https://claudewave.com/api/badge/koller-nexus-vps-ops-mcp" alt="Featured on ClaudeWave: koller-nexus/vps-ops-mcp" width="320" height="64" /></a>

More MCP Servers

vps-ops-mcp alternatives