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 +124 -27
- package/build/application-contract.js +6 -5
- package/build/auth-failure.js +5 -5
- package/build/custom-project-contract.js +3 -3
- package/build/file-restore-contract.js +1 -1
- package/build/index.js +55 -22
- package/build/networking-tools.js +400 -47
- package/build/remote-orders.js +7 -6
- package/build/remote-policy.js +2 -2
- package/build/remote-tools.js +1 -1
- package/build/scope-catalog.js +8 -8
- package/build/service-files.js +3 -2
- package/build/service-rescue-contract.js +1 -1
- package/build/tool-schema.js +16 -3
- package/build/update-info.js +1 -1
- package/package.json +2 -2
package/build/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { installToolInputSchemas } from "./tool-schema.js";
|
|
2
|
+
import { installToolInputSchemas, unboundedInteger } from "./tool-schema.js";
|
|
3
3
|
import { createDnsZoneDescription } from "./dns-zone-contract.js";
|
|
4
4
|
import { registerOrderTools } from "./remote-orders.js";
|
|
5
5
|
import { registerRemoteTools } from "./remote-tools.js";
|
|
@@ -50,9 +50,9 @@ export function createVpsnetServer(options = {}) {
|
|
|
50
50
|
instructions: options.remoteScopes ? (options.remoteProfile === "orders" ? orderInstructions(options.remoteScopes) : remoteInstructions) : [
|
|
51
51
|
"This MCP server controls VPSnet.com services, including VPS service management, DNS zones, domain registration, domain contacts, API keys, billing, and related paid actions.",
|
|
52
52
|
"Use the tool descriptions and API-key scopes to choose the correct surface; do not assume this server is limited to VPS-only operations.",
|
|
53
|
-
"Auth: every request authenticates with the X-API-KEY header (your VPSNet API key).
|
|
53
|
+
"Auth: every request authenticates with the X-API-KEY header (your VPSNet API key). Each API key may make 300 requests per 60 seconds by default, and some operations have lower limits; on HTTP 429 wait the retry_after seconds given in the result (the API also sends Retry-After) before retrying.",
|
|
54
54
|
"This server needs a MANAGEMENT API key (scope full, or read for GET-only use). An AI-scoped key is issued only for VPSnet AI assistant inference and is refused on every account route, so no tool here can work with one. When a tool result carries auth_problem, read its reason and fix and relay them instead of reporting a bare 'Unauthorized'.",
|
|
55
|
-
"Service tools are scope-gated for API keys: service reads (lists, details, graphs, history, options, backup/snapshot/restore-point listings) require services:read; service mutations (start/stop/restart/console, suspend/resume, hostname, rDNS, root password, title, IPv6, extra settings, SSH key deploy, OS reinstall, plan change, renewal, auto-renew, backups, snapshots, firewall flush) require services:manage plus a full-access key; rescue requires services:rescue; paid whole-service restore additionally requires the services:restore paid scope. A key whose granular scope list was left empty keeps everything its access level (full/read) already allows,
|
|
55
|
+
"Service tools are scope-gated for API keys: service reads (lists, details, graphs, history, options, backup/snapshot/restore-point listings) require services:read; service mutations (start/stop/restart/console, suspend/resume, hostname, rDNS, root password, title, IPv6, extra settings, SSH key deploy, OS reinstall, plan change, renewal, auto-renew, backups, snapshots, firewall flush) require services:manage plus a full-access key; rescue requires services:rescue; paid whole-service restore additionally requires the services:restore paid scope. A key whose granular scope list was left empty keeps everything its access level (full/read) already allows, except the permissions that must be added to a key on purpose: networking:read/manage (private networks, the server firewall, port forwarding, public addresses, load balancers, VPN), files:read/manage and the App Cloud permissions. An older full key without a permission list therefore reaches no networking tool until networking:read or networking:manage is added.",
|
|
56
56
|
"Service file manager tools (get_service_file_capabilities, list/stat/read/search, download/upload, write, mkdir, move, delete, extract) need an EXPLICIT files:read or files:manage grant on the API key (an empty permission list does not include them; changes need a full-access key). Call get_service_file_capabilities first and relay an unavailable reason verbatim: Firecracker servers need the updated guest agent (agent_update_required) and Cloud VPS (KVM) needs the VDS file-manager switch (feature_disabled). Writes are compare-and-swap: pass the version or sha256 you read. Slow guests are polled inside the tools; continue a returned operationId with get_service_file_operation instead of repeating a change.",
|
|
57
57
|
"",
|
|
58
58
|
"## Ordering a new VPS",
|
|
@@ -64,7 +64,8 @@ export function createVpsnetServer(options = {}) {
|
|
|
64
64
|
"rootPassword rules: 6-40 chars, alphanumeric only, MUST contain uppercase + lowercase + digit. Example: 'MyPass123'.",
|
|
65
65
|
"sshKey and rootPassword are mutually exclusive — provide one or the other (or neither for auto-generated password).",
|
|
66
66
|
"A paid receipt is not a running server. Read get_service for the original order and follow follow_up: pending activation, finalization and capacity waits require polling the same order. About 10 seconds is a suggested polling interval, never a boot ETA. Check at most 6 times before a progress update; if still pending, retain the key and order number for a later check. Do not reorder, repay, restart or promise a background callback. A running VM, guest access and a healthy application are separate outcomes; KVM and Windows setup may take longer and must be observed.",
|
|
67
|
-
"deploy_ssh_key is
|
|
67
|
+
"deploy_ssh_key is asynchronous: follow its noty UUID with wait_for_event until it reports completed before attempting SSH to any server (not just new ones).",
|
|
68
|
+
"Without an API key, ChatGPT, Claude, Gemini and Grok can use the hosted connector https://mcp.vpsnet.com/mcp instead (OAuth sign-in to the VPSnet account; the customer picks the servers and permissions). Connections are created and removed on https://www.vpsnet.com/en/management/account/ai-connections; API keys are made on https://www.vpsnet.com/en/management/account/api-keys.",
|
|
68
69
|
"",
|
|
69
70
|
"## Deployment capabilities (unordered)",
|
|
70
71
|
"Managed Applications, manual SSH, DNS, APIs, and other tools are peer capabilities. Their order in this prompt or the tool list carries no priority. Choose the path that best matches the user's requested outcome, target support, existing state, and explicit constraints.",
|
|
@@ -87,7 +88,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
87
88
|
"Installation list and detail responses carry a capabilities block for the service's platform: data_restore, console, compose_adoption, custom_projects, and log_service_filter. Treat it as the authority on what is possible for that installation. Do not offer selective data restore when data_restore is false, do not offer Compose adoption or customer recipes when their flags are false, and do not pass a per-service log filter when log_service_filter is false. A separate access.capabilities.can_configure flag governs whether the access mode may be changed.",
|
|
88
89
|
"Never repeat application variable values in summaries or approval text. Refer only to variable names, especially for passwords, tokens, and secrets.",
|
|
89
90
|
"Use manual SSH deployment when it best matches the requested result or the user explicitly requests a custom installation. Do not present a manual deployment as a VPSnet-managed catalog installation.",
|
|
90
|
-
"Service rescue is a separate recovery path for Firecracker VPS and Cloud VPS. Always call get_service_rescue first. Entering rescue restarts the service; call enter_service_rescue only after the user explicitly approves the restart and exact image returned by the capability response. Firecracker exposes the customer filesystem at /mnt/customer; Cloud VPS uses the operator recovery ISO and noVNC. Exit restores the exact original boot and running/stopped state. If exit returns needs_attention, retry exit_service_rescue with the same idempotency key. Never ask for or invent provider nodes, VM IDs, ISO paths, operation nonces, or rollback configuration.",
|
|
91
|
+
"Service rescue is a separate recovery path for Firecracker VPS and Cloud VPS, offered only while VPSnet has it switched on. Always call get_service_rescue first; capability.enabled false means it is not offered now. Entering rescue restarts the service; call enter_service_rescue only after the user explicitly approves the restart and exact image returned by the capability response. Firecracker exposes the customer filesystem at /mnt/customer; Cloud VPS uses the operator recovery ISO and noVNC. Exit restores the exact original boot and running/stopped state. If exit returns needs_attention, retry exit_service_rescue with the same idempotency key. Never ask for or invent provider nodes, VM IDs, ISO paths, operation nonces, or rollback configuration.",
|
|
91
92
|
"",
|
|
92
93
|
"### Manual or custom deployment inside a VPS",
|
|
93
94
|
"Use only the access needed for the user's task. Keep local sandbox and approval controls enabled; request a specific missing capability instead of unrestricted agent access.",
|
|
@@ -228,7 +229,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
228
229
|
const applicationOrderNoSchema = serviceOrderNoSchema;
|
|
229
230
|
const applicationInstallationIdSchema = z
|
|
230
231
|
.string()
|
|
231
|
-
.
|
|
232
|
+
.guid()
|
|
232
233
|
.describe("Managed application installation UUID");
|
|
233
234
|
const applicationSlugSchema = z
|
|
234
235
|
.string()
|
|
@@ -436,7 +437,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
436
437
|
return { content: [{ type: "text", text: formatJson(data) }] };
|
|
437
438
|
});
|
|
438
439
|
server.registerTool("get_service_rescue", {
|
|
439
|
-
description: "Get operator rescue capability and the current durable rescue session for one owned Firecracker VPS or Cloud VPS. Requires services:read. Provider identifiers, ISO paths, nonces, and rollback state are never returned.",
|
|
440
|
+
description: "Get operator rescue capability and the current durable rescue session for one owned Firecracker VPS or Cloud VPS. Requires services:read. Provider identifiers, ISO paths, nonces, and rollback state are never returned. VPSnet can switch rescue off: capability.enabled false means it is not offered now; say so and do not call enter_service_rescue.",
|
|
440
441
|
inputSchema: {
|
|
441
442
|
orderNo: serviceOrderNoSchema,
|
|
442
443
|
},
|
|
@@ -456,7 +457,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
456
457
|
};
|
|
457
458
|
});
|
|
458
459
|
server.registerTool("enter_service_rescue", {
|
|
459
|
-
description: "Restart one owned active Firecracker VPS or Cloud VPS into an operator-owned rescue system. Read get_service_rescue first and use an exact advertised image ID. This interrupts every running service. Call only after the user explicitly confirms the target service, rescue image, and reboot. Requires services:rescue, full API-key access, and a fresh idempotencyKey.",
|
|
460
|
+
description: "Restart one owned active Firecracker VPS or Cloud VPS into an operator-owned rescue system. Read get_service_rescue first and use an exact advertised image ID. This interrupts every running service. Call only after the user explicitly confirms the target service, rescue image, and reboot. Requires services:rescue, full API-key access, and a fresh idempotencyKey. Rescue may be switched off by VPSnet: while get_service_rescue reports capability.enabled false this tool sends nothing and answers serviceRescueImageNotAdvertised (the API itself answers 503 serviceRescueUnavailable).",
|
|
460
461
|
inputSchema: {
|
|
461
462
|
orderNo: serviceOrderNoSchema,
|
|
462
463
|
image: serviceRescueImageIdSchema,
|
|
@@ -507,7 +508,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
507
508
|
orderNo: serviceOrderNoSchema,
|
|
508
509
|
rescue_session_id: z
|
|
509
510
|
.string()
|
|
510
|
-
.
|
|
511
|
+
.guid()
|
|
511
512
|
.describe("Exact current session UUID from get_service_rescue"),
|
|
512
513
|
acknowledge_restart: z
|
|
513
514
|
.literal(true)
|
|
@@ -811,7 +812,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
811
812
|
inputSchema: {
|
|
812
813
|
orderNo: applicationOrderNoSchema,
|
|
813
814
|
installation_id: applicationInstallationIdSchema,
|
|
814
|
-
inspection_id: z.string().
|
|
815
|
+
inspection_id: z.string().guid(),
|
|
815
816
|
kind: z.enum(["health", "logs"]),
|
|
816
817
|
},
|
|
817
818
|
annotations: { title: "Get application inspection", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
@@ -825,7 +826,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
825
826
|
});
|
|
826
827
|
server.registerTool("get_application_recipe_validation", {
|
|
827
828
|
description: "Poll the exact persisted customer recipe validation returned by validate_application_recipe or a pending recipe creation/revision. This GET does not resolve tags or create another validation. Retain the initial resolved_compose_yaml; after this ID succeeds with valid=true, resume creation using that exact pinned document and validation_id. Requires applications:read.",
|
|
828
|
-
inputSchema: { orderNo: applicationOrderNoSchema, validation_id: z.string().
|
|
829
|
+
inputSchema: { orderNo: applicationOrderNoSchema, validation_id: z.string().guid() },
|
|
829
830
|
annotations: { title: "Get application recipe validation", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
830
831
|
}, async ({ orderNo, validation_id }) => {
|
|
831
832
|
const { status, data } = await apiRequest("GET", applicationPath(orderNo, `custom-projects/validations/${encodeURIComponent(validation_id)}`));
|
|
@@ -836,7 +837,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
836
837
|
});
|
|
837
838
|
server.registerTool("get_service_container_discovery", {
|
|
838
839
|
description: "Poll the exact persisted service container discovery returned by discover_service_containers when it remains pending. This GET does not create another discovery and never returns environment values or mounts. Keep the service and discovery UUID until succeeded, failed or expired. Requires applications:read.",
|
|
839
|
-
inputSchema: { orderNo: applicationOrderNoSchema, discovery_id: z.string().
|
|
840
|
+
inputSchema: { orderNo: applicationOrderNoSchema, discovery_id: z.string().guid() },
|
|
840
841
|
annotations: { title: "Get service container discovery", readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
841
842
|
}, async ({ orderNo, discovery_id }) => {
|
|
842
843
|
const { status, data } = await apiRequest("GET", applicationPath(orderNo, `container-discoveries/${encodeURIComponent(discovery_id)}`));
|
|
@@ -1100,7 +1101,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
1100
1101
|
orderNo: applicationOrderNoSchema,
|
|
1101
1102
|
name: customProjectNameSchema,
|
|
1102
1103
|
compose_yaml: customProjectComposeSchema,
|
|
1103
|
-
validation_id: z.string().
|
|
1104
|
+
validation_id: z.string().guid().optional().describe("Resume only the exact successful validation for this service and digest-pinned compose_yaml; retain the initial resolved document"),
|
|
1104
1105
|
env: customProjectEnvironmentSchema,
|
|
1105
1106
|
secret_names: customProjectSecretNamesSchema,
|
|
1106
1107
|
registry_credential_ids: customProjectRegistryCredentialIdsSchema,
|
|
@@ -1159,7 +1160,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
1159
1160
|
orderNo: applicationOrderNoSchema,
|
|
1160
1161
|
project_id: customProjectIdSchema,
|
|
1161
1162
|
compose_yaml: customProjectComposeSchema,
|
|
1162
|
-
validation_id: z.string().
|
|
1163
|
+
validation_id: z.string().guid().optional().describe("Resume only the exact successful validation for this service and digest-pinned compose_yaml; retain the initial resolved document"),
|
|
1163
1164
|
env: customProjectEnvironmentSchema,
|
|
1164
1165
|
secret_names: customProjectSecretNamesSchema,
|
|
1165
1166
|
registry_credential_ids: customProjectRegistryCredentialIdsSchema,
|
|
@@ -1291,7 +1292,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
1291
1292
|
description: "Prepare and poll a short-lived, read-only takeover candidate for one exact unmanaged Compose project from a fresh discovery. The worker verifies container identity, immutable image identity, restart policy, Compose safety, and exclusive local named-volume ownership. Returns only a scrubbed Compose file, variable names, and bounded counts; never variable values, source paths, commands, or unrestricted labels. This tool does not stop or replace containers. Requires applications:manage.",
|
|
1292
1293
|
inputSchema: {
|
|
1293
1294
|
orderNo: applicationOrderNoSchema,
|
|
1294
|
-
discovery_id: z.string().
|
|
1295
|
+
discovery_id: z.string().guid().describe("Fresh discovery UUID returned by discover_service_containers"),
|
|
1295
1296
|
compose_project: composeProjectLabelSchema,
|
|
1296
1297
|
},
|
|
1297
1298
|
annotations: {
|
|
@@ -1851,7 +1852,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
1851
1852
|
return { content: [{ type: "text", text: formatJson(data) }] };
|
|
1852
1853
|
});
|
|
1853
1854
|
server.registerTool("flush_iptables", {
|
|
1854
|
-
description: "Flush iptables rules on VPS (useful when locked out) Requires services:manage and a full-access API key.",
|
|
1855
|
+
description: "Flush iptables rules on VPS (useful when locked out) Requires services:manage and a full-access API key. It clears the rules inside the server only; the public firewall that VPSnet applies to the server's public interface on its node is separate and is not changed by this.",
|
|
1855
1856
|
inputSchema: {
|
|
1856
1857
|
orderNo: serviceOrderNoSchema,
|
|
1857
1858
|
},
|
|
@@ -1907,7 +1908,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
1907
1908
|
return { content: [{ type: "text", text: formatJson(data) }] };
|
|
1908
1909
|
});
|
|
1909
1910
|
server.registerTool("deploy_ssh_key", {
|
|
1910
|
-
description: "Deploy an SSH key to VPS. Returns a noty UUID; follow it with wait_for_event
|
|
1911
|
+
description: "Deploy an SSH key to VPS. Returns a noty UUID; follow it with wait_for_event until it reports completed before attempting SSH. Use list_ssh_keys to get available key IDs. To add your own key first: read ~/.ssh/id_rsa.pub from local machine, then create_ssh_key, then deploy it here. Remote OAuth requires vm:exec; direct API-key use requires services:manage and a full-access key.",
|
|
1911
1912
|
inputSchema: {
|
|
1912
1913
|
orderNo: serviceOrderNoSchema,
|
|
1913
1914
|
ssh_key: positiveIdSchema.describe("SSH key ID from list_ssh_keys"),
|
|
@@ -1916,6 +1917,38 @@ export function createVpsnetServer(options = {}) {
|
|
|
1916
1917
|
const { data } = await apiRequest("POST", svc(orderNo, "change-ssh-key"), { ssh_key });
|
|
1917
1918
|
return { content: [{ type: "text", text: formatJson(data) }] };
|
|
1918
1919
|
});
|
|
1920
|
+
server.registerTool("list_service_ssh_keys", {
|
|
1921
|
+
description: "List which account SSH keys are in root's authorized_keys on one owned Cloud VPS or Firecracker VPS, as the server last reported: per key deployed (true, false, or null when the server was never read) and a removal running or ended in the last 15 minutes; inventory carries source, observedAt, refreshing (a Firecracker VPS answers asynchronously), readFailure, passwordLogin and the count of other keys. refresh=true asks the server again. Container VPS and dedicated servers answer supported false with unsupportedReason. Free. Requires services:read when called with an API key.",
|
|
1922
|
+
inputSchema: {
|
|
1923
|
+
orderNo: serviceOrderNoSchema,
|
|
1924
|
+
refresh: z.boolean().optional().describe("Ask the server again even when the last read is fresh"),
|
|
1925
|
+
},
|
|
1926
|
+
annotations: {
|
|
1927
|
+
title: "List SSH keys on a server",
|
|
1928
|
+
readOnlyHint: true,
|
|
1929
|
+
destructiveHint: false,
|
|
1930
|
+
idempotentHint: true,
|
|
1931
|
+
},
|
|
1932
|
+
}, async ({ orderNo, refresh }) => {
|
|
1933
|
+
const { data } = await apiRequest("GET", svc(orderNo, "ssh-keys") + (refresh === true ? "?refresh=1" : ""));
|
|
1934
|
+
return { content: [{ type: "text", text: formatJson(data) }] };
|
|
1935
|
+
});
|
|
1936
|
+
server.registerTool("remove_service_ssh_key", {
|
|
1937
|
+
description: "Remove one account SSH key (ssh_key from list_ssh_keys) from root's authorized_keys on one owned running Cloud VPS or Firecracker VPS; every line with that key goes, nothing else changes, and the key stays in the account. Free. Confirm with the user first. A key that is not on the server answers state absent. Refused with 409 sshKeyRemoveLastKey when it is the server's last permanent key and root cannot log in with a password: add another key first. Cloud VPS answers at once (removed or absent); Firecracker VPS answers 202 pending and list_service_ssh_keys shows the result in the key's removal. One removal at a time per server, at most 10 per minute; 423 while the server's two-factor lock is on. Requires services:manage and a full-access API key.",
|
|
1938
|
+
inputSchema: {
|
|
1939
|
+
orderNo: serviceOrderNoSchema,
|
|
1940
|
+
ssh_key: positiveIdSchema.describe("SSH key ID from list_ssh_keys"),
|
|
1941
|
+
},
|
|
1942
|
+
annotations: {
|
|
1943
|
+
title: "Remove an SSH key from a server",
|
|
1944
|
+
readOnlyHint: false,
|
|
1945
|
+
destructiveHint: true,
|
|
1946
|
+
idempotentHint: true,
|
|
1947
|
+
},
|
|
1948
|
+
}, async ({ orderNo, ssh_key }) => {
|
|
1949
|
+
const { data } = await apiRequest("DELETE", svc(orderNo, `ssh-keys/${ssh_key}`));
|
|
1950
|
+
return { content: [{ type: "text", text: formatJson(data) }] };
|
|
1951
|
+
});
|
|
1919
1952
|
// --- OS Reinstall ---
|
|
1920
1953
|
server.registerTool("get_os_options", {
|
|
1921
1954
|
description: "Get available OS templates for reinstall Requires services:read when called with an API key.",
|
|
@@ -2360,7 +2393,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
2360
2393
|
});
|
|
2361
2394
|
// --- API Keys ---
|
|
2362
2395
|
server.registerTool("list_api_keys", {
|
|
2363
|
-
description: "Show the API key this request authenticated with: scope (read/full/ai), granular scopes, paid_scopes, paid_operations_enabled, daily_spend_limit_eur, monthly_spend_limit_eur, allowed IPs, expiry and rate_limit (requests per
|
|
2396
|
+
description: "Show the API key this request authenticated with: scope (read/full/ai), granular scopes, paid_scopes, paid_operations_enabled, daily_spend_limit_eur, monthly_spend_limit_eur, allowed IPs, expiry and rate_limit (a stored value the limiter does not read: every key may make 300 requests per 60 seconds by default, fewer on some operations), plus permission_options listing every scope the panel can grant. The backend scopes this endpoint to the calling key itself (apiKeyScopedToSelf), so other keys on the account are never listed here. By design an API key can never create, change or revoke API keys (403 apiKeyForbidden, reason api_keys_cannot_manage_api_keys): that is done in the VPSnet panel while signed in. Read-only.",
|
|
2364
2397
|
inputSchema: {},
|
|
2365
2398
|
}, async () => {
|
|
2366
2399
|
const { data } = await apiRequest("GET", "/account/api-keys");
|
|
@@ -2376,7 +2409,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
2376
2409
|
return { content: [{ type: "text", text: formatJson(data) }] };
|
|
2377
2410
|
});
|
|
2378
2411
|
server.registerTool("get_api_key_activity", {
|
|
2379
|
-
description: "Get the recorded request activity for this API key: recent matched route patterns and statuses, resolved and separately labelled caller-claimed source addresses, endpoint/source totals, and retained daily history. API-key callers can inspect only the same key that authenticated the MCP connection. Key values, headers, query strings, path values, and request bodies are never returned. To protect the control plane during abusive bursts, audit writes are capped per key per minute and retained detail has a separate per-key row ceiling; totals describe recorded rows and are not a billing ledger.",
|
|
2412
|
+
description: "Get the recorded request activity for this API key: recent matched route patterns and statuses, resolved and separately labelled caller-claimed source addresses, endpoint/source totals, and retained daily history. API-key callers can inspect only the same key that authenticated the MCP connection, and this server needs a management key: a management key has no inference usage of its own and an inference key is refused on every account route, so read inference usage in the VPSnet panel. Key values, headers, query strings, path values, and request bodies are never returned. To protect the control plane during abusive bursts, audit writes are capped per key per minute and retained detail has a separate per-key row ceiling; totals describe recorded rows and are not a billing ledger.",
|
|
2380
2413
|
inputSchema: {
|
|
2381
2414
|
id: positiveIdSchema.describe("API key ID from list_api_keys (the calling key's own ID)"),
|
|
2382
2415
|
limit: z.number().int().min(1).max(200).optional().describe("Recent request rows to return (default 50, maximum 200)"),
|
|
@@ -2387,7 +2420,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
2387
2420
|
return { content: [{ type: "text", text: formatJson(data) }] };
|
|
2388
2421
|
});
|
|
2389
2422
|
server.registerTool("get_api_key_inference_usage", {
|
|
2390
|
-
description: "Get exact paid VPSnet AI usage for this inference API key: committed and currently reserved spend for the UTC day and month, request and token totals by public VPSnet model profile, configured spend limits, remaining spend, and notification preferences. API-key callers can inspect only the same key that authenticated the MCP connection. Internal provider model names are never returned. This is read-only and does not change limits, notifications, or billing.",
|
|
2423
|
+
description: "Get exact paid VPSnet AI usage for this inference API key: committed and currently reserved spend for the UTC day and month, request and token totals by public VPSnet model profile, configured spend limits, remaining spend, and notification preferences. API-key callers can inspect only the same key that authenticated the MCP connection, and this server needs a management key: a management key has no inference usage of its own and an inference key is refused on every account route, so read inference usage in the VPSnet panel. Internal provider model names are never returned. This is read-only and does not change limits, notifications, or billing.",
|
|
2391
2424
|
inputSchema: {
|
|
2392
2425
|
id: positiveIdSchema.describe("Inference API key ID from list_api_keys (the calling key's own ID)"),
|
|
2393
2426
|
},
|
|
@@ -2398,7 +2431,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
2398
2431
|
// --- TLS certificates ---
|
|
2399
2432
|
const certificatePaymentSchema = z
|
|
2400
2433
|
.object({
|
|
2401
|
-
payment:
|
|
2434
|
+
payment: unboundedInteger().positive().describe("Payment method ID; use 1 for account balance"),
|
|
2402
2435
|
successUrl: z.string().max(2048).describe("Approved VPSnet redirect URL, or an empty string"),
|
|
2403
2436
|
cancelUrl: z.string().max(2048).describe("Approved VPSnet redirect URL, or an empty string"),
|
|
2404
2437
|
})
|
|
@@ -4403,7 +4436,7 @@ export function createVpsnetServer(options = {}) {
|
|
|
4403
4436
|
template: dnsTemplateIdSchema
|
|
4404
4437
|
.describe("Template ID returned by list_dns_templates, e.g. web_service, null_mx, google_workspace, microsoft_365, mail_security, caa_letsencrypt"),
|
|
4405
4438
|
parameters: z
|
|
4406
|
-
.record(z.union([z.string(), z.number(), z.boolean()]))
|
|
4439
|
+
.record(z.string(), z.union([z.string(), z.number(), z.boolean()]))
|
|
4407
4440
|
.optional()
|
|
4408
4441
|
.describe("Template parameters, e.g. { ipv4, ipv6, www, mx_target, ttl } depending on the template"),
|
|
4409
4442
|
preview: z
|