@chkp/policy-insights-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.
- package/CHANGELOG.md +7 -0
- package/README.md +296 -0
- package/dist/index.js +3192 -0
- package/dist/package.json +49 -0
- package/dist/server-config.json +56 -0
- package/package.json +49 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,3192 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// ../mcp-utils/dist/ui-dialog.js
|
|
13
|
+
var ui_dialog_exports = {};
|
|
14
|
+
__export(ui_dialog_exports, {
|
|
15
|
+
showDialog: () => showDialog,
|
|
16
|
+
showLoginDialog: () => showLoginDialog
|
|
17
|
+
});
|
|
18
|
+
import { createServer } from "http";
|
|
19
|
+
import { URL as URL2 } from "url";
|
|
20
|
+
import { exec } from "child_process";
|
|
21
|
+
import { promisify } from "util";
|
|
22
|
+
import * as fs2 from "fs";
|
|
23
|
+
import * as path from "path";
|
|
24
|
+
async function showDialog(config) {
|
|
25
|
+
const dialog = new UIDialog();
|
|
26
|
+
return dialog.showDialog(config);
|
|
27
|
+
}
|
|
28
|
+
async function showLoginDialog(title, message) {
|
|
29
|
+
return showDialog({
|
|
30
|
+
title: title || "Login Information",
|
|
31
|
+
message,
|
|
32
|
+
fields: [
|
|
33
|
+
{
|
|
34
|
+
name: "address",
|
|
35
|
+
label: "Address",
|
|
36
|
+
type: "text",
|
|
37
|
+
placeholder: "Enter server address...",
|
|
38
|
+
required: true
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "user",
|
|
42
|
+
label: "Username",
|
|
43
|
+
type: "text",
|
|
44
|
+
placeholder: "Enter username...",
|
|
45
|
+
required: true
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "password",
|
|
49
|
+
label: "Password",
|
|
50
|
+
type: "password",
|
|
51
|
+
placeholder: "Enter password...",
|
|
52
|
+
required: true
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
var execAsync, UIDialog;
|
|
58
|
+
var init_ui_dialog = __esm({
|
|
59
|
+
"../mcp-utils/dist/ui-dialog.js"() {
|
|
60
|
+
"use strict";
|
|
61
|
+
execAsync = promisify(exec);
|
|
62
|
+
UIDialog = class {
|
|
63
|
+
constructor() {
|
|
64
|
+
this.server = null;
|
|
65
|
+
this.port = 0;
|
|
66
|
+
this.resolve = null;
|
|
67
|
+
}
|
|
68
|
+
async showDialog(config) {
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
this.resolve = resolve;
|
|
71
|
+
this.server = createServer((req, res) => {
|
|
72
|
+
this.handleRequest(req, res, config);
|
|
73
|
+
});
|
|
74
|
+
this.server.listen(0, "localhost", () => {
|
|
75
|
+
const address = this.server.address();
|
|
76
|
+
if (address && typeof address === "object") {
|
|
77
|
+
this.port = address.port;
|
|
78
|
+
this.openBrowser(`http://localhost:${this.port}`);
|
|
79
|
+
} else {
|
|
80
|
+
reject(new Error("Failed to start server"));
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
setTimeout(() => {
|
|
84
|
+
this.cleanup();
|
|
85
|
+
resolve({ cancelled: true, data: {} });
|
|
86
|
+
}, 5 * 60 * 1e3);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
handleRequest(req, res, config) {
|
|
90
|
+
const url = new URL2(req.url, `http://localhost:${this.port}`);
|
|
91
|
+
if (req.method === "GET" && url.pathname === "/") {
|
|
92
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
93
|
+
res.end(this.generateHTML(config));
|
|
94
|
+
} else if (req.method === "POST" && url.pathname === "/submit") {
|
|
95
|
+
let body = "";
|
|
96
|
+
req.on("data", (chunk) => {
|
|
97
|
+
body += chunk.toString();
|
|
98
|
+
});
|
|
99
|
+
req.on("end", () => {
|
|
100
|
+
const formData = new URLSearchParams(body);
|
|
101
|
+
const result = {};
|
|
102
|
+
for (const field of config.fields) {
|
|
103
|
+
result[field.name] = formData.get(field.name) || "";
|
|
104
|
+
}
|
|
105
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
106
|
+
res.end(`
|
|
107
|
+
<html>
|
|
108
|
+
<head><title>Success</title></head>
|
|
109
|
+
<body style="font-family: Arial, sans-serif; text-align: center; padding: 50px;">
|
|
110
|
+
<h2>Form submitted successfully!</h2>
|
|
111
|
+
<p>You can close this window now.</p>
|
|
112
|
+
<script>setTimeout(() => window.close(), 2000);</script>
|
|
113
|
+
</body>
|
|
114
|
+
</html>
|
|
115
|
+
`);
|
|
116
|
+
this.cleanup();
|
|
117
|
+
if (this.resolve) {
|
|
118
|
+
this.resolve({ cancelled: false, data: result });
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
} else if (req.method === "POST" && url.pathname === "/cancel") {
|
|
122
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
123
|
+
res.end(`
|
|
124
|
+
<html>
|
|
125
|
+
<head><title>Cancelled</title></head>
|
|
126
|
+
<body style="font-family: Arial, sans-serif; text-align: center; padding: 50px;">
|
|
127
|
+
<h2>Form cancelled</h2>
|
|
128
|
+
<p>You can close this window now.</p>
|
|
129
|
+
<script>setTimeout(() => window.close(), 2000);</script>
|
|
130
|
+
</body>
|
|
131
|
+
</html>
|
|
132
|
+
`);
|
|
133
|
+
this.cleanup();
|
|
134
|
+
if (this.resolve) {
|
|
135
|
+
this.resolve({ cancelled: true, data: {} });
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
res.writeHead(404);
|
|
139
|
+
res.end("Not found");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
generateHTML(config) {
|
|
143
|
+
const fieldsHTML = config.fields.map((field) => {
|
|
144
|
+
let fieldHTML = "";
|
|
145
|
+
const fieldType = field.type || "text";
|
|
146
|
+
switch (fieldType) {
|
|
147
|
+
case "textarea":
|
|
148
|
+
fieldHTML = `
|
|
149
|
+
<textarea
|
|
150
|
+
name="${field.name}"
|
|
151
|
+
placeholder="${field.placeholder || ""}"
|
|
152
|
+
${field.required ? "required" : ""}
|
|
153
|
+
style="width: 100%; box-sizing: border-box; min-height: 80px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-family: Arial, sans-serif; font-size: 14px; resize: vertical;"
|
|
154
|
+
>${field.defaultValue || ""}</textarea>
|
|
155
|
+
`;
|
|
156
|
+
break;
|
|
157
|
+
case "select":
|
|
158
|
+
fieldHTML = `
|
|
159
|
+
<select
|
|
160
|
+
name="${field.name}"
|
|
161
|
+
${field.required ? "required" : ""}
|
|
162
|
+
style="width: 100%; box-sizing: border-box; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-family: Arial, sans-serif; font-size: 14px;"
|
|
163
|
+
>
|
|
164
|
+
<option value="">Select an option...</option>
|
|
165
|
+
${(field.options || []).map((option) => `<option value="${option}" ${option === field.defaultValue ? "selected" : ""}>${option}</option>`).join("")}
|
|
166
|
+
</select>
|
|
167
|
+
`;
|
|
168
|
+
break;
|
|
169
|
+
default:
|
|
170
|
+
fieldHTML = `
|
|
171
|
+
<input
|
|
172
|
+
type="${fieldType}"
|
|
173
|
+
name="${field.name}"
|
|
174
|
+
placeholder="${field.placeholder || ""}"
|
|
175
|
+
value="${field.defaultValue || ""}"
|
|
176
|
+
${field.required ? "required" : ""}
|
|
177
|
+
style="width: 100%; box-sizing: border-box; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-family: Arial, sans-serif; font-size: 14px;"
|
|
178
|
+
/>
|
|
179
|
+
`;
|
|
180
|
+
}
|
|
181
|
+
return `
|
|
182
|
+
<div style="margin-bottom: 15px;">
|
|
183
|
+
<label style="display: block; margin-bottom: 5px; font-weight: bold; color: #333;">
|
|
184
|
+
${field.label}${field.required ? " *" : ""}
|
|
185
|
+
</label>
|
|
186
|
+
${fieldHTML}
|
|
187
|
+
</div>
|
|
188
|
+
`;
|
|
189
|
+
}).join("");
|
|
190
|
+
return `
|
|
191
|
+
<!DOCTYPE html>
|
|
192
|
+
<html>
|
|
193
|
+
<head>
|
|
194
|
+
<title>${config.title}</title>
|
|
195
|
+
<meta charset="UTF-8">
|
|
196
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
197
|
+
<style>
|
|
198
|
+
* {
|
|
199
|
+
box-sizing: border-box;
|
|
200
|
+
}
|
|
201
|
+
body {
|
|
202
|
+
font-family: Arial, sans-serif;
|
|
203
|
+
max-width: 500px;
|
|
204
|
+
margin: 50px auto;
|
|
205
|
+
padding: 20px;
|
|
206
|
+
background-color: #f5f5f5;
|
|
207
|
+
line-height: 1.4;
|
|
208
|
+
}
|
|
209
|
+
.dialog {
|
|
210
|
+
background: white;
|
|
211
|
+
padding: 30px;
|
|
212
|
+
border-radius: 8px;
|
|
213
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
214
|
+
}
|
|
215
|
+
.buttons {
|
|
216
|
+
margin-top: 20px;
|
|
217
|
+
text-align: right;
|
|
218
|
+
}
|
|
219
|
+
button {
|
|
220
|
+
padding: 10px 20px;
|
|
221
|
+
margin-left: 10px;
|
|
222
|
+
border: none;
|
|
223
|
+
border-radius: 4px;
|
|
224
|
+
cursor: pointer;
|
|
225
|
+
font-size: 14px;
|
|
226
|
+
font-family: Arial, sans-serif;
|
|
227
|
+
}
|
|
228
|
+
.submit-btn {
|
|
229
|
+
background-color: #007cba;
|
|
230
|
+
color: white;
|
|
231
|
+
}
|
|
232
|
+
.submit-btn:hover {
|
|
233
|
+
background-color: #005a87;
|
|
234
|
+
}
|
|
235
|
+
.cancel-btn {
|
|
236
|
+
background-color: #6c757d;
|
|
237
|
+
color: white;
|
|
238
|
+
}
|
|
239
|
+
.cancel-btn:hover {
|
|
240
|
+
background-color: #545b62;
|
|
241
|
+
}
|
|
242
|
+
input:focus, textarea:focus, select:focus {
|
|
243
|
+
outline: none;
|
|
244
|
+
border-color: #007cba;
|
|
245
|
+
box-shadow: 0 0 0 2px rgba(0, 124, 186, 0.2);
|
|
246
|
+
}
|
|
247
|
+
</style>
|
|
248
|
+
</head>
|
|
249
|
+
<body>
|
|
250
|
+
<div class="dialog">
|
|
251
|
+
<h2 style="margin-top: 0; color: #333;">${config.title}</h2>
|
|
252
|
+
${config.message ? `<p style="color: #666; margin-bottom: 20px;">${config.message}</p>` : ""}
|
|
253
|
+
|
|
254
|
+
<form id="dialogForm" method="POST" action="/submit">
|
|
255
|
+
${fieldsHTML}
|
|
256
|
+
|
|
257
|
+
<div class="buttons">
|
|
258
|
+
<button type="button" class="cancel-btn" onclick="cancel()">
|
|
259
|
+
${config.cancelButtonText || "Cancel"}
|
|
260
|
+
</button>
|
|
261
|
+
<button type="submit" class="submit-btn">
|
|
262
|
+
${config.submitButtonText || "Submit"}
|
|
263
|
+
</button>
|
|
264
|
+
</div>
|
|
265
|
+
</form>
|
|
266
|
+
</div>
|
|
267
|
+
|
|
268
|
+
<script>
|
|
269
|
+
function cancel() {
|
|
270
|
+
fetch('/cancel', { method: 'POST' })
|
|
271
|
+
.then(() => {
|
|
272
|
+
document.body.innerHTML = '<div style="text-align: center; padding: 50px; font-family: Arial, sans-serif;"><h2>Cancelled</h2><p>You can close this window now.</p></div>';
|
|
273
|
+
setTimeout(() => window.close(), 2000);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Auto-focus first input
|
|
278
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
279
|
+
const firstInput = document.querySelector('input, textarea, select');
|
|
280
|
+
if (firstInput) {
|
|
281
|
+
firstInput.focus();
|
|
282
|
+
// If it's a text input, place cursor at end
|
|
283
|
+
if (firstInput.type === 'text' || firstInput.tagName === 'TEXTAREA') {
|
|
284
|
+
const val = firstInput.value;
|
|
285
|
+
firstInput.value = '';
|
|
286
|
+
firstInput.value = val;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// Prevent form submission if required fields are empty
|
|
292
|
+
document.getElementById('dialogForm').addEventListener('submit', function(e) {
|
|
293
|
+
const requiredFields = document.querySelectorAll('[required]');
|
|
294
|
+
for (let field of requiredFields) {
|
|
295
|
+
if (!field.value.trim()) {
|
|
296
|
+
e.preventDefault();
|
|
297
|
+
field.focus();
|
|
298
|
+
alert('Please fill in all required fields.');
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
</script>
|
|
304
|
+
</body>
|
|
305
|
+
</html>
|
|
306
|
+
`;
|
|
307
|
+
}
|
|
308
|
+
async openBrowser(urlString) {
|
|
309
|
+
try {
|
|
310
|
+
let url;
|
|
311
|
+
try {
|
|
312
|
+
url = new URL2(urlString);
|
|
313
|
+
if (!["http:", "https:"].includes(url.protocol) || url.hostname !== "localhost" && url.hostname !== "127.0.0.1") {
|
|
314
|
+
throw new Error("Invalid URL protocol or non-localhost hostname");
|
|
315
|
+
}
|
|
316
|
+
} catch (e) {
|
|
317
|
+
console.error("Invalid URL:", e);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
switch (process.platform) {
|
|
321
|
+
case "darwin": {
|
|
322
|
+
const scriptPath = path.join(process.env.TMPDIR || "/tmp", `open-browser-${Date.now()}.applescript`);
|
|
323
|
+
const script = `open location "${urlString}"`;
|
|
324
|
+
fs2.writeFileSync(scriptPath, script);
|
|
325
|
+
await execAsync(`osascript "${scriptPath}"`);
|
|
326
|
+
try {
|
|
327
|
+
fs2.unlinkSync(scriptPath);
|
|
328
|
+
} catch (e) {
|
|
329
|
+
}
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
case "win32": {
|
|
333
|
+
await execAsync(`rundll32 url.dll,FileProtocolHandler "${urlString}"`);
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
default: {
|
|
337
|
+
const browsers = ["xdg-open", "google-chrome", "firefox", "chromium-browser"];
|
|
338
|
+
for (const browser of browsers) {
|
|
339
|
+
try {
|
|
340
|
+
await execAsync(`which ${browser}`);
|
|
341
|
+
await execAsync(`${browser} "${urlString}"`);
|
|
342
|
+
break;
|
|
343
|
+
} catch {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
} catch (error) {
|
|
350
|
+
console.error("Failed to open browser:", error);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
cleanup() {
|
|
354
|
+
if (this.server) {
|
|
355
|
+
this.server.close();
|
|
356
|
+
this.server = null;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// src/index.ts
|
|
364
|
+
import { z as z2 } from "zod";
|
|
365
|
+
|
|
366
|
+
// src/toolDefinitionMap.ts
|
|
367
|
+
var toolDefinitionMap = [
|
|
368
|
+
{
|
|
369
|
+
"name": "ShowCardInfo",
|
|
370
|
+
"description": "Provide information for the Infinity Cloud Services display card",
|
|
371
|
+
"inputSchema": {
|
|
372
|
+
"type": "object",
|
|
373
|
+
"properties": {}
|
|
374
|
+
},
|
|
375
|
+
"method": "post",
|
|
376
|
+
"pathTemplate": "/insights/v3.0/show-card-info",
|
|
377
|
+
"parameters": [],
|
|
378
|
+
"executionParameters": [],
|
|
379
|
+
"securityRequirements": [],
|
|
380
|
+
"operationId": "ShowCardInfo",
|
|
381
|
+
"baseUrl": ""
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
"name": "ShowConfig",
|
|
385
|
+
"description": "Get user configuration and settings for Policy Insights product",
|
|
386
|
+
"inputSchema": {
|
|
387
|
+
"type": "object",
|
|
388
|
+
"properties": {}
|
|
389
|
+
},
|
|
390
|
+
"method": "post",
|
|
391
|
+
"pathTemplate": "/insights/v3.0/show-config",
|
|
392
|
+
"parameters": [],
|
|
393
|
+
"executionParameters": [],
|
|
394
|
+
"securityRequirements": [],
|
|
395
|
+
"operationId": "ShowConfig",
|
|
396
|
+
"baseUrl": ""
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"name": "ShowRulesUidsWithSuggestions",
|
|
400
|
+
"description": "Retrieve rule UIDs that have suggestions for a specific suggestion type using the required layer UID\nEnhanced to show both direct suggestions and inline layer suggestions",
|
|
401
|
+
"inputSchema": {
|
|
402
|
+
"type": "object",
|
|
403
|
+
"properties": {
|
|
404
|
+
"requestBody": {
|
|
405
|
+
"properties": {
|
|
406
|
+
"layer": {
|
|
407
|
+
"type": "string",
|
|
408
|
+
"format": "uuid",
|
|
409
|
+
"description": "Access layer identifier in UUID format",
|
|
410
|
+
"pattern": "^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$"
|
|
411
|
+
},
|
|
412
|
+
"filters": {
|
|
413
|
+
"properties": {
|
|
414
|
+
"states": {
|
|
415
|
+
"items": {
|
|
416
|
+
"description": "State of a suggestion - either ACCEPTED or REJECTED",
|
|
417
|
+
"enum": [
|
|
418
|
+
"ACCEPTED",
|
|
419
|
+
"REJECTED"
|
|
420
|
+
],
|
|
421
|
+
"type": "string",
|
|
422
|
+
"x-enum-varnames": [
|
|
423
|
+
"ACCEPTED",
|
|
424
|
+
"REJECTED"
|
|
425
|
+
]
|
|
426
|
+
},
|
|
427
|
+
"type": "array",
|
|
428
|
+
"description": "Array of insight state values"
|
|
429
|
+
},
|
|
430
|
+
"user-interaction": {
|
|
431
|
+
"properties": {
|
|
432
|
+
"operator": {
|
|
433
|
+
"description": "Operator for filtering by user-interaction-types",
|
|
434
|
+
"enum": [
|
|
435
|
+
"NOT-IN",
|
|
436
|
+
"IN"
|
|
437
|
+
],
|
|
438
|
+
"type": "string",
|
|
439
|
+
"x-enum-varnames": [
|
|
440
|
+
"NOT_IN",
|
|
441
|
+
"IN"
|
|
442
|
+
]
|
|
443
|
+
},
|
|
444
|
+
"types": {
|
|
445
|
+
"items": {
|
|
446
|
+
"description": "Type of user interaction with an insight",
|
|
447
|
+
"enum": [
|
|
448
|
+
"DECIDE_LATER"
|
|
449
|
+
],
|
|
450
|
+
"type": "string",
|
|
451
|
+
"x-enum-varnames": [
|
|
452
|
+
"DECIDE_LATER"
|
|
453
|
+
]
|
|
454
|
+
},
|
|
455
|
+
"type": "array",
|
|
456
|
+
"description": "Array of user interaction type values"
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
"required": [
|
|
460
|
+
"types"
|
|
461
|
+
],
|
|
462
|
+
"type": "object"
|
|
463
|
+
},
|
|
464
|
+
"security-impact": {
|
|
465
|
+
"enum": [
|
|
466
|
+
"HIGH",
|
|
467
|
+
"MEDIUM_AND_ABOVE",
|
|
468
|
+
"LOW_AND_ABOVE"
|
|
469
|
+
],
|
|
470
|
+
"type": "string",
|
|
471
|
+
"x-enum-varnames": [
|
|
472
|
+
"HIGH",
|
|
473
|
+
"MEDIUM_AND_ABOVE",
|
|
474
|
+
"LOW_AND_ABOVE"
|
|
475
|
+
],
|
|
476
|
+
"description": "Minimum security impact threshold to include"
|
|
477
|
+
},
|
|
478
|
+
"confidence-level": {
|
|
479
|
+
"enum": [
|
|
480
|
+
"HIGH",
|
|
481
|
+
"MEDIUM_AND_ABOVE",
|
|
482
|
+
"LOW_AND_ABOVE"
|
|
483
|
+
],
|
|
484
|
+
"type": "string",
|
|
485
|
+
"x-enum-varnames": [
|
|
486
|
+
"HIGH",
|
|
487
|
+
"MEDIUM_AND_ABOVE",
|
|
488
|
+
"LOW_AND_ABOVE"
|
|
489
|
+
],
|
|
490
|
+
"description": "Minimum confidence threshold to include"
|
|
491
|
+
},
|
|
492
|
+
"default-filter": {
|
|
493
|
+
"enum": [
|
|
494
|
+
"NONE"
|
|
495
|
+
],
|
|
496
|
+
"type": "string",
|
|
497
|
+
"x-enum-varnames": [
|
|
498
|
+
"NONE"
|
|
499
|
+
],
|
|
500
|
+
"description": "Ignore default filtering of the system"
|
|
501
|
+
},
|
|
502
|
+
"suggestions-type": {
|
|
503
|
+
"description": "Type of insight",
|
|
504
|
+
"enum": [
|
|
505
|
+
"unused-objects",
|
|
506
|
+
"tighten-rule",
|
|
507
|
+
"delete-disabled-rule",
|
|
508
|
+
"zero-hits-rule"
|
|
509
|
+
],
|
|
510
|
+
"type": "string",
|
|
511
|
+
"x-enum-varnames": [
|
|
512
|
+
"UnusedObjects",
|
|
513
|
+
"TightenRule",
|
|
514
|
+
"DeleteDisabledRule",
|
|
515
|
+
"ZeroHitsRule"
|
|
516
|
+
]
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
"required": [
|
|
520
|
+
"suggestions-type"
|
|
521
|
+
],
|
|
522
|
+
"type": "object"
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
"required": [
|
|
526
|
+
"layer",
|
|
527
|
+
"filters"
|
|
528
|
+
],
|
|
529
|
+
"type": "object",
|
|
530
|
+
"description": "Parameters for showing rules UIDs with their suggestions"
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
"required": [
|
|
534
|
+
"requestBody"
|
|
535
|
+
]
|
|
536
|
+
},
|
|
537
|
+
"method": "post",
|
|
538
|
+
"pathTemplate": "/insights/v3.0/show-rules-uids-with-suggestions",
|
|
539
|
+
"parameters": [],
|
|
540
|
+
"executionParameters": [],
|
|
541
|
+
"requestBodyContentType": "application/json",
|
|
542
|
+
"securityRequirements": [],
|
|
543
|
+
"operationId": "ShowRulesUidsWithSuggestions",
|
|
544
|
+
"baseUrl": ""
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
"name": "ShowState",
|
|
548
|
+
"description": "Shows Policy Insights enabled/disabled status\nAllows the Infinity Cloud Services page to determine current state",
|
|
549
|
+
"inputSchema": {
|
|
550
|
+
"type": "object",
|
|
551
|
+
"properties": {}
|
|
552
|
+
},
|
|
553
|
+
"method": "post",
|
|
554
|
+
"pathTemplate": "/insights/v3.0/show-state",
|
|
555
|
+
"parameters": [],
|
|
556
|
+
"executionParameters": [],
|
|
557
|
+
"securityRequirements": [],
|
|
558
|
+
"operationId": "ShowState",
|
|
559
|
+
"baseUrl": ""
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
"name": "ShowSuggestionEngineMetadata",
|
|
563
|
+
"description": "Retrieve next suggestions engine run schedule for each suggestion type",
|
|
564
|
+
"inputSchema": {
|
|
565
|
+
"type": "object",
|
|
566
|
+
"properties": {
|
|
567
|
+
"requestBody": {
|
|
568
|
+
"properties": {
|
|
569
|
+
"filters": {
|
|
570
|
+
"properties": {
|
|
571
|
+
"suggestion-type": {
|
|
572
|
+
"description": "Type of insight",
|
|
573
|
+
"enum": [
|
|
574
|
+
"unused-objects",
|
|
575
|
+
"tighten-rule",
|
|
576
|
+
"delete-disabled-rule",
|
|
577
|
+
"zero-hits-rule"
|
|
578
|
+
],
|
|
579
|
+
"type": "string",
|
|
580
|
+
"x-enum-varnames": [
|
|
581
|
+
"UnusedObjects",
|
|
582
|
+
"TightenRule",
|
|
583
|
+
"DeleteDisabledRule",
|
|
584
|
+
"ZeroHitsRule"
|
|
585
|
+
]
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
"type": "object"
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
"type": "object",
|
|
592
|
+
"description": "The JSON request body."
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
"required": [
|
|
596
|
+
"requestBody"
|
|
597
|
+
]
|
|
598
|
+
},
|
|
599
|
+
"method": "post",
|
|
600
|
+
"pathTemplate": "/insights/v3.0/show-suggestion-engine-metadata",
|
|
601
|
+
"parameters": [],
|
|
602
|
+
"executionParameters": [],
|
|
603
|
+
"requestBodyContentType": "application/json",
|
|
604
|
+
"securityRequirements": [],
|
|
605
|
+
"operationId": "ShowSuggestionEngineMetadata",
|
|
606
|
+
"baseUrl": ""
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
"name": "ShowSuggestions",
|
|
610
|
+
"description": 'Retrieve all suggestions with advanced filtering capabilities.\nIncludes suggestions from all inline layers.\nExcludes rejected/accepted suggestions by default.\n\nRequired Parameters:\n- Must provide either "layer" OR "filters.rules-uids" OR "filters.uids"\n- Cannot retrieve suggestions without specifying at least one of these targeting parameters',
|
|
611
|
+
"inputSchema": {
|
|
612
|
+
"type": "object",
|
|
613
|
+
"properties": {
|
|
614
|
+
"requestBody": {
|
|
615
|
+
"properties": {
|
|
616
|
+
"layer": {
|
|
617
|
+
"type": "string",
|
|
618
|
+
"format": "uuid",
|
|
619
|
+
"description": "Access layer identifier in UUID format",
|
|
620
|
+
"pattern": "^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$"
|
|
621
|
+
},
|
|
622
|
+
"options": {
|
|
623
|
+
"properties": {
|
|
624
|
+
"include-inline-layers": {
|
|
625
|
+
"type": "boolean",
|
|
626
|
+
"description": "Whether to include insights on inline layers"
|
|
627
|
+
}
|
|
628
|
+
},
|
|
629
|
+
"type": "object"
|
|
630
|
+
},
|
|
631
|
+
"limit": {
|
|
632
|
+
"type": "number",
|
|
633
|
+
"format": "int32",
|
|
634
|
+
"description": "Maximum number of items to return"
|
|
635
|
+
},
|
|
636
|
+
"offset": {
|
|
637
|
+
"type": "number",
|
|
638
|
+
"format": "int32",
|
|
639
|
+
"description": "Number of items to skip for pagination"
|
|
640
|
+
},
|
|
641
|
+
"filters": {
|
|
642
|
+
"properties": {
|
|
643
|
+
"states": {
|
|
644
|
+
"items": {
|
|
645
|
+
"description": "State of a suggestion - either ACCEPTED or REJECTED",
|
|
646
|
+
"enum": [
|
|
647
|
+
"ACCEPTED",
|
|
648
|
+
"REJECTED"
|
|
649
|
+
],
|
|
650
|
+
"type": "string",
|
|
651
|
+
"x-enum-varnames": [
|
|
652
|
+
"ACCEPTED",
|
|
653
|
+
"REJECTED"
|
|
654
|
+
]
|
|
655
|
+
},
|
|
656
|
+
"type": "array",
|
|
657
|
+
"description": "Array of insight state values"
|
|
658
|
+
},
|
|
659
|
+
"user-interaction": {
|
|
660
|
+
"properties": {
|
|
661
|
+
"operator": {
|
|
662
|
+
"description": "Operator for filtering by user-interaction-types",
|
|
663
|
+
"enum": [
|
|
664
|
+
"NOT-IN",
|
|
665
|
+
"IN"
|
|
666
|
+
],
|
|
667
|
+
"type": "string",
|
|
668
|
+
"x-enum-varnames": [
|
|
669
|
+
"NOT_IN",
|
|
670
|
+
"IN"
|
|
671
|
+
]
|
|
672
|
+
},
|
|
673
|
+
"types": {
|
|
674
|
+
"items": {
|
|
675
|
+
"description": "Type of user interaction with an insight",
|
|
676
|
+
"enum": [
|
|
677
|
+
"DECIDE_LATER"
|
|
678
|
+
],
|
|
679
|
+
"type": "string",
|
|
680
|
+
"x-enum-varnames": [
|
|
681
|
+
"DECIDE_LATER"
|
|
682
|
+
]
|
|
683
|
+
},
|
|
684
|
+
"type": "array",
|
|
685
|
+
"description": "Array of user interaction type values"
|
|
686
|
+
}
|
|
687
|
+
},
|
|
688
|
+
"required": [
|
|
689
|
+
"types"
|
|
690
|
+
],
|
|
691
|
+
"type": "object"
|
|
692
|
+
},
|
|
693
|
+
"security-impact": {
|
|
694
|
+
"enum": [
|
|
695
|
+
"HIGH",
|
|
696
|
+
"MEDIUM_AND_ABOVE",
|
|
697
|
+
"LOW_AND_ABOVE"
|
|
698
|
+
],
|
|
699
|
+
"type": "string",
|
|
700
|
+
"x-enum-varnames": [
|
|
701
|
+
"HIGH",
|
|
702
|
+
"MEDIUM_AND_ABOVE",
|
|
703
|
+
"LOW_AND_ABOVE"
|
|
704
|
+
],
|
|
705
|
+
"description": "Minimum security impact threshold to include"
|
|
706
|
+
},
|
|
707
|
+
"confidence-level": {
|
|
708
|
+
"enum": [
|
|
709
|
+
"HIGH",
|
|
710
|
+
"MEDIUM_AND_ABOVE",
|
|
711
|
+
"LOW_AND_ABOVE"
|
|
712
|
+
],
|
|
713
|
+
"type": "string",
|
|
714
|
+
"x-enum-varnames": [
|
|
715
|
+
"HIGH",
|
|
716
|
+
"MEDIUM_AND_ABOVE",
|
|
717
|
+
"LOW_AND_ABOVE"
|
|
718
|
+
],
|
|
719
|
+
"description": "Minimum confidence threshold to include"
|
|
720
|
+
},
|
|
721
|
+
"default-filter": {
|
|
722
|
+
"enum": [
|
|
723
|
+
"NONE"
|
|
724
|
+
],
|
|
725
|
+
"type": "string",
|
|
726
|
+
"x-enum-varnames": [
|
|
727
|
+
"NONE"
|
|
728
|
+
],
|
|
729
|
+
"description": "Ignore default filtering of the system"
|
|
730
|
+
},
|
|
731
|
+
"uids": {
|
|
732
|
+
"items": {
|
|
733
|
+
"type": "string",
|
|
734
|
+
"format": "uuid",
|
|
735
|
+
"description": "Stringified UUID.",
|
|
736
|
+
"pattern": "^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$"
|
|
737
|
+
},
|
|
738
|
+
"type": "array",
|
|
739
|
+
"description": "Array of insight unique identifiers"
|
|
740
|
+
},
|
|
741
|
+
"rules-uids": {
|
|
742
|
+
"items": {
|
|
743
|
+
"type": "string",
|
|
744
|
+
"format": "uuid",
|
|
745
|
+
"description": "Stringified UUID.",
|
|
746
|
+
"pattern": "^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$"
|
|
747
|
+
},
|
|
748
|
+
"type": "array",
|
|
749
|
+
"description": "Array of rule unique identifiers"
|
|
750
|
+
},
|
|
751
|
+
"types": {
|
|
752
|
+
"items": {
|
|
753
|
+
"description": "Type of insight",
|
|
754
|
+
"enum": [
|
|
755
|
+
"unused-objects",
|
|
756
|
+
"tighten-rule",
|
|
757
|
+
"delete-disabled-rule",
|
|
758
|
+
"zero-hits-rule"
|
|
759
|
+
],
|
|
760
|
+
"type": "string",
|
|
761
|
+
"x-enum-varnames": [
|
|
762
|
+
"UnusedObjects",
|
|
763
|
+
"TightenRule",
|
|
764
|
+
"DeleteDisabledRule",
|
|
765
|
+
"ZeroHitsRule"
|
|
766
|
+
]
|
|
767
|
+
},
|
|
768
|
+
"type": "array",
|
|
769
|
+
"description": "Type of insight"
|
|
770
|
+
}
|
|
771
|
+
},
|
|
772
|
+
"type": "object"
|
|
773
|
+
}
|
|
774
|
+
},
|
|
775
|
+
"type": "object",
|
|
776
|
+
"description": "Parameters for showing suggestions with enhanced v3.0 capabilities"
|
|
777
|
+
}
|
|
778
|
+
},
|
|
779
|
+
"required": [
|
|
780
|
+
"requestBody"
|
|
781
|
+
]
|
|
782
|
+
},
|
|
783
|
+
"method": "post",
|
|
784
|
+
"pathTemplate": "/insights/v3.0/show-suggestions",
|
|
785
|
+
"parameters": [],
|
|
786
|
+
"executionParameters": [],
|
|
787
|
+
"requestBodyContentType": "application/json",
|
|
788
|
+
"securityRequirements": [],
|
|
789
|
+
"operationId": "ShowSuggestions",
|
|
790
|
+
"baseUrl": ""
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
"name": "ShowSuggestionsInfo",
|
|
794
|
+
"description": "Retrieve detailed information such as last engine run, next run schedule and suggestions status, can be specified by suggestion type.\nProvides onboarding guidance for cases where the system has not yet completed its first analysis and generated its first set of insights,\nor if insights were generated but can't see the suggestions.",
|
|
795
|
+
"inputSchema": {
|
|
796
|
+
"type": "object",
|
|
797
|
+
"properties": {
|
|
798
|
+
"requestBody": {
|
|
799
|
+
"properties": {
|
|
800
|
+
"layer": {
|
|
801
|
+
"type": "string",
|
|
802
|
+
"format": "uuid",
|
|
803
|
+
"description": "Access layer identifier in UUID format",
|
|
804
|
+
"pattern": "^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$"
|
|
805
|
+
}
|
|
806
|
+
},
|
|
807
|
+
"required": [
|
|
808
|
+
"layer"
|
|
809
|
+
],
|
|
810
|
+
"type": "object",
|
|
811
|
+
"description": "The JSON request body."
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
"required": [
|
|
815
|
+
"requestBody"
|
|
816
|
+
]
|
|
817
|
+
},
|
|
818
|
+
"method": "post",
|
|
819
|
+
"pathTemplate": "/insights/v3.0/show-suggestions-info",
|
|
820
|
+
"parameters": [],
|
|
821
|
+
"executionParameters": [],
|
|
822
|
+
"requestBodyContentType": "application/json",
|
|
823
|
+
"securityRequirements": [],
|
|
824
|
+
"operationId": "ShowSuggestionsInfo",
|
|
825
|
+
"baseUrl": ""
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
"name": "ShowSuggestionsSummary",
|
|
829
|
+
"description": "Retrieve number of rule suggestions grouped by their type.\nProvides generation batch metadata about the current suggestions we see: how many days of traffic logs were analyzed, on which publish timestamp the suggestions are based on.",
|
|
830
|
+
"inputSchema": {
|
|
831
|
+
"type": "object",
|
|
832
|
+
"properties": {
|
|
833
|
+
"requestBody": {
|
|
834
|
+
"properties": {
|
|
835
|
+
"layer": {
|
|
836
|
+
"type": "string",
|
|
837
|
+
"format": "uuid",
|
|
838
|
+
"description": "Access layer identifier in UUID format",
|
|
839
|
+
"pattern": "^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$"
|
|
840
|
+
},
|
|
841
|
+
"filters": {
|
|
842
|
+
"properties": {
|
|
843
|
+
"states": {
|
|
844
|
+
"items": {
|
|
845
|
+
"description": "State of a suggestion - either ACCEPTED or REJECTED",
|
|
846
|
+
"enum": [
|
|
847
|
+
"ACCEPTED",
|
|
848
|
+
"REJECTED"
|
|
849
|
+
],
|
|
850
|
+
"type": "string",
|
|
851
|
+
"x-enum-varnames": [
|
|
852
|
+
"ACCEPTED",
|
|
853
|
+
"REJECTED"
|
|
854
|
+
]
|
|
855
|
+
},
|
|
856
|
+
"type": "array",
|
|
857
|
+
"description": "Array of insight state values"
|
|
858
|
+
},
|
|
859
|
+
"user-interaction": {
|
|
860
|
+
"properties": {
|
|
861
|
+
"operator": {
|
|
862
|
+
"description": "Operator for filtering by user-interaction-types",
|
|
863
|
+
"enum": [
|
|
864
|
+
"NOT-IN",
|
|
865
|
+
"IN"
|
|
866
|
+
],
|
|
867
|
+
"type": "string",
|
|
868
|
+
"x-enum-varnames": [
|
|
869
|
+
"NOT_IN",
|
|
870
|
+
"IN"
|
|
871
|
+
]
|
|
872
|
+
},
|
|
873
|
+
"types": {
|
|
874
|
+
"items": {
|
|
875
|
+
"description": "Type of user interaction with an insight",
|
|
876
|
+
"enum": [
|
|
877
|
+
"DECIDE_LATER"
|
|
878
|
+
],
|
|
879
|
+
"type": "string",
|
|
880
|
+
"x-enum-varnames": [
|
|
881
|
+
"DECIDE_LATER"
|
|
882
|
+
]
|
|
883
|
+
},
|
|
884
|
+
"type": "array",
|
|
885
|
+
"description": "Array of user interaction type values"
|
|
886
|
+
}
|
|
887
|
+
},
|
|
888
|
+
"required": [
|
|
889
|
+
"types"
|
|
890
|
+
],
|
|
891
|
+
"type": "object"
|
|
892
|
+
},
|
|
893
|
+
"security-impact": {
|
|
894
|
+
"enum": [
|
|
895
|
+
"HIGH",
|
|
896
|
+
"MEDIUM_AND_ABOVE",
|
|
897
|
+
"LOW_AND_ABOVE"
|
|
898
|
+
],
|
|
899
|
+
"type": "string",
|
|
900
|
+
"x-enum-varnames": [
|
|
901
|
+
"HIGH",
|
|
902
|
+
"MEDIUM_AND_ABOVE",
|
|
903
|
+
"LOW_AND_ABOVE"
|
|
904
|
+
],
|
|
905
|
+
"description": "Minimum security impact threshold to include"
|
|
906
|
+
},
|
|
907
|
+
"confidence-level": {
|
|
908
|
+
"enum": [
|
|
909
|
+
"HIGH",
|
|
910
|
+
"MEDIUM_AND_ABOVE",
|
|
911
|
+
"LOW_AND_ABOVE"
|
|
912
|
+
],
|
|
913
|
+
"type": "string",
|
|
914
|
+
"x-enum-varnames": [
|
|
915
|
+
"HIGH",
|
|
916
|
+
"MEDIUM_AND_ABOVE",
|
|
917
|
+
"LOW_AND_ABOVE"
|
|
918
|
+
],
|
|
919
|
+
"description": "Minimum confidence threshold to include"
|
|
920
|
+
},
|
|
921
|
+
"default-filter": {
|
|
922
|
+
"enum": [
|
|
923
|
+
"NONE"
|
|
924
|
+
],
|
|
925
|
+
"type": "string",
|
|
926
|
+
"x-enum-varnames": [
|
|
927
|
+
"NONE"
|
|
928
|
+
],
|
|
929
|
+
"description": "Ignore default filtering of the system"
|
|
930
|
+
}
|
|
931
|
+
},
|
|
932
|
+
"type": "object"
|
|
933
|
+
}
|
|
934
|
+
},
|
|
935
|
+
"type": "object",
|
|
936
|
+
"description": "Parameters for showing suggestions summary"
|
|
937
|
+
}
|
|
938
|
+
},
|
|
939
|
+
"required": [
|
|
940
|
+
"requestBody"
|
|
941
|
+
]
|
|
942
|
+
},
|
|
943
|
+
"method": "post",
|
|
944
|
+
"pathTemplate": "/insights/v3.0/show-suggestions-summary",
|
|
945
|
+
"parameters": [],
|
|
946
|
+
"executionParameters": [],
|
|
947
|
+
"requestBodyContentType": "application/json",
|
|
948
|
+
"securityRequirements": [],
|
|
949
|
+
"operationId": "ShowSuggestionsSummary",
|
|
950
|
+
"baseUrl": ""
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
"name": "ShowPolicyInsightsStatus",
|
|
954
|
+
"description": "Shows Policy Insights status, reflecting the overall status of the product including supported API versions.\nReturns both Insights API versions and Threat Prevention Insights API versions when Threat Prevention is enabled.\nMay also include license status information if available.\nA license is required to activate the product, and the status provides details about the validity and expiration of the product license.",
|
|
955
|
+
"inputSchema": {
|
|
956
|
+
"type": "object",
|
|
957
|
+
"properties": {}
|
|
958
|
+
},
|
|
959
|
+
"method": "post",
|
|
960
|
+
"pathTemplate": "/show-policy-insights-status",
|
|
961
|
+
"parameters": [],
|
|
962
|
+
"executionParameters": [],
|
|
963
|
+
"securityRequirements": [],
|
|
964
|
+
"operationId": "ShowPolicyInsightsStatus",
|
|
965
|
+
"baseUrl": ""
|
|
966
|
+
}
|
|
967
|
+
];
|
|
968
|
+
|
|
969
|
+
// ../infra/dist/api-client.js
|
|
970
|
+
import axios from "axios";
|
|
971
|
+
import https from "https";
|
|
972
|
+
var TokenType;
|
|
973
|
+
(function(TokenType2) {
|
|
974
|
+
TokenType2["API_KEY"] = "API_KEY";
|
|
975
|
+
TokenType2["CI_TOKEN"] = "CI_TOKEN";
|
|
976
|
+
})(TokenType || (TokenType = {}));
|
|
977
|
+
function getMainPackageUserAgent() {
|
|
978
|
+
if (process.env.CP_MCP_MAIN_PKG) {
|
|
979
|
+
if (process.env.CP_MCP_MAIN_PKG.includes("quantum-management-mcp")) {
|
|
980
|
+
return "mgmt-mcp";
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
return "Check Point MCP API Client";
|
|
984
|
+
}
|
|
985
|
+
var ClientResponse = class {
|
|
986
|
+
constructor(status, response) {
|
|
987
|
+
this.status = status;
|
|
988
|
+
this.response = response;
|
|
989
|
+
}
|
|
990
|
+
};
|
|
991
|
+
var APIClientBase = class {
|
|
992
|
+
constructor(authToken = "", tokenType = TokenType.API_KEY) {
|
|
993
|
+
this.authToken = authToken;
|
|
994
|
+
this.tokenType = tokenType;
|
|
995
|
+
this.sid = null;
|
|
996
|
+
this.sessionTimeout = null;
|
|
997
|
+
this.sessionStart = null;
|
|
998
|
+
this.isMDS = false;
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Create an API client instance - generic method for creating clients
|
|
1002
|
+
*/
|
|
1003
|
+
static create(...args) {
|
|
1004
|
+
return new this(...args);
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Get headers for the API requests
|
|
1008
|
+
*/
|
|
1009
|
+
getHeaders() {
|
|
1010
|
+
const headers = {
|
|
1011
|
+
"Content-Type": "application/json",
|
|
1012
|
+
"User-Agent": getMainPackageUserAgent()
|
|
1013
|
+
};
|
|
1014
|
+
if (this.sid) {
|
|
1015
|
+
headers["X-chkp-sid"] = this.sid;
|
|
1016
|
+
}
|
|
1017
|
+
return headers;
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Get debug mode
|
|
1021
|
+
*/
|
|
1022
|
+
get debug() {
|
|
1023
|
+
return !!this._debug;
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* Set debug mode
|
|
1027
|
+
*/
|
|
1028
|
+
set debug(value) {
|
|
1029
|
+
this._debug = value;
|
|
1030
|
+
}
|
|
1031
|
+
/**
|
|
1032
|
+
* Check if this client needs to perform login before making API calls
|
|
1033
|
+
*/
|
|
1034
|
+
needsLogin() {
|
|
1035
|
+
return true;
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Check if this client is in an MDS environment
|
|
1039
|
+
*/
|
|
1040
|
+
async isMDSEnvironment() {
|
|
1041
|
+
if (!this.hasValidSession()) {
|
|
1042
|
+
await this.login();
|
|
1043
|
+
}
|
|
1044
|
+
return this.isMDS;
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Check if the client has a valid session
|
|
1048
|
+
*/
|
|
1049
|
+
hasValidSession() {
|
|
1050
|
+
return !!this.sid && !this.isSessionExpired();
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Get the current session ID (for debugging/logging purposes)
|
|
1054
|
+
*/
|
|
1055
|
+
getSessionId() {
|
|
1056
|
+
return this.sid;
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Create a new API client instance with a specific session ID
|
|
1060
|
+
* Used for domain-specific clients in MDS environments
|
|
1061
|
+
*/
|
|
1062
|
+
static createWithSid(originalClient, sid) {
|
|
1063
|
+
const newClient = Object.create(Object.getPrototypeOf(originalClient));
|
|
1064
|
+
Object.assign(newClient, originalClient);
|
|
1065
|
+
newClient.sid = sid;
|
|
1066
|
+
newClient.sessionStart = Date.now();
|
|
1067
|
+
return newClient;
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* Call an API endpoint
|
|
1071
|
+
*/
|
|
1072
|
+
async callApi(method, uri, data, params) {
|
|
1073
|
+
if (this.needsLogin() && (!this.sid || this.isSessionExpired())) {
|
|
1074
|
+
try {
|
|
1075
|
+
await this.login();
|
|
1076
|
+
} catch (error) {
|
|
1077
|
+
if (error instanceof ClientResponse) {
|
|
1078
|
+
console.error(`Login failed with status ${error.status}:`, error.response);
|
|
1079
|
+
return error;
|
|
1080
|
+
}
|
|
1081
|
+
console.error("Login failed with unexpected error:", error);
|
|
1082
|
+
return new ClientResponse(500, { error: "Authentication failed", message: error.message });
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
let httpsAgent;
|
|
1086
|
+
if (this instanceof OnPremAPIClient) {
|
|
1087
|
+
httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
|
1088
|
+
}
|
|
1089
|
+
try {
|
|
1090
|
+
return await this.makeRequest(this.getHost(), method, uri, data, this.getHeaders(), params, httpsAgent);
|
|
1091
|
+
} catch (error) {
|
|
1092
|
+
if ((error.message?.includes("401") || error.response?.status === 401) && error.message?.toLowerCase().includes("session")) {
|
|
1093
|
+
console.error("Session expired (401), resetting session and retrying...");
|
|
1094
|
+
this.sid = null;
|
|
1095
|
+
this.sessionStart = null;
|
|
1096
|
+
try {
|
|
1097
|
+
await this.login();
|
|
1098
|
+
} catch (loginError) {
|
|
1099
|
+
if (loginError instanceof ClientResponse) {
|
|
1100
|
+
console.error(`Login retry failed with status ${loginError.status}:`, loginError.response);
|
|
1101
|
+
return loginError;
|
|
1102
|
+
}
|
|
1103
|
+
console.error("Login retry failed with unexpected error:", loginError);
|
|
1104
|
+
throw loginError;
|
|
1105
|
+
}
|
|
1106
|
+
return await this.makeRequest(this.getHost(), method, uri, data, this.getHeaders(), params, httpsAgent);
|
|
1107
|
+
}
|
|
1108
|
+
throw error;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Check if the session is expired based on sessionTimeout and sessionStart
|
|
1113
|
+
*/
|
|
1114
|
+
isSessionExpired() {
|
|
1115
|
+
if (!this.sid || !this.sessionTimeout || !this.sessionStart)
|
|
1116
|
+
return true;
|
|
1117
|
+
const now = Date.now();
|
|
1118
|
+
return now > this.sessionStart + (this.sessionTimeout - 5) * 1e3;
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Login to the API using the API key
|
|
1122
|
+
*/
|
|
1123
|
+
async login() {
|
|
1124
|
+
const apiTokenHeader = this.tokenType === TokenType.API_KEY ? "api-key" : "ci-token";
|
|
1125
|
+
const loginResp = await this.makeRequest(this.getHost(), "POST", "login", { [apiTokenHeader]: this.authToken }, { "Content-Type": "application/json" });
|
|
1126
|
+
if (loginResp.status !== 200 || !loginResp.response || !loginResp.response.sid) {
|
|
1127
|
+
throw loginResp;
|
|
1128
|
+
}
|
|
1129
|
+
this.sid = loginResp.response.sid;
|
|
1130
|
+
this.sessionTimeout = loginResp.response["session-timeout"] || null;
|
|
1131
|
+
this.sessionStart = Date.now();
|
|
1132
|
+
if (loginResp.response.uid) {
|
|
1133
|
+
await this.detectMDS(loginResp.response.uid);
|
|
1134
|
+
}
|
|
1135
|
+
return loginResp.response.sid;
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Detect if this is an MDS environment by checking the session details
|
|
1139
|
+
*/
|
|
1140
|
+
async detectMDS(sessionUid, handleSelfSigned = false) {
|
|
1141
|
+
try {
|
|
1142
|
+
let httpsAgent;
|
|
1143
|
+
if (handleSelfSigned) {
|
|
1144
|
+
httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
|
1145
|
+
}
|
|
1146
|
+
const sessionResp = await this.makeRequest(this.getHost(), "POST", "show-session", { uid: sessionUid }, this.getHeaders(), null, httpsAgent);
|
|
1147
|
+
if (sessionResp.status === 200 && sessionResp.response?.domain?.["domain-type"] === "mds") {
|
|
1148
|
+
this.isMDS = true;
|
|
1149
|
+
}
|
|
1150
|
+
} catch (error) {
|
|
1151
|
+
console.warn("Could not determine MDS status:", error);
|
|
1152
|
+
this.isMDS = false;
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* Make a request to a Check Point API
|
|
1157
|
+
*/
|
|
1158
|
+
async makeRequest(host, method, uri, data, headers = {}, params = null, httpsAgent) {
|
|
1159
|
+
uri = uri.replace(/^\//, "");
|
|
1160
|
+
const url = `${host}/${uri}`;
|
|
1161
|
+
const config = {
|
|
1162
|
+
method: method.toUpperCase(),
|
|
1163
|
+
url,
|
|
1164
|
+
headers,
|
|
1165
|
+
params: params || void 0
|
|
1166
|
+
};
|
|
1167
|
+
if (httpsAgent) {
|
|
1168
|
+
config.httpsAgent = httpsAgent;
|
|
1169
|
+
}
|
|
1170
|
+
if (method.toUpperCase() !== "GET" && data !== void 0) {
|
|
1171
|
+
config.data = data;
|
|
1172
|
+
}
|
|
1173
|
+
console.error(`API Request: ${method} ${url}`);
|
|
1174
|
+
try {
|
|
1175
|
+
const response = await axios(config);
|
|
1176
|
+
return new ClientResponse(response.status, response.data);
|
|
1177
|
+
} catch (error) {
|
|
1178
|
+
if (error.response) {
|
|
1179
|
+
console.error(`\u274C API Error (${error.response.status}):`);
|
|
1180
|
+
console.error("Headers:", error.response.headers);
|
|
1181
|
+
console.error("Data:", error.response.data);
|
|
1182
|
+
if (this.debug) {
|
|
1183
|
+
console.error("Debug mode: Printing request details:");
|
|
1184
|
+
console.error("Request Method:", method);
|
|
1185
|
+
console.error("Request URL:", url);
|
|
1186
|
+
console.error("Request Headers:", config.headers);
|
|
1187
|
+
console.error("Request Data:", config.data);
|
|
1188
|
+
console.error("Request Params:", config.params);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
if (error.response) {
|
|
1192
|
+
throw new Error(`API request failed: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
|
|
1193
|
+
}
|
|
1194
|
+
throw error;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1198
|
+
var SmartOneCloudAPIClient = class extends APIClientBase {
|
|
1199
|
+
constructor(authToken, tokenType, s1cUrl) {
|
|
1200
|
+
super(authToken, tokenType);
|
|
1201
|
+
this.s1cUrl = s1cUrl;
|
|
1202
|
+
}
|
|
1203
|
+
getHost() {
|
|
1204
|
+
return this.s1cUrl;
|
|
1205
|
+
}
|
|
1206
|
+
};
|
|
1207
|
+
var OnPremAPIClient = class extends APIClientBase {
|
|
1208
|
+
constructor(apiKey, managementHost, managementPort = "443", username, password) {
|
|
1209
|
+
super(apiKey || "");
|
|
1210
|
+
this.managementHost = managementHost;
|
|
1211
|
+
this.managementPort = managementPort;
|
|
1212
|
+
this.username = username;
|
|
1213
|
+
this.password = password;
|
|
1214
|
+
}
|
|
1215
|
+
getHost() {
|
|
1216
|
+
const managementHost = this.managementHost;
|
|
1217
|
+
const port = this.managementPort;
|
|
1218
|
+
return `https://${managementHost}:${port}/web_api`;
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Override login() to support both api-key and username/password authentication
|
|
1222
|
+
* and allow self-signed certificates
|
|
1223
|
+
*/
|
|
1224
|
+
async login() {
|
|
1225
|
+
const isUsingApiKey = !!this.authToken;
|
|
1226
|
+
const isUsingCredentials = !!(this.username && this.password);
|
|
1227
|
+
if (!isUsingApiKey && !isUsingCredentials) {
|
|
1228
|
+
throw new ClientResponse(401, { message: "Authentication failed: No API key or username/password provided" });
|
|
1229
|
+
}
|
|
1230
|
+
const httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
|
1231
|
+
const loginPayload = isUsingApiKey ? { "api-key": this.authToken } : { "user": this.username, "password": this.password };
|
|
1232
|
+
const loginResp = await this.makeRequest(this.getHost(), "POST", "login", loginPayload, { "Content-Type": "application/json" }, null, httpsAgent);
|
|
1233
|
+
if (loginResp.status !== 200 || !loginResp.response || !loginResp.response.sid) {
|
|
1234
|
+
throw loginResp;
|
|
1235
|
+
}
|
|
1236
|
+
this.sid = loginResp.response.sid;
|
|
1237
|
+
this.sessionTimeout = loginResp.response["session-timeout"] || null;
|
|
1238
|
+
this.sessionStart = Date.now();
|
|
1239
|
+
if (loginResp.response.uid) {
|
|
1240
|
+
await this.detectMDS(loginResp.response.uid, true);
|
|
1241
|
+
}
|
|
1242
|
+
return loginResp.response.sid;
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
|
|
1246
|
+
// ../infra/dist/string-utils.js
|
|
1247
|
+
function nullOrEmpty(val) {
|
|
1248
|
+
return val === void 0 || val === null || typeof val === "string" && (val.trim() === "" || val === "undefined" || val === "null");
|
|
1249
|
+
}
|
|
1250
|
+
function sanitizeData(kwargs) {
|
|
1251
|
+
const data = {};
|
|
1252
|
+
for (const [key, value] of Object.entries(kwargs)) {
|
|
1253
|
+
if (value === null || value === void 0 || value === "" || Array.isArray(value) && value.length === 0) {
|
|
1254
|
+
continue;
|
|
1255
|
+
}
|
|
1256
|
+
const safeKey = key.replace(/_/g, "-");
|
|
1257
|
+
data[safeKey] = value;
|
|
1258
|
+
}
|
|
1259
|
+
return data;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// ../mcp-utils/dist/launcher.js
|
|
1263
|
+
import { Command } from "commander";
|
|
1264
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1265
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
1266
|
+
import fs from "fs";
|
|
1267
|
+
import http from "http";
|
|
1268
|
+
import { randomUUID } from "crypto";
|
|
1269
|
+
|
|
1270
|
+
// ../mcp-utils/dist/settings-manager.js
|
|
1271
|
+
var SettingsManager = class _SettingsManager {
|
|
1272
|
+
/**
|
|
1273
|
+
* Creates a new SettingsManager
|
|
1274
|
+
* @param settingsClass The Settings class to use for creating settings instances
|
|
1275
|
+
*/
|
|
1276
|
+
constructor(settingsClass) {
|
|
1277
|
+
this.settingsMap = /* @__PURE__ */ new Map();
|
|
1278
|
+
this.defaultSessionId = "default";
|
|
1279
|
+
this.settingsClass = settingsClass;
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Get settings for a specific session
|
|
1283
|
+
* @param sessionId The session ID (defaults to 'default' for stdio mode)
|
|
1284
|
+
* @returns Settings instance for the session
|
|
1285
|
+
*/
|
|
1286
|
+
getSettings(sessionId) {
|
|
1287
|
+
const sid = sessionId || this.defaultSessionId;
|
|
1288
|
+
if (!this.settingsMap.has(sid)) {
|
|
1289
|
+
this.settingsMap.set(sid, new this.settingsClass());
|
|
1290
|
+
}
|
|
1291
|
+
return this.settingsMap.get(sid);
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Set settings for a specific session
|
|
1295
|
+
* @param settings The settings object to set
|
|
1296
|
+
* @param sessionId The session ID (defaults to 'default' for stdio mode)
|
|
1297
|
+
*/
|
|
1298
|
+
setSettings(settings, sessionId) {
|
|
1299
|
+
const sid = sessionId || this.defaultSessionId;
|
|
1300
|
+
this.settingsMap.set(sid, settings);
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* Injects debug settings from source into settings object
|
|
1304
|
+
* @param settings The settings object to update
|
|
1305
|
+
* @param source Source object containing debug information
|
|
1306
|
+
* @private
|
|
1307
|
+
*/
|
|
1308
|
+
injectDebug(settings, source) {
|
|
1309
|
+
const debug = source?.debug ?? _SettingsManager.globalDebugState ?? process.env.DEBUG;
|
|
1310
|
+
if (typeof debug !== "undefined") {
|
|
1311
|
+
if (source?.debug !== void 0) {
|
|
1312
|
+
_SettingsManager.globalDebugState = source.debug;
|
|
1313
|
+
}
|
|
1314
|
+
if (typeof settings.set === "function") {
|
|
1315
|
+
settings.set("debug", debug);
|
|
1316
|
+
} else {
|
|
1317
|
+
settings.debug = debug;
|
|
1318
|
+
}
|
|
1319
|
+
if (debug) {
|
|
1320
|
+
console.error("Debug enabled. Source object contents:");
|
|
1321
|
+
console.error(JSON.stringify(source, null, 2));
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Print settings object for debugging by dynamically discovering its properties
|
|
1327
|
+
* @param settings The settings object to print
|
|
1328
|
+
* @private
|
|
1329
|
+
*/
|
|
1330
|
+
printSettingsDebug(settings) {
|
|
1331
|
+
if (typeof settings.get === "function") {
|
|
1332
|
+
console.error("Settings (using get method):");
|
|
1333
|
+
if (settings.data && typeof settings.data === "object") {
|
|
1334
|
+
Object.entries(settings.data).forEach(([key, value]) => {
|
|
1335
|
+
console.error(` ${key}: ${JSON.stringify(value)}`);
|
|
1336
|
+
});
|
|
1337
|
+
} else {
|
|
1338
|
+
console.error(" Unable to enumerate settings properties - no accessible data structure");
|
|
1339
|
+
}
|
|
1340
|
+
} else {
|
|
1341
|
+
console.error("Settings (plain object):");
|
|
1342
|
+
Object.entries(settings).forEach(([key, value]) => {
|
|
1343
|
+
console.error(` ${key}: ${JSON.stringify(value)}`);
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Create settings from command-line arguments
|
|
1349
|
+
* @param args Command line arguments
|
|
1350
|
+
* @param sessionId Optional session ID
|
|
1351
|
+
* @returns Settings instance
|
|
1352
|
+
*/
|
|
1353
|
+
createFromArgs(args, sessionId) {
|
|
1354
|
+
const settings = this.settingsClass.fromArgs(args);
|
|
1355
|
+
this.injectDebug(settings, args);
|
|
1356
|
+
this.setSettings(settings, sessionId);
|
|
1357
|
+
return settings;
|
|
1358
|
+
}
|
|
1359
|
+
/**
|
|
1360
|
+
* Create settings from HTTP headers
|
|
1361
|
+
* @param headers HTTP headers
|
|
1362
|
+
* @param sessionId Optional session ID
|
|
1363
|
+
* @returns Settings instance
|
|
1364
|
+
*/
|
|
1365
|
+
createFromHeaders(headers, sessionId) {
|
|
1366
|
+
const verbose = _SettingsManager.globalDebugState;
|
|
1367
|
+
if (verbose) {
|
|
1368
|
+
console.error("[SettingsManager.createFromHeaders] Verbose: Starting with sessionId:", sessionId || "(default)");
|
|
1369
|
+
console.error("[SettingsManager.createFromHeaders] Verbose: Incoming headers count:", Object.keys(headers).length);
|
|
1370
|
+
}
|
|
1371
|
+
if (_SettingsManager.globalDebugState) {
|
|
1372
|
+
console.error("=== createFromHeaders Debug Info ===");
|
|
1373
|
+
console.error("Incoming headers:");
|
|
1374
|
+
console.error(JSON.stringify(headers, null, 2));
|
|
1375
|
+
}
|
|
1376
|
+
if (verbose && (!headers || Object.keys(headers).length === 0)) {
|
|
1377
|
+
console.error("[SettingsManager.createFromHeaders] Verbose: WARNING - Headers object is empty or undefined");
|
|
1378
|
+
}
|
|
1379
|
+
const normalizedHeaders = {};
|
|
1380
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
1381
|
+
const normalizedKey = key.includes("_") ? key.replace(/_/g, "-") : key;
|
|
1382
|
+
normalizedHeaders[normalizedKey] = value;
|
|
1383
|
+
if (verbose) {
|
|
1384
|
+
console.error(`[SettingsManager.createFromHeaders] Verbose: Header normalized: "${key}" -> "${normalizedKey}"`);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
if (verbose) {
|
|
1388
|
+
console.error("[SettingsManager.createFromHeaders] Verbose: Normalized headers count:", Object.keys(normalizedHeaders).length);
|
|
1389
|
+
}
|
|
1390
|
+
if (_SettingsManager.globalDebugState) {
|
|
1391
|
+
console.error("Normalized headers:");
|
|
1392
|
+
console.error(JSON.stringify(normalizedHeaders, null, 2));
|
|
1393
|
+
}
|
|
1394
|
+
const debugHeader = normalizedHeaders["debug"] || normalizedHeaders["Debug"] || normalizedHeaders["DEBUG"];
|
|
1395
|
+
const debugSource = { debug: debugHeader !== void 0 ? debugHeader : _SettingsManager.globalDebugState };
|
|
1396
|
+
if (verbose) {
|
|
1397
|
+
console.error("[SettingsManager.createFromHeaders] Verbose: Calling settingsClass.fromHeaders");
|
|
1398
|
+
}
|
|
1399
|
+
const settings = this.settingsClass.fromHeaders(normalizedHeaders);
|
|
1400
|
+
if (verbose) {
|
|
1401
|
+
console.error("[SettingsManager.createFromHeaders] Verbose: Settings object created");
|
|
1402
|
+
}
|
|
1403
|
+
this.injectDebug(settings, debugSource);
|
|
1404
|
+
if (_SettingsManager.globalDebugState) {
|
|
1405
|
+
console.error("Final settings object for session:", sessionId || "(default)");
|
|
1406
|
+
this.printSettingsDebug(settings);
|
|
1407
|
+
console.error("=== End createFromHeaders Debug Info ===");
|
|
1408
|
+
}
|
|
1409
|
+
if (verbose) {
|
|
1410
|
+
console.error("[SettingsManager.createFromHeaders] Verbose: Storing settings for session:", sessionId || "(default)");
|
|
1411
|
+
}
|
|
1412
|
+
this.setSettings(settings, sessionId);
|
|
1413
|
+
return settings;
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Clear settings for a session
|
|
1417
|
+
* @param sessionId The session ID to clear
|
|
1418
|
+
*/
|
|
1419
|
+
clearSession(sessionId) {
|
|
1420
|
+
if (sessionId !== this.defaultSessionId) {
|
|
1421
|
+
this.settingsMap.delete(sessionId);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
};
|
|
1425
|
+
SettingsManager.globalDebugState = void 0;
|
|
1426
|
+
|
|
1427
|
+
// ../mcp-utils/dist/launcher.js
|
|
1428
|
+
async function launchMCPServer(configPath, serverModule2) {
|
|
1429
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
1430
|
+
const program = new Command();
|
|
1431
|
+
if (config.description) {
|
|
1432
|
+
program.description(config.description);
|
|
1433
|
+
}
|
|
1434
|
+
config.options.forEach((option) => {
|
|
1435
|
+
const envValue = option.env ? process.env[option.env] : void 0;
|
|
1436
|
+
const defaultValue = envValue || option.default;
|
|
1437
|
+
if (option.type === "boolean") {
|
|
1438
|
+
const boolDefault = envValue === "true" || option.default === "true";
|
|
1439
|
+
program.option(option.flag, option.description, boolDefault);
|
|
1440
|
+
} else {
|
|
1441
|
+
program.option(option.flag, option.description, defaultValue);
|
|
1442
|
+
}
|
|
1443
|
+
});
|
|
1444
|
+
const transportTypeDefault = process.env.MCP_TRANSPORT_TYPE || "stdio";
|
|
1445
|
+
program.option("--transport <type>", "Transport type (stdio or http)", transportTypeDefault);
|
|
1446
|
+
const transportPortDefault = process.env.MCP_TRANSPORT_PORT || "3000";
|
|
1447
|
+
program.option("--transport-port <number>", "Port for network transports (e.g., HTTP)", transportPortDefault);
|
|
1448
|
+
const debugDefault = process.env.DEBUG === "true" || false;
|
|
1449
|
+
program.option("--debug", "Enable debug mode", debugDefault);
|
|
1450
|
+
const telemetryEnabledDefault = process.env.TELEMETRY_DISABLED === "true" ? false : true;
|
|
1451
|
+
program.option("--no-telemetry", "Disable anonymous usage telemetry", telemetryEnabledDefault);
|
|
1452
|
+
const telemetryUrlDefault = process.env.TELEMETRY_URL || "https://metrics.security.ai.checkpoint.com/api/v1/metrics/collect";
|
|
1453
|
+
program.option("--telemetry-url <url>", "URL for telemetry server", telemetryUrlDefault);
|
|
1454
|
+
program.parse(process.argv);
|
|
1455
|
+
const options = program.opts();
|
|
1456
|
+
if (options.telemetry === false) {
|
|
1457
|
+
process.env.TELEMETRY_DISABLED = "true";
|
|
1458
|
+
}
|
|
1459
|
+
if (options.telemetryUrl) {
|
|
1460
|
+
process.env.TELEMETRY_URL = options.telemetryUrl;
|
|
1461
|
+
}
|
|
1462
|
+
if (!serverModule2.settingsManager) {
|
|
1463
|
+
throw new Error("ServerModule must have a settingsManager. Create it with createServerModule.");
|
|
1464
|
+
}
|
|
1465
|
+
const settings = serverModule2.settingsManager.createFromArgs(options);
|
|
1466
|
+
if (typeof serverModule2.server.applyToolPolicy === "function") {
|
|
1467
|
+
console.error("[launchMCPServer] Applying tool policy before connecting");
|
|
1468
|
+
serverModule2.server.applyToolPolicy();
|
|
1469
|
+
}
|
|
1470
|
+
const transportType = (options.transport || process.env.MCP_TRANSPORT_TYPE || "stdio").toLowerCase() === "http" ? "http" : "stdio";
|
|
1471
|
+
const transportPort = options.transportPort ? parseInt(options.transportPort, 10) : process.env.MCP_TRANSPORT_PORT ? parseInt(process.env.MCP_TRANSPORT_PORT, 10) : 3e3;
|
|
1472
|
+
if (transportType === "http") {
|
|
1473
|
+
await launchHTTPServer(config, serverModule2, transportPort);
|
|
1474
|
+
} else {
|
|
1475
|
+
const transport = new StdioServerTransport();
|
|
1476
|
+
const defaultSessionId = "default";
|
|
1477
|
+
const sessionMetadata = {
|
|
1478
|
+
type: "stdio",
|
|
1479
|
+
startedAt: /* @__PURE__ */ new Date()
|
|
1480
|
+
};
|
|
1481
|
+
serverModule2.sessionManager.createSession(defaultSessionId, sessionMetadata);
|
|
1482
|
+
transport.extraContext = () => {
|
|
1483
|
+
return {
|
|
1484
|
+
sessionId: defaultSessionId,
|
|
1485
|
+
transport
|
|
1486
|
+
};
|
|
1487
|
+
};
|
|
1488
|
+
await serverModule2.server.connect(transport);
|
|
1489
|
+
console.error(`${config.name} running on stdio transport. Version: ${serverModule2.pkg.version}`);
|
|
1490
|
+
console.error(`Transport type: stdio`);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
async function launchHTTPServer(config, serverModule2, port) {
|
|
1494
|
+
const transports = {};
|
|
1495
|
+
const serverInstances = {};
|
|
1496
|
+
const server2 = http.createServer(async (req, res) => {
|
|
1497
|
+
if (req.url === "/" || req.url === "/mcp") {
|
|
1498
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
1499
|
+
if (req.method === "POST") {
|
|
1500
|
+
const chunks = [];
|
|
1501
|
+
try {
|
|
1502
|
+
for await (const chunk of req) {
|
|
1503
|
+
chunks.push(Buffer.from(chunk));
|
|
1504
|
+
}
|
|
1505
|
+
const bodyBuffer = Buffer.concat(chunks);
|
|
1506
|
+
let body;
|
|
1507
|
+
try {
|
|
1508
|
+
const bodyText = bodyBuffer.toString("utf8");
|
|
1509
|
+
if (bodyText) {
|
|
1510
|
+
body = JSON.parse(bodyText);
|
|
1511
|
+
}
|
|
1512
|
+
} catch (err) {
|
|
1513
|
+
console.error("Error parsing request body:", err);
|
|
1514
|
+
}
|
|
1515
|
+
let transport;
|
|
1516
|
+
if (sessionId && transports[sessionId]) {
|
|
1517
|
+
const verbose = SettingsManager.globalDebugState;
|
|
1518
|
+
if (verbose) {
|
|
1519
|
+
console.error("[launchHTTPServer] Verbose: Reusing existing transport for session:", sessionId);
|
|
1520
|
+
}
|
|
1521
|
+
transport = transports[sessionId];
|
|
1522
|
+
if (!serverModule2.settingsManager) {
|
|
1523
|
+
throw new Error("ServerModule must have a settingsManager. Create it with createServerModule.");
|
|
1524
|
+
}
|
|
1525
|
+
if (verbose) {
|
|
1526
|
+
console.error("[launchHTTPServer] Verbose: Converting headers for existing session");
|
|
1527
|
+
}
|
|
1528
|
+
const envHeaders = headersToEnvVars(req.headers, config);
|
|
1529
|
+
if (verbose) {
|
|
1530
|
+
console.error("[launchHTTPServer] Verbose: Creating settings from headers for existing session");
|
|
1531
|
+
}
|
|
1532
|
+
serverModule2.settingsManager.createFromHeaders(envHeaders, sessionId);
|
|
1533
|
+
} else if (!sessionId && body && body.method === "initialize") {
|
|
1534
|
+
transport = new StreamableHTTPServerTransport({
|
|
1535
|
+
sessionIdGenerator: () => randomUUID(),
|
|
1536
|
+
onsessioninitialized: (sid) => {
|
|
1537
|
+
const verbose = SettingsManager.globalDebugState;
|
|
1538
|
+
if (verbose) {
|
|
1539
|
+
console.error("[launchHTTPServer] Verbose: New session initialized:", sid);
|
|
1540
|
+
}
|
|
1541
|
+
transports[sid] = transport;
|
|
1542
|
+
if (verbose) {
|
|
1543
|
+
console.error("[launchHTTPServer] Verbose: Converting headers for new session");
|
|
1544
|
+
console.error("[launchHTTPServer] Verbose: Raw request headers:", Object.keys(req.headers));
|
|
1545
|
+
}
|
|
1546
|
+
const headers = headersToEnvVars(req.headers, config);
|
|
1547
|
+
if (verbose) {
|
|
1548
|
+
console.error("[launchHTTPServer] Verbose: Converted headers count:", Object.keys(headers).length);
|
|
1549
|
+
}
|
|
1550
|
+
const metadata = {
|
|
1551
|
+
userAgent: req.headers["user-agent"],
|
|
1552
|
+
origin: req.headers.origin || req.headers.referer,
|
|
1553
|
+
remoteAddress: req.socket.remoteAddress,
|
|
1554
|
+
initialPath: req.url
|
|
1555
|
+
};
|
|
1556
|
+
if (verbose) {
|
|
1557
|
+
console.error("[launchHTTPServer] Verbose: Creating session in session manager");
|
|
1558
|
+
}
|
|
1559
|
+
serverModule2.sessionManager.createSession(sid, metadata);
|
|
1560
|
+
if (verbose) {
|
|
1561
|
+
console.error("[launchHTTPServer] Verbose: Creating settings from headers for new session");
|
|
1562
|
+
}
|
|
1563
|
+
serverModule2.settingsManager.createFromHeaders(headers, sid);
|
|
1564
|
+
if (verbose) {
|
|
1565
|
+
console.error("[launchHTTPServer] Verbose: Session initialization complete");
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
});
|
|
1569
|
+
transport.onclose = () => {
|
|
1570
|
+
const sid = transport.sessionId;
|
|
1571
|
+
if (sid) {
|
|
1572
|
+
delete transports[sid];
|
|
1573
|
+
if (serverInstances[sid]) {
|
|
1574
|
+
delete serverInstances[sid];
|
|
1575
|
+
}
|
|
1576
|
+
serverModule2.settingsManager.clearSession(sid);
|
|
1577
|
+
serverModule2.apiManagerFactory.clearSession(sid);
|
|
1578
|
+
serverModule2.sessionManager.removeSession(sid);
|
|
1579
|
+
}
|
|
1580
|
+
};
|
|
1581
|
+
if (!serverModule2.settingsManager) {
|
|
1582
|
+
throw new Error("ServerModule must have a settingsManager. Create it with createServerModule.");
|
|
1583
|
+
}
|
|
1584
|
+
transport.extraContext = (msg) => {
|
|
1585
|
+
const sessionId2 = transport.sessionId;
|
|
1586
|
+
return {
|
|
1587
|
+
sessionId: sessionId2,
|
|
1588
|
+
transport
|
|
1589
|
+
};
|
|
1590
|
+
};
|
|
1591
|
+
let serverToConnect;
|
|
1592
|
+
if (serverModule2.createServerInstance) {
|
|
1593
|
+
const sessionServer = serverModule2.createServerInstance();
|
|
1594
|
+
serverToConnect = sessionServer;
|
|
1595
|
+
const originalOnSessionInit = transport.onsessioninitialized;
|
|
1596
|
+
transport.onsessioninitialized = (sid) => {
|
|
1597
|
+
serverInstances[sid] = sessionServer;
|
|
1598
|
+
if (originalOnSessionInit) {
|
|
1599
|
+
originalOnSessionInit(sid);
|
|
1600
|
+
}
|
|
1601
|
+
};
|
|
1602
|
+
} else {
|
|
1603
|
+
serverToConnect = serverModule2.server;
|
|
1604
|
+
console.error("Warning: Using shared server instance. Consider providing createServerInstance for better multi-user support.");
|
|
1605
|
+
}
|
|
1606
|
+
await serverToConnect.connect(transport).catch((error) => {
|
|
1607
|
+
console.error("Error connecting to HTTP transport:", error);
|
|
1608
|
+
});
|
|
1609
|
+
} else {
|
|
1610
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1611
|
+
res.end(JSON.stringify({
|
|
1612
|
+
jsonrpc: "2.0",
|
|
1613
|
+
error: {
|
|
1614
|
+
code: -32e3,
|
|
1615
|
+
message: "Bad Request: No valid session ID provided"
|
|
1616
|
+
},
|
|
1617
|
+
id: null
|
|
1618
|
+
}));
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
await transport.handleRequest(req, res, body);
|
|
1622
|
+
} catch (error) {
|
|
1623
|
+
console.error("Error handling POST request:", error);
|
|
1624
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1625
|
+
res.end(JSON.stringify({
|
|
1626
|
+
jsonrpc: "2.0",
|
|
1627
|
+
error: {
|
|
1628
|
+
code: -32e3,
|
|
1629
|
+
message: "Internal server error: " + error.message
|
|
1630
|
+
},
|
|
1631
|
+
id: null
|
|
1632
|
+
}));
|
|
1633
|
+
}
|
|
1634
|
+
} else if (req.method === "GET") {
|
|
1635
|
+
if (!sessionId || !transports[sessionId]) {
|
|
1636
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
1637
|
+
res.end("Invalid or missing session ID");
|
|
1638
|
+
return;
|
|
1639
|
+
}
|
|
1640
|
+
const transport = transports[sessionId];
|
|
1641
|
+
await transport.handleRequest(req, res);
|
|
1642
|
+
} else if (req.method === "DELETE") {
|
|
1643
|
+
if (!sessionId || !transports[sessionId]) {
|
|
1644
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
1645
|
+
res.end("Invalid or missing session ID");
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
const transport = transports[sessionId];
|
|
1649
|
+
await transport.handleRequest(req, res);
|
|
1650
|
+
} else {
|
|
1651
|
+
res.writeHead(405, { "Content-Type": "text/plain", "Allow": "GET, POST, DELETE" });
|
|
1652
|
+
res.end("Method not allowed");
|
|
1653
|
+
}
|
|
1654
|
+
} else if (req.url === "/health" || req.url === "/status") {
|
|
1655
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1656
|
+
const sessionCount = serverModule2.sessionManager.getSessionCount();
|
|
1657
|
+
const sessions = serverModule2.sessionManager.getAllSessions().map((session) => ({
|
|
1658
|
+
id: session.sessionId,
|
|
1659
|
+
createdAt: session.createdAt,
|
|
1660
|
+
lastActive: session.lastActive
|
|
1661
|
+
// Don't include potentially sensitive metadata
|
|
1662
|
+
}));
|
|
1663
|
+
res.end(JSON.stringify({
|
|
1664
|
+
status: "ok",
|
|
1665
|
+
server: config.name,
|
|
1666
|
+
version: serverModule2.pkg.version,
|
|
1667
|
+
activeSessions: sessionCount,
|
|
1668
|
+
sessions
|
|
1669
|
+
}));
|
|
1670
|
+
} else {
|
|
1671
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1672
|
+
res.end("Not found");
|
|
1673
|
+
}
|
|
1674
|
+
});
|
|
1675
|
+
server2.listen(port, () => {
|
|
1676
|
+
console.error(`${config.name} running on HTTP transport at http://localhost:${port}. Version: ${serverModule2.pkg.version}`);
|
|
1677
|
+
console.error(`Transport type: HTTP, Transport-port: ${port}`);
|
|
1678
|
+
});
|
|
1679
|
+
server2.on("error", (err) => {
|
|
1680
|
+
console.error(`Server error: ${err.message}`);
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
function headersToEnvVars(headers, config) {
|
|
1684
|
+
const verbose = SettingsManager.globalDebugState;
|
|
1685
|
+
if (verbose) {
|
|
1686
|
+
console.error("[headersToEnvVars] Verbose: Converting headers to env vars");
|
|
1687
|
+
console.error("[headersToEnvVars] Verbose: Input headers count:", Object.keys(headers).length);
|
|
1688
|
+
console.error("[headersToEnvVars] Verbose: Input header keys:", Object.keys(headers));
|
|
1689
|
+
if (!headers || Object.keys(headers).length === 0) {
|
|
1690
|
+
console.error("[headersToEnvVars] Verbose: WARNING - Headers object is empty");
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
if (!headers || Object.keys(headers).length === 0) {
|
|
1694
|
+
return {};
|
|
1695
|
+
}
|
|
1696
|
+
const result = {};
|
|
1697
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
1698
|
+
if (value !== void 0) {
|
|
1699
|
+
const envName = name.toUpperCase().replace(/-/g, "_");
|
|
1700
|
+
result[envName] = value;
|
|
1701
|
+
if (verbose) {
|
|
1702
|
+
console.error(`[headersToEnvVars] Verbose: Basic mapping: "${name}" -> "${envName}"`);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
if (verbose) {
|
|
1707
|
+
console.error("[headersToEnvVars] Verbose: After basic mapping, result keys:", Object.keys(result));
|
|
1708
|
+
}
|
|
1709
|
+
if (config && config.options) {
|
|
1710
|
+
if (verbose) {
|
|
1711
|
+
console.error("[headersToEnvVars] Verbose: Config provided, building header-to-env mapping");
|
|
1712
|
+
}
|
|
1713
|
+
const headerToEnvMap = {};
|
|
1714
|
+
for (const option of config.options) {
|
|
1715
|
+
if (option.env) {
|
|
1716
|
+
const flagName = option.flag.split(" ")[0].replace(/^--?/, "").replace(/-/g, "_");
|
|
1717
|
+
headerToEnvMap[flagName.toLowerCase()] = option.env;
|
|
1718
|
+
if (verbose) {
|
|
1719
|
+
console.error(`[headersToEnvVars] Verbose: Mapping: "${flagName.toLowerCase()}" -> "${option.env}"`);
|
|
1720
|
+
}
|
|
1721
|
+
headerToEnvMap[option.env.toLowerCase()] = option.env;
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
if (verbose) {
|
|
1725
|
+
console.error("[headersToEnvVars] Verbose: headerToEnvMap:", headerToEnvMap);
|
|
1726
|
+
}
|
|
1727
|
+
let mappedCount = 0;
|
|
1728
|
+
for (const [headerName, headerValue] of Object.entries(headers)) {
|
|
1729
|
+
if (headerValue !== void 0) {
|
|
1730
|
+
const normalizedHeaderName = headerName.toLowerCase().replace(/-/g, "_");
|
|
1731
|
+
const envVarName = headerToEnvMap[normalizedHeaderName];
|
|
1732
|
+
if (envVarName) {
|
|
1733
|
+
result[envVarName] = headerValue;
|
|
1734
|
+
mappedCount++;
|
|
1735
|
+
if (verbose) {
|
|
1736
|
+
console.error(`[headersToEnvVars] Verbose: Config mapping: "${headerName}" -> "${envVarName}"`);
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
if (verbose) {
|
|
1742
|
+
console.error(`[headersToEnvVars] Verbose: Mapped ${mappedCount} headers using config`);
|
|
1743
|
+
}
|
|
1744
|
+
} else if (verbose) {
|
|
1745
|
+
console.error("[headersToEnvVars] Verbose: No config provided, skipping config-based mapping");
|
|
1746
|
+
}
|
|
1747
|
+
if (verbose) {
|
|
1748
|
+
console.error("[headersToEnvVars] Verbose: Final result keys:", Object.keys(result));
|
|
1749
|
+
console.error("[headersToEnvVars] Verbose: Final result (sanitized):", Object.fromEntries(Object.entries(result).map(([k, v]) => [k, k.toLowerCase().includes("key") || k.toLowerCase().includes("token") || k.toLowerCase().includes("password") ? "***" : v])));
|
|
1750
|
+
}
|
|
1751
|
+
return result;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
// ../mcp-utils/dist/api-manager-factory.js
|
|
1755
|
+
var APIManagerFactory = class {
|
|
1756
|
+
/**
|
|
1757
|
+
* Creates a new APIManagerFactory
|
|
1758
|
+
* @param apiManagerClass The API Manager class to use for creating instances
|
|
1759
|
+
* @param settingsManager The settings manager to get settings from
|
|
1760
|
+
*/
|
|
1761
|
+
constructor(apiManagerClass, settingsManager) {
|
|
1762
|
+
this.apiManagerMap = /* @__PURE__ */ new Map();
|
|
1763
|
+
this.defaultSessionId = "default";
|
|
1764
|
+
this.apiManagerClass = apiManagerClass;
|
|
1765
|
+
this.settingsManager = settingsManager;
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Get or create an API manager for a specific session
|
|
1769
|
+
* @param sessionId The session ID (defaults to 'default' for stdio mode)
|
|
1770
|
+
* @returns API Manager instance for the session
|
|
1771
|
+
*/
|
|
1772
|
+
getAPIManager(sessionId) {
|
|
1773
|
+
const verbose = SettingsManager.globalDebugState;
|
|
1774
|
+
const sid = sessionId || this.defaultSessionId;
|
|
1775
|
+
if (verbose) {
|
|
1776
|
+
console.error("[APIManagerFactory.getAPIManager] Verbose: Getting API manager for session:", sid);
|
|
1777
|
+
}
|
|
1778
|
+
if (!this.apiManagerMap.has(sid)) {
|
|
1779
|
+
if (verbose) {
|
|
1780
|
+
console.error("[APIManagerFactory.getAPIManager] Verbose: API manager not in cache, creating new one");
|
|
1781
|
+
}
|
|
1782
|
+
const settings2 = this.settingsManager.getSettings(sid);
|
|
1783
|
+
if (verbose) {
|
|
1784
|
+
console.error("[APIManagerFactory.getAPIManager] Verbose: Retrieved settings from settings manager");
|
|
1785
|
+
console.error("[APIManagerFactory.getAPIManager] Verbose: Creating API manager from settings");
|
|
1786
|
+
}
|
|
1787
|
+
const apiManager2 = this.createAPIManagerFromSettings(settings2);
|
|
1788
|
+
if (verbose) {
|
|
1789
|
+
console.error("[APIManagerFactory.getAPIManager] Verbose: API manager created successfully");
|
|
1790
|
+
}
|
|
1791
|
+
this.apiManagerMap.set(sid, apiManager2);
|
|
1792
|
+
} else if (verbose) {
|
|
1793
|
+
console.error("[APIManagerFactory.getAPIManager] Verbose: Using cached API manager");
|
|
1794
|
+
}
|
|
1795
|
+
const apiManager = this.apiManagerMap.get(sid);
|
|
1796
|
+
const settings = this.settingsManager.getSettings(sid);
|
|
1797
|
+
if (settings && typeof settings.debug !== "undefined") {
|
|
1798
|
+
apiManager.debug = !!settings.debug;
|
|
1799
|
+
}
|
|
1800
|
+
return apiManager;
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Create an API manager from settings
|
|
1804
|
+
* @param settings Settings instance
|
|
1805
|
+
* @returns API Manager instance
|
|
1806
|
+
*/
|
|
1807
|
+
createAPIManagerFromSettings(settings) {
|
|
1808
|
+
const verbose = SettingsManager.globalDebugState;
|
|
1809
|
+
if (verbose) {
|
|
1810
|
+
console.error("[APIManagerFactory.createAPIManagerFromSettings] Verbose: Creating API manager from settings");
|
|
1811
|
+
console.error("[APIManagerFactory.createAPIManagerFromSettings] Verbose: Settings type:", typeof settings);
|
|
1812
|
+
console.error("[APIManagerFactory.createAPIManagerFromSettings] Verbose: Settings keys:", settings ? Object.keys(settings) : "null");
|
|
1813
|
+
}
|
|
1814
|
+
const apiManager = this.apiManagerClass.create(settings);
|
|
1815
|
+
if (verbose) {
|
|
1816
|
+
console.error("[APIManagerFactory.createAPIManagerFromSettings] Verbose: API manager created");
|
|
1817
|
+
}
|
|
1818
|
+
return apiManager;
|
|
1819
|
+
}
|
|
1820
|
+
/**
|
|
1821
|
+
* Clear API manager for a session
|
|
1822
|
+
* @param sessionId The session ID to clear
|
|
1823
|
+
*/
|
|
1824
|
+
clearSession(sessionId) {
|
|
1825
|
+
if (sessionId !== this.defaultSessionId) {
|
|
1826
|
+
this.apiManagerMap.delete(sessionId);
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
};
|
|
1830
|
+
|
|
1831
|
+
// ../mcp-utils/dist/session-context.js
|
|
1832
|
+
var _a;
|
|
1833
|
+
var SessionContext = class {
|
|
1834
|
+
/**
|
|
1835
|
+
* Start automatic cleanup timer
|
|
1836
|
+
*/
|
|
1837
|
+
static startCleanupTimer() {
|
|
1838
|
+
if (this.cleanupTimer)
|
|
1839
|
+
return;
|
|
1840
|
+
this.cleanupTimer = setInterval(() => {
|
|
1841
|
+
this.cleanupExpiredSessions();
|
|
1842
|
+
}, this.CLEANUP_INTERVAL_MS);
|
|
1843
|
+
if (this.cleanupTimer.unref) {
|
|
1844
|
+
this.cleanupTimer.unref();
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
/**
|
|
1848
|
+
* Clean up expired sessions
|
|
1849
|
+
*/
|
|
1850
|
+
static cleanupExpiredSessions() {
|
|
1851
|
+
const now = Date.now();
|
|
1852
|
+
const expiredSessions = [];
|
|
1853
|
+
for (const [sessionId, sessionInfo] of this.sessionData.entries()) {
|
|
1854
|
+
if (sessionId === this.DEFAULT_SESSION_ID)
|
|
1855
|
+
continue;
|
|
1856
|
+
if (now - sessionInfo.lastAccessed > this.SESSION_TIMEOUT_MS) {
|
|
1857
|
+
expiredSessions.push(sessionId);
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
expiredSessions.forEach((sessionId) => {
|
|
1861
|
+
this.sessionData.delete(sessionId);
|
|
1862
|
+
});
|
|
1863
|
+
if (this.sessionData.size > this.MAX_SESSIONS) {
|
|
1864
|
+
const sessions = Array.from(this.sessionData.entries()).filter(([sessionId]) => sessionId !== this.DEFAULT_SESSION_ID).sort(([, a], [, b]) => a.lastAccessed - b.lastAccessed);
|
|
1865
|
+
const toRemove = sessions.slice(0, sessions.length - this.MAX_SESSIONS + 1);
|
|
1866
|
+
toRemove.forEach(([sessionId]) => {
|
|
1867
|
+
this.sessionData.delete(sessionId);
|
|
1868
|
+
});
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
/**
|
|
1872
|
+
* Get the current session ID from the MCP extra context
|
|
1873
|
+
* @param extra Extra context passed to MCP tool callbacks
|
|
1874
|
+
* @returns The session ID or DEFAULT_SESSION_ID if not available
|
|
1875
|
+
*/
|
|
1876
|
+
static getSessionId(extra) {
|
|
1877
|
+
if (!extra)
|
|
1878
|
+
return this.DEFAULT_SESSION_ID;
|
|
1879
|
+
if (extra.transport && extra.transport.sessionId) {
|
|
1880
|
+
return extra.transport.sessionId;
|
|
1881
|
+
}
|
|
1882
|
+
if (extra.sessionId) {
|
|
1883
|
+
return extra.sessionId;
|
|
1884
|
+
}
|
|
1885
|
+
return this.DEFAULT_SESSION_ID;
|
|
1886
|
+
}
|
|
1887
|
+
/**
|
|
1888
|
+
* Get settings for the current session
|
|
1889
|
+
* @param serverModule ServerModule with settingsManager
|
|
1890
|
+
* @param extra Extra context passed to MCP tool callbacks
|
|
1891
|
+
* @returns Settings for the current session
|
|
1892
|
+
*/
|
|
1893
|
+
static getSettings(serverModule2, extra) {
|
|
1894
|
+
const sessionId = this.getSessionId(extra);
|
|
1895
|
+
if (!serverModule2.settingsManager) {
|
|
1896
|
+
throw new Error("ServerModule does not have a settingsManager. Create it with createServerModule.");
|
|
1897
|
+
}
|
|
1898
|
+
return serverModule2.settingsManager.getSettings(sessionId);
|
|
1899
|
+
}
|
|
1900
|
+
/**
|
|
1901
|
+
* Get API manager for the current session
|
|
1902
|
+
* @param serverModule ServerModule with apiManagerFactory
|
|
1903
|
+
* @param extra Extra context passed to MCP tool callbacks
|
|
1904
|
+
* @returns API manager for the current session
|
|
1905
|
+
*/
|
|
1906
|
+
static getAPIManager(serverModule2, extra) {
|
|
1907
|
+
const sessionId = this.getSessionId(extra);
|
|
1908
|
+
if (!serverModule2.apiManagerFactory) {
|
|
1909
|
+
throw new Error("ServerModule does not have an apiManagerFactory. Create it with createServerModule.");
|
|
1910
|
+
}
|
|
1911
|
+
return serverModule2.apiManagerFactory.getAPIManager(sessionId);
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Set session data for the current session
|
|
1915
|
+
* @param key The key to store the data under
|
|
1916
|
+
* @param value The value to store
|
|
1917
|
+
* @param extra Extra context with session information
|
|
1918
|
+
*/
|
|
1919
|
+
static setData(key, value, extra) {
|
|
1920
|
+
const sessionId = this.getSessionId(extra);
|
|
1921
|
+
const now = Date.now();
|
|
1922
|
+
if (!this.sessionData.has(sessionId)) {
|
|
1923
|
+
this.sessionData.set(sessionId, {
|
|
1924
|
+
data: /* @__PURE__ */ new Map(),
|
|
1925
|
+
lastAccessed: now,
|
|
1926
|
+
createdAt: now
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
const sessionInfo = this.sessionData.get(sessionId);
|
|
1930
|
+
sessionInfo.lastAccessed = now;
|
|
1931
|
+
sessionInfo.data.set(key, value);
|
|
1932
|
+
}
|
|
1933
|
+
/**
|
|
1934
|
+
* Get session data for the current session
|
|
1935
|
+
* @param key The key to retrieve data for
|
|
1936
|
+
* @param extra Extra context with session information
|
|
1937
|
+
* @returns The stored data or undefined if not found
|
|
1938
|
+
*/
|
|
1939
|
+
static getData(key, extra) {
|
|
1940
|
+
const sessionId = this.getSessionId(extra);
|
|
1941
|
+
if (!this.sessionData.has(sessionId)) {
|
|
1942
|
+
return void 0;
|
|
1943
|
+
}
|
|
1944
|
+
const sessionInfo = this.sessionData.get(sessionId);
|
|
1945
|
+
sessionInfo.lastAccessed = Date.now();
|
|
1946
|
+
return sessionInfo.data.get(key);
|
|
1947
|
+
}
|
|
1948
|
+
/**
|
|
1949
|
+
* Clear session data for a specific session
|
|
1950
|
+
* @param sessionId The session ID to clear
|
|
1951
|
+
*/
|
|
1952
|
+
static clearSessionData(sessionId) {
|
|
1953
|
+
this.sessionData.delete(sessionId);
|
|
1954
|
+
}
|
|
1955
|
+
/**
|
|
1956
|
+
* Get session statistics (for monitoring)
|
|
1957
|
+
*/
|
|
1958
|
+
static getSessionStats() {
|
|
1959
|
+
const now = Date.now();
|
|
1960
|
+
let oldestAccess = null;
|
|
1961
|
+
for (const [, sessionInfo] of this.sessionData.entries()) {
|
|
1962
|
+
if (oldestAccess === null || sessionInfo.lastAccessed < oldestAccess) {
|
|
1963
|
+
oldestAccess = sessionInfo.lastAccessed;
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return {
|
|
1967
|
+
totalSessions: this.sessionData.size,
|
|
1968
|
+
memoryUsage: this.sessionData.size * 1e3,
|
|
1969
|
+
// Rough estimate
|
|
1970
|
+
oldestSession: oldestAccess ? now - oldestAccess : null
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
/**
|
|
1974
|
+
* Get or prompt for user interactive data with automatic caching and expiration
|
|
1975
|
+
* @param options Configuration for the interactive data request
|
|
1976
|
+
* @param extra Extra context with session information
|
|
1977
|
+
* @returns Promise that resolves to the user data (either from cache or fresh prompt)
|
|
1978
|
+
*/
|
|
1979
|
+
static async getOrPromptUserData(options, extra) {
|
|
1980
|
+
const sessionId = this.getSessionId(extra);
|
|
1981
|
+
const now = Date.now();
|
|
1982
|
+
const expirationMs = (options.expirationMinutes || 30) * 60 * 1e3;
|
|
1983
|
+
const cachedData = this.getData(options.cacheKey, extra);
|
|
1984
|
+
if (cachedData && cachedData.expiresAt && now < cachedData.expiresAt) {
|
|
1985
|
+
const refreshedData = {
|
|
1986
|
+
...cachedData,
|
|
1987
|
+
expiresAt: now + expirationMs,
|
|
1988
|
+
lastUsed: now
|
|
1989
|
+
};
|
|
1990
|
+
this.setData(options.cacheKey, refreshedData, extra);
|
|
1991
|
+
let dataToReturn2 = cachedData.data;
|
|
1992
|
+
if (options.fieldsToShow) {
|
|
1993
|
+
dataToReturn2 = {};
|
|
1994
|
+
for (const field of options.fieldsToShow) {
|
|
1995
|
+
if (cachedData.data[field] !== void 0) {
|
|
1996
|
+
dataToReturn2[field] = cachedData.data[field];
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
console.error(`Using cached user data for session: ${sessionId}, key: ${options.cacheKey}`);
|
|
2001
|
+
return { cancelled: false, data: dataToReturn2 };
|
|
2002
|
+
}
|
|
2003
|
+
console.error(`Prompting user for data for session: ${sessionId}, key: ${options.cacheKey}`);
|
|
2004
|
+
let result;
|
|
2005
|
+
if (options.showLoginDialog) {
|
|
2006
|
+
const { showLoginDialog: showLoginDialog2 } = await Promise.resolve().then(() => (init_ui_dialog(), ui_dialog_exports));
|
|
2007
|
+
result = await showLoginDialog2(options.dialogTitle, options.dialogMessage);
|
|
2008
|
+
} else {
|
|
2009
|
+
const { showDialog: showDialog2 } = await Promise.resolve().then(() => (init_ui_dialog(), ui_dialog_exports));
|
|
2010
|
+
const defaultFields = [
|
|
2011
|
+
{
|
|
2012
|
+
name: "message",
|
|
2013
|
+
label: "Message",
|
|
2014
|
+
type: "text",
|
|
2015
|
+
placeholder: "Enter your message here...",
|
|
2016
|
+
required: true
|
|
2017
|
+
}
|
|
2018
|
+
];
|
|
2019
|
+
result = await showDialog2({
|
|
2020
|
+
title: options.dialogTitle || "Input Required",
|
|
2021
|
+
message: options.dialogMessage,
|
|
2022
|
+
fields: options.customFields || defaultFields
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
2025
|
+
if (result.cancelled) {
|
|
2026
|
+
return result;
|
|
2027
|
+
}
|
|
2028
|
+
const cachedEntry = {
|
|
2029
|
+
data: result.data,
|
|
2030
|
+
expiresAt: now + expirationMs,
|
|
2031
|
+
createdAt: now,
|
|
2032
|
+
lastUsed: now
|
|
2033
|
+
};
|
|
2034
|
+
this.setData(options.cacheKey, cachedEntry, extra);
|
|
2035
|
+
let dataToReturn = result.data;
|
|
2036
|
+
if (options.fieldsToShow) {
|
|
2037
|
+
dataToReturn = {};
|
|
2038
|
+
for (const field of options.fieldsToShow) {
|
|
2039
|
+
if (result.data[field] !== void 0) {
|
|
2040
|
+
dataToReturn[field] = result.data[field];
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
return { cancelled: false, data: dataToReturn };
|
|
2045
|
+
}
|
|
2046
|
+
/**
|
|
2047
|
+
* Clear cached user data for a specific key
|
|
2048
|
+
* @param cacheKey The cache key to clear
|
|
2049
|
+
* @param extra Extra context with session information
|
|
2050
|
+
*/
|
|
2051
|
+
static clearUserData(cacheKey, extra) {
|
|
2052
|
+
const sessionId = this.getSessionId(extra);
|
|
2053
|
+
if (this.sessionData.has(sessionId)) {
|
|
2054
|
+
const sessionInfo = this.sessionData.get(sessionId);
|
|
2055
|
+
sessionInfo.data.delete(cacheKey);
|
|
2056
|
+
sessionInfo.lastAccessed = Date.now();
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
/**
|
|
2060
|
+
* Check if user data exists and is not expired
|
|
2061
|
+
* @param cacheKey The cache key to check
|
|
2062
|
+
* @param extra Extra context with session information
|
|
2063
|
+
* @returns true if valid cached data exists, false otherwise
|
|
2064
|
+
*/
|
|
2065
|
+
static hasValidUserData(cacheKey, extra) {
|
|
2066
|
+
const cachedData = this.getData(cacheKey, extra);
|
|
2067
|
+
if (!cachedData || !cachedData.expiresAt) {
|
|
2068
|
+
return false;
|
|
2069
|
+
}
|
|
2070
|
+
return Date.now() < cachedData.expiresAt;
|
|
2071
|
+
}
|
|
2072
|
+
};
|
|
2073
|
+
_a = SessionContext;
|
|
2074
|
+
SessionContext.DEFAULT_SESSION_ID = "default";
|
|
2075
|
+
SessionContext.sessionData = /* @__PURE__ */ new Map();
|
|
2076
|
+
SessionContext.SESSION_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
|
|
2077
|
+
SessionContext.CLEANUP_INTERVAL_MS = 60 * 60 * 1e3;
|
|
2078
|
+
SessionContext.MAX_SESSIONS = 1e3;
|
|
2079
|
+
SessionContext.cleanupTimer = null;
|
|
2080
|
+
(() => {
|
|
2081
|
+
_a.startCleanupTimer();
|
|
2082
|
+
})();
|
|
2083
|
+
|
|
2084
|
+
// ../mcp-utils/dist/session-manager.js
|
|
2085
|
+
var DEFAULT_SESSION_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
2086
|
+
var SessionManager = class {
|
|
2087
|
+
constructor() {
|
|
2088
|
+
this.sessions = /* @__PURE__ */ new Map();
|
|
2089
|
+
}
|
|
2090
|
+
/**
|
|
2091
|
+
* Create a new session
|
|
2092
|
+
* @param sessionId The session ID
|
|
2093
|
+
* @param metadata Optional metadata to store with the session
|
|
2094
|
+
* @returns Session info
|
|
2095
|
+
*/
|
|
2096
|
+
createSession(sessionId, metadata = {}) {
|
|
2097
|
+
const now = /* @__PURE__ */ new Date();
|
|
2098
|
+
const sessionInfo = {
|
|
2099
|
+
sessionId,
|
|
2100
|
+
createdAt: now,
|
|
2101
|
+
lastActive: now,
|
|
2102
|
+
...metadata
|
|
2103
|
+
};
|
|
2104
|
+
this.sessions.set(sessionId, sessionInfo);
|
|
2105
|
+
return sessionInfo;
|
|
2106
|
+
}
|
|
2107
|
+
/**
|
|
2108
|
+
* Get info for a session
|
|
2109
|
+
* @param sessionId The session ID
|
|
2110
|
+
* @returns Session info or undefined if not found
|
|
2111
|
+
*/
|
|
2112
|
+
getSession(sessionId) {
|
|
2113
|
+
if (this.sessions.has(sessionId)) {
|
|
2114
|
+
this.touchSession(sessionId);
|
|
2115
|
+
}
|
|
2116
|
+
return this.sessions.get(sessionId);
|
|
2117
|
+
}
|
|
2118
|
+
/**
|
|
2119
|
+
* Update session activity timestamp
|
|
2120
|
+
* @param sessionId The session ID
|
|
2121
|
+
*/
|
|
2122
|
+
touchSession(sessionId) {
|
|
2123
|
+
const session = this.sessions.get(sessionId);
|
|
2124
|
+
if (session) {
|
|
2125
|
+
session.lastActive = /* @__PURE__ */ new Date();
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
/**
|
|
2129
|
+
* Remove a session
|
|
2130
|
+
* @param sessionId The session ID
|
|
2131
|
+
*/
|
|
2132
|
+
removeSession(sessionId) {
|
|
2133
|
+
this.sessions.delete(sessionId);
|
|
2134
|
+
SessionContext.clearSessionData(sessionId);
|
|
2135
|
+
}
|
|
2136
|
+
/**
|
|
2137
|
+
* Get all active sessions
|
|
2138
|
+
* @returns Array of session info objects
|
|
2139
|
+
*/
|
|
2140
|
+
getAllSessions() {
|
|
2141
|
+
return Array.from(this.sessions.values());
|
|
2142
|
+
}
|
|
2143
|
+
/**
|
|
2144
|
+
* Get count of active sessions
|
|
2145
|
+
* @returns Number of active sessions
|
|
2146
|
+
*/
|
|
2147
|
+
getSessionCount() {
|
|
2148
|
+
return this.sessions.size;
|
|
2149
|
+
}
|
|
2150
|
+
/**
|
|
2151
|
+
* Clean up inactive sessions older than the specified timeout
|
|
2152
|
+
* @param timeoutMs Timeout in milliseconds (default: 30 minutes)
|
|
2153
|
+
* @returns Number of sessions removed
|
|
2154
|
+
*/
|
|
2155
|
+
cleanupInactiveSessions(timeoutMs = DEFAULT_SESSION_TIMEOUT_MS) {
|
|
2156
|
+
const now = /* @__PURE__ */ new Date();
|
|
2157
|
+
let removedCount = 0;
|
|
2158
|
+
for (const [sessionId, session] of this.sessions.entries()) {
|
|
2159
|
+
const inactiveTime = now.getTime() - session.lastActive.getTime();
|
|
2160
|
+
if (inactiveTime > timeoutMs) {
|
|
2161
|
+
this.removeSession(sessionId);
|
|
2162
|
+
removedCount++;
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
return removedCount;
|
|
2166
|
+
}
|
|
2167
|
+
};
|
|
2168
|
+
|
|
2169
|
+
// ../mcp-utils/dist/server-utils.js
|
|
2170
|
+
function getHeaderValue(headers, key) {
|
|
2171
|
+
const normalizedKey = key.replace(/_/g, "-");
|
|
2172
|
+
const value = headers[normalizedKey] || headers[normalizedKey.toUpperCase()] || headers[normalizedKey.toLowerCase()];
|
|
2173
|
+
return typeof value === "string" ? value : Array.isArray(value) ? value[0] : void 0;
|
|
2174
|
+
}
|
|
2175
|
+
function createApiRunner(serverModule2) {
|
|
2176
|
+
return async (method, uri, data, extra, domain) => {
|
|
2177
|
+
const apiManager = SessionContext.getAPIManager(serverModule2, extra);
|
|
2178
|
+
return await apiManager.callApi(method, uri, data, domain);
|
|
2179
|
+
};
|
|
2180
|
+
}
|
|
2181
|
+
function wrapServerWithTracking(server2, createServerFn) {
|
|
2182
|
+
const registrations = [];
|
|
2183
|
+
const originalTool = server2.tool?.bind(server2);
|
|
2184
|
+
const originalPrompt = server2.prompt?.bind(server2);
|
|
2185
|
+
const originalResource = server2.resource?.bind(server2);
|
|
2186
|
+
if (originalTool) {
|
|
2187
|
+
server2.tool = function(...args) {
|
|
2188
|
+
registrations.push({ type: "tool", method: "tool", args: [...args] });
|
|
2189
|
+
return originalTool(...args);
|
|
2190
|
+
};
|
|
2191
|
+
}
|
|
2192
|
+
if (originalPrompt) {
|
|
2193
|
+
server2.prompt = function(...args) {
|
|
2194
|
+
registrations.push({ type: "prompt", method: "prompt", args: [...args] });
|
|
2195
|
+
return originalPrompt(...args);
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
if (originalResource) {
|
|
2199
|
+
server2.resource = function(...args) {
|
|
2200
|
+
registrations.push({ type: "resource", method: "resource", args: [...args] });
|
|
2201
|
+
return originalResource(...args);
|
|
2202
|
+
};
|
|
2203
|
+
}
|
|
2204
|
+
const createInstance = () => {
|
|
2205
|
+
const newServer = createServerFn();
|
|
2206
|
+
for (const reg of registrations) {
|
|
2207
|
+
if (newServer[reg.method]) {
|
|
2208
|
+
newServer[reg.method](...reg.args);
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
if (typeof server2.setToolPolicy === "function" && typeof newServer.setToolPolicy === "function") {
|
|
2212
|
+
const toolPolicy = server2._toolPolicyCallback;
|
|
2213
|
+
if (toolPolicy) {
|
|
2214
|
+
newServer.setToolPolicy(toolPolicy);
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
return newServer;
|
|
2218
|
+
};
|
|
2219
|
+
return { wrappedServer: server2, createInstance };
|
|
2220
|
+
}
|
|
2221
|
+
function createServerModule(server2, Settings2, pkg2, apiManagerClass, toolPolicyCallback, createServerFn) {
|
|
2222
|
+
const settingsManager = new SettingsManager(Settings2);
|
|
2223
|
+
const apiManagerFactory = new APIManagerFactory(apiManagerClass, settingsManager);
|
|
2224
|
+
const sessionManager = new SessionManager();
|
|
2225
|
+
if (toolPolicyCallback && typeof server2.setToolPolicy === "function") {
|
|
2226
|
+
console.error("[createServerModule] Setting tool policy callback on server");
|
|
2227
|
+
server2.setToolPolicy(toolPolicyCallback);
|
|
2228
|
+
}
|
|
2229
|
+
const serverFactory = createServerFn || server2._createServerFn;
|
|
2230
|
+
let createServerInstance;
|
|
2231
|
+
if (serverFactory) {
|
|
2232
|
+
const { wrappedServer, createInstance } = wrapServerWithTracking(server2, serverFactory);
|
|
2233
|
+
createServerInstance = createInstance;
|
|
2234
|
+
console.error("[createServerModule] Server factory enabled - HTTP multi-user support active");
|
|
2235
|
+
} else {
|
|
2236
|
+
console.error("[createServerModule] Warning: No server factory provided - HTTP multi-user may have issues");
|
|
2237
|
+
}
|
|
2238
|
+
return {
|
|
2239
|
+
server: server2,
|
|
2240
|
+
Settings: Settings2,
|
|
2241
|
+
settingsManager,
|
|
2242
|
+
apiManagerFactory,
|
|
2243
|
+
sessionManager,
|
|
2244
|
+
pkg: pkg2,
|
|
2245
|
+
toolPolicyCallback,
|
|
2246
|
+
createServerInstance
|
|
2247
|
+
};
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
// ../mcp-utils/dist/index.js
|
|
2251
|
+
init_ui_dialog();
|
|
2252
|
+
|
|
2253
|
+
// ../mcp-utils/dist/telemetry.js
|
|
2254
|
+
import machineIdPkg from "node-machine-id";
|
|
2255
|
+
import { createHash } from "crypto";
|
|
2256
|
+
var { machineIdSync } = machineIdPkg;
|
|
2257
|
+
var machineId = null;
|
|
2258
|
+
var hashedMachineId = null;
|
|
2259
|
+
function isTelemetryDisabled() {
|
|
2260
|
+
return process.env.TELEMETRY_DISABLED === "true" || process.env.TELEMETRY_DISABLED === "1";
|
|
2261
|
+
}
|
|
2262
|
+
function getTelemetryUrl() {
|
|
2263
|
+
return process.env.TELEMETRY_URL || "https://metrics.security.ai.checkpoint.com/api/v1/metrics/collect";
|
|
2264
|
+
}
|
|
2265
|
+
function hashString(input) {
|
|
2266
|
+
return createHash("sha256").update(input).digest("hex");
|
|
2267
|
+
}
|
|
2268
|
+
function getMachineId() {
|
|
2269
|
+
if (!machineId) {
|
|
2270
|
+
try {
|
|
2271
|
+
machineId = machineIdSync();
|
|
2272
|
+
} catch (error) {
|
|
2273
|
+
console.warn("Failed to get machine ID for telemetry:", error);
|
|
2274
|
+
machineId = "unknown";
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
return machineId;
|
|
2278
|
+
}
|
|
2279
|
+
function getHashedMachineId() {
|
|
2280
|
+
if (!hashedMachineId) {
|
|
2281
|
+
hashedMachineId = hashString(getMachineId());
|
|
2282
|
+
}
|
|
2283
|
+
return hashedMachineId;
|
|
2284
|
+
}
|
|
2285
|
+
function calculateChecksum(mcpName, toolName, machineId2, clientVersion) {
|
|
2286
|
+
const data = mcpName + machineId2.slice(0, 16) + toolName + clientVersion;
|
|
2287
|
+
return hashString(data);
|
|
2288
|
+
}
|
|
2289
|
+
async function trackToolCall(mcpName, toolName, clientVersion, extra) {
|
|
2290
|
+
if (isTelemetryDisabled()) {
|
|
2291
|
+
return;
|
|
2292
|
+
}
|
|
2293
|
+
try {
|
|
2294
|
+
const machineId2 = getHashedMachineId();
|
|
2295
|
+
const checksum = calculateChecksum(mcpName, toolName, machineId2, clientVersion);
|
|
2296
|
+
fetch(getTelemetryUrl(), {
|
|
2297
|
+
method: "POST",
|
|
2298
|
+
headers: { "Content-Type": "application/json" },
|
|
2299
|
+
body: JSON.stringify({
|
|
2300
|
+
mcp_name: mcpName,
|
|
2301
|
+
tool_name: toolName,
|
|
2302
|
+
machine_id: machineId2,
|
|
2303
|
+
client_version: clientVersion,
|
|
2304
|
+
checksum
|
|
2305
|
+
})
|
|
2306
|
+
}).catch(() => {
|
|
2307
|
+
});
|
|
2308
|
+
} catch (error) {
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2312
|
+
// ../mcp-utils/dist/mcp-server.js
|
|
2313
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2314
|
+
var CPMcpServer = class extends McpServer {
|
|
2315
|
+
constructor(serverInfo, options) {
|
|
2316
|
+
super(serverInfo, options);
|
|
2317
|
+
this.mcpName = serverInfo.name;
|
|
2318
|
+
this.mcpVersion = serverInfo.version || "0.0.0";
|
|
2319
|
+
}
|
|
2320
|
+
/**
|
|
2321
|
+
* Set a tool policy callback to filter which tools are available
|
|
2322
|
+
* This should be called after all tools are registered but before connecting
|
|
2323
|
+
* @param callback Function that returns true if a tool should be enabled
|
|
2324
|
+
*/
|
|
2325
|
+
setToolPolicy(callback) {
|
|
2326
|
+
console.error("[CPMcpServer] Setting tool policy callback");
|
|
2327
|
+
this.toolPolicyCallback = callback;
|
|
2328
|
+
}
|
|
2329
|
+
/**
|
|
2330
|
+
* Apply the tool policy by checking all registered tools
|
|
2331
|
+
* This should be called after all tools are registered but before connecting
|
|
2332
|
+
*/
|
|
2333
|
+
applyToolPolicy() {
|
|
2334
|
+
if (!this.toolPolicyCallback) {
|
|
2335
|
+
console.error("[CPMcpServer] No tool policy callback set, allowing all tools");
|
|
2336
|
+
return;
|
|
2337
|
+
}
|
|
2338
|
+
console.error("[CPMcpServer] Applying tool policy");
|
|
2339
|
+
const registeredTools = this._registeredTools;
|
|
2340
|
+
if (!registeredTools || typeof registeredTools !== "object") {
|
|
2341
|
+
console.error("[CPMcpServer] No tools registered yet");
|
|
2342
|
+
return;
|
|
2343
|
+
}
|
|
2344
|
+
const toolNames = Object.keys(registeredTools);
|
|
2345
|
+
console.error(`[CPMcpServer] Found ${toolNames.length} registered tools:`, toolNames);
|
|
2346
|
+
let enabledCount = 0;
|
|
2347
|
+
let disabledCount = 0;
|
|
2348
|
+
for (const [toolName, tool] of Object.entries(registeredTools)) {
|
|
2349
|
+
const isAllowed = this.toolPolicyCallback(toolName);
|
|
2350
|
+
if (!isAllowed) {
|
|
2351
|
+
console.error(`[CPMcpServer] Tool '${toolName}' is NOT allowed by policy - disabling`);
|
|
2352
|
+
if (typeof tool.disable === "function") {
|
|
2353
|
+
tool.disable();
|
|
2354
|
+
disabledCount++;
|
|
2355
|
+
}
|
|
2356
|
+
} else {
|
|
2357
|
+
console.error(`[CPMcpServer] Tool '${toolName}' is allowed by policy`);
|
|
2358
|
+
enabledCount++;
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
console.error(`[CPMcpServer] Policy applied: ${enabledCount}/${toolNames.length} tools enabled, ${disabledCount} disabled`);
|
|
2362
|
+
}
|
|
2363
|
+
// Override the tool method to wrap callbacks with telemetry
|
|
2364
|
+
tool(...args) {
|
|
2365
|
+
const callback = args[args.length - 1];
|
|
2366
|
+
if (typeof callback === "function") {
|
|
2367
|
+
const toolName = args[0];
|
|
2368
|
+
const wrappedCallback = async (...callbackArgs) => {
|
|
2369
|
+
let extra = callbackArgs[1];
|
|
2370
|
+
if (!extra && callbackArgs[0]?.sessionId) {
|
|
2371
|
+
extra = callbackArgs[0];
|
|
2372
|
+
}
|
|
2373
|
+
trackToolCall(this.mcpName, toolName, this.mcpVersion, extra).catch(() => {
|
|
2374
|
+
});
|
|
2375
|
+
if (callbackArgs.length === 1 && callbackArgs[0]?.sessionId) {
|
|
2376
|
+
return callback({}, callbackArgs[0]);
|
|
2377
|
+
}
|
|
2378
|
+
return callback(...callbackArgs);
|
|
2379
|
+
};
|
|
2380
|
+
args[args.length - 1] = wrappedCallback;
|
|
2381
|
+
}
|
|
2382
|
+
return super.tool(...args);
|
|
2383
|
+
}
|
|
2384
|
+
};
|
|
2385
|
+
|
|
2386
|
+
// ../mcp-utils/dist/package-utils.js
|
|
2387
|
+
import { readFileSync } from "fs";
|
|
2388
|
+
import { join as join2, dirname } from "path";
|
|
2389
|
+
import { fileURLToPath } from "url";
|
|
2390
|
+
function readPackageJson(importMetaUrl) {
|
|
2391
|
+
const pkg2 = JSON.parse(readFileSync(join2(dirname(fileURLToPath(importMetaUrl)), "../package.json"), "utf-8"));
|
|
2392
|
+
process.env.CP_MCP_MAIN_PKG = `${pkg2.name} v${pkg2.version}`;
|
|
2393
|
+
return pkg2;
|
|
2394
|
+
}
|
|
2395
|
+
function createMcpServer(importMetaUrl, serverInfo, options) {
|
|
2396
|
+
const pkg2 = readPackageJson(importMetaUrl);
|
|
2397
|
+
const fullServerInfo = {
|
|
2398
|
+
...serverInfo,
|
|
2399
|
+
name: serverInfo.name || pkg2.name,
|
|
2400
|
+
version: serverInfo.version || pkg2.version
|
|
2401
|
+
};
|
|
2402
|
+
const createServerFn = () => {
|
|
2403
|
+
return new CPMcpServer(fullServerInfo, options);
|
|
2404
|
+
};
|
|
2405
|
+
const server2 = new CPMcpServer(fullServerInfo, options);
|
|
2406
|
+
server2._createServerFn = createServerFn;
|
|
2407
|
+
return { server: server2, pkg: pkg2 };
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
// ../infra/dist/api-manager.js
|
|
2411
|
+
var APIManagerBase = class {
|
|
2412
|
+
constructor(client) {
|
|
2413
|
+
this.client = client;
|
|
2414
|
+
this.requestInfo = null;
|
|
2415
|
+
this.detailsLevel = "full";
|
|
2416
|
+
this._debug = false;
|
|
2417
|
+
this.domainClients = /* @__PURE__ */ new Map();
|
|
2418
|
+
this.gatewayDomainMap = /* @__PURE__ */ new Map();
|
|
2419
|
+
this.domains = null;
|
|
2420
|
+
}
|
|
2421
|
+
/**
|
|
2422
|
+
* Set debug mode for the API client
|
|
2423
|
+
*/
|
|
2424
|
+
set debug(value) {
|
|
2425
|
+
this._debug = value;
|
|
2426
|
+
if (this.client) {
|
|
2427
|
+
if ("debug" in this.client) {
|
|
2428
|
+
this.client.debug = value;
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
/**
|
|
2433
|
+
* Get debug mode
|
|
2434
|
+
*/
|
|
2435
|
+
get debug() {
|
|
2436
|
+
return this._debug;
|
|
2437
|
+
}
|
|
2438
|
+
/**
|
|
2439
|
+
* Call an API endpoint
|
|
2440
|
+
*/
|
|
2441
|
+
async callApi(method, uri, data, domain) {
|
|
2442
|
+
const sanitizedData = sanitizeData(data);
|
|
2443
|
+
const apiClient = domain ? await this.getDomainApiClientByDomain(domain) : this.client;
|
|
2444
|
+
const clientResponse = await apiClient.callApi(method, uri, sanitizedData, void 0);
|
|
2445
|
+
return clientResponse.response;
|
|
2446
|
+
}
|
|
2447
|
+
/**
|
|
2448
|
+
* Get the result of a management API task (similar to getTaskResult but for management tasks)
|
|
2449
|
+
*/
|
|
2450
|
+
async getManagementTaskResult(taskId, domain, maxRetries = 5) {
|
|
2451
|
+
let retries = 0;
|
|
2452
|
+
const timeouts = [500, 500, 1e3, 2e3, 5e3];
|
|
2453
|
+
while (retries < maxRetries) {
|
|
2454
|
+
const taskParams2 = { "task-id": taskId };
|
|
2455
|
+
const taskResp2 = await this.callApi("POST", "show-task", taskParams2, domain);
|
|
2456
|
+
const tasks = taskResp2?.tasks || [];
|
|
2457
|
+
if (tasks.length > 0) {
|
|
2458
|
+
const taskStatus = tasks[0].status;
|
|
2459
|
+
if (taskStatus === "succeeded" || taskStatus === "failed") {
|
|
2460
|
+
return { response: taskResp2 };
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
const timeout = timeouts[Math.min(retries, timeouts.length - 1)];
|
|
2464
|
+
await new Promise((resolve) => setTimeout(resolve, timeout));
|
|
2465
|
+
retries++;
|
|
2466
|
+
}
|
|
2467
|
+
const taskParams = { "task-id": taskId };
|
|
2468
|
+
const taskResp = await this.callApi("POST", "show-task", taskParams, domain);
|
|
2469
|
+
return { response: taskResp };
|
|
2470
|
+
}
|
|
2471
|
+
/**
|
|
2472
|
+
* Check if the current environment is MDS
|
|
2473
|
+
*/
|
|
2474
|
+
async isMds() {
|
|
2475
|
+
return await this.client.isMDSEnvironment();
|
|
2476
|
+
}
|
|
2477
|
+
/**
|
|
2478
|
+
* Get domains from show-domains API with full details including server information
|
|
2479
|
+
*/
|
|
2480
|
+
async getDomains() {
|
|
2481
|
+
if (this.domains !== null) {
|
|
2482
|
+
return this.domains;
|
|
2483
|
+
}
|
|
2484
|
+
const response = await this.callApi("post", "show-domains", {
|
|
2485
|
+
"details-level": "full"
|
|
2486
|
+
});
|
|
2487
|
+
const domains = [];
|
|
2488
|
+
if (response.objects) {
|
|
2489
|
+
for (const obj of response.objects) {
|
|
2490
|
+
if (obj.name && obj.type) {
|
|
2491
|
+
domains.push({
|
|
2492
|
+
name: obj.name,
|
|
2493
|
+
type: obj.type,
|
|
2494
|
+
servers: obj.servers || []
|
|
2495
|
+
});
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
this.domains = domains;
|
|
2500
|
+
return domains;
|
|
2501
|
+
}
|
|
2502
|
+
/**
|
|
2503
|
+
* Create an API manager instance
|
|
2504
|
+
*/
|
|
2505
|
+
static create(args) {
|
|
2506
|
+
throw new Error("Method must be implemented by subclass");
|
|
2507
|
+
}
|
|
2508
|
+
/**
|
|
2509
|
+
* Get the appropriate API client for a specific gateway, handling MDS domain routing
|
|
2510
|
+
*/
|
|
2511
|
+
async getDomainApiClient(gatewayName) {
|
|
2512
|
+
const isMDS = await this.client.isMDSEnvironment();
|
|
2513
|
+
if (!isMDS) {
|
|
2514
|
+
return this.client;
|
|
2515
|
+
}
|
|
2516
|
+
const existingDomain = this.gatewayDomainMap.get(gatewayName);
|
|
2517
|
+
if (existingDomain) {
|
|
2518
|
+
const existingClient = this.domainClients.get(existingDomain);
|
|
2519
|
+
if (existingClient && existingClient.hasValidSession()) {
|
|
2520
|
+
return existingClient;
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
const gatewayInfo = await this.getGatewayInfo(gatewayName);
|
|
2524
|
+
if (!gatewayInfo) {
|
|
2525
|
+
throw new Error(`Gateway '${gatewayName}' not found`);
|
|
2526
|
+
}
|
|
2527
|
+
const gatewayDomain = gatewayInfo.domain;
|
|
2528
|
+
if (!gatewayDomain) {
|
|
2529
|
+
return this.client;
|
|
2530
|
+
}
|
|
2531
|
+
const gatewayDomainName = gatewayDomain.name;
|
|
2532
|
+
const existingDomainClient = this.domainClients.get(gatewayDomainName);
|
|
2533
|
+
if (existingDomainClient && existingDomainClient.hasValidSession()) {
|
|
2534
|
+
this.gatewayDomainMap.set(gatewayName, gatewayDomainName);
|
|
2535
|
+
return existingDomainClient;
|
|
2536
|
+
}
|
|
2537
|
+
const domainSid = await this.loginToDomain(gatewayDomainName);
|
|
2538
|
+
const domainClient = this.createClientWithSid(domainSid);
|
|
2539
|
+
this.domainClients.set(gatewayDomainName, domainClient);
|
|
2540
|
+
this.gatewayDomainMap.set(gatewayName, gatewayDomainName);
|
|
2541
|
+
return domainClient;
|
|
2542
|
+
}
|
|
2543
|
+
/**
|
|
2544
|
+
* Get the appropriate API client for a specific domain, handling MDS domain routing
|
|
2545
|
+
* This method handles multi-MDS environments where domains may be distributed across
|
|
2546
|
+
* different MDS servers with active/standby configurations.
|
|
2547
|
+
*/
|
|
2548
|
+
async getDomainApiClientByDomain(domainName) {
|
|
2549
|
+
const isMDS = await this.client.isMDSEnvironment();
|
|
2550
|
+
if (!isMDS) {
|
|
2551
|
+
return this.client;
|
|
2552
|
+
}
|
|
2553
|
+
const existingDomainClient = this.domainClients.get(domainName);
|
|
2554
|
+
if (existingDomainClient && existingDomainClient.hasValidSession()) {
|
|
2555
|
+
return existingDomainClient;
|
|
2556
|
+
}
|
|
2557
|
+
const isOnCurrentMDS = await this.isDomainOnCurrentMDS(domainName);
|
|
2558
|
+
if (isOnCurrentMDS) {
|
|
2559
|
+
const domainSid2 = await this.loginToDomain(domainName);
|
|
2560
|
+
const domainClient2 = this.createClientWithSid(domainSid2);
|
|
2561
|
+
this.domainClients.set(domainName, domainClient2);
|
|
2562
|
+
return domainClient2;
|
|
2563
|
+
}
|
|
2564
|
+
const targetMDSIP = await this.getMDSServerForDomain(domainName);
|
|
2565
|
+
if (!targetMDSIP) {
|
|
2566
|
+
throw new Error(`Domain '${domainName}' not found or has no available MDS servers. Make sure the domain exists and you have access to it.`);
|
|
2567
|
+
}
|
|
2568
|
+
const currentHost = this.client.getHost();
|
|
2569
|
+
const portMatch = currentHost.match(/:(\d+)/);
|
|
2570
|
+
const port = portMatch ? portMatch[1] : "443";
|
|
2571
|
+
const newMDSClient = this.createClientForMDS(targetMDSIP, port);
|
|
2572
|
+
if ("debug" in newMDSClient) {
|
|
2573
|
+
newMDSClient.debug = this._debug;
|
|
2574
|
+
}
|
|
2575
|
+
await newMDSClient.login();
|
|
2576
|
+
const loginResponse = await newMDSClient.callApi("post", "login-to-domain", {
|
|
2577
|
+
"domain": domainName
|
|
2578
|
+
}, void 0);
|
|
2579
|
+
if (!loginResponse.response.sid) {
|
|
2580
|
+
throw new Error(`Failed to login to domain '${domainName}' on MDS server ${targetMDSIP}`);
|
|
2581
|
+
}
|
|
2582
|
+
const domainSid = loginResponse.response.sid;
|
|
2583
|
+
const domainClient = this.createClientWithSid(domainSid);
|
|
2584
|
+
this.domainClients.set(domainName, domainClient);
|
|
2585
|
+
return domainClient;
|
|
2586
|
+
}
|
|
2587
|
+
/**
|
|
2588
|
+
* Get gateway information from show-gateways-and-servers
|
|
2589
|
+
*/
|
|
2590
|
+
async getGatewayInfo(gatewayName) {
|
|
2591
|
+
const response = await this.callApi("post", "show-gateways-and-servers", {
|
|
2592
|
+
"details-level": "full"
|
|
2593
|
+
});
|
|
2594
|
+
if (response.objects) {
|
|
2595
|
+
return response.objects.find((obj) => obj.name === gatewayName);
|
|
2596
|
+
}
|
|
2597
|
+
return null;
|
|
2598
|
+
}
|
|
2599
|
+
/**
|
|
2600
|
+
* Login to a specific domain using the main API client
|
|
2601
|
+
*/
|
|
2602
|
+
async loginToDomain(domainName) {
|
|
2603
|
+
const response = await this.callApi("post", "login-to-domain", {
|
|
2604
|
+
"domain": domainName
|
|
2605
|
+
});
|
|
2606
|
+
if (!response.sid) {
|
|
2607
|
+
throw new Error(`Failed to login to domain '${domainName}'`);
|
|
2608
|
+
}
|
|
2609
|
+
return response.sid;
|
|
2610
|
+
}
|
|
2611
|
+
/**
|
|
2612
|
+
* Create a new API client instance with the given session ID
|
|
2613
|
+
*/
|
|
2614
|
+
createClientWithSid(sid) {
|
|
2615
|
+
if (this.client instanceof OnPremAPIClient) {
|
|
2616
|
+
return APIClientBase.createWithSid.call(OnPremAPIClient, this.client, sid);
|
|
2617
|
+
} else if (this.client instanceof SmartOneCloudAPIClient) {
|
|
2618
|
+
return APIClientBase.createWithSid.call(SmartOneCloudAPIClient, this.client, sid);
|
|
2619
|
+
} else {
|
|
2620
|
+
throw new Error("Unknown client type");
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
/**
|
|
2624
|
+
* Check if a domain exists on the current MDS server (either active or standby)
|
|
2625
|
+
*/
|
|
2626
|
+
async isDomainOnCurrentMDS(domainName) {
|
|
2627
|
+
const domains = await this.getDomains();
|
|
2628
|
+
const domain = domains.find((d) => d.name === domainName);
|
|
2629
|
+
if (!domain?.servers || domain.servers.length === 0) {
|
|
2630
|
+
return false;
|
|
2631
|
+
}
|
|
2632
|
+
const currentHost = this.client.getHost();
|
|
2633
|
+
return domain.servers.some((server2) => {
|
|
2634
|
+
const ipv4 = server2["ipv4-address"];
|
|
2635
|
+
const ipv6 = server2["ipv6-address"];
|
|
2636
|
+
return ipv4 && currentHost.includes(ipv4) || ipv6 && currentHost.includes(ipv6);
|
|
2637
|
+
});
|
|
2638
|
+
}
|
|
2639
|
+
/**
|
|
2640
|
+
* Get the appropriate MDS server IP for a domain
|
|
2641
|
+
* Prefers the active server, but returns any available server
|
|
2642
|
+
* Returns IPv4 if available, otherwise IPv6
|
|
2643
|
+
*/
|
|
2644
|
+
async getMDSServerForDomain(domainName) {
|
|
2645
|
+
const domains = await this.getDomains();
|
|
2646
|
+
const domain = domains.find((d) => d.name === domainName);
|
|
2647
|
+
if (!domain?.servers || domain.servers.length === 0) {
|
|
2648
|
+
return null;
|
|
2649
|
+
}
|
|
2650
|
+
const activeServer = domain.servers.find((s) => s.active === true);
|
|
2651
|
+
if (activeServer) {
|
|
2652
|
+
if (activeServer["ipv4-address"]) {
|
|
2653
|
+
return activeServer["ipv4-address"];
|
|
2654
|
+
}
|
|
2655
|
+
if (activeServer["ipv6-address"]) {
|
|
2656
|
+
return activeServer["ipv6-address"];
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
const ipv4Server = domain.servers.find((s) => s["ipv4-address"]);
|
|
2660
|
+
if (ipv4Server?.["ipv4-address"]) {
|
|
2661
|
+
return ipv4Server["ipv4-address"];
|
|
2662
|
+
}
|
|
2663
|
+
const ipv6Server = domain.servers.find((s) => s["ipv6-address"]);
|
|
2664
|
+
return ipv6Server?.["ipv6-address"] || null;
|
|
2665
|
+
}
|
|
2666
|
+
/**
|
|
2667
|
+
* Create a new API client for a different MDS server
|
|
2668
|
+
* Handles both IPv4 and IPv6 addresses
|
|
2669
|
+
* Only supports OnPremAPIClient for multi-MDS scenarios
|
|
2670
|
+
*/
|
|
2671
|
+
createClientForMDS(mdsIP, port = "443") {
|
|
2672
|
+
if (this.client instanceof OnPremAPIClient) {
|
|
2673
|
+
const currentClient = this.client;
|
|
2674
|
+
const formattedHost = mdsIP.includes(":") && !mdsIP.startsWith("[") ? `[${mdsIP}]` : mdsIP;
|
|
2675
|
+
return new OnPremAPIClient(currentClient.authToken || void 0, formattedHost, port, currentClient.username, currentClient.password);
|
|
2676
|
+
} else if (this.client instanceof SmartOneCloudAPIClient) {
|
|
2677
|
+
throw new Error("Multi-MDS routing is not supported for SmartOneCloud environments");
|
|
2678
|
+
} else {
|
|
2679
|
+
throw new Error("Unknown client type for MDS routing");
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
/**
|
|
2683
|
+
* Run a script on a target gateway
|
|
2684
|
+
*/
|
|
2685
|
+
async runScript(targetGateway, scriptName, script) {
|
|
2686
|
+
const apiClient = await this.getDomainApiClient(targetGateway);
|
|
2687
|
+
const payload = {
|
|
2688
|
+
"script-name": scriptName,
|
|
2689
|
+
"script": script,
|
|
2690
|
+
"targets": [targetGateway]
|
|
2691
|
+
};
|
|
2692
|
+
const clientResponse = await apiClient.callApi("post", "run-script", payload, void 0);
|
|
2693
|
+
const resp = clientResponse.response;
|
|
2694
|
+
if (!resp.tasks) {
|
|
2695
|
+
return [false, { message: "Failed to run the script" }];
|
|
2696
|
+
}
|
|
2697
|
+
return [true, { tasks: resp.tasks.map((task) => task["task-id"]) }];
|
|
2698
|
+
}
|
|
2699
|
+
/**
|
|
2700
|
+
* Get the result of a task
|
|
2701
|
+
*/
|
|
2702
|
+
async getTaskResult(gatewayName, taskId, maxRetries = 5) {
|
|
2703
|
+
const client = await this.getDomainApiClient(gatewayName);
|
|
2704
|
+
let retries = 0;
|
|
2705
|
+
const timeouts = [1e3, 1e3, 2e3, 5e3, 5e3];
|
|
2706
|
+
while (retries < maxRetries) {
|
|
2707
|
+
const payload = {
|
|
2708
|
+
"task-id": taskId,
|
|
2709
|
+
"details-level": "full"
|
|
2710
|
+
};
|
|
2711
|
+
const response = await client.callApi("post", "show-task", payload);
|
|
2712
|
+
const taskDetails = response.response.tasks?.[0];
|
|
2713
|
+
if (taskDetails?.status === "succeeded" || taskDetails?.status === "failed") {
|
|
2714
|
+
if (taskDetails["task-details"]?.[0]?.responseMessage) {
|
|
2715
|
+
const responseMessageBase64 = taskDetails["task-details"][0].responseMessage;
|
|
2716
|
+
const decoded = Buffer.from(responseMessageBase64, "base64").toString("utf-8");
|
|
2717
|
+
return [taskDetails.status === "succeeded", decoded];
|
|
2718
|
+
}
|
|
2719
|
+
return [false, "failed to get task result"];
|
|
2720
|
+
} else {
|
|
2721
|
+
const timeout = timeouts[Math.min(retries, timeouts.length - 1)];
|
|
2722
|
+
console.error(`Try #${retries}: Task ${taskId} is still running, waiting for ${timeout}ms...`);
|
|
2723
|
+
retries++;
|
|
2724
|
+
await new Promise((resolve) => setTimeout(resolve, timeout));
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
return [false, "Task did not complete in time"];
|
|
2728
|
+
}
|
|
2729
|
+
};
|
|
2730
|
+
var APIManagerForAPIKey = class extends APIManagerBase {
|
|
2731
|
+
static create(args) {
|
|
2732
|
+
const verbose = SettingsManager.globalDebugState;
|
|
2733
|
+
if (verbose) {
|
|
2734
|
+
console.error("[APIManagerForAPIKey.create] Verbose: Creating API manager");
|
|
2735
|
+
console.error("[APIManagerForAPIKey.create] Verbose: Args received:", {
|
|
2736
|
+
apiKey: args.apiKey ? "***" : void 0,
|
|
2737
|
+
username: args.username ? "***" : void 0,
|
|
2738
|
+
password: args.password ? "***" : void 0,
|
|
2739
|
+
managementHost: args.managementHost,
|
|
2740
|
+
managementPort: args.managementPort,
|
|
2741
|
+
s1cUrl: args.s1cUrl,
|
|
2742
|
+
cloudInfraToken: args.cloudInfraToken ? "***" : void 0
|
|
2743
|
+
});
|
|
2744
|
+
}
|
|
2745
|
+
const hasAnyValue = args.apiKey || args.username || args.password || args.s1cUrl || args.managementHost || args.cloudInfraToken;
|
|
2746
|
+
if (!hasAnyValue) {
|
|
2747
|
+
if (verbose) {
|
|
2748
|
+
console.error("[APIManagerForAPIKey.create] Verbose: ERROR - Args object is effectively empty, no values provided");
|
|
2749
|
+
console.error("[APIManagerForAPIKey.create] Verbose: All args keys:", Object.keys(args));
|
|
2750
|
+
}
|
|
2751
|
+
throw new Error("No authentication or connection parameters provided. Args object is empty or contains only undefined values.");
|
|
2752
|
+
}
|
|
2753
|
+
if (args.managementHost) {
|
|
2754
|
+
if (verbose) {
|
|
2755
|
+
console.error("[APIManagerForAPIKey.create] Verbose: Using on-prem management with host:", args.managementHost);
|
|
2756
|
+
}
|
|
2757
|
+
const onPremClient = new OnPremAPIClient(args.apiKey, args.managementHost, args.managementPort || "443", args.username, args.password);
|
|
2758
|
+
return new this(onPremClient);
|
|
2759
|
+
}
|
|
2760
|
+
if (verbose) {
|
|
2761
|
+
console.error("[APIManagerForAPIKey.create] Verbose: managementHost not provided, checking s1cUrl");
|
|
2762
|
+
}
|
|
2763
|
+
if (!args.s1cUrl) {
|
|
2764
|
+
if (verbose) {
|
|
2765
|
+
console.error("[APIManagerForAPIKey.create] Verbose: ERROR - Neither managementHost nor s1cUrl provided");
|
|
2766
|
+
}
|
|
2767
|
+
throw new Error("Either management host or S1C URL must be provided");
|
|
2768
|
+
}
|
|
2769
|
+
if (verbose) {
|
|
2770
|
+
console.error("[APIManagerForAPIKey.create] Verbose: Using S1C with URL:", args.s1cUrl);
|
|
2771
|
+
}
|
|
2772
|
+
let keyType;
|
|
2773
|
+
let key;
|
|
2774
|
+
if (args.cloudInfraToken) {
|
|
2775
|
+
if (verbose) {
|
|
2776
|
+
console.error("[APIManagerForAPIKey.create] Verbose: Using cloud infra token");
|
|
2777
|
+
}
|
|
2778
|
+
keyType = TokenType.CI_TOKEN;
|
|
2779
|
+
key = args.cloudInfraToken;
|
|
2780
|
+
} else if (args.apiKey) {
|
|
2781
|
+
if (verbose) {
|
|
2782
|
+
console.error("[APIManagerForAPIKey.create] Verbose: Using API key");
|
|
2783
|
+
}
|
|
2784
|
+
keyType = TokenType.API_KEY;
|
|
2785
|
+
key = args.apiKey;
|
|
2786
|
+
} else {
|
|
2787
|
+
if (verbose) {
|
|
2788
|
+
console.error("[APIManagerForAPIKey.create] Verbose: ERROR - No API key or cloud infra token provided");
|
|
2789
|
+
}
|
|
2790
|
+
throw new Error("API key or cloud infrastructure token is required");
|
|
2791
|
+
}
|
|
2792
|
+
return new this(SmartOneCloudAPIClient.create(key, keyType, args.s1cUrl));
|
|
2793
|
+
}
|
|
2794
|
+
};
|
|
2795
|
+
|
|
2796
|
+
// ../infra/dist/settings.js
|
|
2797
|
+
var Settings = class _Settings {
|
|
2798
|
+
normalizeRegion(region) {
|
|
2799
|
+
if (!region) {
|
|
2800
|
+
return void 0;
|
|
2801
|
+
}
|
|
2802
|
+
const normalized = region.trim().toUpperCase();
|
|
2803
|
+
return this.isValidRegion(normalized) ? normalized : void 0;
|
|
2804
|
+
}
|
|
2805
|
+
/**
|
|
2806
|
+
* Extract the base gateway URL (scheme + host) from a full URL.
|
|
2807
|
+
* Allows users to copy-paste any URL from the API key creation dialog
|
|
2808
|
+
* without having to strip the path manually.
|
|
2809
|
+
* Falls back to the original string if URL parsing fails.
|
|
2810
|
+
*/
|
|
2811
|
+
static stripGatewayPath(url) {
|
|
2812
|
+
try {
|
|
2813
|
+
const parsed = new URL(url);
|
|
2814
|
+
return `${parsed.protocol}//${parsed.host}`;
|
|
2815
|
+
} catch {
|
|
2816
|
+
return url;
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
/**
|
|
2820
|
+
* Detect the region from a gateway base URL
|
|
2821
|
+
*/
|
|
2822
|
+
static detectRegionFromUrl(url) {
|
|
2823
|
+
if (url.includes("cloudinfra-gw-us.portal.checkpoint.com"))
|
|
2824
|
+
return "US";
|
|
2825
|
+
if (url.includes("cloudinfra-gw.portal.checkpoint.com"))
|
|
2826
|
+
return "EU";
|
|
2827
|
+
if (url.includes("dev-cloudinfra-gw"))
|
|
2828
|
+
return "STG";
|
|
2829
|
+
return void 0;
|
|
2830
|
+
}
|
|
2831
|
+
constructor({ apiKey = process.env.API_KEY, username = process.env.USERNAME, password = process.env.PASSWORD, s1cUrl = process.env.S1C_URL, managementHost = process.env.MANAGEMENT_HOST, managementPort = process.env.MANAGEMENT_PORT || "443", cloudInfraToken = process.env.CLOUD_INFRA_TOKEN, clientId = process.env.CLIENT_ID, secretKey = process.env.SECRET_KEY, region = process.env.REGION || "EU", devPort = process.env.DEV_PORT || "8006", gatewayUrl } = {}) {
|
|
2832
|
+
this.region = "EU";
|
|
2833
|
+
this.devPort = "8006";
|
|
2834
|
+
this.gatewayUrl = "";
|
|
2835
|
+
const verbose = SettingsManager.globalDebugState;
|
|
2836
|
+
if (verbose) {
|
|
2837
|
+
console.error("[Settings] Verbose: Constructor called with params:", {
|
|
2838
|
+
apiKey: apiKey ? "***" : void 0,
|
|
2839
|
+
username: username ? "***" : void 0,
|
|
2840
|
+
password: password ? "***" : void 0,
|
|
2841
|
+
s1cUrl,
|
|
2842
|
+
managementHost,
|
|
2843
|
+
managementPort,
|
|
2844
|
+
cloudInfraToken: cloudInfraToken ? "***" : void 0,
|
|
2845
|
+
clientId,
|
|
2846
|
+
secretKey: secretKey ? "***" : void 0,
|
|
2847
|
+
region,
|
|
2848
|
+
devPort
|
|
2849
|
+
});
|
|
2850
|
+
}
|
|
2851
|
+
this.apiKey = apiKey;
|
|
2852
|
+
this.username = username;
|
|
2853
|
+
this.password = password;
|
|
2854
|
+
this.s1cUrl = s1cUrl;
|
|
2855
|
+
this.managementHost = managementHost;
|
|
2856
|
+
this.managementPort = managementPort;
|
|
2857
|
+
this.cloudInfraToken = cloudInfraToken;
|
|
2858
|
+
this.clientId = clientId;
|
|
2859
|
+
this.secretKey = secretKey;
|
|
2860
|
+
this.region = this.normalizeRegion(region) || "EU";
|
|
2861
|
+
this.devPort = devPort;
|
|
2862
|
+
this.gatewayUrl = this.resolveGatewayUrl(this.region, gatewayUrl);
|
|
2863
|
+
if (verbose) {
|
|
2864
|
+
console.error("[Settings] Verbose: After assignment:", {
|
|
2865
|
+
apiKey: this.apiKey ? "***" : void 0,
|
|
2866
|
+
username: this.username ? "***" : void 0,
|
|
2867
|
+
password: this.password ? "***" : void 0,
|
|
2868
|
+
s1cUrl: this.s1cUrl,
|
|
2869
|
+
managementHost: this.managementHost,
|
|
2870
|
+
managementPort: this.managementPort,
|
|
2871
|
+
cloudInfraToken: this.cloudInfraToken ? "***" : void 0,
|
|
2872
|
+
region: this.region
|
|
2873
|
+
});
|
|
2874
|
+
}
|
|
2875
|
+
this.validate();
|
|
2876
|
+
}
|
|
2877
|
+
/**
|
|
2878
|
+
* Check if the provided string is a valid region
|
|
2879
|
+
*/
|
|
2880
|
+
isValidRegion(region) {
|
|
2881
|
+
return ["EU", "US", "STG", "LOCAL"].includes(region.toUpperCase());
|
|
2882
|
+
}
|
|
2883
|
+
/**
|
|
2884
|
+
* Get the base gateway URL for a given region
|
|
2885
|
+
*/
|
|
2886
|
+
getRegionGatewayUrl(region) {
|
|
2887
|
+
switch (region) {
|
|
2888
|
+
case "EU":
|
|
2889
|
+
return "https://cloudinfra-gw.portal.checkpoint.com";
|
|
2890
|
+
case "US":
|
|
2891
|
+
return "https://cloudinfra-gw-us.portal.checkpoint.com";
|
|
2892
|
+
case "STG":
|
|
2893
|
+
case "LOCAL":
|
|
2894
|
+
return "https://dev-cloudinfra-gw.kube1.iaas.checkpoint.com";
|
|
2895
|
+
default:
|
|
2896
|
+
return "";
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
/**
|
|
2900
|
+
* Resolve the base gateway URL from either a provided URL or the configured region.
|
|
2901
|
+
* If a URL is provided, its path suffix is stripped so users can paste the full
|
|
2902
|
+
* auth URL from the API key creation dialog (e.g. ending in /auth/external).
|
|
2903
|
+
* When the URL implies a different region, this.region is updated to match.
|
|
2904
|
+
*/
|
|
2905
|
+
resolveGatewayUrl(region, providedUrl) {
|
|
2906
|
+
if (!providedUrl) {
|
|
2907
|
+
return this.getRegionGatewayUrl(region);
|
|
2908
|
+
}
|
|
2909
|
+
const base = _Settings.stripGatewayPath(providedUrl);
|
|
2910
|
+
const detectedRegion = _Settings.detectRegionFromUrl(base);
|
|
2911
|
+
if (detectedRegion && detectedRegion !== this.region) {
|
|
2912
|
+
this.region = detectedRegion;
|
|
2913
|
+
}
|
|
2914
|
+
return base;
|
|
2915
|
+
}
|
|
2916
|
+
/**
|
|
2917
|
+
* Get the base Cloud Infra Gateway URL.
|
|
2918
|
+
* Returns the precomputed gatewayUrl (derived from region or a provided URL).
|
|
2919
|
+
*/
|
|
2920
|
+
getCloudInfraGateway() {
|
|
2921
|
+
return this.gatewayUrl;
|
|
2922
|
+
}
|
|
2923
|
+
/**
|
|
2924
|
+
* Validate the settings
|
|
2925
|
+
*/
|
|
2926
|
+
validate() {
|
|
2927
|
+
const verbose = SettingsManager.globalDebugState;
|
|
2928
|
+
if (verbose) {
|
|
2929
|
+
console.error("[Settings] Verbose: Validating settings...");
|
|
2930
|
+
console.error("[Settings] Verbose: s1cUrl:", this.s1cUrl || "(empty)");
|
|
2931
|
+
console.error("[Settings] Verbose: managementHost:", this.managementHost || "(empty)");
|
|
2932
|
+
console.error("[Settings] Verbose: apiKey:", this.apiKey ? "***" : "(empty)");
|
|
2933
|
+
console.error("[Settings] Verbose: cloudInfraToken:", this.cloudInfraToken ? "***" : "(empty)");
|
|
2934
|
+
console.error("[Settings] Verbose: username:", this.username ? "***" : "(empty)");
|
|
2935
|
+
console.error("[Settings] Verbose: password:", this.password ? "***" : "(empty)");
|
|
2936
|
+
}
|
|
2937
|
+
if (!nullOrEmpty(this.s1cUrl) && nullOrEmpty(this.apiKey) && nullOrEmpty(this.cloudInfraToken)) {
|
|
2938
|
+
if (verbose) {
|
|
2939
|
+
console.error("[Settings] Verbose: Validation FAILED - S1C URL provided but no API key or CI token");
|
|
2940
|
+
}
|
|
2941
|
+
throw new Error("API key or CI Token is required for S1C (via --api-key or API_KEY env var)");
|
|
2942
|
+
}
|
|
2943
|
+
if (!nullOrEmpty(this.managementHost) && nullOrEmpty(this.apiKey) && (nullOrEmpty(this.username) || nullOrEmpty(this.password))) {
|
|
2944
|
+
if (verbose) {
|
|
2945
|
+
console.error("[Settings] Verbose: Validation FAILED - Management host provided but no API key or credentials");
|
|
2946
|
+
}
|
|
2947
|
+
throw new Error("Either API key or username/password are required for on-prem management (via CLI args or env vars)");
|
|
2948
|
+
}
|
|
2949
|
+
if (nullOrEmpty(this.s1cUrl) && nullOrEmpty(this.managementHost)) {
|
|
2950
|
+
if (verbose) {
|
|
2951
|
+
console.error("[Settings] Verbose: WARNING - Neither s1cUrl nor managementHost provided");
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
2954
|
+
if (verbose) {
|
|
2955
|
+
console.error("[Settings] Verbose: Validation PASSED");
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
/**
|
|
2959
|
+
* Create settings from command-line arguments
|
|
2960
|
+
*/
|
|
2961
|
+
static fromArgs(args) {
|
|
2962
|
+
const verbose = SettingsManager.globalDebugState;
|
|
2963
|
+
if (verbose) {
|
|
2964
|
+
console.error("[Settings.fromArgs] Verbose: Creating settings from args");
|
|
2965
|
+
console.error("[Settings.fromArgs] Verbose: Raw args:", {
|
|
2966
|
+
apiKey: args.apiKey ? "***" : void 0,
|
|
2967
|
+
username: args.username ? "***" : void 0,
|
|
2968
|
+
password: args.password ? "***" : void 0,
|
|
2969
|
+
s1cUrl: args.s1cUrl,
|
|
2970
|
+
managementHost: args.managementHost,
|
|
2971
|
+
managementPort: args.managementPort,
|
|
2972
|
+
cloudInfraToken: args.cloudInfraToken ? "***" : void 0,
|
|
2973
|
+
region: args.region,
|
|
2974
|
+
hasOtherKeys: Object.keys(args).length > 10
|
|
2975
|
+
});
|
|
2976
|
+
const hasAnyValue = args.apiKey || args.username || args.password || args.s1cUrl || args.managementHost || args.cloudInfraToken;
|
|
2977
|
+
if (!hasAnyValue) {
|
|
2978
|
+
console.error("[Settings.fromArgs] Verbose: WARNING - Args object appears empty, no authentication values found");
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
return new _Settings({
|
|
2982
|
+
apiKey: args.apiKey,
|
|
2983
|
+
username: args.username,
|
|
2984
|
+
password: args.password,
|
|
2985
|
+
s1cUrl: args.s1cUrl,
|
|
2986
|
+
managementHost: args.managementHost,
|
|
2987
|
+
managementPort: args.managementPort,
|
|
2988
|
+
cloudInfraToken: args.cloudInfraToken,
|
|
2989
|
+
clientId: args.clientId,
|
|
2990
|
+
secretKey: args.secretKey,
|
|
2991
|
+
region: typeof args.region === "string" ? args.region.trim().toUpperCase() : void 0,
|
|
2992
|
+
devPort: args.devPort,
|
|
2993
|
+
gatewayUrl: args.gatewayUrl
|
|
2994
|
+
});
|
|
2995
|
+
}
|
|
2996
|
+
/**
|
|
2997
|
+
* Create settings from HTTP headers
|
|
2998
|
+
* Maps headers to environment variable format based on server config
|
|
2999
|
+
*/
|
|
3000
|
+
static fromHeaders(headers) {
|
|
3001
|
+
const verbose = SettingsManager.globalDebugState;
|
|
3002
|
+
if (verbose) {
|
|
3003
|
+
console.error("[Settings.fromHeaders] Verbose: Creating settings from headers");
|
|
3004
|
+
console.error("[Settings.fromHeaders] Verbose: Available header keys:", Object.keys(headers));
|
|
3005
|
+
}
|
|
3006
|
+
const extractedValues = {
|
|
3007
|
+
apiKey: getHeaderValue(headers, "API-KEY"),
|
|
3008
|
+
username: getHeaderValue(headers, "USERNAME"),
|
|
3009
|
+
password: getHeaderValue(headers, "PASSWORD"),
|
|
3010
|
+
s1cUrl: getHeaderValue(headers, "S1C-URL"),
|
|
3011
|
+
managementHost: getHeaderValue(headers, "MANAGEMENT-HOST"),
|
|
3012
|
+
managementPort: getHeaderValue(headers, "MANAGEMENT-PORT"),
|
|
3013
|
+
cloudInfraToken: getHeaderValue(headers, "CLOUD-INFRA-TOKEN"),
|
|
3014
|
+
clientId: getHeaderValue(headers, "CLIENT-ID"),
|
|
3015
|
+
secretKey: getHeaderValue(headers, "SECRET-KEY"),
|
|
3016
|
+
region: getHeaderValue(headers, "REGION"),
|
|
3017
|
+
devPort: getHeaderValue(headers, "DEV-PORT"),
|
|
3018
|
+
gatewayUrl: getHeaderValue(headers, "GATEWAY-URL")
|
|
3019
|
+
};
|
|
3020
|
+
if (verbose) {
|
|
3021
|
+
console.error("[Settings.fromHeaders] Verbose: Extracted values:", {
|
|
3022
|
+
apiKey: extractedValues.apiKey ? "***" : void 0,
|
|
3023
|
+
username: extractedValues.username ? "***" : void 0,
|
|
3024
|
+
password: extractedValues.password ? "***" : void 0,
|
|
3025
|
+
s1cUrl: extractedValues.s1cUrl,
|
|
3026
|
+
managementHost: extractedValues.managementHost,
|
|
3027
|
+
managementPort: extractedValues.managementPort,
|
|
3028
|
+
cloudInfraToken: extractedValues.cloudInfraToken ? "***" : void 0,
|
|
3029
|
+
region: extractedValues.region,
|
|
3030
|
+
devPort: extractedValues.devPort
|
|
3031
|
+
});
|
|
3032
|
+
const hasAnyValue = extractedValues.apiKey || extractedValues.username || extractedValues.password || extractedValues.s1cUrl || extractedValues.managementHost || extractedValues.cloudInfraToken;
|
|
3033
|
+
if (!hasAnyValue) {
|
|
3034
|
+
console.error("[Settings.fromHeaders] Verbose: WARNING - No authentication values found in headers");
|
|
3035
|
+
console.error("[Settings.fromHeaders] Verbose: Full headers object (sanitized):", Object.fromEntries(Object.entries(headers).map(([k, v]) => [k, k.toLowerCase().includes("key") || k.toLowerCase().includes("token") || k.toLowerCase().includes("password") ? "***" : v])));
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
return new _Settings({
|
|
3039
|
+
apiKey: extractedValues.apiKey,
|
|
3040
|
+
username: extractedValues.username,
|
|
3041
|
+
password: extractedValues.password,
|
|
3042
|
+
s1cUrl: extractedValues.s1cUrl,
|
|
3043
|
+
managementHost: extractedValues.managementHost,
|
|
3044
|
+
managementPort: extractedValues.managementPort,
|
|
3045
|
+
cloudInfraToken: extractedValues.cloudInfraToken,
|
|
3046
|
+
clientId: extractedValues.clientId,
|
|
3047
|
+
secretKey: extractedValues.secretKey,
|
|
3048
|
+
region: extractedValues.region?.toUpperCase(),
|
|
3049
|
+
devPort: extractedValues.devPort,
|
|
3050
|
+
gatewayUrl: extractedValues.gatewayUrl
|
|
3051
|
+
});
|
|
3052
|
+
}
|
|
3053
|
+
};
|
|
3054
|
+
|
|
3055
|
+
// ../infra/dist/external-user-token-manager.js
|
|
3056
|
+
import axios2 from "axios";
|
|
3057
|
+
|
|
3058
|
+
// src/index.ts
|
|
3059
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
3060
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3061
|
+
|
|
3062
|
+
// src/zodSchemas.ts
|
|
3063
|
+
import { z } from "zod";
|
|
3064
|
+
var zodSchemas = {
|
|
3065
|
+
ShowCardInfo: { domain: z.string().optional(), domains_to_process: z.enum(["ALL_DOMAINS_ON_THIS_SERVER", "CURRENT_DOMAIN"]).optional() },
|
|
3066
|
+
ShowConfig: { domain: z.string().optional(), domains_to_process: z.enum(["ALL_DOMAINS_ON_THIS_SERVER", "CURRENT_DOMAIN"]).optional() },
|
|
3067
|
+
ShowRulesUidsWithSuggestions: { domain: z.string().optional(), domains_to_process: z.enum(["ALL_DOMAINS_ON_THIS_SERVER", "CURRENT_DOMAIN"]).optional(), "requestBody": z.object({ "layer": z.string().uuid().regex(new RegExp("^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$")).describe("Access layer identifier in UUID format"), "filters": z.object({ "states": z.array(z.enum(["ACCEPTED", "REJECTED"]).describe("State of a suggestion - either ACCEPTED or REJECTED")).describe("Array of insight state values").optional(), "user-interaction": z.object({ "operator": z.enum(["NOT-IN", "IN"]).describe("Operator for filtering by user-interaction-types").optional(), "types": z.array(z.literal("DECIDE_LATER").describe("Type of user interaction with an insight")).describe("Array of user interaction type values") }).optional(), "security-impact": z.enum(["HIGH", "MEDIUM_AND_ABOVE", "LOW_AND_ABOVE"]).describe("Minimum security impact threshold to include").optional(), "confidence-level": z.enum(["HIGH", "MEDIUM_AND_ABOVE", "LOW_AND_ABOVE"]).describe("Minimum confidence threshold to include").optional(), "default-filter": z.literal("NONE").describe("Ignore default filtering of the system").optional(), "suggestions-type": z.enum(["unused-objects", "tighten-rule", "delete-disabled-rule", "zero-hits-rule"]).describe("Type of insight") }) }).describe("Parameters for showing rules UIDs with their suggestions") },
|
|
3068
|
+
ShowState: { domain: z.string().optional(), domains_to_process: z.enum(["ALL_DOMAINS_ON_THIS_SERVER", "CURRENT_DOMAIN"]).optional() },
|
|
3069
|
+
ShowSuggestionEngineMetadata: { domain: z.string().optional(), domains_to_process: z.enum(["ALL_DOMAINS_ON_THIS_SERVER", "CURRENT_DOMAIN"]).optional(), "requestBody": z.object({ "filters": z.object({ "suggestion-type": z.enum(["unused-objects", "tighten-rule", "delete-disabled-rule", "zero-hits-rule"]).describe("Type of insight").optional() }).optional() }).describe("The JSON request body.") },
|
|
3070
|
+
ShowSuggestions: { domain: z.string().optional(), domains_to_process: z.enum(["ALL_DOMAINS_ON_THIS_SERVER", "CURRENT_DOMAIN"]).optional(), "requestBody": z.object({ "layer": z.string().uuid().regex(new RegExp("^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$")).describe("Access layer identifier in UUID format").optional(), "options": z.object({ "include-inline-layers": z.boolean().describe("Whether to include insights on inline layers").optional() }).optional(), "limit": z.number().describe("Maximum number of items to return").optional(), "offset": z.number().describe("Number of items to skip for pagination").optional(), "filters": z.object({ "states": z.array(z.enum(["ACCEPTED", "REJECTED"]).describe("State of a suggestion - either ACCEPTED or REJECTED")).describe("Array of insight state values").optional(), "user-interaction": z.object({ "operator": z.enum(["NOT-IN", "IN"]).describe("Operator for filtering by user-interaction-types").optional(), "types": z.array(z.literal("DECIDE_LATER").describe("Type of user interaction with an insight")).describe("Array of user interaction type values") }).optional(), "security-impact": z.enum(["HIGH", "MEDIUM_AND_ABOVE", "LOW_AND_ABOVE"]).describe("Minimum security impact threshold to include").optional(), "confidence-level": z.enum(["HIGH", "MEDIUM_AND_ABOVE", "LOW_AND_ABOVE"]).describe("Minimum confidence threshold to include").optional(), "default-filter": z.literal("NONE").describe("Ignore default filtering of the system").optional(), "uids": z.array(z.string().uuid().regex(new RegExp("^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$")).describe("Stringified UUID.")).describe("Array of insight unique identifiers").optional(), "rules-uids": z.array(z.string().uuid().regex(new RegExp("^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$")).describe("Stringified UUID.")).describe("Array of rule unique identifiers").optional(), "types": z.array(z.enum(["unused-objects", "tighten-rule", "delete-disabled-rule", "zero-hits-rule"]).describe("Type of insight")).describe("Type of insight").optional() }).optional() }).describe("Parameters for showing suggestions with enhanced v3.0 capabilities") },
|
|
3071
|
+
ShowSuggestionsInfo: { domain: z.string().optional(), domains_to_process: z.enum(["ALL_DOMAINS_ON_THIS_SERVER", "CURRENT_DOMAIN"]).optional(), "requestBody": z.object({ "layer": z.string().uuid().regex(new RegExp("^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$")).describe("Access layer identifier in UUID format") }).describe("The JSON request body.") },
|
|
3072
|
+
ShowSuggestionsSummary: { domain: z.string().optional(), domains_to_process: z.enum(["ALL_DOMAINS_ON_THIS_SERVER", "CURRENT_DOMAIN"]).optional(), "requestBody": z.object({ "layer": z.string().uuid().regex(new RegExp("^[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$")).describe("Access layer identifier in UUID format").optional(), "filters": z.object({ "states": z.array(z.enum(["ACCEPTED", "REJECTED"]).describe("State of a suggestion - either ACCEPTED or REJECTED")).describe("Array of insight state values").optional(), "user-interaction": z.object({ "operator": z.enum(["NOT-IN", "IN"]).describe("Operator for filtering by user-interaction-types").optional(), "types": z.array(z.literal("DECIDE_LATER").describe("Type of user interaction with an insight")).describe("Array of user interaction type values") }).optional(), "security-impact": z.enum(["HIGH", "MEDIUM_AND_ABOVE", "LOW_AND_ABOVE"]).describe("Minimum security impact threshold to include").optional(), "confidence-level": z.enum(["HIGH", "MEDIUM_AND_ABOVE", "LOW_AND_ABOVE"]).describe("Minimum confidence threshold to include").optional(), "default-filter": z.literal("NONE").describe("Ignore default filtering of the system").optional() }).optional() }).describe("Parameters for showing suggestions summary") },
|
|
3073
|
+
ShowPolicyInsightsStatus: { domain: z.string().optional(), domains_to_process: z.enum(["ALL_DOMAINS_ON_THIS_SERVER", "CURRENT_DOMAIN"]).optional() }
|
|
3074
|
+
};
|
|
3075
|
+
|
|
3076
|
+
// src/serverInfo.ts
|
|
3077
|
+
function getServerInfo() {
|
|
3078
|
+
return {
|
|
3079
|
+
description: '"Policy Insights analyzes Access Control policies and network traffic to identify opportunities for optimization. It examines traffic patterns and policy configurations, and suggests modifications to improve your security posture.\\\\n\\\\n## Key Benefits\\\\n- Reduces attack surface by making rules more restrictive and eliminating unnecessary traffic permissions\\\\n- Simplifies access control policies for easier management and auditing. Policy Insights automatically generates intelligent insights to streamline network security. It helps narrow down allowed traffic, remove unused objects and rules, and reduce potential threats, simplifying policy management."',
|
|
3080
|
+
websiteUrl: "https://support.checkpoint.com/results/sk/sk183313"
|
|
3081
|
+
};
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
// src/index.ts
|
|
3085
|
+
var { server, pkg } = createMcpServer(import.meta.url, getServerInfo());
|
|
3086
|
+
var SERVER_PACKAGE_NAME = pkg["name"];
|
|
3087
|
+
var serverModule = createServerModule(server, Settings, pkg, APIManagerForAPIKey);
|
|
3088
|
+
var runApi = createApiRunner(serverModule);
|
|
3089
|
+
server.tool(
|
|
3090
|
+
`${SERVER_PACKAGE_NAME.split("/").pop().replace(/-mcp$/, "")}__init`,
|
|
3091
|
+
"Verify, login and initialize management connection. Use this tool on your first interaction with the server.",
|
|
3092
|
+
z2.object({}).strict(),
|
|
3093
|
+
async (args, extra) => {
|
|
3094
|
+
try {
|
|
3095
|
+
const apiManager = SessionContext.getAPIManager(serverModule, extra);
|
|
3096
|
+
const isMds = await apiManager.isMds();
|
|
3097
|
+
if (!isMds) {
|
|
3098
|
+
return {
|
|
3099
|
+
content: [
|
|
3100
|
+
{
|
|
3101
|
+
type: "text",
|
|
3102
|
+
text: `${SERVER_PACKAGE_NAME} server is up and running. The environment is NOT part of Multi Domain system, there is no need to use domain parameters in tool calls.`
|
|
3103
|
+
}
|
|
3104
|
+
]
|
|
3105
|
+
};
|
|
3106
|
+
} else {
|
|
3107
|
+
const domains = await apiManager.getDomains();
|
|
3108
|
+
const domainList = domains.map((domain) => `${domain.name} (${domain.type})`).join(", ");
|
|
3109
|
+
return {
|
|
3110
|
+
content: [
|
|
3111
|
+
{
|
|
3112
|
+
type: "text",
|
|
3113
|
+
text: `${SERVER_PACKAGE_NAME} server is up and running. The environment is part of Multi Domain system. You need to use the domain parameter for calling APIs, if you are not sure which to use, ask the user. The domains in the system are: ${domainList}`
|
|
3114
|
+
}
|
|
3115
|
+
]
|
|
3116
|
+
};
|
|
3117
|
+
}
|
|
3118
|
+
} catch (error) {
|
|
3119
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3120
|
+
return {
|
|
3121
|
+
content: [
|
|
3122
|
+
{
|
|
3123
|
+
type: "text",
|
|
3124
|
+
text: `Error initializing ${SERVER_PACKAGE_NAME} connection: ${errorMessage}`
|
|
3125
|
+
}
|
|
3126
|
+
]
|
|
3127
|
+
};
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
);
|
|
3131
|
+
for (const toolDef of toolDefinitionMap) {
|
|
3132
|
+
const toolName = toolDef.name;
|
|
3133
|
+
if (!toolName) {
|
|
3134
|
+
console.error("\u274C Tool definition missing name:", toolDef);
|
|
3135
|
+
continue;
|
|
3136
|
+
}
|
|
3137
|
+
server.tool(
|
|
3138
|
+
toolName,
|
|
3139
|
+
toolDef.description,
|
|
3140
|
+
zodSchemas[toolName],
|
|
3141
|
+
async (args, extra) => {
|
|
3142
|
+
return await executeApiTool(toolName, toolDef, args, extra);
|
|
3143
|
+
}
|
|
3144
|
+
);
|
|
3145
|
+
}
|
|
3146
|
+
async function executeApiTool(toolName, definition, validatedArgs, extra) {
|
|
3147
|
+
try {
|
|
3148
|
+
const urlPath = definition.pathTemplate;
|
|
3149
|
+
console.error(`=== Executing tool "${toolName}" ===`);
|
|
3150
|
+
console.error(`URL Path: ${urlPath}`);
|
|
3151
|
+
console.error(`Method: ${definition.method}`);
|
|
3152
|
+
console.error(`Raw args:`, JSON.stringify(validatedArgs, null, 2));
|
|
3153
|
+
console.error(`RequestBody:`, JSON.stringify(validatedArgs?.["requestBody"], null, 2));
|
|
3154
|
+
console.error(`Extra context:`, JSON.stringify(extra, null, 2));
|
|
3155
|
+
console.error(`Definition:`, JSON.stringify(definition, null, 2));
|
|
3156
|
+
let domain = void 0;
|
|
3157
|
+
if (validatedArgs.domain) {
|
|
3158
|
+
domain = typeof validatedArgs.domain === "string" && validatedArgs.domain.trim() !== "" ? validatedArgs.domain : void 0;
|
|
3159
|
+
console.error(`Sending request to domain:`, JSON.stringify(domain, null, 2));
|
|
3160
|
+
}
|
|
3161
|
+
const requestBody = validatedArgs?.["requestBody"] || {};
|
|
3162
|
+
if (validatedArgs.domains_to_process) {
|
|
3163
|
+
requestBody["domains-to-process"] = typeof validatedArgs.domain === "string" && validatedArgs.domain.trim() !== "" ? validatedArgs.domain : void 0;
|
|
3164
|
+
}
|
|
3165
|
+
const resp = await runApi("POST", urlPath, requestBody, extra, domain);
|
|
3166
|
+
console.error(`=== DEBUG: Response received ===`);
|
|
3167
|
+
console.error(`Response:`, JSON.stringify(resp, null, 2));
|
|
3168
|
+
return { content: [{ type: "text", text: JSON.stringify(resp, null, 2) }] };
|
|
3169
|
+
} catch (error) {
|
|
3170
|
+
console.error(`=== DEBUG: Error in executeApiTool ===`);
|
|
3171
|
+
console.error(`Error type:`, typeof error);
|
|
3172
|
+
console.error(`Error:`, error);
|
|
3173
|
+
console.error(`Error stack:`, error instanceof Error ? error.stack : "No stack trace");
|
|
3174
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3175
|
+
return {
|
|
3176
|
+
content: [{ type: "text", text: `Error executing tool '${toolName}': ${errorMessage}` }]
|
|
3177
|
+
};
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
async function main() {
|
|
3181
|
+
await launchMCPServer(
|
|
3182
|
+
join3(dirname2(fileURLToPath2(import.meta.url)), "server-config.json"),
|
|
3183
|
+
serverModule
|
|
3184
|
+
);
|
|
3185
|
+
}
|
|
3186
|
+
main().catch((error) => {
|
|
3187
|
+
console.error("Fatal error in main():", error);
|
|
3188
|
+
process.exit(1);
|
|
3189
|
+
});
|
|
3190
|
+
export {
|
|
3191
|
+
server
|
|
3192
|
+
};
|