@rarecloudio/mcp-server
Official# @rarecloudio/mcp-server
Model Context Protocol server for the [RareCloud](https://rarecloud.io) API.
Drop into [Claude Code](https://claude.com/claude-code), Claude Desktop, [Cursor](https://cursor.com), or your own MCP client to let AI agents inspect, reason about, and now also **manage** your RareCloud account: list servers, browse the catalog, check billing, inspect cloud infrastructure, deploy a VM, resize it, attach storage, and more.
## What it does
Exposes **222 tools** wrapping the RareCloud REST API: **110 read tools** (inspect / list / get / check, always safe) plus **112 write/action tools** (deploy, resize, destroy, order, renew, and similar mutations). 85 of the writes are gated behind an explicit `confirm:true`; the other 27 are plain. See [Safety model](#safety-model) below for how it works.
### Read tools (110)
| Category | Tool | Purpose |
|---|---|---|
| Catalog | `list_catalog_products` | Orderable products in the catalog (filter by kind / backend) |
| | `get_catalog_plan` | Full product detail: plans (sizes), specs, per-cycle pricing, billing tracks |
| | `list_regions` | Available datacenter regions |
| | `list_images` | OS images (Ubuntu / Debian / Rocky / Windows Server / …) installable on new servers; only deployable images are listed |
| | `get_product_details` | Order-ready detail for one SKU: cycles + prices, plans, config options |
| | `list_prepurchase_os_templates` | OS templates selectable at purchase time for a VPS / dedicated SKU |
| | `list_catalog_listings` | Deploy-wizard product cards for one category (the console "create" tiles) |
| | `list_kubernetes_versions` | Managed-Kubernetes (Gardener) versions on offer, newest-supported first |
| Services | `list_services` | All services in the account: VPS, cloud VMs, proxies, hosting, domains (each with `apiAccess`); a first "partial results" note when some categories could not be loaded |
| | `get_service` | Full detail for one service: status, network, billing state, usage, `apiAccess`; for a cloud VM also `tags` and `bandwidthUsage` |
| | `get_service_metrics` | CPU / RAM / disk / bandwidth time series for one service |
| | `list_backups` | Backups for one legacy VPS |
| | `get_provisioning_state` | Setup state of a pending service (paid? VM exists yet? stuck?) |
| | `list_os_templates` | Operating systems a legacy VPS can be reinstalled with |
| | `list_upgrade_options` | Plans + cycles a service could upgrade / downgrade to |
| | `get_service_iso` | Mounted-ISO status for a legacy VPS (is a rescue/install ISO attached?) |
| | `list_service_ssh_key_library` | SSH keys registered in a legacy VPS's key library |
| | `get_service_autorenew` | Whether a service auto-renews from account balance |
| Orders | `list_orders` | The account's orders: the purchase records behind its services |
| | `get_order` | One order: line items, status, payment status, and its invoice |
| Billing | `list_invoices` | Invoice history: number, status, issued date, total |
| | `get_invoice` | Full invoice detail: line items, taxes, payment method + timestamp |
| | `get_credit_balance` | Current prepaid credit balance |
| | `get_credit_ledger` | Credit movements (top-ups, vouchers, metering debits, refunds) |
| | `get_invoice_pay_preview` | Preview what paying an invoice from balance would consume (bonus → credit → shortfall) |
| | `list_payment_methods` | Available payment options (WHMCS gateways) |
| | `get_billing_campaign` | The active credit (deposit-match) promo, or none |
| | `get_bonus_balance` | Promo (bonus) balance, in cents (EUR) |
| | `get_bonus_ledger` | Bonus-credit ledger: campaign grants and promo consumption |
| | `get_billing_alert` | Spending-alert state: threshold, month-to-date spend, triggered? |
| | `get_billing_state` | Cloud auto-suspend state (normal / grace-period / suspended) |
| Support | `list_tickets` | Support tickets: id, subject, status, department, last-updated |
| | `get_ticket` | One support ticket with its full message thread |
| | `list_ticket_departments` | Support departments + their ids (for opening a ticket) |
| Account | `get_account` | Profile: email, name, country, billing currency, creation date |
| | `list_ssh_keys` | SSH keys on a specific server (legacy VPS) |
| | `get_account_limits` | Resource limits and current usage (servers / vCPUs / IPs / volumes / …) |
| | `list_account_clients` | Users linked to this client account (accepted members + pending invites) |
| | `get_affiliate` | Affiliate status + stats: referral link, conversions, commissions, payouts |
| | `get_two_factor_status` | Whether 2FA (TOTP) is enabled on the account |
| | `list_account_ssh_keys` | Account-wide SSH public keys (offered at deploy time) |
| | `get_account_activity` | Account audit trail: sign-ins, 2FA changes, service + billing actions |
| | `list_account_emails` | Emails WHMCS sent to this account, newest first |
| | `list_account_contacts` | Billing / technical contacts (email-copy recipients, no login) |
| | `list_api_access` | Resources the user made read-only for agents and API tokens (check before planning changes) |
| Cloud infrastructure | `list_volumes` | Block-storage volumes: id, name, size, status, attachment, region |
| | `get_volume` | One block-storage volume and which VM it is attached to |
| | `list_networks` | Private networks (VPCs): id, name, CIDR, status, attached VM count |
| | `get_network` | One private network (VPC) and its attached VMs |
| | `list_load_balancers` | L4 load balancers: id, name, status, public IP, port, member count |
| | `get_load_balancer` | One load balancer with its members (backend VMs + ports) |
| | `list_load_balancer_members` | Backend members of a load balancer (private fixed IP + port) |
| | `list_reserved_ips` | Reserved (static) public IPs and their attachments |
| | `list_firewalls` | Cloud firewalls (security groups): default and Private network flags (`isPrivateNetwork`), rule counts, attached VMs |
| | `get_firewall` | One firewall with its full rule set (`remoteCidr` or `remoteFirewallId` per rule) and attached VMs |
| Object Storage | `get_object_storage` | The S3-compatible storage service: status, namespace handle, price card, month-to-date charge, limits (null if not enabled) |
| | `list_object_storage_regions` | Regions a bucket can be created in, with their S3 endpoints |
| | `get_object_storage_usage` | Daily usage series for the account: stored bytes, egress, CDN traffic (1-90 days) |
| | `list_buckets` | Buckets: id, full name, region, status, versioning, public (CDN) state, size |
| | `get_bucket` | One bucket: endpoint and URLs, public URL, versioning, size and object count |
| | `get_bucket_usage` | Daily usage series for one bucket (1-90 days) |
| | `list_object_storage_keys` | S3 access keys: id, name, access key id, scope, status (never the secret) |
| Container Registry | `get_registry` | The account's private OCI registry: handle, hostname, tier, status, hourly usage sample, quota, push state (incl. the repository cap), linked-cluster counts |
| | `list_registry_tiers` | Billing tiers: storage quota, burst ceiling, monthly price (EUR/USD), overage rate, availability |
| | `suggest_registry_handle` | Up to 3 free, valid, non-reserved handle suggestions from a `base` string |
| | `list_registry_credentials` | Robot credentials (docker login / pull / push), metadata only, never a secret; `status: "active"` for usable ones only |
| | `list_registry_repositories` | Repositories under the account's registry handle, paginated (`lastPush` is the newest image's build time) |
| | `get_registry_repository` | One repository's tags: digest, build time (`createdAt`), platforms, CVE severity counts |
| | `list_registry_tag_vulnerabilities` | Paginated CVE findings for one tag |
| | `list_registry_clusters` | Kubernetes clusters linked to the registry, with syncer health and credential name |
| Domains | `list_domains` | Registered domains: id, name, status, expiry, auto-renew, `apiAccess` |
| | `get_domain` | One domain: nameservers, transfer lock, WHOIS privacy, auto-renew, expiry, `apiAccess` |
| | `check_domain_availability` | Whether a domain name is available to register |
| | `get_tld_pricing` | Register / transfer / renew prices per TLD, in the account currency |
| | `get_domain_nameservers` | Nameservers currently set on an owned domain |
| | `get_domain_contacts` | Registrant WHOIS contact on an owned domain |
| | `get_domain_dns` | DNS host records on an owned domain (A / CNAME / MX / TXT / …) |
| | `get_domain_management` | Combined management snapshot for an owned domain in one call |
| Managed Kubernetes | `get_cluster_scale` | Current scale of a managed K8s cluster: node pools + add-ons |
| | `list_cluster_pools` | Worker node pools: name, machine type, count, autoscale min/max |
| | `get_cluster_kubeconfig` | Short-lived admin kubeconfig (expires in hours), **live secret** |
| | `list_cluster_kubeconfigs` | Long-lived kubeconfig credentials, metadata only (token never returned) |
| | `download_cluster_kubeconfig` | Re-download a long-lived credential's kubeconfig (active-only), **live secret** |
| Proxies | `list_proxies` | Residential proxy services: id, name, flavor, status, plan, expiry |
| | `get_proxy_catalog` | Proxy order-wizard catalog: ISP IP-count tiers + GB Residential buckets, pricing |
| | `get_proxy` | One proxy service: flavor, status, plan, location, expiry / renewal |
| | `get_proxy_list` | Live proxy endpoints + credentials for an ISP fixed-IP plan, **live secret** |
| | `get_proxy_auth` | Auth settings for a proxy service: method, credentials, IP whitelist, **live secret** |
| | `list_gb_residential_countries` | Countries selectable when creating a GB Residential proxy-request |
| | `list_gb_rotation_intervals` | Rotation intervals selectable for a GB Residential proxy-request |
| | `list_proxy_requests` | Proxy-requests on a GB Residential bucket (country + rotation + count groups) |
| | `get_proxy_request_list` | Live endpoints + credentials for one GB Residential proxy-request, **live secret** |
| | `get_proxy_replacements` | IP-replacement allowance + history for a proxy service |
| | `list_proxy_replacement_locations` | Locations a replacement IP can be placed in (ISP only) |
| | `get_proxy_bandwidth` | Bandwidth usage of a GB Residential bucket: total, used, available |
| | `check_proxy` | Live check of every proxy of a service: up/down, exit IP, ISP, geo, latency (a POST: sends a small amount of traffic through each proxy and refreshes the shown location) |
| | `get_proxy_auto_rotation` | Auto-rotation settings of a mobile proxy line |
| AI Sandboxes | `list_sandboxes` | Sandboxes: id, name, status, template, image, labels, env names (never values), run mode, expiry |
| | `get_sandbox` | One sandbox: status (and why it is pending), image, labels, env names, run mode, `expiresAt` |
| | `list_sandbox_templates` | Templates (python / node / base): size, image, price per hour in EUR and USD |
| | `read_sandbox_file` | Read one file by absolute path (text, or base64 for binary; up to 25 MiB) |
| | `get_sandbox_logs` | Last lines of a run-mode sandbox's output, plain text (404 = logs gone; 503 = not available yet) |
| | `check_order` | Would `deploy_service` be accepted right now? Same body, creates and reserves nothing; on a refusal returns the message plus the Add funds or Pay invoice link for the human (needs `services:write`) |
| Snapshots | `list_snapshots` | Every VM snapshot the account owns, across all cloud VMs: state (creating / securing / ready / failed), size, source VM |
| | `list_service_snapshots` | Snapshots of one cloud VM (up to 5 per VM); check before a risky change |
| | `get_snapshot` | One VM snapshot (poll a new one until `ready`) |
| Quotas | `get_quota_limits` | Effective cloud quotas with live usage per resource (used / limit / state), plus registry and sandboxes figures |
| | `estimate_limits` | Would a managed Kubernetes cluster's pools fit the quota? POST that creates and reserves nothing |
| | `list_quota_requests` | Quota-increase requests and their status (pending / approved / auto_approved / denied) |
| Reverse DNS | `get_service_rdns` | Reverse DNS (PTR) record of a cloud VM's primary public IPv4 |
Tools marked **live secret** return a real credential (a kubeconfig bearer token, proxy `ip:port:user:pass`, an S3 secret access key, or a registry credential secret). Their descriptions carry the standard SECURITY sentence (see [Safety model](#safety-model)).
### Write / action tools (112)
The **Safety** column is each tool's kind (see [Safety model](#safety-model)). **spends**, **destructive**, **disruptive** and **sensitive** tools are gated (85 tools): they refuse to run, making **no** API call, unless the call passes `confirm:true`, so an agent must surface the action and its cost or consequence to the user first. **plain** tools (27) cost nothing, tear nothing down, and run without confirmation.
| Category | Tool | Safety | Purpose |
|---|---|---|---|
| Services | `set_service_hostname` | plain | Rename a service (legacy VPS hostname, or the cloud VM's server name) |
| | `deploy_service` | **spends** | Deploy (order + provision) a new service: polymorphic across VM / k8s / volume / load-balancer / network / proxy / domain; load balancers, volumes and networks take no SKU (call `check_order` first; returns a **live secret**) |
| | `destroy_service` | **destructive** | Permanently destroy a service and release its resources (also load balancers, volumes and private networks by id) |
| | `resize_service` | **spends** | Resize a cloud VM to a new flavor/plan |
| | `upgrade_service` | **spends** | Create an upgrade order moving a service to a new product/plan |
| | `renew_service` | **spends** | Ensure a renewal invoice exists for a service |
| | `cancel_service` | **destructive** | File a cancellation request: immediate or end-of-term |
| | `set_service_autorenew` | plain | Toggle auto-renew for a service |
| | `create_service_backup` | plain | Create an on-demand backup of a legacy VPS |
| | `mount_service_iso` | plain | Mount a rescue/install ISO on a VPS |
| | `unmount_service_iso` | plain | Unmount the currently mounted ISO from a VPS |
| | `set_service_password` | **disruptive** | Set the root/administrator password of a legacy VPS |
| | `start_service` | plain | Power on a service |
| | `stop_service` | **disruptive** | Power off a service |
| | `reboot_service` | **disruptive** | Reboot a service |
| | `reinstall_service` | **destructive** | Reinstall (rebuild from scratch) a service, wiping the disk (returns a **live secret**) |
| | `reset_service_password` | **disruptive** | Reset the root password live via qemu-guest-agent, on a running cloud VM |
| | `add_service_ssh_key` | **sensitive** | Install an SSH public key directly onto a running service |
| | `add_service_ssh_key_to_library` | plain | Register an SSH key in a legacy VPS's reinstall-time key library |
| | `apply_service_ssh_key_library` | **disruptive** | Apply a set of library SSH keys to a legacy VPS, replacing the current set |
| | `set_service_tags` | plain | Replace a cloud VM's tags (the whole set; `[]` clears them) |
| Managed Kubernetes | `set_cluster_scale` | **disruptive** | Set the autoscaling bounds of a cluster's first node pool |
| | `add_cluster_pool` | **spends** | Add a named worker node pool |
| | `update_cluster_pool` | **disruptive** | Edit an existing node pool's bounds / machineType / volume size |
| | `delete_cluster_pool` | **destructive** | Remove a worker node pool |
| | `rename_cluster_pool` | **disruptive** | Rename a worker node pool (rolls its nodes) |
| | `enable_cluster_ha` | **spends** | Enable the HA control plane: add-only, irreversible |
| | `create_cluster_kubeconfig` | **sensitive** | Mint a long-lived, revocable kubeconfig credential (returns a **live secret**) |
| | `revoke_cluster_kubeconfig` | **destructive** | Revoke a long-lived kubeconfig credential |
| Cloud infra: volumes / networks / IPs | `create_volume` | **spends** | Create a new block-storage volume |
| | `delete_volume` | **destructive** | Delete a block-storage volume permanently |
| | `attach_volume` | plain | Attach a volume to a cloud VM |
| | `detach_volume` | **disruptive** | Detach a volume from a cloud VM |
| | `create_network` | plain | Create a new private network (VPC) |
| | `delete_network` | **destructive** | Delete a private network (VPC) |
| | `attach_network_vm` | **disruptive** | Move a cloud VM into a private network |
| | `reserve_ip` | **spends** | Reserve a new static public IP |
| | `release_reserved_ip` | **destructive** | Release (permanently delete) a reserved public IP |
| | `attach_reserved_ip` | plain | Attach a reserved public IP to a cloud VM |
| | `detach_reserved_ip` | **disruptive** | Detach a reserved public IP from its VM |
| Cloud infra: firewalls / load balancers | `create_firewall` | plain | Create a new cloud firewall (security group) |
| | `delete_firewall` | **destructive** | Delete a cloud firewall (the default and the Private network firewall answer 409) |
| | `add_firewall_rule` | plain | Add an inbound/outbound rule to a firewall (inbound on the Private network firewall needs a private source range) |
| | `delete_firewall_rule` | **destructive** | Remove a rule from a firewall |
| | `attach_firewall` | plain | Attach a firewall to a cloud VM |
| | `detach_firewall` | **disruptive** | Detach a firewall from a cloud VM |
| | `create_load_balancer` | **spends** | Create a new L4 load balancer (VIP + listener + pool + floating IP); returns at once with status `pending`, poll `get_load_balancer` until `active` |
| | `delete_load_balancer` | **destructive** | Delete a load balancer; `deleted` at once, or `deleting` when it was still being set up |
| | `add_load_balancer_member` | plain | Add a VM as a member of a load-balancer pool (409 while the load balancer is being set up; 503 with Retry-After changes nothing) |
| | `remove_load_balancer_member` | **destructive** | Remove a member from a load-balancer pool |
| Object Storage | `enable_object_storage` | **spends** | Enable Object Storage (starts the monthly base fee); optional, the first bucket does it too |
| | `disable_object_storage` | **destructive** | Delete the storage account for good (only once every bucket is deleted and every key revoked) |
| | `create_bucket` | **spends** | Create a bucket (the first one enables or wakes the service and its base fee) |
| | `update_bucket` | **sensitive** | Toggle a bucket's versioning or public CDN delivery (public makes every object readable by anyone) |
| | `delete_bucket` | **destructive** | Delete a bucket; `purge:true` deletes every object in it first |
| | `create_object_storage_key` | **sensitive** | Create an S3 access key scoped to buckets + read/readwrite (returns a **live secret**, shown once) |
| | `delete_object_storage_key` | **destructive** | Revoke an S3 access key |
| Container Registry | `enable_registry` | **spends** | Enable the registry with an immutable handle and a tier, or reopen / re-enable a closed one |
| | `set_registry_tier` | **spends** | Change the registry's billing tier (a downgrade below measured usage is refused) |
| | `close_registry` | **destructive** | Close the registry (the API also wants the handle typed back); storage is purged after `deleteAfter` unless reopened |
| | `create_registry_credential` | **sensitive** | Create a pull or push robot credential (returns a **live secret**, shown once) |
| | `revoke_registry_credential` | **destructive** | Revoke a robot credential immediately |
| | `delete_registry_repository` | **destructive** | Delete every image in a repository (an empty repository answers `deleted: 0`) |
| | `delete_registry_tag` | **destructive** | Delete one tag (404 if it does not exist); the image stays pullable by digest about 8 days |
| | `delete_registry_manifest` | **destructive** | Delete an image by digest with every tag on it; `confirm_multiple_tags` when more than one tag points at it (409 otherwise) |
| | `link_registry_cluster` | **sensitive** | Link a managed Kubernetes cluster (installs the secret-syncer; relay the returned disclosure verbatim) |
| | `unlink_registry_cluster` | **destructive** | Unlink a cluster, removing everything the link installed and revoking its credential |
| | `rotate_registry_cluster_link` | **disruptive** | Rotate a linked cluster's pull credential (no secret returned) |
| | `create_registry_kubernetes_manifest` | **sensitive** | Pull-secret manifest for a cluster you run yourself (returns a **live secret**, shown once) |
| Domains | `register_domain` | **spends** | Register a new domain name |
| | `transfer_domain` | **spends** | Transfer a domain in from another registrar |
| | `renew_domain` | **spends** | Renew an owned domain |
| | `set_domain_nameservers` | **disruptive** | Replace an owned domain's nameservers (2-5) |
| | `set_domain_contacts` | **sensitive** | Update an owned domain's registrant WHOIS contact |
| | `set_domain_dns` | **disruptive** | Replace an owned domain's DNS host records |
| | `manage_domain` | **sensitive** | Dispatch a single domain management action (nameservers / lock / autorenew / idprotect / epp) |
| Account | `update_account` | **sensitive** | Update the account's billing / contact profile |
| | `add_account_ssh_key` | plain | Add an account-wide SSH public key |
| | `delete_account_ssh_key` | **destructive** | Delete an account-wide SSH key |
| | `resend_email_verification` | plain | Resend the account's email-verification email |
| | `manage_account_contact` | **sensitive** | Add, update, or delete a billing/technical contact |
| | `create_affiliate_link` | plain | Mint a signed affiliate referral link (no money movement) |
| Billing | `set_billing_alert` | plain | Set (or update) the month-to-date spend alert |
| | `delete_billing_alert` | **destructive** | Remove the month-to-date spend alert |
| | `redeem_voucher` | plain | Redeem a credit voucher / promo code (adds credit: never spends) |
| Support | `create_ticket` | **sensitive** | Open a support ticket |
| | `reply_ticket` | **sensitive** | Post a reply to an existing support ticket |
| | `close_ticket` | plain | Close a support ticket |
| Proxies | `order_proxy` | **spends** | Order a new residential proxy plan: ISP or GB Residential (returns a **live secret**) |
| | `renew_proxy` | **spends** | Renew a proxy service for another billing term |
| | `set_proxy_auto_renew` | plain | Turn a proxy service's auto-renew on/off |
| | `cancel_proxy` | **destructive** | Cancel a proxy service |
| | `set_proxy_auth_method` | **disruptive** | Switch a proxy service's authentication method |
| | `set_proxy_credentials` | **disruptive** | Set a proxy service's username/password |
| | `add_proxy_whitelisted_ip` | plain | Add an IP to a proxy service's whitelist |
| | `remove_proxy_whitelisted_ip` | **destructive** | Remove an IP from a proxy service's whitelist |
| | `request_proxy_replacement` | **disruptive** | Request an IP replacement, consuming the monthly allowance; optional `locationId` / `locationLabel` from `list_proxy_replacement_locations` move the new IP |
| | `create_proxy_request` | plain | Create a proxy-request on a GB Residential bucket |
| | `delete_proxy_request` | **destructive** | Delete a proxy-request from a GB Residential bucket |
| | `set_proxy_auto_rotation` | **disruptive** | Turn a mobile line's automatic IP rotation on/off and set its interval |
| | `rotate_proxy` | **disruptive** | Rotate a mobile line's exit IP now |
| AI Sandboxes | `create_sandbox` | **spends** | Create a sandbox from a template or image, with lifetime, name, env, labels, network switch and optional run mode (billed per second; env values never returned) |
| | `delete_sandbox` | **destructive** | Terminate a sandbox and delete everything in it |
| | `run_sandbox_code` | plain | Run a Python or Node snippet in a sandbox; returns stdout, stderr, exit code |
| | `run_sandbox_command` | plain | Run a shell command (`sh -c`) in a sandbox; returns stdout, stderr, exit code |
| | `write_sandbox_file` | plain | Create or overwrite one file in a sandbox (text or base64) |
| Snapshots | `create_snapshot` | **spends** | Snapshot a cloud VM's root disk; take one before `reinstall_service` / `resize_service` (billed for the storage it uses) |
| | `delete_snapshot` | **destructive** | Delete a VM snapshot (refused while VMs created from it exist) |
| | `restore_snapshot` | **destructive** | Restore a cloud VM from one of its own snapshots: the undo; replaces the root disk |
| Quotas | `request_quota_increase` | **sensitive** | Ask for a higher quota; modest ones apply at once, larger ones open a support ticket |
| Reverse DNS | `set_service_rdns` | **disruptive** | Set the reverse DNS (PTR) record of a cloud VM's public IPv4 (e.g. for a mail server) |
| | `delete_service_rdns` | **disruptive** | Remove the reverse DNS (PTR) record of a cloud VM's public IPv4 |
Notably absent by design: no password/2FA changes, no sub-user invites, no payment-method or API-token management, no credit top-up, no invoice payment, no affiliate activate/withdraw, and no way to change a resource's API access. Those are identity, credential, or raw-money-movement operations that stay out of an agent's reach: they have no tool at all (see [Security](#security)). Registry robot credentials (`create_registry_credential`, `create_registry_kubernetes_manifest`) are a different class: infrastructure access, like SSH keys and kubeconfigs, so they have tools, gated as **sensitive** and shown once. Sandbox port exposure has no tool either, for a different reason: the API answers 501 for it (preview URLs are not part of AI Sandboxes v1).
## Safety model
Every read tool only inspects account state and is always safe to call. Every write tool has exactly **one safety kind**, and everything safety-related is derived from it in one place (the `writeTool` factory), so no tool hand-writes its own warning:
| Kind | Meaning | Gated | `destructiveHint` |
|---|---|---|---|
| **plain** | No charge, nothing torn down, nothing running is interrupted | no | false |
| **spends** | Places an order or otherwise charges the account | yes | false |
| **destructive** | Irreversible: deletes data or a resource, revokes access, cancels a service | yes | true |
| **disruptive** | Reversible, but interrupts something running or locks someone out (power off, reboot, detach, move a VM between networks, roll a node pool, replace DNS, replace credentials or keys) | yes | true |
| **sensitive** | Grants access, changes ownership or legal data, or speaks for you (SSH key install, long-lived kubeconfig, domain contacts, account profile, support tickets) | yes | false |
- **Gated tools refuse with zero API calls unless the call passes `confirm: true`.** No side effect, no partial charge, nothing to undo. The refusal says what the tool would have done, for example `stop_service was NOT executed because it is disruptive: it powers the server off; everything running on it stops until it is started again.`, so the agent can go back to you for an explicit go-ahead. The confirm is per call; there is no "confirm once, run twice" shortcut.
- **Every description ends with one standard `Safety:` sentence** naming the kind and the concrete consequence, so the agent sees the same information before it calls.
- **Every tool carries MCP annotations.** All reads set `readOnlyHint: true` (so a client can auto-approve them), plus `idempotentHint: true` and `destructiveHint: false`. All writes set `readOnlyHint: false`, and `destructiveHint` is true for destructive and disruptive tools, so an MCP client's own guardrails can treat those more cautiously. Every tool sets `openWorldHint: true` (it talks to the live RareCloud API).
- **Credentials are marked.** Tools whose result contains a live credential (`deploy_service` and `reinstall_service` when they return a one-time console password, `order_proxy` for an ISP plan's proxy list, `create_cluster_kubeconfig`, `create_object_storage_key`, `create_registry_credential`, `create_registry_kubernetes_manifest`, `get_cluster_kubeconfig`, `download_cluster_kubeconfig`, `get_proxy_list`, `get_proxy_auth`, `get_proxy_request_list`) carry one standard sentence: *SECURITY: the result contains ..., a live credential. Treat it as a secret: do not repeat it to the user, or write it to files or logs, unless the user explicitly asks; pass it straight to whatever needs it.* Tools that take a secret as input (`set_service_password`, `reset_service_password`, `set_proxy_credentials`, and `create_sandbox` for its `env` values) tell the agent never to echo the value back. `create_sandbox` never returns `env` values: the result names the variables only (`envKeys`).
### Resources the user made read-only for agents
In the console you can switch **API access** off for any service (VPS, cloud VM, cluster, volume, load balancer, network, hosting, proxy) or domain. That resource becomes read-only for every API token, so for this server too:
- The agent can still list it and read its details. `list_services`, `get_service`, `list_domains` and `get_domain` show `apiAccess: "read_only"` (missing means `"full"`), and `list_api_access` lists every read-only resource in one call, so the agent can check before it plans a change.
- Every change to it, and every read of its credentials (kubeconfigs, proxy credentials and similar), is refused by the API with `RESOURCE_PROTECTED`. The agent gets this error text: *The user made this resource read-only for agents and API tokens, so this request was refused and nothing was changed. Agents can still list it and read its details, but cannot change it or read its credentials. Do not retry, and do not try to reach the same result through another tool. If the change is really wanted, ask the user to turn API access on for this resource in the console: \<link\>*
- Only you can turn API access back on, signed in to the console. The switch endpoints (`PUT /v1/services/{id}/api-access`, `PUT /v1/domains/{id}/api-access`) have no tool on purpose, and a registry test pins that: an agent that could flip the switch could make a protected resource writable and then change it.
### Safe retries (idempotency keys)
A dropped connection after the API created something used to leave the agent guessing whether to retry, and a retry could create a second VM or charge twice. The 46 write tools that map to a route where the API honours an `Idempotency-Key` take an optional `idempotency_key` input (1 to 255 printable ASCII characters): reuse the same value if you retry the exact same request, and the API runs it at most once and returns the first answer again.
- Without `idempotency_key`, the server makes a fresh UUIDv4 key for the call and, if the connection drops or times out before the answer arrives, retries **once** with that same key.
- If the API says the first request with that key is still running (`409 IDEMPOTENCY_IN_PROGRESS`), the server waits the `Retry-After` time (at most 10 seconds) and asks again with the same key, up to 3 times.
- `422 IDEMPOTENCY_KEY_REUSED` (the key was used for a different request) and every other API error are final: no retry.
- A replayed answer starts with a note saying it is a replay and that the operation ran once. Secrets are never stored for a replay: when the first answer held one (a console password, a secret key), the note passes on `secretsOmittedOnReplay` so the agent knows it was shown only the first time.
- The confirm gate still comes first: without `confirm:true` a gated tool makes no key and no request.
- No other POST ever carries the header, and no other request is ever retried.
The tools: `add_account_ssh_key`, `add_cluster_pool`, `add_firewall_rule`, `add_load_balancer_member`, `add_proxy_whitelisted_ip`, `add_service_ssh_key`, `add_service_ssh_key_to_library`, `cancel_service`, `create_bucket`, `create_cluster_kubeconfig`, `create_firewall`, `create_load_balancer`, `create_network`, `create_object_storage_key`, `create_proxy_request`, `create_registry_credential`, `create_sandbox`, `create_service_backup`, `create_snapshot`, `create_ticket`, `create_volume`, `deploy_service`, `enable_cluster_ha`, `enable_object_storage`, `enable_registry`, `link_registry_cluster`, `manage_account_contact`, `order_proxy`, `reboot_service`, `redeem_voucher`, `register_domain`, `reinstall_service`, `renew_domain`, `renew_proxy`, `renew_service`, `reply_ticket`, `request_proxy_replacement`, `request_quota_increase`, `reserve_ip`, `reset_service_password`, `resize_service`, `set_cluster_scale`, `start_service`, `stop_service`, `transfer_domain`, `upgrade_service`.
For anything outside the 112 write tools, the agent can read, recommend, and generate Terraform/CLI commands. You copy-paste them or run them via [the RareCloud CLI](https://github.com/RareCloudio/rarecloud-cli).
## Install
Requires Node.js **21+** (the package's `engines` field). The test suite needs it too: `npm test` passes a glob (`src/**/*.test.ts`) straight to `node --test`, which only gained glob-pattern support in Node 21.
```bash
npm install -g @rarecloudio/mcp-server
```
Or run directly with `npx`:
```bash
npx @rarecloudio/mcp-server
```
## Configure
Get an API token: **Dashboard → Account → API tokens → New token**. Pick scopes for what you want the agent to do:
- Read-only agent: the explicit read scopes `account:read`, `services:read`, `billing:read`, `domains:read`, `tickets:read`.
- An agent that can also act: add the matching `{domain}:write` scope(s): `services:write` (covers cloud VMs, managed Kubernetes, volumes, networks, reserved IPs, firewalls, load balancers, Object Storage, the container registry, AI Sandboxes, **and residential proxies**: there is no separate proxy or registry scope; the read-only `check_order` also needs it, because it answers whether this token can order), `domains:write`, `account:write`, `billing:write`, `tickets:write`.
- Full access: bare `*`.
Scope matching is **exact per token**: wildcard patterns like `*:read` are not supported; a token must carry the precise scope string a tool's description names. `account:write` / `billing:write` / `tickets:write` are deliberately narrow: they cover only the safe write tools listed above (profile fields, SSH keys, contacts, spend alerts, voucher redemption, tickets) and exclude every identity/credential/money-movement operation (password/2FA changes, sub-user invites, payment methods, API tokens, credit top-up, invoice payment, affiliate activate/withdraw): those simply have no tool here, gated or otherwise.
Copy the token; it is shown only once.
Set the env var:
```bash
export RARECLOUD_API_TOKEN="rc_pat_..."
```
Optional, for self-hosted / staging instances (defaults to `https://api.rarecloud.io`):
```bash
export RARECLOUD_API_ENDPOINT="https://your-instance.example.com"
```
## Use with Claude Desktop
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
```json
{
"mcpServers": {
"rarecloud": {
"command": "npx",
"args": ["-y", "@rarecloudio/mcp-server"],
"env": {
"RARECLOUD_API_TOKEN": "rc_pat_..."
}
}
}
}
```
Restart Claude Desktop. The tools become available under the 🔌 menu.
## Use with Claude Code
```bash
claude mcp add rarecloud -e RARECLOUD_API_TOKEN=rc_pat_... -- npx -y @rarecloudio/mcp-server
```
## Use with Cursor
Edit `~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"rarecloud": {
"command": "npx",
"args": ["-y", "@rarecloudio/mcp-server"],
"env": { "RARECLOUD_API_TOKEN": "rc_pat_..." }
}
}
}
```
## Example prompts
Once configured, try:
- *"What VPS plans do you offer in Frankfurt?"* → uses `list_catalog_products` + `list_regions`
- *"List my running servers and their monthly cost"* → `list_services` + per-service spec lookup
- *"Am I close to any resource limits?"* → `get_account_limits`
- *"Show my block volumes and which VM each is attached to"* → `list_volumes`
- *"Any unpaid invoices, and what would paying the latest one from my balance cost?"* → `list_invoices` + `get_invoice_pay_preview`
- *"Give me a Terraform config for a 2 vCPU / 4 GB VPS in The Hague"* → `get_catalog_plan` + composition
- *"Deploy a 2 vCPU / 4 GB VM in The Hague named web-01"* → `get_product_details` to confirm the plan and cost, `check_order` to see the order will be accepted, then `deploy_service` with `confirm:true` once you approve
- *"Resize db-02 to the next size up"* → `list_upgrade_options` + `resize_service` (confirm required)
- *"Mint a 90-day view-only kubeconfig for my cluster for CI"* → `create_cluster_kubeconfig` (confirm required: it mints a long-lived credential)
## Develop locally
```bash
git clone https://github.com/RareCloudio/rarecloud-mcp-server
cd rarecloud-mcp-server
npm install
npm run dev # runs from source via tsx
npm run build # compiles to dist/
```
Then point Claude Desktop at your local checkout:
```json
{
"mcpServers": {
"rarecloud-dev": {
"command": "node",
"args": ["/absolute/path/to/rarecloud-mcp-server/dist/index.js"],
"env": { "RARECLOUD_API_TOKEN": "rc_pat_..." }
}
}
}
```
## Testing
```bash
npm test
```
Tests run on the built-in Node test runner (`node:test`) via `tsx`: no build step, no network. Each tool is exercised against an injected mock client that records the request path and returns a canned payload, so the suite asserts path construction, input-schema shape, JSON-vs-raw output, secret-handling guidance, and error mapping without ever calling the live API. For write tools, the same fake-client harness also proves every gated tool (85, pinned by name and kind) refuses with its reason and makes zero requests when `confirm` is omitted, that every tool carries the right MCP annotations, that both the zod input and the JSON `inputSchema` enforce the same bounds (mirrored both layers), and that every dynamic path segment is guarded against path traversal. Further tests drop the first answer of an idempotent request and prove the retry reuses the same key, pin which tools take `idempotency_key` against the API's covered routes, and pin the `RESOURCE_PROTECTED` error text. A registry invariant test pins the exposed tool count (222) and enforces unique names, well-formed schemas, and, for the write-scope surfaces, an exact pinned set of tool names per scope, so a future change can't silently add a tool under the wrong scope.
## Security
- Tokens never touch shell history (we use env vars, not CLI flags).
- Each tool maps 1:1 to a RareCloud API endpoint; the MCP server doesn't aggregate or transform data beyond what the API returns.
- **Scope is exact-match per token, enforced server-side.** A token only unlocks the tools whose scope it carries; there is no wildcard scope matching (`*:read` does not imply `services:read`) and no client-side scope bypass: an unscoped or under-scoped token gets the API's own `[FORBIDDEN]` response back.
- **Writes exist and are gated.** 112 of the 222 tools mutate state. The 85 that spend money, destroy something, disrupt something running, or are security-sensitive require `confirm:true` and make no API call at all without it (see [Safety model](#safety-model)). The remaining 27 are plain (no charge, nothing torn down) and run without confirmation once the token's scope allows them.
- **No identity/credential/money-movement surface, by design, not by gate.** Password/2FA changes, sub-user invites, payment-method management, API-token management, credit top-up, invoice payment, and affiliate activate/withdraw, and the per-resource API access switch, have no tool here at all: an agent holding even a maximally-scoped token cannot reach them. A registry test pins this exclusion list so a future change can't quietly add one back.
- The tools that return live credentials (kubeconfigs, proxy endpoint/auth lists, one-time console passwords) carry the standard SECURITY sentence so the agent doesn't echo them back unprompted.
- Revoke a token at any time: **Dashboard → Account → API tokens**. Revocation is instant, no propagation delay.
## License
MIT.
TDQS
Scored across 156 tools
The tools have highly detailed descriptions that clearly distinguish between similar resources (e.g., list_ssh_keys vs list_account_ssh_keys). However, the sheer volume of 156 tools makes it difficult for an agent to quickly differentiate without reading every description.
Most tools follow a consistent verb_noun snake_case pattern (e.g., list_services, create_volume). A few tools like manage_domain are more generic, and some use set_ vs update_ inconsistently, but the overall pattern is clear.
156 tools is far beyond the typical well-scoped range of 3-15. While the server covers a broad API surface, this granularity makes it unwieldy; many tools could be combined or parameterized.
The tools cover nearly all aspects of the RareCloud platform: account, billing, services, domains, proxies, networking, firewalls, and tickets. A few write operations are intentionally omitted, but the surface is comprehensive for common workflows.