@mguttmann/hetzner-cloud-mcp 0.1.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.
Files changed (62) hide show
  1. package/.env.example +25 -0
  2. package/LICENSE +21 -0
  3. package/README.md +148 -0
  4. package/dist/config.js +53 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/http/action-polling.js +34 -0
  7. package/dist/http/action-polling.js.map +1 -0
  8. package/dist/http/client.js +94 -0
  9. package/dist/http/client.js.map +1 -0
  10. package/dist/http/errors.js +36 -0
  11. package/dist/http/errors.js.map +1 -0
  12. package/dist/http/pagination.js +51 -0
  13. package/dist/http/pagination.js.map +1 -0
  14. package/dist/index.js +80 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/logger.js +12 -0
  17. package/dist/logger.js.map +1 -0
  18. package/dist/server.js +37 -0
  19. package/dist/server.js.map +1 -0
  20. package/dist/tools/_error.js +25 -0
  21. package/dist/tools/_error.js.map +1 -0
  22. package/dist/tools/confirm.js +46 -0
  23. package/dist/tools/confirm.js.map +1 -0
  24. package/dist/tools/generated/operations.js +49725 -0
  25. package/dist/tools/generated/operations.js.map +1 -0
  26. package/dist/tools/generated/tools.js +162 -0
  27. package/dist/tools/generated/tools.js.map +1 -0
  28. package/dist/tools/raw_request.js +87 -0
  29. package/dist/tools/raw_request.js.map +1 -0
  30. package/dist/tools/registry.js +19 -0
  31. package/dist/tools/registry.js.map +1 -0
  32. package/dist/tools/wait_action.js +37 -0
  33. package/dist/tools/wait_action.js.map +1 -0
  34. package/dist/tools/wrappers/_server_action.js +23 -0
  35. package/dist/tools/wrappers/_server_action.js.map +1 -0
  36. package/dist/tools/wrappers/apply_firewall_to_server.js +47 -0
  37. package/dist/tools/wrappers/apply_firewall_to_server.js.map +1 -0
  38. package/dist/tools/wrappers/server_backup.js +25 -0
  39. package/dist/tools/wrappers/server_backup.js.map +1 -0
  40. package/dist/tools/wrappers/server_change_type.js +27 -0
  41. package/dist/tools/wrappers/server_change_type.js.map +1 -0
  42. package/dist/tools/wrappers/server_get.js +53 -0
  43. package/dist/tools/wrappers/server_get.js.map +1 -0
  44. package/dist/tools/wrappers/server_list.js +69 -0
  45. package/dist/tools/wrappers/server_list.js.map +1 -0
  46. package/dist/tools/wrappers/server_metrics.js +55 -0
  47. package/dist/tools/wrappers/server_metrics.js.map +1 -0
  48. package/dist/tools/wrappers/server_power.js +32 -0
  49. package/dist/tools/wrappers/server_power.js.map +1 -0
  50. package/dist/tools/wrappers/server_rebuild.js +34 -0
  51. package/dist/tools/wrappers/server_rebuild.js.map +1 -0
  52. package/dist/tools/wrappers/server_rescue.js +34 -0
  53. package/dist/tools/wrappers/server_rescue.js.map +1 -0
  54. package/dist/tools/wrappers/server_snapshot.js +33 -0
  55. package/dist/tools/wrappers/server_snapshot.js.map +1 -0
  56. package/dist/types.js +2 -0
  57. package/dist/types.js.map +1 -0
  58. package/package.json +72 -0
  59. package/scripts/generate.ts +245 -0
  60. package/scripts/refresh-snapshot.ts +33 -0
  61. package/scripts/refresh-spec.ts +35 -0
  62. package/specs/cloud.spec.json +77624 -0
