vpsnet-mcp 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## Features
6
6
 
7
- - **280+ tools** covering VPSNet service management, managed applications, free and paid TLS certificates, Automatic SSL subscriptions, DNS, domains, billing, API keys, and account operations
7
+ - **<!-- tool-count -->371<!-- /tool-count --> tools** (local package; the hosted connector offers a subset) covering VPSNet service management, networking (private networks, server firewall, port forwarding, public addresses, load balancers, VPN), managed applications, free and paid TLS certificates, Automatic SSL subscriptions, DNS, domains, billing, API keys, and account operations
8
8
  - Account & profile management
9
9
  - VPS lifecycle (start, stop, restart, reinstall OS)
10
10
  - Plan changes (free upgrades/downgrades; KVM/Firecracker disks cannot shrink)
@@ -20,7 +20,7 @@
20
20
 
21
21
  ## Remote OAuth connector
22
22
 
23
- The remote profile also includes scoped DNS, domain and certificate management, public SSH keys, server recovery and backup browsing. It uses the same customer APIs as the panel; permissions are enforced by the backend on every request.
23
+ The remote profile also includes scoped DNS, domain and certificate management, public SSH keys, backup browsing and, while VPSnet offers it, server rescue. It uses the same customer APIs as the panel; permissions are enforced by the backend on every request.
24
24
 
25
25
  The remote connector uses `https://mcp.vpsnet.com/mcp` and customer consent through
26
26
  VPSnet. See [Remote AI connections](docs/REMOTE_MCP.md) for connection setup,
@@ -307,7 +307,7 @@ This MCP server manages your VPS infrastructure through the VPSnet.com API, incl
307
307
 
308
308
  Most AI coding environments (Claude Code, Cline, Cursor, Codex) have built-in terminal access, so the AI can SSH into your VPS immediately after deploying a key — no extra tools needed.
309
309
 
