Skip to main content
Glama
ojoilesanmi

Secure VPS Operations MCP Server

by ojoilesanmi

Secure VPS Operations MCP Server

A secure, read-only Model Context Protocol (MCP) server for inspecting a VPS over SSH without giving an AI assistant unrestricted shell access.

The core idea is simple: the AI selects approved operations; it never constructs or executes arbitrary shell commands.

What This Project Does

This project exposes a small set of MCP tools for safe VPS inspection:

  • get_system_health

  • get_disk_usage

  • list_containers

  • get_container_logs

  • get_service_status

  • check_nginx_configuration

  • check_ssl_expiry

  • check_database_health

Each MCP tool validates input locally, checks configured allowlists, then calls a fixed SSH gateway command on the VPS. The gateway maps operation names to root-owned scripts under /usr/local/lib/mcp/scripts.

There is intentionally no generic execute_shell tool.

Related MCP server: MCP VPS Manager

Architecture

AI Client
    |
    v
MCP Client
    |
    v
Local Python MCP Server
    |
    v
SSH key authentication
    |
    v
Dedicated VPS user
    |
    v
/usr/local/bin/mcp-command-gateway
    |
    v
Root-owned allowlisted scripts

Why Python

This first version uses Python 3.11+ because the official MCP Python SDK, asyncssh, and Pydantic make a small control-plane server straightforward to build and audit.

Java would also be viable, especially inside an existing Spring-based internal platform, but Python keeps this MCP adapter smaller and simpler for the first release.

Security Model

The security boundary is based on constraints rather than prompting:

  • No unrestricted shell tool

  • Dedicated SSH user, not root

  • SSH key authentication only

  • Host-key verification through known_hosts

  • Fixed gateway command on the VPS

  • Operation allowlist in the gateway

  • Resource allowlists for containers, services, domains, and databases

  • Root-owned scripts that the SSH user cannot edit

  • Narrow sudo rules only where required

  • Output sanitisation before returning data to the model

  • Append-only JSONL audit logs

Local Setup

Create a virtual environment:

python3.11 -m venv .venv
source .venv/bin/activate
pip install -e '.[test]'

Create local configuration:

cp .env.example .env

Edit .env:

SSH_HOST=your-vps-host-or-ip
SSH_PORT=22
SSH_USERNAME=mcp-operator
SSH_PRIVATE_KEY_FILE=/path/to/private/key
SSH_KNOWN_HOSTS_FILE=/path/to/known_hosts

ALLOWED_CONTAINERS=grafana,prometheus,opensearch
ALLOWED_SERVICES=app.service,docker.service,nginx.service
ALLOWED_DOMAINS=api-dev.example.com,api-staging.example.com
ALLOWED_DATABASES=appdb

Pin the VPS host key:

ssh-keyscan -H your-vps-host-or-ip >> ~/.ssh/known_hosts

Run tests:

python -m pytest

Run the MCP server locally:

contabo-ops-mcp

For stdio MCP usage, the server will appear to wait for input. That is expected. An MCP client starts the process and communicates with it over stdin/stdout.

VPS Setup

Create a dedicated user on the VPS:

sudo useradd --create-home --shell /bin/bash mcp-operator
sudo mkdir -p /home/mcp-operator/.ssh
sudo chmod 700 /home/mcp-operator/.ssh
sudo chown -R mcp-operator:mcp-operator /home/mcp-operator

Create an SSH key locally:

ssh-keygen -t ed25519 -f ~/.ssh/vps_mcp -C "vps-operations-mcp"

Add the public key to the VPS:

sudo tee /home/mcp-operator/.ssh/authorized_keys > /dev/null <<'EOF'
PASTE_PUBLIC_KEY_HERE
EOF

sudo chown -R mcp-operator:mcp-operator /home/mcp-operator/.ssh
sudo chmod 700 /home/mcp-operator/.ssh
sudo chmod 600 /home/mcp-operator/.ssh/authorized_keys
sudo chmod 755 /home/mcp-operator

Test SSH from your local machine:

ssh -i ~/.ssh/vps_mcp mcp-operator@your-vps-host-or-ip

Gateway Installation

Copy the gateway to the VPS:

scp -i ~/.ssh/vps_mcp vps/mcp-command-gateway mcp-operator@your-vps-host-or-ip:/tmp/mcp-command-gateway