@@ -0,0 +1,162 @@
1
+ import { fetchAllPages } from "../../http/pagination.js";
2
+ import { pollAction } from "../../http/action-polling.js";
3
+ import { asToolError } from "../_error.js";
4
+ function inputSchemaFor(op) {
5
+ const properties = {};
6
+ const required = [];
7
+ for (const p of op.parameters) {
8
+ properties[p.name] = {
9
+ ...p.schema,
10
+ ...(p.description ? { description: p.description } : {}),
11
+ };
12
+ if (p.required)
13
+ required.push(p.name);
14
+ }
15
+ if (op.requestBodySchema) {
16
+ properties.body = op.requestBodySchema;
17
+ if (op.requestBodyRequired)
18
+ required.push("body");
19
+ }
20
+ if (op.returnsAction) {
21
+ properties.wait = {
22
+ type: "boolean",
23
+ default: true,
24
+ description: "Poll the resulting action until success/error or timeout.",
25
+ };
26
+ }
27
+ // page/per_page convenience for list endpoints (top-level or per-resource action history)
28
+ if (isListEndpoint(op)) {
29
+ properties.auto_paginate = {
30
+ type: "boolean",
31
+ default: true,
32
+ description: "Auto-merge all pages up to the soft-cap. Set false to use raw page/per_page.",
33
+ };
34
+ }
35
+ return {
36
+ type: "object",
37
+ properties,
38
+ required,
39
+ additionalProperties: false,
40
+ };
41
+ }
42
+ function buildPath(path, params) {
43
+ return path.replace(/\{([^}]+)\}/g, (_, name) => {
44
+ const v = params[name];
45
+ if (v === undefined || v === null) {
46
+ throw new Error(`Missing path parameter "${name}" for ${path}`);
47
+ }
48
+ return encodeURIComponent(String(v));
49
+ });
50
+ }
51
+ function splitInput(op, input) {
52
+ const pathVars = {};
53
+ const query = {};
54
+ const paramByName = new Map(op.parameters.map((p) => [p.name, p]));
55
+ for (const [k, v] of Object.entries(input)) {
56
+ if (k === "body" || k === "wait" || k === "auto_paginate")
57
+ continue;
58
+ const p = paramByName.get(k);
59
+ if (!p)
60
+ continue; // ignore unknown — schema will have caught it server-side
61
+ if (p.in === "path")
62
+ pathVars[k] = v;
63
+ else if (p.in === "query")
64
+ query[k] = v;
65
+ }
66
+ return {
67
+ pathVars,
68
+ query,
69
+ body: input.body,
70
+ wait: input.wait !== false,
71
+ autoPaginate: input.auto_paginate !== false,
72
+ };
73
+ }
74
+ function isPathParam(seg) {
75
+ return seg.startsWith("{") && seg.endsWith("}");
76
+ }
77
+ function isListEndpoint(op) {
78
+ if (op.method !== "GET")
79
+ return false;
80
+ const segs = op.path.split("/").filter(Boolean);
81
+ // Top-level list: /servers, /actions, /zones, ...
82
+ if (segs.length === 1 && !isPathParam(segs[0]))
83
+ return true;
84
+ // Per-resource action history: /servers/{id}/actions, /zones/{id_or_name}/actions, ...
85
+ if (segs.length === 3 &&
86
+ !isPathParam(segs[0]) &&
87
+ isPathParam(segs[1]) &&
88
+ segs[2] === "actions") {
89
+ return true;
90
+ }
91
+ return false;
92
+ }
93
+ function resourceKey(op) {
94
+ const segs = op.path.split("/").filter(Boolean);
95
+ // Use the last non-param segment as the resource key. For /servers it's "servers";
96
+ // for /servers/{id}/actions it's "actions".
97
+ for (let i = segs.length - 1; i >= 0; i--) {
98
+ const s = segs[i];
99
+ if (!isPathParam(s))
100
+ return s;
101
+ }
102
+ // Shouldn't happen on a list endpoint, but keep a safe fallback.
103
+ return segs[0];
104
+ }
105
+ export function buildGeneratedTools(client, operations, limits) {
106
+ const request = client.request.bind(client);
107
+ return operations.map((op) => ({
108
+ name: op.toolName,
109
+ description: [op.summary, op.description].filter(Boolean).join("\n\n") ||
110
+ `${op.method} ${op.path}`,
111
+ inputSchema: inputSchemaFor(op),
112
+ annotations: {
113
+ readOnlyHint: op.method === "GET",
114
+ destructiveHint: op.isDestructive,
115
+ openWorldHint: true,
116
+ },
117
+ handler: async (rawInput) => {
118
+ const { pathVars, query, body, wait, autoPaginate } = splitInput(op, rawInput);
119
+ const finalPath = buildPath(op.path, pathVars);
120
+ // Auto-paginate list endpoints when no explicit page is given
121
+ if (isListEndpoint(op) && autoPaginate && query.page === undefined) {
122
+ const merged = await fetchAllPages(request, op.method, finalPath, query, { resourceKey: resourceKey(op), maxItems: limits.maxItems, maxPages: limits.maxPages });
123
+ return {
124
+ content: [
125
+ {
126
+ type: "text",
127
+ text: JSON.stringify({ [resourceKey(op)]: merged.items, truncated: merged.truncated, pagination: merged.pagination ?? null }, null, 2),
128
+ },
129
+ ],
130
+ };
131
+ }
132
+ const res = await request(op.method, finalPath, { query: query, body });
133
+ // Hetzner 4xx/5xx -> typed error -> isError:true ToolResult
134
+ const errResult = asToolError(res);
135
+ if (errResult)
136
+ return errResult;
137
+ // If this returns an Action and caller wants to wait, poll it
138
+ if (op.returnsAction && wait && res.body?.action?.id) {
139
+ const pollOpts = limits.actionPoll ?? { timeoutMs: 60_000, intervalMs: 2_000 };
140
+ const result = await pollAction(request, res.body.action.id, pollOpts);
141
+ return {
142
+ content: [
143
+ {
144
+ type: "text",
145
+ text: JSON.stringify({
146
+ ...(res.body ?? {}),
147
+ action: result.action,
148
+ polling_timed_out: result.timedOut,
149
+ }, null, 2),
150
+ },
151
+ ],
152
+ };
153
+ }
154
+ return {
155
+ content: [
156
+ { type: "text", text: JSON.stringify(res.body ?? {}, null, 2) },
157
+ ],
158
+ };
159
+ },
160
+ }));
161
+ }
162
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/tools/generated/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ const VALID = ["GET", "POST", "PUT", "PATCH", "DELETE"];
2
+ export function makeRawRequestTool(deps) {
3
+ return {
4
+ name: "hcloud_raw_request",
5
+ description: "Escape hatch: issue an arbitrary request against the Hetzner Cloud API. Bearer auth, retries and pagination are NOT applied automatically — this is a pass-through. Use only when no dedicated tool fits.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ method: { type: "string", enum: VALID },
10
+ path: {
11
+ type: "string",
12
+ pattern: "^/.+",
13
+ description: "Path beginning with '/', e.g. '/servers/42/actions/poweron'.",
14
+ },
15
+ query: { type: "object", additionalProperties: true },
16
+ body: {
17
+ type: ["object", "array", "string", "number", "boolean", "null"],
18
+ description: "Request body, JSON-serialised when sent.",
19
+ },
20
+ confirm: {
21
+ type: "string",
22
+ enum: ["YES"],
23
+ description: 'Required when HETZNER_CONFIRM_WRITES=true and method is not GET. Set to "YES" to actually execute; without it the tool returns a preview only. Ignored for GET and when confirm mode is disabled.',
24
+ },
25
+ },
26
+ required: ["method", "path"],
27
+ additionalProperties: false,
28
+ },
29
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
30
+ handler: async (input) => {
31
+ const method = input.method;
32
+ const path = input.path;
33
+ if (!VALID.includes(method)) {
34
+ return {
35
+ content: [
36
+ {
37
+ type: "text",
38
+ text: `Unsupported method "${String(input.method)}". Allowed: ${VALID.join(", ")}.`,
39
+ },
40
+ ],
41
+ isError: true,
42
+ };
43
+ }
44
+ if (typeof path !== "string" || !path.startsWith("/")) {
45
+ return {
46
+ content: [
47
+ {
48
+ type: "text",
49
+ text: `Path must start with "/", got: ${JSON.stringify(input.path)}.`,
50
+ },
51
+ ],
52
+ isError: true,
53
+ };
54
+ }
55
+ const isWrite = method !== "GET";
56
+ if (isWrite && deps.confirmWrites && input.confirm !== "YES") {
57
+ const { confirm: _drop, ...preview } = input;
58
+ return {
59
+ content: [
60
+ {
61
+ type: "text",
62
+ text: `PREVIEW — would execute hcloud_raw_request\n` +
63
+ `Input: ${JSON.stringify(preview, null, 2)}\n` +
64
+ `To execute, retry the same call with confirm: "YES".`,
65
+ },
66
+ ],
67
+ };
68
+ }
69
+ const res = await deps.client.request(method, path, {
70
+ query: input.query,
71
+ body: input.body,
72
+ });
73
+ return {
74
+ content: [
75
+ {
76
+ type: "text",
77
+ text: JSON.stringify({
78
+ status: res.status,
79
+ body: res.body ?? null,
80
+ }, null, 2),
81
+ },
82
+ ],
83
+ };
84
+ },
85
+ };
86
+ }
87
+ //# sourceMappingURL=raw_request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw_request.js","sourceRoot":"","sources":["../../src/tools/raw_request.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export class ToolRegistry {
2
+ byName = new Map();
3
+ register(tool) {
4
+ if (this.byName.has(tool.name)) {
5
+ throw new Error(`Tool "${tool.name}" is already registered`);
6
+ }
7
+ this.byName.set(tool.name, tool);
8
+ }
9
+ getAll() {
10
+ return Array.from(this.byName.values()).sort((a, b) => a.name.localeCompare(b.name));
11
+ }
12
+ getByName(name) {
13
+ return this.byName.get(name);
14
+ }
15
+ size() {
16
+ return this.byName.size;
17
+ }
18
+ }
19
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,YAAY;IACN,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAC;IAErD,QAAQ,CAAC,IAAa;QACpB,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,SAAS,IAAI,CAAC,IAAI,yBAAyB,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,MAAM;QACJ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACpD,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAC7B,CAAC;IACJ,CAAC;IAED,SAAS,CAAC,IAAY;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,37 @@
1
+ import { pollAction } from "../http/action-polling.js";
2
+ export function makeWaitActionTool(deps) {
3
+ return {
4
+ name: "hcloud_wait_action",
5
+ description: "Poll an existing Hetzner Cloud action until it reaches terminal status (success/error) or the timeout elapses. Returns the final action plus a polling_timed_out flag.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ id: { type: "integer", minimum: 1 },
10
+ timeout_ms: { type: "integer", minimum: 1, description: "Override the default poll timeout for this call." },
11
+ interval_ms: { type: "integer", minimum: 1, description: "Override the default poll interval for this call." },
12
+ },
13
+ required: ["id"],
14
+ additionalProperties: false,
15
+ },
16
+ annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
17
+ handler: async (input) => {
18
+ const id = input.id;
19
+ const opts = {
20
+ timeoutMs: typeof input.timeout_ms === "number" ? input.timeout_ms : deps.defaultPoll.timeoutMs,
21
+ intervalMs: typeof input.interval_ms === "number" ? input.interval_ms : deps.defaultPoll.intervalMs,
22
+ ...(deps.defaultPoll.sleep ? { sleep: deps.defaultPoll.sleep } : {}),
23
+ ...(deps.defaultPoll.now ? { now: deps.defaultPoll.now } : {}),
24
+ };
25
+ const result = await pollAction(deps.client.request.bind(deps.client), id, opts);
26
+ return {
27
+ content: [
28
+ {
29
+ type: "text",
30
+ text: JSON.stringify({ action: result.action, polling_timed_out: result.timedOut }, null, 2),
31
+ },
32
+ ],
33
+ };
34
+ },
35
+ };
36
+ }
37
+ //# sourceMappingURL=wait_action.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait_action.js","sourceRoot":"","sources":["../../src/tools/wait_action.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAoB,MAAM,2BAA2B,CAAC;AAOzE,MAAM,UAAU,kBAAkB,CAAC,IAAoB;IACrD,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EACT,wKAAwK;QAC1K,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;gBACnC,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,kDAAkD,EAAE;gBAC5G,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,mDAAmD,EAAE;aAC/G;YACD,QAAQ,EAAE,CAAC,IAAI,CAAC;YAChB,oBAAoB,EAAE,KAAK;SAC5B;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE;QAChF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAuB,EAAE;YAC5C,MAAM,EAAE,GAAG,KAAK,CAAC,EAAY,CAAC;YAC9B,MAAM,IAAI,GAAgB;gBACxB,SAAS,EAAE,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS;gBAC/F,UAAU,EAAE,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU;gBACnG,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpE,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/D,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,UAAU,CAC7B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAqC,EACzE,EAAE,EACF,IAAI,CACL,CAAC;YACF,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,MAAM,CAAC,QAAQ,EAAE,EAC7D,IAAI,EACJ,CAAC,CACF;qBACF;iBACF;aACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { pollAction } from "../../http/action-polling.js";
2
+ import { asToolError } from "../_error.js";
3
+ export async function runServerAction(deps, serverId, action, body, wait) {
4
+ const res = await deps.client.request("POST", `/servers/${serverId}/actions/${action}`, body ? { body } : {});
5
+ const errResult = asToolError(res);
6
+ if (errResult)
7
+ return errResult;
8
+ if (!wait || !res.body?.action?.id) {
9
+ return {
10
+ content: [{ type: "text", text: JSON.stringify(res.body ?? {}, null, 2) }],
11
+ };
12
+ }
13
+ const polled = await pollAction(deps.client.request.bind(deps.client), res.body.action.id, deps.actionPoll);
14
+ return {
15
+ content: [
16
+ {
17
+ type: "text",
18
+ text: JSON.stringify({ ...(res.body ?? {}), action: polled.action, polling_timed_out: polled.timedOut }, null, 2),
19
+ },
20
+ ],
21
+ };
22
+ }
23
+ //# sourceMappingURL=_server_action.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_server_action.js","sourceRoot":"","sources":["../../../src/tools/wrappers/_server_action.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAoB,MAAM,8BAA8B,CAAC;AAE5E,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAO3C,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAsB,EACtB,QAAgB,EAChB,MAAc,EACd,IAAyC,EACzC,IAAa;IAEb,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CACnC,MAAM,EACN,YAAY,QAAQ,YAAY,MAAM,EAAE,EACxC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CACrB,CAAC;IACF,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAChC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACnC,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC3E,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAC7B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAqC,EACzE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAClB,IAAI,CAAC,UAAU,CAChB,CAAC;IACF,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,MAAM,CAAC,QAAQ,EAAE,EAClF,IAAI,EACJ,CAAC,CACF;aACF;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { asToolError } from "../_error.js";
2
+ export function makeApplyFirewallToServerTool(deps) {
3
+ return {
4
+ name: "hcloud_apply_firewall_to_server",
5
+ description: "Apply a firewall (by id or by name) to a server. Hand-tuned wrapper around POST /firewalls/{id}/actions/apply_to_resources.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ firewall_id: { type: "integer", minimum: 1 },
10
+ firewall_name: { type: "string", minLength: 1 },
11
+ server_id: { type: "integer", minimum: 1 },
12
+ },
13
+ required: ["server_id"],
14
+ additionalProperties: false,
15
+ },
16
+ annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
17
+ handler: async (input) => {
18
+ const serverId = input.server_id;
19
+ const hasId = typeof input.firewall_id === "number";
20
+ const hasName = typeof input.firewall_name === "string";
21
+ if (hasId === hasName) {
22
+ return { content: [{ type: "text", text: "Provide exactly one of `firewall_id` or `firewall_name`." }], isError: true };
23
+ }
24
+ let fwId;
25
+ if (hasId) {
26
+ fwId = input.firewall_id;
27
+ }
28
+ else {
29
+ const lookup = await deps.client.request("GET", "/firewalls", { query: { name: input.firewall_name } });
30
+ const lookupErr = asToolError(lookup);
31
+ if (lookupErr)
32
+ return lookupErr;
33
+ const found = lookup.body?.firewalls?.[0];
34
+ if (!found) {
35
+ return { content: [{ type: "text", text: `Firewall with name="${input.firewall_name}" not found.` }], isError: true };
36
+ }
37
+ fwId = found.id;
38
+ }
39
+ const res = await deps.client.request("POST", `/firewalls/${fwId}/actions/apply_to_resources`, { body: { apply_to: [{ type: "server", server: { id: serverId } }] } });
40
+ const errResult = asToolError(res);
41
+ if (errResult)
42
+ return errResult;
43
+ return { content: [{ type: "text", text: JSON.stringify(res.body ?? {}, null, 2) }] };
44
+ },
45
+ };
46
+ }
47
+ //# sourceMappingURL=apply_firewall_to_server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply_firewall_to_server.js","sourceRoot":"","sources":["../../../src/tools/wrappers/apply_firewall_to_server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAO3C,MAAM,UAAU,6BAA6B,CAAC,IAAuB;IACnE,OAAO;QACL,IAAI,EAAE,iCAAiC;QACvC,WAAW,EACT,6HAA6H;QAC/H,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;gBAC5C,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE;gBAC/C,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;aAC3C;YACD,QAAQ,EAAE,CAAC,WAAW,CAAC;YACvB,oBAAoB,EAAE,KAAK;SAC5B;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE;QACjF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAuB,EAAE;YAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAmB,CAAC;YAC3C,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,CAAC;YACpD,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,aAAa,KAAK,QAAQ,CAAC;YACxD,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;gBACtB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,0DAA0D,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC1H,CAAC;YACD,IAAI,IAAY,CAAC;YACjB,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,GAAG,KAAK,CAAC,WAAqB,CAAC;YACrC,CAAC;iBAAM,CAAC;gBACN,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CACtC,KAAK,EACL,YAAY,EACZ,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,aAAuB,EAAE,EAAE,CACnD,CAAC;gBACF,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;gBACtC,IAAI,SAAS;oBAAE,OAAO,SAAS,CAAC;gBAChC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,KAAK,CAAC,aAAa,cAAc,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBACxH,CAAC;gBACD,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC;YAClB,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CACnC,MAAM,EACN,cAAc,IAAI,6BAA6B,EAC/C,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CACvE,CAAC;YACF,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;YACnC,IAAI,SAAS;gBAAE,OAAO,SAAS,CAAC;YAChC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACxF,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { runServerAction } from "./_server_action.js";
2
+ export function makeServerBackupTool(deps) {
3
+ return {
4
+ name: "hcloud_server_backup",
5
+ description: "Toggle Hetzner-managed automatic backups on a server. Hand-tuned wrapper around enable_backup / disable_backup actions.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ id: { type: "integer", minimum: 1 },
10
+ enable: { type: "boolean", description: "true to turn backups on, false to turn them off." },
11
+ wait: { type: "boolean", default: true },
12
+ },
13
+ required: ["id", "enable"],
14
+ additionalProperties: false,
15
+ },
16
+ annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
17
+ handler: async (input) => {
18
+ const id = input.id;
19
+ const action = input.enable === true ? "enable_backup" : "disable_backup";
20
+ const wait = input.wait !== false;
21
+ return runServerAction(deps, id, action, undefined, wait);
22
+ },
23
+ };
24
+ }
25
+ //# sourceMappingURL=server_backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server_backup.js","sourceRoot":"","sources":["../../../src/tools/wrappers/server_backup.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAyB,MAAM,qBAAqB,CAAC;AAE7E,MAAM,UAAU,oBAAoB,CAAC,IAAsB;IACzD,OAAO;QACL,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EACT,yHAAyH;QAC3H,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;gBACnC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,kDAAkD,EAAE;gBAC5F,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE;aACzC;YACD,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC;YAC1B,oBAAoB,EAAE,KAAK;SAC5B;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE;QACjF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAuB,EAAE;YAC5C,MAAM,EAAE,GAAG,KAAK,CAAC,EAAY,CAAC;YAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,gBAAgB,CAAC;YAC1E,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC;YAClC,OAAO,eAAe,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAC5D,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { runServerAction } from "./_server_action.js";
2
+ export function makeServerChangeTypeTool(deps) {
3
+ return {
4
+ name: "hcloud_server_change_type",
5
+ description: "Change a server's hardware type. Defaults upgrade_disk to false (disk size kept; safer to downgrade later). Hand-tuned wrapper; polls the resulting action by default.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ id: { type: "integer", minimum: 1 },
10
+ server_type: { type: "string", minLength: 1 },
11
+ upgrade_disk: { type: "boolean", default: false },
12
+ wait: { type: "boolean", default: true },
13
+ },
14
+ required: ["id", "server_type"],
15
+ additionalProperties: false,
16
+ },
17
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
18
+ handler: async (input) => {
19
+ const id = input.id;
20
+ const server_type = input.server_type;
21
+ const upgrade_disk = input.upgrade_disk === true;
22
+ const wait = input.wait !== false;
23
+ return runServerAction(deps, id, "change_type", { server_type, upgrade_disk }, wait);
24
+ },
25
+ };
26
+ }
27
+ //# sourceMappingURL=server_change_type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server_change_type.js","sourceRoot":"","sources":["../../../src/tools/wrappers/server_change_type.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAyB,MAAM,qBAAqB,CAAC;AAE7E,MAAM,UAAU,wBAAwB,CAAC,IAAsB;IAC7D,OAAO;QACL,IAAI,EAAE,2BAA2B;QACjC,WAAW,EACT,wKAAwK;QAC1K,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;gBACnC,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE;gBAC7C,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;gBACjD,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE;aACzC;YACD,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC;YAC/B,oBAAoB,EAAE,KAAK;SAC5B;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;QAChF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAuB,EAAE;YAC5C,MAAM,EAAE,GAAG,KAAK,CAAC,EAAY,CAAC;YAC9B,MAAM,WAAW,GAAG,KAAK,CAAC,WAAqB,CAAC;YAChD,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC;YACjD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC;YAClC,OAAO,eAAe,CAAC,IAAI,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,IAAI,CAAC,CAAC;QACvF,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { asToolError } from "../_error.js";
2
+ function errorResult(message) {
3
+ return {
4
+ content: [{ type: "text", text: message }],
5
+ isError: true,
6
+ };
7
+ }
8
+ export function makeServerGetTool(client) {
9
+ return {
10
+ name: "hcloud_get_server",
11
+ description: "Fetch a single Hetzner Cloud server by numeric id OR by exact name. Hand-tuned wrapper; use hcloud_get_server_raw for the id-only generated tool.",
12
+ inputSchema: {
13
+ type: "object",
14
+ properties: {
15
+ id: { type: "integer", minimum: 1 },
16
+ name: { type: "string", minLength: 1 },
17
+ },
18
+ additionalProperties: false,
19
+ },
20
+ annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
21
+ handler: async (input) => {
22
+ const hasId = typeof input.id === "number";
23
+ const hasName = typeof input.name === "string";
24
+ if (hasId === hasName) {
25
+ return errorResult("Provide exactly one of `id` or `name`.");
26
+ }
27
+ if (hasId) {
28
+ const res = await client.request("GET", `/servers/${input.id}`);
29
+ const errResult = asToolError(res);
30
+ if (errResult)
31
+ return errResult;
32
+ if (!res.body?.server) {
33
+ return errorResult(`Server with id=${input.id} not found.`);
34
+ }
35
+ return {
36
+ content: [{ type: "text", text: JSON.stringify(res.body, null, 2) }],
37
+ };
38
+ }
39
+ const res = await client.request("GET", "/servers", { query: { name: input.name } });
40
+ const errResult = asToolError(res);
41
+ if (errResult)
42
+ return errResult;
43
+ const found = res.body?.servers?.[0];
44
+ if (!found) {
45
+ return errorResult(`Server with name="${input.name}" not found.`);
46
+ }
47
+ return {
48
+ content: [{ type: "text", text: JSON.stringify({ server: found }, null, 2) }],
49
+ };
50
+ },
51
+ };
52
+ }
53
+ //# sourceMappingURL=server_get.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server_get.js","sourceRoot":"","sources":["../../../src/tools/wrappers/server_get.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAI3C,SAAS,WAAW,CAAC,OAAe;IAClC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAyB;IACzD,OAAO;QACL,IAAI,EAAE,mBAAmB;QACzB,WAAW,EACT,mJAAmJ;QACrJ,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;gBACnC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE;aACvC;YACD,oBAAoB,EAAE,KAAK;SAC5B;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE;QAChF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACvB,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,CAAC;YAC3C,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;YAC/C,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;gBACtB,OAAO,WAAW,CAAC,wCAAwC,CAAC,CAAC;YAC/D,CAAC;YAED,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,CAC9B,KAAK,EACL,YAAY,KAAK,CAAC,EAAE,EAAE,CACvB,CAAC;gBACF,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;gBACnC,IAAI,SAAS;oBAAE,OAAO,SAAS,CAAC;gBAChC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;oBACtB,OAAO,WAAW,CAAC,kBAAkB,KAAK,CAAC,EAAE,aAAa,CAAC,CAAC;gBAC9D,CAAC;gBACD,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;iBACrE,CAAC;YACJ,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,CAC9B,KAAK,EACL,UAAU,EACV,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAc,EAAE,EAAE,CAC1C,CAAC;YACF,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;YACnC,IAAI,SAAS;gBAAE,OAAO,SAAS,CAAC;YAChC,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,WAAW,CAAC,qBAAqB,KAAK,CAAC,IAAI,cAAc,CAAC,CAAC;YACpE,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC9E,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { fetchAllPages } from "../../http/pagination.js";
2
+ export function makeServerListTool(client, limits) {
3
+ return {
4
+ name: "hcloud_list_servers",
5
+ description: "List Hetzner Cloud servers. Hand-tuned wrapper around GET /servers with an optional client-side name_contains filter and a default sort of 'name'. Use hcloud_list_servers_raw for the unfiltered, generator-built tool.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ name_contains: {
10
+ type: "string",
11
+ description: "Case-insensitive substring filter applied after fetching.",
12
+ },
13
+ label_selector: {
14
+ type: "string",
15
+ description: "Hetzner label selector, forwarded as query parameter.",
16
+ },
17
+ sort: {
18
+ type: "string",
19
+ enum: [
20
+ "id", "id:asc", "id:desc",
21
+ "name", "name:asc", "name:desc",
22
+ "created", "created:asc", "created:desc",
23
+ ],
24
+ default: "name",
25
+ },
26
+ page: { type: "integer", minimum: 1 },
27
+ per_page: { type: "integer", minimum: 1, maximum: 50 },
28
+ },
29
+ additionalProperties: false,
30
+ },
31
+ annotations: {
32
+ readOnlyHint: true,
33
+ destructiveHint: false,
34
+ openWorldHint: true,
35
+ },
36
+ handler: async (input) => {
37
+ const query = {
38
+ sort: typeof input.sort === "string" ? input.sort : "name",
39
+ };
40
+ if (typeof input.label_selector === "string") {
41
+ query.label_selector = input.label_selector;
42
+ }
43
+ if (typeof input.page === "number")
44
+ query.page = input.page;
45
+ if (typeof input.per_page === "number")
46
+ query.per_page = input.per_page;
47
+ const request = client.request.bind(client);
48
+ const page = await fetchAllPages(request, "GET", "/servers", query, { resourceKey: "servers", maxItems: limits.maxItems, maxPages: limits.maxPages });
49
+ let servers = page.items;
50
+ if (typeof input.name_contains === "string" && input.name_contains.length > 0) {
51
+ const needle = input.name_contains.toLowerCase();
52
+ servers = servers.filter((s) => s.name.toLowerCase().includes(needle));
53
+ }
54
+ return {
55
+ content: [
56
+ {
57
+ type: "text",
58
+ text: JSON.stringify({
59
+ servers,
60
+ truncated: page.truncated,
61
+ pagination: page.pagination ?? null,
62
+ }, null, 2),
63
+ },
64
+ ],
65
+ };
66
+ },
67
+ };
68
+ }
69
+ //# sourceMappingURL=server_list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server_list.js","sourceRoot":"","sources":["../../../src/tools/wrappers/server_list.ts"],"names":[],"mappings":"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"}