310
- For environments without native SSH access, pair this with [mcp-server-ssh](https://github.com/bacarrdy/mcp-server-ssh) for direct server connectivity via MCP tools.
310
+ For environments without native SSH access, pair this with [mcp-server-ssh](https://github.com/bacarrdy/mcp-ssh-server) for direct server connectivity via MCP tools.
311
311
 
312
312
  **Combined config:**
313
313
 
@@ -628,8 +628,13 @@ Every request is sent with the `X-API-KEY` header (`VPSNET_API_KEY`).
628
628
  - **Granular scopes only narrow a key.** A key with an empty scope list keeps
629
629
  everything its access level allows; listing scopes (for example `dns:read`,
630
630
  `services:manage`) restricts it. `X:manage` includes `X:read`. Networking is the
631
- exception: `networking:read` / `networking:manage` / `networking:order` are never
632
- implied by `full` or `read` and must be granted explicitly.
631
+ exception: `networking:read` / `networking:manage` / `networking:order`,
632
+ `files:read` / `files:manage` (service file manager) and the App Cloud permissions
633
+ `projects:*` / `projectdb:*` are never implied by `full` or `read` and must be added
634
+ to the key explicitly. A key created
635
+ without a permission list (for example an older `full` key) reaches no network
636
+ function (private networks, the server firewall, port forwarding, public addresses,
637
+ load balancers, VPN) until `networking:read` or `networking:manage` is added to it.
633
638
  - **Paid operations are a separate gate.** A tool marked `Paid` or `Quote` in the
634
639
  tables below needs a `full`-access key, `paid_operations_enabled`, the named paid
635
640
  scope (`vps:order`, `vds:order`, `ds:order`, `fc:order`, `domains:order`,
@@ -639,9 +644,11 @@ Every request is sent with the `X-API-KEY` header (`VPSNET_API_KEY`).
639
644
  an uncertain attempt, never a new one). Orders run quote, then confirm with the
640
645
  returned `quoteToken`; disclose the exact EUR total to the user before confirming.
641
646
  Use `list_api_keys` to see your key's scopes, paid scopes, caps and rate limit.
642
- - **Rate limits.** Requests are rate-limited per key (`rate_limit` in
643
- `list_api_keys`, requests per minute). On HTTP `429` back off and retry after
644
- `retry_after` seconds instead of retrying immediately.
647
+ - **Rate limits.** Each key has one request budget: 300 requests per 60 seconds by
648
+ default, and some DNS and domain operations have lower limits. On HTTP `429` wait
649
+ the `retry_after` seconds of the result (the API also sends `Retry-After`;
650
+ `X-RateLimit-Limit` / `-Remaining` show the budget) instead of retrying immediately. (The `rate_limit` value shown by
651
+ `list_api_keys` is stored with the key but is not what the limiter applies.)
645
652
  - API keys can never create, change or revoke API keys, and never receive admin
646
653
  access.
647
654
 
@@ -743,12 +750,14 @@ everything else.
743
750
  | `get_rdns` | Get current rDNS records | `services:read` | free |
744
751
  | `change_rdns` | Change reverse DNS (PTR) record | `services:manage` | free |
745
752
  | `clear_rdns` | Clear a PTR override and restore the automatic value | `services:manage` | free |
746
- | `flush_iptables` | Flush iptables rules (useful when locked out) | `services:manage` | free |
753
+ | `flush_iptables` | Flush the iptables rules inside the server (useful when locked out by them); the server's public firewall is separate | `services:manage` | free |
747
754
  | `get_title` | Get the current service display title | `services:read` | free |
748
755
  | `change_title` | Change service display title | `services:manage` | free |
749
756
  | `toggle_ipv6` | Enable or disable IPv6 | `services:manage` | free |
750
757
  | `toggle_extra_settings` | Toggle ppp, fuse, tuntap, or nfs | `services:manage` | free |
751
758
  | `deploy_ssh_key` | Deploy an SSH key to a VPS; remote OAuth also requires `vm:exec` | `services:manage` | free |
759
+ | `list_service_ssh_keys` | List which account SSH keys are on a Cloud VPS or Firecracker VPS; local package only | `services:read` | free |
760
+ | `remove_service_ssh_key` | Remove one account SSH key from a server's root authorized_keys; local package only | `services:manage` | free |
752
761
 
753
762
  ### OS Reinstall
754
763
  | Tool | Description | Scope | Paid |
@@ -990,7 +999,7 @@ short-lived quote token.
990
999
  ### Service Rescue
991
1000
  | Tool | Description | Scope | Paid |
992
1001
  |------|-------------|-------|------|
993
- | `get_service_rescue` | Get rescue capability and current durable rescue session | `services:read` | free |
1002
+ | `get_service_rescue` | Get rescue capability and current durable rescue session; rescue is offered only while VPSnet has it switched on | `services:read` | free |
994
1003
  | `enter_service_rescue` | Restart an eligible service into an advertised rescue image | `services:rescue` | free |
995
1004
  | `exit_service_rescue` | Restore the exact pre-rescue boot configuration and state | `services:rescue` | free |
996
1005
 
@@ -1090,10 +1099,11 @@ requested or decrypted by these tools. Router recipes retain a literal PSK
1090
1099
  placeholder; fill it only in the customer's external configuration workflow. Never automatically
1091
1100
  repeat a pickup after an uncertain response.
1092
1101
 
1093
- For personal devices use WireGuard; IPsec IKEv2 is a site-to-site option only.
1094
- Read the selected gateway's `capabilities.site_ipsec` and `ipsec_profiles`
1095
- before selecting the protocol, vendor or cipher mode. A listed tool does not
1096
- prove an older gateway image supports IPsec. Read router recipes with
1102
+ Devices support WireGuard or the operating system's built-in IKEv2 client when
1103
+ `capabilities.device_ikev2` is available. Connected locations support WireGuard
1104
+ or IPsec IKEv2; read `capabilities.site_ipsec` and `ipsec_profiles` before choosing
1105
+ site protocol, vendor or cipher mode. A listed tool does not prove an older
1106
+ gateway image supports that protocol. Read router recipes with
1097
1107
  `get_network_vpn_peer_recipe`; don't use a different vendor profile than the
1098
1108
  one used to create the peer unless the returned API guidance supports it.
1099
1109
  For IPsec, connected means an established SA and the handshake timestamp is a
@@ -1105,8 +1115,48 @@ that broader authorization explicitly. Selected-server access uses
1105
1115
  `grant_scope=servers`; replacing grants without a scope also selects servers,
1106
1116
  so inspect and preserve the intended scope when editing an existing device.
1107
1117
 
1108
- This release exposes no customer network rename, existing-port fixed-IP edit,
1109
- or appliance restart/rebuild tools. Fixed DHCP
1118
+ Site health webhooks use `list_network_vpn_site_health_webhooks` with
1119
+ `networking:read` and `create_network_vpn_site_health_webhook` or
1120
+ `delete_network_vpn_site_health_webhook` with `networking:manage`. The list
1121
+ shows only the public destination host. Creation needs a caller-generated
1122
+ X25519 public reveal key and returns the signing secret only in a sealed
1123
+ envelope for external decryption. The subscription and removal are immediate
1124
+ resources, with no operation ID or idempotency key. After an uncertain create,
1125
+ list the site's subscriptions before deciding whether to create another.
1126
+
1127
+ NAT port forwarding publishes TCP or UDP ports of a private network's NAT public address on
1128
+ servers of that network. Read `get_network_port_forwards` first (rules, the router generation, per-rule
1129
+ exposure and eligible targets); `set_network_port_forwards` replaces the complete rule set at that
1130
+ generation, and an empty list withdraws every rule. A target is a Firecracker server of the network: one
1131
+ without a public IPv4 of its own, or the private interface of one that has its own public IPv4 (its replies
1132
+ go back through the network; the target's `reply_route` says whether that is in place). Cloud VPS servers
1133
+ are not targets. Security groups still decide what a server accepts.
1134
+ Poll the rules resource until `applied_generation` equals `generation`.
1135
+
1136
+ The firewall of a server's own public interface (VPS and Cloud VPS, IPv4 and IPv6 incoming allow
1137
+ rules) is read with `get_service_public_firewall` and replaced as a whole with
1138
+ `set_service_public_firewall` at the read `generation`; `apply_service_public_firewall` sends the
1139
+ saved rules to the node again. Keep the management port (SSH, or RDP on Windows) open for the user's
1140
+ own address and ask the user for that address: `client_address` in the answer is only the address
1141
+ the API saw for the request. Over the hosted connector, network changes act only on servers selected for the connection (`service_not_selected` otherwise).
1142
+
1143
+ `set_public_address_outgoing_source` makes an additional address attached to a VPS's public interface
1144
+ the source of the server's new outgoing IPv4 connections (or switches back to the server's own IP);
1145
+ `recheck_public_address_outgoing_source` asks a server again after an address left it.
1146
+ Reverse DNS of an additional address, a floating binding, a VPN's or a public load balancer's
1147
+ address uses `get_public_ip_rdns`, `set_public_ip_rdns` and `reset_public_ip_rdns` with a `target`
1148
+ field; a server's own primary address keeps `get_rdns` / `change_rdns`.
1149
+ `rebuild_network_load_balancer` rebuilds a public load balancer's proxies one at a time.
1150
+
1151
+ An owned public address can also go directly onto the public interface of a server that has its own
1152
+ public IPv4 (`attach_public_address_to_server_interface`), only while `get_networking_capabilities`
1153
+ reports `public_address_server_public` as true; the tool reads that first and refuses without a change
1154
+ otherwise. Pick the server from `list_public_address_server_targets`, then follow the attachment on
1155
+ `get_network_public_address` (`target.kind=server_public`,
1156
+ `carrier.node_state`, `carrier.guest_state`, `carrier.instruction`). When the server agent is off the
1157
+ instruction is what the customer runs inside the server; `check_network_public_address_reach` asks again.
1158
+
1159
+ This release exposes no customer network rename or existing-port fixed-IP edit. Fixed DHCP
1110
1160
  addresses are selected at attach; removing/recreating an attachment requires
1111
1161
  separate approval and is not represented as an in-place edit. Legacy unpaid
1112
1162
  LB/VPN create routes, legacy stock-before-payment purchases and enabling
@@ -1133,6 +1183,9 @@ feature gate.
1133
1183
  | `set_private_network_names` | Replace the complete internal DNS zone label and alias list | `networking:manage` | free |
1134
1184
  | `list_private_network_ports` | Read owned network ports, their fixed DHCP addresses, generations and attachment states | `networking:read` | free |
1135
1185
  | `list_service_private_ports` | Read private ports and order attachment recovery state for one owned service order number. | `networking:read` | free |
1186
+ | `get_service_public_firewall` | Read the firewall of a server's public interface (VPS or Cloud VPS): rules, generation and state | `networking:read` | free |
1187
+ | `set_service_public_firewall` | Switch the server's public firewall on or off and replace all its incoming rules at the read generation | `networking:manage` | free |
1188
+ | `apply_service_public_firewall` | Send the saved firewall rules to the server's node again | `networking:manage` | free |
1136
1189
  | `list_network_attachment_candidates` | Read attachable services and each attachment_mode | `networking:read` | free |
1137
1190
  | `attach_private_network_port` | Attach an owned service; omit ipv4 for automatic allocation or pass a fixed usable address | `networking:manage` | free |
1138
1191
  | `detach_private_network_port` | Detach the owned server port | `networking:manage` | free |
@@ -1140,6 +1193,8 @@ feature gate.
1140
1193
  | `get_network_vpn_summary` | Read the network's VPN summary, including truthful absence; connected locations are managed on the gateway | `networking:read` | free |
1141
1194
  | `get_network_routed_egress` | Read this network's NAT/internet access, public address and qualification state. | `networking:read` | free |
1142
1195
  | `set_network_routed_egress` | Request the currently supported NAT transition for an owned network; the backend may refuse mode changes | `networking:manage` | free |
1196
+ | `get_network_port_forwards` | Read the NAT port forwarding rules of an owned private network: applied rules (protocol, external_port on the network's NAT public address, the target server's private_port_id and its internal_port), the router generation to send to set_network_port_forwards (not the network generation), state (empty, pending, active, failed), per-rule exposure (open_to_internet is true when the server's security groups admit that port from every IPv4 address), targets with eligible and unavailable_reason_code, capability (available, limit, protocols), last_change (a refused change with its nat_port_forward_refused_* reason_code) and suspended (rules kept while the network has no NAT address; they are on no router). | `networking:read` | free |
1197
+ | `set_network_port_forwards` | Replace the COMPLETE NAT port forwarding rule set of an owned network (rules: [] withdraws all of them) at the router generation read from get_network_port_forwards. | `networking:manage` | free |
1143
1198
  | `get_security_group_capabilities` | Read security-group availability and whether the network default policy can be changed. | `networking:read` | free |
1144
1199
  | `list_network_security_groups` | List groups in the owned project | `networking:read` | free |
1145
1200
  | `create_network_security_group` | Create a named allow-rule set | `networking:manage` | free |
@@ -1163,6 +1218,7 @@ feature gate.
1163
1218
  | `remove_network_load_balancer_member` | Remove a member from rotation using the load balancer generation. | `networking:manage` | free |
1164
1219
  | `add_network_load_balancer_listener` | Add a listener and optional initial members using currently offered protocol capabilities | `networking:manage` | free |
1165
1220
  | `remove_network_load_balancer_listener` | Remove a listener and its members; deleting the last listener is refused. | `networking:manage` | free |
1221
+ | `rebuild_network_load_balancer` | Rebuild every proxy of a public load balancer, one at a time, keeping its address and listeners | `networking:manage` | free |
1166
1222
  | `list_network_vpn_gateways` | List owned VPN gateways, their device peers and safe status | `networking:read` | free |
1167
1223
  | `get_network_vpn_gateway` | Read one owned VPN gateway, protocol-specific peer status, IPsec capabilities/profiles, device grant scopes and site options | `networking:read` | free |
1168
1224
  | `delete_network_vpn_gateway` | Request teardown of an owned VPN gateway; all devices lose connectivity | `networking:manage` | free |
@@ -1172,13 +1228,16 @@ feature gate.
1172
1228
  | `create_network_vpn_peer` | Add a device, or a connected location (site-to-site office router), with an externally generated one-time PUBLIC reveal key | `networking:manage` | free |
1173
1229
  | `take_network_vpn_peer_config` | Consume the device's sealed configuration ONCE | `networking:manage` | free |
1174
1230
  | `revoke_network_vpn_peer` | Revoke one device using the VPN GATEWAY generation | `networking:manage` | free |
1175
- | `set_network_vpn_peer_grants` | Replace the device's complete reachable-server list when standalone VPN is available | `networking:manage` | free |
1231
+ | `set_network_vpn_peer_grants` | Replace a device or site's complete individual-server or network-wide access choice | `networking:manage` | free |
1176
1232
  | `get_network_vpn_egress_options` | Read supported VPN Internet exits and qualification | `networking:read` | free |
1177
1233
  | `set_network_vpn_peer_egress` | Set a device's private-only, inherited NAT, or advertised chosen exit policy | `networking:manage` | free |
1178
1234
  | `get_network_vpn_peer_recipe` | Read public IPsec router instructions with a PSK placeholder; no secret retrieval | `networking:read` | free |
1179
1235
  | `get_network_vpn_peer_history` | Read a device's or connected location's traffic and handshake history (24 h raw, 7 d, 30 d, 13 months) | `networking:read` | free |
1180
1236
  | `set_network_vpn_site_options` | Switch hub-and-spoke between the locations connected to a VPN | `networking:manage` | free |
1181
1237
  | `set_network_vpn_site_alert` | Switch the office-down e-mail of one connected location | `networking:manage` | free |
1238
+ | `list_network_vpn_site_health_webhooks` | List a site's signed health subscriptions and last delivery outcomes; URLs show public hosts only | `networking:read` | free |
1239
+ | `create_network_vpn_site_health_webhook` | Create a signed site health subscription with an external X25519 reveal public key; returns sealed signing material | `networking:manage` | free |
1240
+ | `delete_network_vpn_site_health_webhook` | Remove a site's subscription and cancel pending deliveries | `networking:manage` | free |
1182
1241
  | `set_network_site_route_mode` | Choose DHCP routes or an internal router for a network's routes to connected locations | `networking:manage` | free |
1183
1242
  | `list_network_products` | Read current paid products, live tier names, prices and purchase capability; public proxy load balancer 3/5-node offerings must come from this catalog. | `networking:read` | free |
1184
1243
  | `list_network_product_periods` | Read owned product periods, renewal availability and lifecycle facts. | `networking:read` | free |
@@ -1198,6 +1257,14 @@ feature gate.
1198
1257
  | `quote_network_public_address` | Quote a new paid public address for common checkout; no charge | `networking:manage` | Quote: `networking:order` |
1199
1258
  | `attach_public_address_to_network` | Attach or move an already-paid address to an owned network's NAT | `networking:manage` | free |
1200
1259
  | `attach_public_address_to_server` | Attach or move an owned paid public address to an eligible zero-public-IP server's private port | `networking:manage` | free |
1260
+ | `list_public_address_server_targets` | Search and page the account's servers as targets for attach_public_address_to_server_interface. | `networking:read` | free |
1261
+ | `attach_public_address_to_server_interface` | Attach an owned paid public address directly to the public interface of a server that has its own public IPv4 (service_id from list_public_address_server_targets with eligible true). | `networking:manage` | free |
1262
+ | `check_network_public_address_reach` | Ask again whether an owned public address attached to a server's public interface is reachable from the internet, and ask the server's own step again (for example after the server agent was started). | `networking:manage` | free |
1263
+ | `set_public_address_outgoing_source` | Use an additional address on a VPS's public interface for the server's new outgoing IPv4 connections, or switch back | `networking:manage` | free |
1264
+ | `recheck_public_address_outgoing_source` | Ask a server again to put its outgoing source back on its own IP | `networking:manage` | free |
1265
+ | `get_public_ip_rdns` | Read the reverse DNS of an additional, floating, VPN or load-balancer address (`target`) | `networking:read` | free |
1266
+ | `set_public_ip_rdns` | Set the reverse DNS hostname of such an address at its revision | `networking:manage` | free |
1267
+ | `reset_public_ip_rdns` | Remove the custom reverse DNS of such an address | `networking:manage` | free |
1201
1268
  | `detach_network_public_address` | Detach an owned public address from its current target; it stays owned for the paid period | `networking:manage` | free |
1202
1269
  | `quote_public_address_renewal` | Quote the address's next month without charging; use the returned quote and this key for confirmation. | `networking:manage` | Quote: `networking:order` |
1203
1270
  | `renew_network_public_address` | Pay the approved address renewal from balance with its exact quote ID/token and original key. | `networking:manage` | Paid: `networking:order` |
@@ -1205,9 +1272,32 @@ feature gate.
1205
1272
  | `get_network_public_binding` | Read one existing owned public binding's generation, state and assigned address | `networking:read` | free |
1206
1273
  | `bind_network_public_ip` | Bind an already reserved floating public binding to an owned private port when supported | `networking:manage` | free |
1207
1274
  | `move_network_public_ip` | Move a prepared floating public binding to another owned private port; confirm interruption to the old target. | `networking:manage` | free |
1208
- | `configure_network_public_forwarding` | Configure an existing reserved forwarding binding's TCP/UDP listeners | `networking:manage` | free |
1209
1275
  | `delete_network_public_binding` | Request deletion of an existing binding using its generation | `networking:manage` | free |
1210
1276
 
1277
+ ### VPN gateways and sites (more)
1278
+ | Tool | Description | Scope | Paid |
1279
+ |------|-------------|-------|------|
1280
+ | `restart_network_vpn_gateway` | Restart the owned VPN VM in place. | `networking:manage` | free |
1281
+ | `rebuild_network_vpn_gateway` | Rebuild the owned VPN VM with its existing address and devices. | `networking:manage` | free |
1282
+ | `set_network_vpn_internet_exit` | Choose none, the VPN's own IPv4, or its attached network NAT as Internet exit. | `networking:manage` | free |
1283
+ | `take_network_vpn_site_line_config` | Consume the second IPsec line's sealed key exactly once with line=2. | `networking:manage` | free |
1284
+ | `rotate_network_vpn_ipsec_key` | Rotate an IPsec site's pre-shared key. | `networking:manage` | free |
1285
+ | `save_network_vpn_router_setup` | Save nonsecret backend-catalogue router version and local interface/zone fields for an IPsec site, optionally line 2. | `networking:manage` | free |
1286
+ | `set_network_vpn_site_bgp` | Enable or change BGP over an eligible IPsec site using the gateway generation. | `networking:manage` | free |
1287
+ | `add_network_vpn_site_line` | Add line 2 to an IPsec site using the gateway generation and an external X25519 public reveal key. | `networking:manage` | free |
1288
+ | `set_network_vpn_site_main_line` | Choose line 1 or 2 as the main IPsec line using the gateway generation; optional DPD applies to both. | `networking:manage` | free |
1289
+ | `remove_network_vpn_site_second_line` | Remove line 2 using the gateway generation. | `networking:manage` | free |
1290
+ | `start_network_vpn_tunnel_test` | Start a backend tunnel test for a site or supported WireGuard peer; optional line selects 1 or 2. | `networking:manage` | free |
1291
+ | `get_network_vpn_tunnel_test` | Read one owned tunnel test by its returned ID; while running, poll no faster than the backend's one-second guidance. | `networking:read` | free |
1292
+ | `set_network_vpn_site_reach` | Set this site's load-balancer/floating-IP reach choice, or null to follow its VPN default. | `networking:manage` | free |
1293
+
1294
+ | `rename_network_vpn_gateway` | Rename an owned VPN's customer label. | `networking:manage` | free |
1295
+ | `update_network_vpn_gateway_image` | Apply the backend-qualified reviewed VPN image in place. | `networking:manage` | free |
1296
+ | `check_network_vpn_public_access` | Preview the complete VPN public-source lists without applying them. | `networking:read` | free |
1297
+ | `set_network_vpn_public_access` | Replace the complete WireGuard/IPsec public-source lists at the VPN gateway generation. | `networking:manage` | free |
1298
+ | `set_network_vpn_ipsec_tuning` | Replace an IPsec site's advanced tunnel choices using the gateway generation. | `networking:manage` | free |
1299
+ | `quote_network_vpn_traffic_pack` | Quote a traffic pack for this owned VPN using an offered tier from get_network_vpn_gateway traffic. | `networking:manage` | Quote: `networking:order` |
1300
+
1211
1301
  <!-- tool-reference:end -->
1212
1302
 
1213
1303
  ## Worked examples
@@ -1285,12 +1375,19 @@ at the location given by `zone.verification.next_step`, then call
1285
1375
 
1286
1376
  ## Getting an API key
1287
1377
 
1288
- 1. Log in at [vpsnet.com](https://www.vpsnet.com)
1289
- 2. Go to **Account** > **API Keys**
1290
- 3. Click **Create API Key**
1291
- 4. Give it a name and copy the key
1378
+ 1. Log in at [vpsnet.com](https://www.vpsnet.com) and open **Account** > **API Keys**:
1379
+ <https://www.vpsnet.com/en/management/account/api-keys>
1380
+ 2. Click **Create API Key**
1381
+ 3. Give it a name, choose the access level and, for network tools, add `networking:read`
1382
+ or `networking:manage` (they are never included by default)
1383
+ 4. Copy the key
1384
+
1385
+ The key is shown only once — store it securely. The full API description is
1386
+ <https://www.vpsnet.com/openapi-v1.yml>.
1292
1387
 
1293
- The key is shown only once — store it securely.
1388
+ To use ChatGPT, Claude, Gemini or Grok without an API key, connect the hosted
1389
+ connector instead; connections are created and managed in **Account** > **AI connections**:
1390
+ <https://www.vpsnet.com/en/management/account/ai-connections>.
1294
1391
 
1295
1392
  ## Troubleshooting
1296
1393
 
@@ -1343,18 +1440,18 @@ Malformed or oversized URL identifiers are rejected before an API request.
1343
1440
  |---|---|---|
1344
1441
  | `aiScopedApiKeyCannotManageAccount` (403) | The key is an **AI-scoped key**. Those are issued only for VPSnet AI assistant inference and are deliberately refused on the entire account API. Granting scopes cannot change this — the restriction is on the key type. | Create a separate key with scope `full` (or `read` for GET-only use) and use that here. Keep the AI-scoped key for inference. |
1345
1442
  | `apiKeyRejected` (401) | The key failed authentication outright. The API returns one identical 401 for every cause, so it is one of: unknown, revoked, expired, malformed, or your source IP is not on the key's IP allowlist. | Check the key is active and copied whole, and that any IP allowlist includes the address this server calls from. |
1346
- | `readOnlyApiKeyCannotWrite` (401) | A read-scoped key was used for a write; read keys are limited to GET. | Use a full-scope key, or stay on read-only tools. |
1347
- | `apiKeyScopeMissing` (403) | The key authenticated but lacks the granular scope named in `requiredScope`. | Add that scope in Account > API Keys. |
1443
+ | `readOnlyApiKeyCannotWrite` (403) | A read-scoped key was used for a write; read keys are limited to GET. | Use a full-scope key, or stay on read-only tools. |
1444
+ | `apiKeyScopeMissing` (403) | The key authenticated but lacks the granular scope named in `requiredScope`. | Add that scope in Account > API Keys (https://www.vpsnet.com/en/management/account/api-keys). |
1348
1445
  | `apiKeyForbidden` (403) | The endpoint refuses API keys entirely. API keys never grant admin access. | Use the panel with a signed-in session. |
1349
1446
 
1350
1447
  - Verify the key is correct (starts with `vpsnet_` followed by 43 characters)
1351
1448
  - Keys are shown only once at creation — if lost, create a new one
1352
- - Check that the key hasn't expired (Account > API Keys)
1449
+ - Check that the key hasn't expired (Account > API Keys: https://www.vpsnet.com/en/management/account/api-keys)
1353
1450
 
1354
1451
  ### `deploy_ssh_key` succeeded but SSH still fails
1355
1452
 
1356
1453
  - All VPSnet.com servers use `root` as the SSH username
1357
- - Key deployment is async — wait 15-30 seconds after deploying before attempting SSH
1454
+ - Key deployment is asynchronous: follow the returned noty UUID with `wait_for_event` until it reports completed before attempting SSH
1358
1455
 
1359
1456
  ### `fetch is not defined` or unexpected errors
1360
1457
 
@@ -1,3 +1,4 @@
1
+ import { unboundedInteger } from './tool-schema.js';
1
2
  import { z } from "zod";
2
3
  export const applicationLogTailLinesSchema = z
3
4
  .number()
@@ -32,7 +33,7 @@ export const applicationActionSchema = z
32
33
  .describe("Supported lifecycle action. Update and rollback apply the exact backend-advertised immutable release. Selective data restore is a separate revision-bound operation.");
33
34
  export const applicationActionIdSchema = z
34
35
  .string()
35
- .uuid()
36
+ .guid()
36
37
  .describe("Exact action UUID from the current installation latest_action.id");
37
38
  export const applicationExpectedVersionSchema = z
38
39
  .string()
@@ -82,7 +83,7 @@ const externalHttpsUrlSchema = z.string().max(500).refine((value) => {
82
83
  * app-additional-addresses-design-1005 section 2.3.
83
84
  */
84
85
  export const applicationAdditionalAddressSchema = z.object({
85
- zone_id: z.number().int().min(1),
86
+ zone_id: unboundedInteger().min(1),
86
87
  name: z
87
88
  .string()
88
89
  .max(190)
@@ -97,7 +98,7 @@ export const applicationSingleAccessSchema = z.discriminatedUnion("mode", [
97
98
  z.object({ mode: z.literal("external_https"), url: externalHttpsUrlSchema }).strict(),
98
99
  z.object({
99
100
  mode: z.literal("managed_https"),
100
- zone_id: z.number().int().positive(),
101
+ zone_id: unboundedInteger().positive(),
101
102
  subdomain: z
102
103
  .string()
103
104
  .max(190)
@@ -192,11 +193,11 @@ export function applicationResourceThresholdRequestBody(input) {
192
193
  }
193
194
  export const applicationDataRestorePointIdSchema = z
194
195
  .string()
195
- .uuid()
196
+ .guid()
196
197
  .describe("Opaque eligible backup-point UUID returned by list_application_restore_points");
197
198
  export const applicationDataRestoreIdSchema = z
198
199
  .string()
199
- .uuid()
200
+ .guid()
200
201
  .describe("Opaque selective restore UUID returned by restore_application_data");
201
202
  export const applicationDataRestoreQuoteTokenSchema = z
202
203
  .string()
@@ -17,7 +17,7 @@ function message(data) {
17
17
  const raw = record(data).message;
18
18
  return typeof raw === "string" ? raw : "";
19
19
  }
20
- const MANAGEMENT_KEY_FIX = "Create a management API key in the VPSnet panel under Account > API Keys "
20
+ const MANAGEMENT_KEY_FIX = "Create a management API key in the VPSnet panel under Account > API Keys (https://www.vpsnet.com/en/management/account/api-keys) "
21
21
  + "(scope 'full', or 'read' if you only need GET reads) and set it as "
22
22
  + "VPSNET_API_KEY. A key is 'vpsnet_' followed by 43 characters.";
23
23
  /**
@@ -74,8 +74,8 @@ export function explainAuthFailure(status, data) {
74
74
  ? `The API key authenticated successfully but is missing the '${required}' scope.`
75
75
  : "The API key authenticated successfully but is missing a scope this endpoint requires.",
76
76
  fix: required
77
- ? `Add the '${required}' scope to the key in Account > API Keys, or use a key that already has it.`
78
- : "Grant the endpoint's scope to the key in Account > API Keys.",
77
+ ? `Add the '${required}' scope to the key in Account > API Keys (https://www.vpsnet.com/en/management/account/api-keys), or use a key that already has it.`
78
+ : "Grant the endpoint's scope to the key in Account > API Keys (https://www.vpsnet.com/en/management/account/api-keys).",
79
79
  };
80
80
  }
81
81
  if (payload.apiKeyForbidden === true) {
@@ -105,7 +105,7 @@ export function explainAuthFailure(status, data) {
105
105
  + "not exist, was revoked, has expired, is malformed, or your source "
106
106
  + "IP is not on the key's IP allowlist. Note this is NOT the "
107
107
  + "AI-scoped-key case, which returns 403 with its own message.",
108
- fix: "Check the key in Account > API Keys: confirm it is active, unexpired, "
108
+ fix: "Check the key in Account > API Keys (https://www.vpsnet.com/en/management/account/api-keys): confirm it is active, unexpired, "
109
109
  + "copied whole, and that any IP allowlist on it includes the address "
110
110
  + "this server calls from. " + MANAGEMENT_KEY_FIX,
111
111
  };
@@ -113,7 +113,7 @@ export function explainAuthFailure(status, data) {
113
113
  return {
114
114
  code: "apiKeyForbiddenUnclassified",
115
115
  reason: "The account API refused this request for the authenticated key.",
116
- fix: "Check the key's scopes and access settings in Account > API Keys.",
116
+ fix: "Check the key's scopes and access settings in Account > API Keys (https://www.vpsnet.com/en/management/account/api-keys).",
117
117
  };
118
118
  }
119
119
  /**
@@ -1,11 +1,11 @@
1
1
  import { z } from "zod";
2
2
  export const customProjectIdSchema = z
3
3
  .string()
4
- .uuid()
4
+ .guid()
5
5
  .describe("Customer-owned recipe project UUID returned by list_application_recipes");
6
6
  export const composeAdoptionIdSchema = z
7
7
  .string()
8
- .uuid()
8
+ .guid()
9
9
  .describe("Opaque Compose adoption UUID returned by the prepare operation");
10
10
  export const composeProjectLabelSchema = z
11
11
  .string()
@@ -45,7 +45,7 @@ export const customProjectSecretNamesSchema = z
45
45
  .default([])
46
46
  .describe("Secret variable names only; definitions and exports never contain values");
47
47
  export const customProjectRegistryCredentialIdsSchema = z
48
- .array(z.string().uuid())
48
+ .array(z.string().guid())
49
49
  .max(8)
50
50
  .refine((ids) => new Set(ids).size === ids.length, {
51
51
  message: "Registry credential IDs must be unique",
@@ -22,7 +22,7 @@ export const fileBrowsePointIdSchema = z
22
22
  .describe("Backup point ID returned by list_restore_file_points");
23
23
  export const fileBrowseIdSchema = z
24
24
  .string()
25
- .uuid()
25
+ .guid()
26
26
  .describe("Browse UUID returned by browse_restore_files");
27
27
  export const fileBrowseDirectoryEntryIdSchema = z
28
28
  .string()