Install it on the VPS:

sudo install -o root -g root -m 755 /tmp/mcp-command-gateway /usr/local/bin/mcp-command-gateway
sudo mkdir -p /usr/local/lib/mcp/scripts
sudo chown -R root:root /usr/local/lib/mcp
sudo chmod -R 755 /usr/local/lib/mcp

The gateway accepts structured JSON like this:

{
  "operation": "system.health",
  "arguments": {}
}

It rejects unknown operations and never accepts raw shell commands.

Example Script

Create /usr/local/lib/mcp/scripts/system-health on the VPS:

sudo tee /usr/local/lib/mcp/scripts/system-health > /dev/null <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail

load_average="$(cut -d ' ' -f1-3 /proc/loadavg)"
uptime_seconds="$(cut -d. -f1 /proc/uptime)"
hostname="$(hostname)"

printf '{"success":true,"hostname":"%s","uptimeSeconds":%s,"loadAverage":"%s"}\n' \
  "$hostname" \
  "$uptime_seconds" \
  "$load_average"
EOF

sudo chown root:root /usr/local/lib/mcp/scripts/system-health
sudo chmod 755 /usr/local/lib/mcp/scripts/system-health

Test directly on the VPS:

printf '{"operation":"system.health","arguments":{}}' | /usr/local/bin/mcp-command-gateway

Test from your local machine over SSH:

ssh -i ~/.ssh/vps_mcp mcp-operator@your-vps-host-or-ip \
  'printf '\''{"operation":"system.health","arguments":{}}'\'' | /usr/local/bin/mcp-command-gateway'

MCP Client Configuration

For an MCP client that supports local stdio servers, configure the command as:

{
  "mcp": {
    "vps-ops": {
      "type": "local",
      "command": [
        "/absolute/path/to/project/.venv/bin/python",
        "/absolute/path/to/project/src/contabo_mcp/main.py"
      ],
      "enabled": true,
      "env": {
        "PYTHONPATH": "/absolute/path/to/project/src"
      }
    }
  }
}

Restart the MCP client after changing its config.

Example prompts:

  • "Check system health on the VPS."

  • "Show disk usage on the VPS."

  • "Show the last 20 logs for the Grafana container."

  • "Check SSL expiry for api-dev.example.com."

  • "Check status of nginx.service."

Development

Run tests:

source .venv/bin/activate
python -m pytest

Check config loading:

python -c "from contabo_mcp.config import get_settings; print(get_settings().ssh_host)"

Check the SSH gateway from Python:

python - <<'PY'
import asyncio
from contabo_mcp.config import get_settings
from contabo_mcp.ssh_gateway import SshGateway

async def main():
    gateway = SshGateway(get_settings())
    result = await gateway.execute("system.health", {})
    print(result.exit_code)
    print(result.stdout)
    print(result.stderr)

asyncio.run(main())
PY

Current Scope

This repository is intentionally read-only for the first release.

Write operations such as service restarts, Nginx reloads, certificate renewal, backups, deployments, and rollbacks should be added only after implementing:

  • Explicit approval handling

  • Risk classification

  • Narrow sudo rules

  • Idempotency checks

  • Post-action health verification

  • Stronger audit records

  • Failure and rollback behavior

License

This project is licensed under the MIT License. See LICENSE for details.

Install Server
A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    C
    maintenance
    Provides read-only server monitoring and diagnostic tools for AI assistants to manage Linux and Unraid systems via SSH. It enables natural language interactions for container management, storage health checks, and system log analysis while keeping credentials secure.
    Last updated
    17
    ISC
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI assistants to perform controlled Linux system administration tasks like reading logs, managing services, cron jobs, WordPress, and executing sandboxed Python code, with strict security constraints.
    Last updated
    29
    2
    GPL 2.0
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI agents to monitor MetaTrader 5 accounts on remote Windows VPS via SSH, providing read-only access to positions, history, and logs without executing trades.
    Last updated
    16
    MIT

View all related MCP servers

Related MCP Connectors

  • Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.

  • Operate your Linux servers from your LLM. Every action runs through an auditable allowlist.

  • Read-only access to Auralogs production logs: search logs, inspect errors, review AI analyses.

View all MCP Connectors

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/ojoilesanmi/secure-vps-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server