Manage your netcup VPS fleet from the terminal — power, snapshots, firewall, rDNS, metrics — with every API endpoint one command away.
Install · Authenticate · Commands · Any endpoint · Library
Note
netcup's legacy SOAP webservice was shut down on 2026‑05‑01. This tool targets the modern
REST API (scp-core) with OAuth2 / Keycloak device‑flow auth.
| 🧭 Spec-driven | Every command is backed by the API's own OpenAPI spec — no hand-maintained endpoint lists. |
| 🔌 All endpoints, always | Curated commands for daily ops + a generic layer (call / api) that reaches all operations. |
| 🔮 Future-proof | New netcup endpoint? netcup spec update and it's instantly usable — zero code changes. |
| 🔐 Secure by default | Only the offline refresh token is stored (mode 0600); the 300 s access token is cached & auto-refreshed. |
| 🎨 Pretty output | Rich tables with humanized sizes, or --json for clean jq piping. |
| 🤝 Shared core | Same engine powers the netcup-mcp server. |
pip install netcup-api # from PyPI (once published)
# or from source:
git clone https://github.com/fullya99/netcup-cli && cd netcup-cli
pip install -e .Authentication uses the OAuth2 device-code flow against netcup's Keycloak realm.
netcup auth login # prints a URL + code, opens your browser
netcup auth status # who am I? (incl. SCP userId)
netcup auth logout # revoke the refresh token & wipe local credsTip
The offline refresh token stays valid as long as it's used at least once every 30 days.
Only the refresh token is persisted (~/.config/netcup-api/, 0600); the access token is cached and refreshed automatically.
# Servers
netcup servers list # table of your servers
netcup servers get <serverId>
netcup servers start <serverId> # power ON
netcup servers stop <serverId> # power OFF
netcup servers set-hostname <serverId> web01.example.com
# Snapshots
netcup snapshots create <serverId> before-upgrade --online
netcup snapshots revert <serverId> before-upgrade
netcup snapshots list <serverId>
# Networking
netcup rdns set 203.0.113.10 host.example.com
netcup rdns set 2a03:4000:: host.example.com --v6
netcup interfaces <serverId>
# Keys, firewall, disks, ISO/images, metrics, tasks
netcup ssh-keys add laptop --key-file ~/.ssh/id_ed25519.pub
netcup firewall policies
netcup disks <serverId>
netcup iso list / netcup iso available <serverId>
netcup images list
netcup metrics <serverId> cpu # cpu | disk | network | network/packet
netcup tasks listAdd --json / -j to any command for raw JSON (great with jq).
The CLI is OpenAPI-driven, so the full API is one command away — even endpoints with no curated wrapper:
netcup endpoints # list every endpoint
netcup endpoints snapshot # filter by text
netcup endpoints --tag "Server Networking"
netcup describe get-servers-by-serverId # params + request body schema
# Invoke any operation by id (userId is auto-filled). Path via -p, query via -q, body via -d.
netcup call get-servers -q limit=10
netcup call patch-servers-by-serverId -p serverId=12345 -d '{"state":"ON"}'
# Or the raw escape hatch:
netcup api GET /api/v1/servers -q q=web
netcup api PATCH /api/v1/servers/12345 -d '{"hostname":"web01"}'Keep the spec current:
netcup spec info # bundled spec version + endpoint/tag count
netcup spec update # pull the latest spec from the live APIfrom netcup_api import NetcupClient
c = NetcupClient() # uses your stored credentials
for s in c.list_servers(limit=10):
print(s["name"], s["state"])
c.set_server_state("12345", "ON")
c.call("post-servers-by-serverId-snapshots",
path_params={"serverId": "12345"},
body={"name": "snap1", "onlineSnapshot": True})| Topic | Detail |
|---|---|
| Access token | valid 300 s — refreshed automatically by the client |
| Refresh token | offline; dies after 30 days unused → re-run netcup auth login |
PATCH /servers/{id} |
one attribute per request (else HTTP 400); Content-Type: application/merge-patch+json (handled for you) |
| Image/ISO uploads | the API returns presigned S3 URLs; the binary PUT to that URL is a separate step |
| Env var | Default |
|---|---|
NETCUP_CONFIG_DIR |
~/.config/netcup-api |
NETCUP_BASE_HOST |
https://www.servercontrolpanel.de |
NETCUP_OPENAPI |
path to an explicit spec file (overrides bundled/cached) |
pip install -e ".[dev]"
ruff check . # lint
pytest -q # offline tests (no network, no auth)See CLAUDE.md for architecture, the spec-driven principle, and contribution rules.
Want Claude / any MCP client to drive your infra in natural language? Pair this with the companion MCP server: netcup-mcp.
MIT © Antoine Chenais