@chkp/documentation-mcp 0.1.4 → 0.1.6

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/dist/index.js CHANGED
@@ -1,52 +1,1483 @@
1
1
  #!/usr/bin/env node
2
- import { z } from 'zod';
3
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
- import { launchMCPServer, createServerModule, createApiRunner, } from '@chkp/mcp-utils';
5
- import { readFileSync } from 'fs';
6
- import { join, dirname } from 'path';
7
- import { fileURLToPath } from 'url';
8
- import { DocumentationToolAPIManager } from './documentation-api-manager.js';
9
- import { DocumentationToolSettings } from './settings.js';
10
- const pkg = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '../package.json'), 'utf-8'));
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 } 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 URL(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 URL(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 } from "zod";
365
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
366
+
367
+ // ../mcp-utils/dist/launcher.js
368
+ import { Command } from "commander";
369
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
370
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
371
+ import fs from "fs";
372
+ import http from "http";
373
+ import { randomUUID } from "crypto";
374
+ async function launchMCPServer(configPath, serverModule2) {
375
+ const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
376
+ const program = new Command();
377
+ if (config.description) {
378
+ program.description(config.description);
379
+ }
380
+ config.options.forEach((option) => {
381
+ const envValue = option.env ? process.env[option.env] : void 0;
382
+ const defaultValue = option.default || envValue;
383
+ if (option.type === "boolean") {
384
+ const boolDefault = envValue === "true" || option.default === "true";
385
+ program.option(option.flag, option.description, boolDefault);
386
+ } else {
387
+ program.option(option.flag, option.description, defaultValue);
388
+ }
389
+ });
390
+ const transportTypeDefault = process.env.MCP_TRANSPORT_TYPE || "stdio";
391
+ program.option("--transport <type>", "Transport type (stdio or http)", transportTypeDefault);
392
+ const transportPortDefault = process.env.MCP_TRANSPORT_PORT || "3000";
393
+ program.option("--transport-port <number>", "Port for network transports (e.g., HTTP)", transportPortDefault);
394
+ const debugDefault = process.env.DEBUG === "true" || false;
395
+ program.option("--debug", "Enable debug mode", debugDefault);
396
+ program.parse(process.argv);
397
+ const options = program.opts();
398
+ if (!serverModule2.settingsManager) {
399
+ throw new Error("ServerModule must have a settingsManager. Create it with createServerModule.");
400
+ }
401
+ const settings = serverModule2.settingsManager.createFromArgs(options);
402
+ const transportType = (options.transport || process.env.MCP_TRANSPORT_TYPE || "stdio").toLowerCase() === "http" ? "http" : "stdio";
403
+ const transportPort = options.transportPort ? parseInt(options.transportPort, 10) : process.env.MCP_TRANSPORT_PORT ? parseInt(process.env.MCP_TRANSPORT_PORT, 10) : 3e3;
404
+ if (transportType === "http") {
405
+ await launchHTTPServer(config, serverModule2, transportPort);
406
+ } else {
407
+ const transport = new StdioServerTransport();
408
+ const defaultSessionId = "default";
409
+ const sessionMetadata = {
410
+ type: "stdio",
411
+ startedAt: /* @__PURE__ */ new Date()
412
+ };
413
+ serverModule2.sessionManager.createSession(defaultSessionId, sessionMetadata);
414
+ transport.extraContext = () => {
415
+ return {
416
+ sessionId: defaultSessionId,
417
+ transport
418
+ };
419
+ };
420
+ await serverModule2.server.connect(transport);
421
+ console.error(`${config.name} running on stdio transport. Version: ${serverModule2.pkg.version}`);
422
+ console.error(`Transport type: stdio`);
423
+ }
424
+ }
425
+ async function launchHTTPServer(config, serverModule2, port) {
426
+ const transports = {};
427
+ const server2 = http.createServer(async (req, res) => {
428
+ if (req.url === "/" || req.url === "/mcp") {
429
+ const sessionId = req.headers["mcp-session-id"];
430
+ if (req.method === "POST") {
431
+ const chunks = [];
432
+ try {
433
+ for await (const chunk of req) {
434
+ chunks.push(Buffer.from(chunk));
435
+ }
436
+ const bodyBuffer = Buffer.concat(chunks);
437
+ let body;
438
+ try {
439
+ const bodyText = bodyBuffer.toString("utf8");
440
+ if (bodyText) {
441
+ body = JSON.parse(bodyText);
442
+ }
443
+ } catch (err) {
444
+ console.error("Error parsing request body:", err);
445
+ }
446
+ let transport;
447
+ if (sessionId && transports[sessionId]) {
448
+ transport = transports[sessionId];
449
+ if (!serverModule2.settingsManager) {
450
+ throw new Error("ServerModule must have a settingsManager. Create it with createServerModule.");
451
+ }
452
+ serverModule2.settingsManager.createFromHeaders(headersToEnvVars(req.headers, config), sessionId);
453
+ } else if (!sessionId && body && body.method === "initialize") {
454
+ transport = new StreamableHTTPServerTransport({
455
+ sessionIdGenerator: () => randomUUID(),
456
+ onsessioninitialized: (sid) => {
457
+ transports[sid] = transport;
458
+ const headers = headersToEnvVars(req.headers, config);
459
+ const metadata = {
460
+ userAgent: req.headers["user-agent"],
461
+ origin: req.headers.origin || req.headers.referer,
462
+ remoteAddress: req.socket.remoteAddress,
463
+ initialPath: req.url
464
+ };
465
+ serverModule2.sessionManager.createSession(sid, metadata);
466
+ serverModule2.settingsManager.createFromHeaders(headers, sid);
467
+ }
468
+ });
469
+ transport.onclose = () => {
470
+ const sid = transport.sessionId;
471
+ if (sid) {
472
+ delete transports[sid];
473
+ serverModule2.settingsManager.clearSession(sid);
474
+ serverModule2.apiManagerFactory.clearSession(sid);
475
+ serverModule2.sessionManager.removeSession(sid);
476
+ }
477
+ };
478
+ if (!serverModule2.settingsManager) {
479
+ throw new Error("ServerModule must have a settingsManager. Create it with createServerModule.");
480
+ }
481
+ transport.extraContext = (msg) => {
482
+ const sessionId2 = transport.sessionId;
483
+ return {
484
+ sessionId: sessionId2,
485
+ transport
486
+ };
487
+ };
488
+ await serverModule2.server.connect(transport).catch((error) => {
489
+ console.error("Error connecting to HTTP transport:", error);
490
+ });
491
+ } else {
492
+ res.writeHead(400, { "Content-Type": "application/json" });
493
+ res.end(JSON.stringify({
494
+ jsonrpc: "2.0",
495
+ error: {
496
+ code: -32e3,
497
+ message: "Bad Request: No valid session ID provided"
498
+ },
499
+ id: null
500
+ }));
501
+ return;
502
+ }
503
+ await transport.handleRequest(req, res, body);
504
+ } catch (error) {
505
+ console.error("Error handling POST request:", error);
506
+ res.writeHead(500, { "Content-Type": "application/json" });
507
+ res.end(JSON.stringify({
508
+ jsonrpc: "2.0",
509
+ error: {
510
+ code: -32e3,
511
+ message: "Internal server error: " + error.message
512
+ },
513
+ id: null
514
+ }));
515
+ }
516
+ } else if (req.method === "GET") {
517
+ if (!sessionId || !transports[sessionId]) {
518
+ res.writeHead(400, { "Content-Type": "text/plain" });
519
+ res.end("Invalid or missing session ID");
520
+ return;
521
+ }
522
+ const transport = transports[sessionId];
523
+ await transport.handleRequest(req, res);
524
+ } else if (req.method === "DELETE") {
525
+ if (!sessionId || !transports[sessionId]) {
526
+ res.writeHead(400, { "Content-Type": "text/plain" });
527
+ res.end("Invalid or missing session ID");
528
+ return;
529
+ }
530
+ const transport = transports[sessionId];
531
+ await transport.handleRequest(req, res);
532
+ } else {
533
+ res.writeHead(405, { "Content-Type": "text/plain", "Allow": "GET, POST, DELETE" });
534
+ res.end("Method not allowed");
535
+ }
536
+ } else if (req.url === "/health" || req.url === "/status") {
537
+ res.writeHead(200, { "Content-Type": "application/json" });
538
+ const sessionCount = serverModule2.sessionManager.getSessionCount();
539
+ const sessions = serverModule2.sessionManager.getAllSessions().map((session) => ({
540
+ id: session.sessionId,
541
+ createdAt: session.createdAt,
542
+ lastActive: session.lastActive
543
+ // Don't include potentially sensitive metadata
544
+ }));
545
+ res.end(JSON.stringify({
546
+ status: "ok",
547
+ server: config.name,
548
+ version: serverModule2.pkg.version,
549
+ activeSessions: sessionCount,
550
+ sessions
551
+ }));
552
+ } else {
553
+ res.writeHead(404, { "Content-Type": "text/plain" });
554
+ res.end("Not found");
555
+ }
556
+ });
557
+ server2.listen(port, () => {
558
+ console.error(`${config.name} running on HTTP transport at http://localhost:${port}. Version: ${serverModule2.pkg.version}`);
559
+ console.error(`Transport type: HTTP, Transport-port: ${port}`);
560
+ });
561
+ server2.on("error", (err) => {
562
+ console.error(`Server error: ${err.message}`);
563
+ });
564
+ }
565
+ function headersToEnvVars(headers, config) {
566
+ const result = {};
567
+ for (const [name, value] of Object.entries(headers)) {
568
+ if (value !== void 0) {
569
+ const envName = name.toUpperCase().replace(/-/g, "_");
570
+ result[envName] = value;
571
+ }
572
+ }
573
+ if (config && config.options) {
574
+ const headerToEnvMap = {};
575
+ for (const option of config.options) {
576
+ if (option.env) {
577
+ const flagName = option.flag.split(" ")[0].replace(/^--?/, "").replace(/-/g, "_");
578
+ headerToEnvMap[flagName.toLowerCase()] = option.env;
579
+ headerToEnvMap[option.env.toLowerCase()] = option.env;
580
+ }
581
+ }
582
+ for (const [headerName, headerValue] of Object.entries(headers)) {
583
+ if (headerValue !== void 0) {
584
+ const normalizedHeaderName = headerName.toLowerCase().replace(/-/g, "_");
585
+ const envVarName = headerToEnvMap[normalizedHeaderName];
586
+ if (envVarName) {
587
+ result[envVarName] = headerValue;
588
+ }
589
+ }
590
+ }
591
+ }
592
+ return result;
593
+ }
594
+
595
+ // ../mcp-utils/dist/settings-manager.js
596
+ var SettingsManager = class _SettingsManager {
597
+ /**
598
+ * Creates a new SettingsManager
599
+ * @param settingsClass The Settings class to use for creating settings instances
600
+ */
601
+ constructor(settingsClass) {
602
+ this.settingsMap = /* @__PURE__ */ new Map();
603
+ this.defaultSessionId = "default";
604
+ this.settingsClass = settingsClass;
605
+ }
606
+ /**
607
+ * Get settings for a specific session
608
+ * @param sessionId The session ID (defaults to 'default' for stdio mode)
609
+ * @returns Settings instance for the session
610
+ */
611
+ getSettings(sessionId) {
612
+ const sid = sessionId || this.defaultSessionId;
613
+ if (!this.settingsMap.has(sid)) {
614
+ this.settingsMap.set(sid, new this.settingsClass());
615
+ }
616
+ return this.settingsMap.get(sid);
617
+ }
618
+ /**
619
+ * Set settings for a specific session
620
+ * @param settings The settings object to set
621
+ * @param sessionId The session ID (defaults to 'default' for stdio mode)
622
+ */
623
+ setSettings(settings, sessionId) {
624
+ const sid = sessionId || this.defaultSessionId;
625
+ this.settingsMap.set(sid, settings);
626
+ }
627
+ /**
628
+ * Injects debug settings from source into settings object
629
+ * @param settings The settings object to update
630
+ * @param source Source object containing debug information
631
+ * @private
632
+ */
633
+ injectDebug(settings, source) {
634
+ const debug = source?.debug ?? _SettingsManager.globalDebugState ?? process.env.DEBUG;
635
+ if (typeof debug !== "undefined") {
636
+ if (source?.debug !== void 0) {
637
+ _SettingsManager.globalDebugState = source.debug;
638
+ }
639
+ if (typeof settings.set === "function") {
640
+ settings.set("debug", debug);
641
+ } else {
642
+ settings.debug = debug;
643
+ }
644
+ if (debug) {
645
+ console.error("Debug enabled. Source object contents:");
646
+ console.error(JSON.stringify(source, null, 2));
647
+ }
648
+ }
649
+ }
650
+ /**
651
+ * Print settings object for debugging by dynamically discovering its properties
652
+ * @param settings The settings object to print
653
+ * @private
654
+ */
655
+ printSettingsDebug(settings) {
656
+ if (typeof settings.get === "function") {
657
+ console.error("Settings (using get method):");
658
+ if (settings.data && typeof settings.data === "object") {
659
+ Object.entries(settings.data).forEach(([key, value]) => {
660
+ console.error(` ${key}: ${JSON.stringify(value)}`);
661
+ });
662
+ } else {
663
+ console.error(" Unable to enumerate settings properties - no accessible data structure");
664
+ }
665
+ } else {
666
+ console.error("Settings (plain object):");
667
+ Object.entries(settings).forEach(([key, value]) => {
668
+ console.error(` ${key}: ${JSON.stringify(value)}`);
669
+ });
670
+ }
671
+ }
672
+ /**
673
+ * Create settings from command-line arguments
674
+ * @param args Command line arguments
675
+ * @param sessionId Optional session ID
676
+ * @returns Settings instance
677
+ */
678
+ createFromArgs(args, sessionId) {
679
+ const settings = this.settingsClass.fromArgs(args);
680
+ this.injectDebug(settings, args);
681
+ this.setSettings(settings, sessionId);
682
+ return settings;
683
+ }
684
+ /**
685
+ * Create settings from HTTP headers
686
+ * @param headers HTTP headers
687
+ * @param sessionId Optional session ID
688
+ * @returns Settings instance
689
+ */
690
+ createFromHeaders(headers, sessionId) {
691
+ if (_SettingsManager.globalDebugState) {
692
+ console.error("=== createFromHeaders Debug Info ===");
693
+ console.error("Incoming headers:");
694
+ console.error(JSON.stringify(headers, null, 2));
695
+ }
696
+ const normalizedHeaders = {};
697
+ for (const [key, value] of Object.entries(headers)) {
698
+ const normalizedKey = key.includes("_") ? key.replace(/_/g, "-") : key;
699
+ normalizedHeaders[normalizedKey] = value;
700
+ }
701
+ if (_SettingsManager.globalDebugState) {
702
+ console.error("Normalized headers:");
703
+ console.error(JSON.stringify(normalizedHeaders, null, 2));
704
+ }
705
+ const debugHeader = normalizedHeaders["debug"] || normalizedHeaders["Debug"] || normalizedHeaders["DEBUG"];
706
+ const debugSource = { debug: debugHeader !== void 0 ? debugHeader : _SettingsManager.globalDebugState };
707
+ const settings = this.settingsClass.fromHeaders(normalizedHeaders);
708
+ this.injectDebug(settings, debugSource);
709
+ if (_SettingsManager.globalDebugState) {
710
+ console.error("Final settings object:");
711
+ this.printSettingsDebug(settings);
712
+ console.error("=== End createFromHeaders Debug Info ===");
713
+ }
714
+ this.setSettings(settings, sessionId);
715
+ return settings;
716
+ }
717
+ /**
718
+ * Clear settings for a session
719
+ * @param sessionId The session ID to clear
720
+ */
721
+ clearSession(sessionId) {
722
+ if (sessionId !== this.defaultSessionId) {
723
+ this.settingsMap.delete(sessionId);
724
+ }
725
+ }
726
+ };
727
+ SettingsManager.globalDebugState = void 0;
728
+
729
+ // ../mcp-utils/dist/api-manager-factory.js
730
+ var APIManagerFactory = class {
731
+ /**
732
+ * Creates a new APIManagerFactory
733
+ * @param apiManagerClass The API Manager class to use for creating instances
734
+ * @param settingsManager The settings manager to get settings from
735
+ */
736
+ constructor(apiManagerClass, settingsManager) {
737
+ this.apiManagerMap = /* @__PURE__ */ new Map();
738
+ this.defaultSessionId = "default";
739
+ this.apiManagerClass = apiManagerClass;
740
+ this.settingsManager = settingsManager;
741
+ }
742
+ /**
743
+ * Get or create an API manager for a specific session
744
+ * @param sessionId The session ID (defaults to 'default' for stdio mode)
745
+ * @returns API Manager instance for the session
746
+ */
747
+ getAPIManager(sessionId) {
748
+ const sid = sessionId || this.defaultSessionId;
749
+ if (!this.apiManagerMap.has(sid)) {
750
+ const settings2 = this.settingsManager.getSettings(sid);
751
+ const apiManager2 = this.createAPIManagerFromSettings(settings2);
752
+ this.apiManagerMap.set(sid, apiManager2);
753
+ }
754
+ const apiManager = this.apiManagerMap.get(sid);
755
+ const settings = this.settingsManager.getSettings(sid);
756
+ if (settings && typeof settings.debug !== "undefined") {
757
+ apiManager.debug = !!settings.debug;
758
+ }
759
+ return apiManager;
760
+ }
761
+ /**
762
+ * Create an API manager from settings
763
+ * @param settings Settings instance
764
+ * @returns API Manager instance
765
+ */
766
+ createAPIManagerFromSettings(settings) {
767
+ return this.apiManagerClass.create(settings);
768
+ }
769
+ /**
770
+ * Clear API manager for a session
771
+ * @param sessionId The session ID to clear
772
+ */
773
+ clearSession(sessionId) {
774
+ if (sessionId !== this.defaultSessionId) {
775
+ this.apiManagerMap.delete(sessionId);
776
+ }
777
+ }
778
+ };
779
+
780
+ // ../mcp-utils/dist/session-context.js
781
+ var _a;
782
+ var SessionContext = class {
783
+ /**
784
+ * Start automatic cleanup timer
785
+ */
786
+ static startCleanupTimer() {
787
+ if (this.cleanupTimer)
788
+ return;
789
+ this.cleanupTimer = setInterval(() => {
790
+ this.cleanupExpiredSessions();
791
+ }, this.CLEANUP_INTERVAL_MS);
792
+ if (this.cleanupTimer.unref) {
793
+ this.cleanupTimer.unref();
794
+ }
795
+ }
796
+ /**
797
+ * Clean up expired sessions
798
+ */
799
+ static cleanupExpiredSessions() {
800
+ const now = Date.now();
801
+ const expiredSessions = [];
802
+ for (const [sessionId, sessionInfo] of this.sessionData.entries()) {
803
+ if (sessionId === this.DEFAULT_SESSION_ID)
804
+ continue;
805
+ if (now - sessionInfo.lastAccessed > this.SESSION_TIMEOUT_MS) {
806
+ expiredSessions.push(sessionId);
807
+ }
808
+ }
809
+ expiredSessions.forEach((sessionId) => {
810
+ this.sessionData.delete(sessionId);
811
+ });
812
+ if (this.sessionData.size > this.MAX_SESSIONS) {
813
+ const sessions = Array.from(this.sessionData.entries()).filter(([sessionId]) => sessionId !== this.DEFAULT_SESSION_ID).sort(([, a], [, b]) => a.lastAccessed - b.lastAccessed);
814
+ const toRemove = sessions.slice(0, sessions.length - this.MAX_SESSIONS + 1);
815
+ toRemove.forEach(([sessionId]) => {
816
+ this.sessionData.delete(sessionId);
817
+ });
818
+ }
819
+ }
820
+ /**
821
+ * Get the current session ID from the MCP extra context
822
+ * @param extra Extra context passed to MCP tool callbacks
823
+ * @returns The session ID or DEFAULT_SESSION_ID if not available
824
+ */
825
+ static getSessionId(extra) {
826
+ if (!extra)
827
+ return this.DEFAULT_SESSION_ID;
828
+ if (extra.transport && extra.transport.sessionId) {
829
+ return extra.transport.sessionId;
830
+ }
831
+ if (extra.sessionId) {
832
+ return extra.sessionId;
833
+ }
834
+ return this.DEFAULT_SESSION_ID;
835
+ }
836
+ /**
837
+ * Get settings for the current session
838
+ * @param serverModule ServerModule with settingsManager
839
+ * @param extra Extra context passed to MCP tool callbacks
840
+ * @returns Settings for the current session
841
+ */
842
+ static getSettings(serverModule2, extra) {
843
+ const sessionId = this.getSessionId(extra);
844
+ if (!serverModule2.settingsManager) {
845
+ throw new Error("ServerModule does not have a settingsManager. Create it with createServerModule.");
846
+ }
847
+ return serverModule2.settingsManager.getSettings(sessionId);
848
+ }
849
+ /**
850
+ * Get API manager for the current session
851
+ * @param serverModule ServerModule with apiManagerFactory
852
+ * @param extra Extra context passed to MCP tool callbacks
853
+ * @returns API manager for the current session
854
+ */
855
+ static getAPIManager(serverModule2, extra) {
856
+ const sessionId = this.getSessionId(extra);
857
+ if (!serverModule2.apiManagerFactory) {
858
+ throw new Error("ServerModule does not have an apiManagerFactory. Create it with createServerModule.");
859
+ }
860
+ return serverModule2.apiManagerFactory.getAPIManager(sessionId);
861
+ }
862
+ /**
863
+ * Set session data for the current session
864
+ * @param key The key to store the data under
865
+ * @param value The value to store
866
+ * @param extra Extra context with session information
867
+ */
868
+ static setData(key, value, extra) {
869
+ const sessionId = this.getSessionId(extra);
870
+ const now = Date.now();
871
+ if (!this.sessionData.has(sessionId)) {
872
+ this.sessionData.set(sessionId, {
873
+ data: /* @__PURE__ */ new Map(),
874
+ lastAccessed: now,
875
+ createdAt: now
876
+ });
877
+ }
878
+ const sessionInfo = this.sessionData.get(sessionId);
879
+ sessionInfo.lastAccessed = now;
880
+ sessionInfo.data.set(key, value);
881
+ }
882
+ /**
883
+ * Get session data for the current session
884
+ * @param key The key to retrieve data for
885
+ * @param extra Extra context with session information
886
+ * @returns The stored data or undefined if not found
887
+ */
888
+ static getData(key, extra) {
889
+ const sessionId = this.getSessionId(extra);
890
+ if (!this.sessionData.has(sessionId)) {
891
+ return void 0;
892
+ }
893
+ const sessionInfo = this.sessionData.get(sessionId);
894
+ sessionInfo.lastAccessed = Date.now();
895
+ return sessionInfo.data.get(key);
896
+ }
897
+ /**
898
+ * Clear session data for a specific session
899
+ * @param sessionId The session ID to clear
900
+ */
901
+ static clearSessionData(sessionId) {
902
+ this.sessionData.delete(sessionId);
903
+ }
904
+ /**
905
+ * Get session statistics (for monitoring)
906
+ */
907
+ static getSessionStats() {
908
+ const now = Date.now();
909
+ let oldestAccess = null;
910
+ for (const [, sessionInfo] of this.sessionData.entries()) {
911
+ if (oldestAccess === null || sessionInfo.lastAccessed < oldestAccess) {
912
+ oldestAccess = sessionInfo.lastAccessed;
913
+ }
914
+ }
915
+ return {
916
+ totalSessions: this.sessionData.size,
917
+ memoryUsage: this.sessionData.size * 1e3,
918
+ // Rough estimate
919
+ oldestSession: oldestAccess ? now - oldestAccess : null
920
+ };
921
+ }
922
+ /**
923
+ * Get or prompt for user interactive data with automatic caching and expiration
924
+ * @param options Configuration for the interactive data request
925
+ * @param extra Extra context with session information
926
+ * @returns Promise that resolves to the user data (either from cache or fresh prompt)
927
+ */
928
+ static async getOrPromptUserData(options, extra) {
929
+ const sessionId = this.getSessionId(extra);
930
+ const now = Date.now();
931
+ const expirationMs = (options.expirationMinutes || 30) * 60 * 1e3;
932
+ const cachedData = this.getData(options.cacheKey, extra);
933
+ if (cachedData && cachedData.expiresAt && now < cachedData.expiresAt) {
934
+ const refreshedData = {
935
+ ...cachedData,
936
+ expiresAt: now + expirationMs,
937
+ lastUsed: now
938
+ };
939
+ this.setData(options.cacheKey, refreshedData, extra);
940
+ let dataToReturn2 = cachedData.data;
941
+ if (options.fieldsToShow) {
942
+ dataToReturn2 = {};
943
+ for (const field of options.fieldsToShow) {
944
+ if (cachedData.data[field] !== void 0) {
945
+ dataToReturn2[field] = cachedData.data[field];
946
+ }
947
+ }
948
+ }
949
+ console.error(`Using cached user data for session: ${sessionId}, key: ${options.cacheKey}`);
950
+ return { cancelled: false, data: dataToReturn2 };
951
+ }
952
+ console.error(`Prompting user for data for session: ${sessionId}, key: ${options.cacheKey}`);
953
+ let result;
954
+ if (options.showLoginDialog) {
955
+ const { showLoginDialog: showLoginDialog2 } = await Promise.resolve().then(() => (init_ui_dialog(), ui_dialog_exports));
956
+ result = await showLoginDialog2(options.dialogTitle, options.dialogMessage);
957
+ } else {
958
+ const { showDialog: showDialog2 } = await Promise.resolve().then(() => (init_ui_dialog(), ui_dialog_exports));
959
+ const defaultFields = [
960
+ {
961
+ name: "message",
962
+ label: "Message",
963
+ type: "text",
964
+ placeholder: "Enter your message here...",
965
+ required: true
966
+ }
967
+ ];
968
+ result = await showDialog2({
969
+ title: options.dialogTitle || "Input Required",
970
+ message: options.dialogMessage,
971
+ fields: options.customFields || defaultFields
972
+ });
973
+ }
974
+ if (result.cancelled) {
975
+ return result;
976
+ }
977
+ const cachedEntry = {
978
+ data: result.data,
979
+ expiresAt: now + expirationMs,
980
+ createdAt: now,
981
+ lastUsed: now
982
+ };
983
+ this.setData(options.cacheKey, cachedEntry, extra);
984
+ let dataToReturn = result.data;
985
+ if (options.fieldsToShow) {
986
+ dataToReturn = {};
987
+ for (const field of options.fieldsToShow) {
988
+ if (result.data[field] !== void 0) {
989
+ dataToReturn[field] = result.data[field];
990
+ }
991
+ }
992
+ }
993
+ return { cancelled: false, data: dataToReturn };
994
+ }
995
+ /**
996
+ * Clear cached user data for a specific key
997
+ * @param cacheKey The cache key to clear
998
+ * @param extra Extra context with session information
999
+ */
1000
+ static clearUserData(cacheKey, extra) {
1001
+ const sessionId = this.getSessionId(extra);
1002
+ if (this.sessionData.has(sessionId)) {
1003
+ const sessionInfo = this.sessionData.get(sessionId);
1004
+ sessionInfo.data.delete(cacheKey);
1005
+ sessionInfo.lastAccessed = Date.now();
1006
+ }
1007
+ }
1008
+ /**
1009
+ * Check if user data exists and is not expired
1010
+ * @param cacheKey The cache key to check
1011
+ * @param extra Extra context with session information
1012
+ * @returns true if valid cached data exists, false otherwise
1013
+ */
1014
+ static hasValidUserData(cacheKey, extra) {
1015
+ const cachedData = this.getData(cacheKey, extra);
1016
+ if (!cachedData || !cachedData.expiresAt) {
1017
+ return false;
1018
+ }
1019
+ return Date.now() < cachedData.expiresAt;
1020
+ }
1021
+ };
1022
+ _a = SessionContext;
1023
+ SessionContext.DEFAULT_SESSION_ID = "default";
1024
+ SessionContext.sessionData = /* @__PURE__ */ new Map();
1025
+ SessionContext.SESSION_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
1026
+ SessionContext.CLEANUP_INTERVAL_MS = 60 * 60 * 1e3;
1027
+ SessionContext.MAX_SESSIONS = 1e3;
1028
+ SessionContext.cleanupTimer = null;
1029
+ (() => {
1030
+ _a.startCleanupTimer();
1031
+ })();
1032
+
1033
+ // ../mcp-utils/dist/session-manager.js
1034
+ var DEFAULT_SESSION_TIMEOUT_MS = 15 * 60 * 1e3;
1035
+ var SessionManager = class {
1036
+ constructor() {
1037
+ this.sessions = /* @__PURE__ */ new Map();
1038
+ }
1039
+ /**
1040
+ * Create a new session
1041
+ * @param sessionId The session ID
1042
+ * @param metadata Optional metadata to store with the session
1043
+ * @returns Session info
1044
+ */
1045
+ createSession(sessionId, metadata = {}) {
1046
+ const now = /* @__PURE__ */ new Date();
1047
+ const sessionInfo = {
1048
+ sessionId,
1049
+ createdAt: now,
1050
+ lastActive: now,
1051
+ ...metadata
1052
+ };
1053
+ this.sessions.set(sessionId, sessionInfo);
1054
+ return sessionInfo;
1055
+ }
1056
+ /**
1057
+ * Get info for a session
1058
+ * @param sessionId The session ID
1059
+ * @returns Session info or undefined if not found
1060
+ */
1061
+ getSession(sessionId) {
1062
+ if (this.sessions.has(sessionId)) {
1063
+ this.touchSession(sessionId);
1064
+ }
1065
+ return this.sessions.get(sessionId);
1066
+ }
1067
+ /**
1068
+ * Update session activity timestamp
1069
+ * @param sessionId The session ID
1070
+ */
1071
+ touchSession(sessionId) {
1072
+ const session = this.sessions.get(sessionId);
1073
+ if (session) {
1074
+ session.lastActive = /* @__PURE__ */ new Date();
1075
+ }
1076
+ }
1077
+ /**
1078
+ * Remove a session
1079
+ * @param sessionId The session ID
1080
+ */
1081
+ removeSession(sessionId) {
1082
+ this.sessions.delete(sessionId);
1083
+ SessionContext.clearSessionData(sessionId);
1084
+ }
1085
+ /**
1086
+ * Get all active sessions
1087
+ * @returns Array of session info objects
1088
+ */
1089
+ getAllSessions() {
1090
+ return Array.from(this.sessions.values());
1091
+ }
1092
+ /**
1093
+ * Get count of active sessions
1094
+ * @returns Number of active sessions
1095
+ */
1096
+ getSessionCount() {
1097
+ return this.sessions.size;
1098
+ }
1099
+ /**
1100
+ * Clean up inactive sessions older than the specified timeout
1101
+ * @param timeoutMs Timeout in milliseconds (default: 30 minutes)
1102
+ * @returns Number of sessions removed
1103
+ */
1104
+ cleanupInactiveSessions(timeoutMs = DEFAULT_SESSION_TIMEOUT_MS) {
1105
+ const now = /* @__PURE__ */ new Date();
1106
+ let removedCount = 0;
1107
+ for (const [sessionId, session] of this.sessions.entries()) {
1108
+ const inactiveTime = now.getTime() - session.lastActive.getTime();
1109
+ if (inactiveTime > timeoutMs) {
1110
+ this.removeSession(sessionId);
1111
+ removedCount++;
1112
+ }
1113
+ }
1114
+ return removedCount;
1115
+ }
1116
+ };
1117
+
1118
+ // ../mcp-utils/dist/server-utils.js
1119
+ function getHeaderValue(headers, key) {
1120
+ const value = headers[key] || headers[key.toUpperCase()] || headers[key.toLowerCase()];
1121
+ return typeof value === "string" ? value : Array.isArray(value) ? value[0] : void 0;
1122
+ }
1123
+ function createApiRunner(serverModule2) {
1124
+ return async (method, uri, data, extra, domain) => {
1125
+ const apiManager = SessionContext.getAPIManager(serverModule2, extra);
1126
+ return await apiManager.callApi(method, uri, data, domain);
1127
+ };
1128
+ }
1129
+ function createServerModule(server2, Settings2, pkg2, apiManagerClass) {
1130
+ const settingsManager = new SettingsManager(Settings2);
1131
+ const apiManagerFactory = new APIManagerFactory(apiManagerClass, settingsManager);
1132
+ const sessionManager = new SessionManager();
1133
+ return {
1134
+ server: server2,
1135
+ Settings: Settings2,
1136
+ settingsManager,
1137
+ apiManagerFactory,
1138
+ sessionManager,
1139
+ pkg: pkg2
1140
+ };
1141
+ }
1142
+
1143
+ // ../mcp-utils/dist/index.js
1144
+ init_ui_dialog();
1145
+
1146
+ // src/index.ts
1147
+ import { readFileSync } from "fs";
1148
+ import { join as join2, dirname } from "path";
1149
+ import { fileURLToPath } from "url";
1150
+
1151
+ // src/documentation-api-manager.ts
1152
+ import axios3 from "axios";
1153
+
1154
+ // ../infra/dist/api-client.js
1155
+ import axios from "axios";
1156
+ import https from "https";
1157
+ var TokenType;
1158
+ (function(TokenType2) {
1159
+ TokenType2["API_KEY"] = "API_KEY";
1160
+ TokenType2["CI_TOKEN"] = "CI_TOKEN";
1161
+ })(TokenType || (TokenType = {}));
1162
+
1163
+ // ../infra/dist/string-utils.js
1164
+ function nullOrEmpty(val) {
1165
+ return val === void 0 || val === null || typeof val === "string" && (val.trim() === "" || val === "undefined" || val === "null");
1166
+ }
1167
+
1168
+ // ../infra/dist/settings.js
1169
+ var Settings = class _Settings {
1170
+ 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" } = {}) {
1171
+ this.region = "EU";
1172
+ this.devPort = "8006";
1173
+ this.apiKey = apiKey;
1174
+ this.username = username;
1175
+ this.password = password;
1176
+ this.s1cUrl = s1cUrl;
1177
+ this.managementHost = managementHost;
1178
+ this.managementPort = managementPort;
1179
+ this.cloudInfraToken = cloudInfraToken;
1180
+ this.clientId = clientId;
1181
+ this.secretKey = secretKey;
1182
+ this.region = this.isValidRegion(region) ? region : "EU";
1183
+ this.devPort = devPort;
1184
+ this.validate();
1185
+ }
1186
+ /**
1187
+ * Check if the provided string is a valid region
1188
+ */
1189
+ isValidRegion(region) {
1190
+ return ["EU", "US", "STG", "LOCAL"].includes(region.toUpperCase());
1191
+ }
1192
+ /**
1193
+ * Get Cloud Infra Gateway based on region
1194
+ */
1195
+ getCloudInfraGateway() {
1196
+ switch (this.region) {
1197
+ case "EU":
1198
+ return "https://cloudinfra-gw.portal.checkpoint.com";
1199
+ case "US":
1200
+ return "https://cloudinfra-gw-us.portal.checkpoint.com";
1201
+ case "STG":
1202
+ case "LOCAL":
1203
+ return "https://dev-cloudinfra-gw.kube1.iaas.checkpoint.com";
1204
+ default:
1205
+ return "";
1206
+ }
1207
+ }
1208
+ /**
1209
+ * Validate the settings
1210
+ */
1211
+ validate() {
1212
+ if (!nullOrEmpty(this.s1cUrl) && nullOrEmpty(this.apiKey) && nullOrEmpty(this.cloudInfraToken)) {
1213
+ throw new Error("API key or CI Token is required for S1C (via --api-key or API_KEY env var)");
1214
+ }
1215
+ if (!nullOrEmpty(this.managementHost) && nullOrEmpty(this.apiKey) && (nullOrEmpty(this.username) || nullOrEmpty(this.password))) {
1216
+ throw new Error("Either API key or username/password are required for on-prem management (via CLI args or env vars)");
1217
+ }
1218
+ if (nullOrEmpty(this.s1cUrl) && nullOrEmpty(this.managementHost)) {
1219
+ }
1220
+ }
1221
+ /**
1222
+ * Create settings from command-line arguments
1223
+ */
1224
+ static fromArgs(args) {
1225
+ return new _Settings({
1226
+ apiKey: args.apiKey,
1227
+ username: args.username,
1228
+ password: args.password,
1229
+ s1cUrl: args.s1cUrl,
1230
+ managementHost: args.managementHost,
1231
+ managementPort: args.managementPort,
1232
+ cloudInfraToken: args.cloudInfraToken,
1233
+ clientId: args.clientId,
1234
+ secretKey: args.secretKey,
1235
+ region: typeof args.region === "string" ? args.region.toUpperCase() : void 0,
1236
+ devPort: args.devPort
1237
+ });
1238
+ }
1239
+ /**
1240
+ * Create settings from HTTP headers
1241
+ * Maps headers to environment variable format based on server config
1242
+ */
1243
+ static fromHeaders(headers) {
1244
+ return new _Settings({
1245
+ apiKey: getHeaderValue(headers, "API-KEY"),
1246
+ username: getHeaderValue(headers, "USERNAME"),
1247
+ password: getHeaderValue(headers, "PASSWORD"),
1248
+ s1cUrl: getHeaderValue(headers, "S1C-URL"),
1249
+ managementHost: getHeaderValue(headers, "MANAGEMENT-HOST"),
1250
+ managementPort: getHeaderValue(headers, "MANAGEMENT-PORT"),
1251
+ cloudInfraToken: getHeaderValue(headers, "CLOUD-INFRA-TOKEN"),
1252
+ clientId: getHeaderValue(headers, "CLIENT-ID"),
1253
+ secretKey: getHeaderValue(headers, "SECRET-KEY"),
1254
+ region: getHeaderValue(headers, "REGION")?.toUpperCase(),
1255
+ devPort: getHeaderValue(headers, "DEV-PORT")
1256
+ });
1257
+ }
1258
+ };
1259
+
1260
+ // ../infra/dist/external-user-token-manager.js
1261
+ import axios2 from "axios";
1262
+ var ExternalTokenManager = class _ExternalTokenManager {
1263
+ /**
1264
+ * Create a new ExternalTokenManager
1265
+ *
1266
+ * @param settings Settings containing clientId and secretKey
1267
+ */
1268
+ constructor(settings) {
1269
+ this.settings = settings;
1270
+ this.tokenCache = /* @__PURE__ */ new Map();
1271
+ }
1272
+ authUrl() {
1273
+ const gatewayUrl = this.settings.getCloudInfraGateway();
1274
+ return `${gatewayUrl}/auth/external`;
1275
+ }
1276
+ /**
1277
+ * Get a valid auth token, fetching a new one if necessary
1278
+ * @returns Promise resolving to a valid token
1279
+ */
1280
+ async getToken() {
1281
+ if (!this.settings.clientId || !this.settings.secretKey) {
1282
+ throw new Error("Client ID and Secret Key are required for external user authentication");
1283
+ }
1284
+ const cacheKey = `${this.settings.clientId}:${this.settings.region || "EU"}`;
1285
+ const cached = this.tokenCache.get(cacheKey);
1286
+ if (cached && cached.expiresAt > Date.now()) {
1287
+ return cached.token;
1288
+ }
1289
+ const response = await axios2.post(this.authUrl(), {
1290
+ clientId: this.settings.clientId,
1291
+ accessKey: this.settings.secretKey
1292
+ }, {
1293
+ timeout: 3e4,
1294
+ validateStatus: () => true
1295
+ });
1296
+ if (response.status !== 200) {
1297
+ const errorData = response.data ? JSON.stringify(response.data) : "No response data";
1298
+ throw new Error(`Failed to get auth token: ${response.statusText} (${response.status}). Response data: ${errorData}`);
1299
+ }
1300
+ const responseData = response.data;
1301
+ const token = responseData.data.token;
1302
+ const expiresIn = responseData.data.expiresIn;
1303
+ if (!token || !expiresIn) {
1304
+ throw new Error("Invalid token response from auth server");
1305
+ }
1306
+ const tokenInfo = {
1307
+ token,
1308
+ expiresAt: Date.now() + expiresIn * 1e3 - 5e3
1309
+ };
1310
+ this.tokenCache.set(cacheKey, tokenInfo);
1311
+ return token;
1312
+ }
1313
+ /**
1314
+ * Create a token service instance
1315
+ * @param settings Settings containing clientId and secretKey
1316
+ * @returns A new ExternalUserTokenManager
1317
+ * instance
1318
+ */
1319
+ static create(settings) {
1320
+ return new _ExternalTokenManager(settings);
1321
+ }
1322
+ };
1323
+ var ExternalUserTokenManager = class _ExternalUserTokenManager extends ExternalTokenManager {
1324
+ static create(settings) {
1325
+ return new _ExternalUserTokenManager(settings);
1326
+ }
1327
+ authUrl() {
1328
+ const gatewayUrl = this.settings.getCloudInfraGateway();
1329
+ return `${gatewayUrl}/auth/external/user`;
1330
+ }
1331
+ };
1332
+
1333
+ // src/documentation-api-manager.ts
1334
+ var DocumentationToolAPIManager = class _DocumentationToolAPIManager {
1335
+ constructor(settings) {
1336
+ this.settings = settings;
1337
+ this.tokenService = new ExternalUserTokenManager(settings);
1338
+ this.axios = axios3.create({
1339
+ timeout: 3e4,
1340
+ validateStatus: () => true
1341
+ });
1342
+ }
1343
+ /**
1344
+ * Create a new DocumentationToolAPIManager instance from settings for Documentation Tool
1345
+ * @param settings The complete settings object for this session
1346
+ * @returns A new DocumentationToolAPIManager instance
1347
+ */
1348
+ static create(settings) {
1349
+ return new _DocumentationToolAPIManager(settings);
1350
+ }
1351
+ /**
1352
+ * Get a valid auth token using the shared token service
1353
+ */
1354
+ async getToken() {
1355
+ return await this.tokenService.getToken();
1356
+ }
1357
+ /**
1358
+ * Get the base URL for API calls, handling local development if needed
1359
+ */
1360
+ getBaseUrl() {
1361
+ if (this.settings.region === "LOCAL") {
1362
+ return `http://localhost:${this.settings.devPort || "8006"}`;
1363
+ }
1364
+ return `${this.settings.getCloudInfraGateway()}/app/console-one`;
1365
+ }
1366
+ async callApi(method, uri, data) {
1367
+ const token = await this.getToken();
1368
+ const chatUrl = `${this.getBaseUrl()}/${uri}`;
1369
+ const question = data.question;
1370
+ const product = data.product;
1371
+ const headers = {
1372
+ Authorization: `Bearer ${token}`,
1373
+ "Content-Type": "application/json"
1374
+ };
1375
+ const params = {
1376
+ question,
1377
+ product,
1378
+ skip_llm: true
1379
+ };
1380
+ try {
1381
+ const response = await this.axios.post(chatUrl, params, {
1382
+ headers
1383
+ });
1384
+ if (response.status !== 200) {
1385
+ console.error(
1386
+ "Error response body:",
1387
+ JSON.stringify(response.data, null, 2)
1388
+ );
1389
+ throw new Error(
1390
+ `Chat request failed: ${response.statusText} (${response.status})`
1391
+ );
1392
+ }
1393
+ return {
1394
+ response: response.data.response
1395
+ };
1396
+ } catch (error) {
1397
+ const axiosError = error;
1398
+ console.error("Axios error:", axiosError.message);
1399
+ if (axiosError.response) {
1400
+ console.error("Error status:", axiosError.response.status);
1401
+ console.error(
1402
+ "Error headers:",
1403
+ JSON.stringify(axiosError.response.headers, null, 2)
1404
+ );
1405
+ console.error(
1406
+ "Error data:",
1407
+ JSON.stringify(axiosError.response.data, null, 2)
1408
+ );
1409
+ }
1410
+ throw error;
1411
+ }
1412
+ }
1413
+ };
1414
+
1415
+ // src/settings.ts
1416
+ var DocumentationToolSettings = class _DocumentationToolSettings extends Settings {
1417
+ constructor(args = {}) {
1418
+ super(args);
1419
+ }
1420
+ /**
1421
+ * Create DocumentationToolSettings from command-line arguments for Documentation Tool
1422
+ */
1423
+ static fromArgs(args) {
1424
+ return new _DocumentationToolSettings({
1425
+ ...args
1426
+ });
1427
+ }
1428
+ };
1429
+
1430
+ // src/index.ts
1431
+ var pkg = JSON.parse(
1432
+ readFileSync(
1433
+ join2(dirname(fileURLToPath(import.meta.url)), "../package.json"),
1434
+ "utf-8"
1435
+ )
1436
+ );
11
1437
  process.env.CP_MCP_MAIN_PKG = `${pkg.name} v${pkg.version}`;
12
- // Create a new MCP server instance
13
- const server = new McpServer({
14
- name: 'checkpoint-documentation',
15
- description: 'Comprehensive Check Point documentation assistant providing instant access to product information, technical specifications, configuration guidance, and feature documentation across the entire Check Point security portfolio.',
16
- version: '1.0.0',
1438
+ var server = new McpServer({
1439
+ name: "checkpoint-documentation",
1440
+ description: "Comprehensive Check Point documentation assistant providing instant access to product information, technical specifications, configuration guidance, and feature documentation across the entire Check Point security portfolio.",
1441
+ version: "1.0.0"
17
1442
  });
18
- // Create a multi-user server module
19
- const serverModule = createServerModule(server, DocumentationToolSettings, pkg, DocumentationToolAPIManager);
20
- // Create an API runner function
21
- const runApi = createApiRunner(serverModule);
22
- server.tool('ask-checkpoint-docs', 'Ask Check Point documentation. Use this to get information about Check Point products and features.', {
23
- text: z.string().describe(`The question to ask Check Point, in clear text with clear concise context and instructions.
1443
+ var serverModule = createServerModule(
1444
+ server,
1445
+ DocumentationToolSettings,
1446
+ pkg,
1447
+ DocumentationToolAPIManager
1448
+ );
1449
+ var runApi = createApiRunner(serverModule);
1450
+ server.tool(
1451
+ "ask-checkpoint-docs",
1452
+ "Ask Check Point documentation. Use this to get information about Check Point products and features.",
1453
+ {
1454
+ text: z.string().describe(
1455
+ `The question to ask Check Point, in clear text with clear concise context and instructions.
24
1456
  The question should be about one of the Check Point products (e.g., Smart-1 Cloud, Harmony SASE, CloudGuard, Harmony Endpoint, etc.).
25
- Include relevant technical details, product names, feature names, and specific use cases for the most accurate and helpful response.`),
26
- product: z
27
- .enum([
28
- 's1c',
29
- 'maas',
30
- 'mobile',
31
- 'endpoint',
32
- 'edr',
33
- 'xdr',
34
- 'playblocks',
35
- 'infinity-events',
36
- 'cloudguard',
37
- 'cloudguardnetwork',
38
- 'cloudnetworksecurity',
39
- 'rfp-copilot',
40
- 'harmony-sase',
41
- 'customer-support',
42
- 'smp',
43
- 'appsec',
44
- 'sd-wan',
45
- 'horizonmonitoring',
46
- 'ndr',
47
- ])
48
- .optional()
49
- .describe(`Select the specific Check Point product to target for focused documentation queries. This parameter helps narrow down search results to the most relevant product-specific information. Defaults to 's1c' (Smart-1 Cloud) if not specified. Choose from:
1457
+ Include relevant technical details, product names, feature names, and specific use cases for the most accurate and helpful response.`
1458
+ ),
1459
+ product: z.enum([
1460
+ "s1c",
1461
+ "maas",
1462
+ "mobile",
1463
+ "endpoint",
1464
+ "edr",
1465
+ "xdr",
1466
+ "playblocks",
1467
+ "infinity-events",
1468
+ "cloudguard",
1469
+ "cloudguardnetwork",
1470
+ "cloudnetworksecurity",
1471
+ "rfp-copilot",
1472
+ "harmony-sase",
1473
+ "customer-support",
1474
+ "smp",
1475
+ "appsec",
1476
+ "sd-wan",
1477
+ "horizonmonitoring",
1478
+ "ndr"
1479
+ ]).optional().describe(
1480
+ `Select the specific Check Point product to target for focused documentation queries. This parameter helps narrow down search results to the most relevant product-specific information. Defaults to 's1c' (Smart-1 Cloud) if not specified. Choose from:
50
1481
 
51
1482
  Cloud Management & Security:
52
1483
  - s1c: Smart-1 Cloud - Cloud-based security management platform for centralized policy management (DEFAULT)
@@ -80,37 +1511,47 @@ server.tool('ask-checkpoint-docs', 'Ask Check Point documentation. Use this to g
80
1511
  Usage Guidelines:
81
1512
  - Defaults to s1c (Smart-1 Cloud) for general management and security questions
82
1513
  - Specify a different product when the user's question is clearly about that specific product
83
- - For troubleshooting or configuration questions, specify the exact product involved.`),
84
- }, async ({ text, product }, extra) => {
1514
+ - For troubleshooting or configuration questions, specify the exact product involved.`
1515
+ )
1516
+ },
1517
+ async ({ text, product }, extra) => {
85
1518
  try {
86
- const result = await runApi('post', 'api/v1/doc/ask_docs', { question: text, product }, extra);
87
- return {
88
- content: [
89
- {
90
- type: 'text',
91
- text: result.response,
92
- },
93
- ],
94
- };
95
- }
96
- catch (error) {
97
- return {
98
- content: [
99
- {
100
- type: 'text',
101
- text: `API Error: ${error.message}`,
102
- },
103
- ],
104
- };
1519
+ const result = await runApi(
1520
+ "post",
1521
+ "api/v1/doc/ask_docs",
1522
+ { question: text, product },
1523
+ extra
1524
+ );
1525
+ return {
1526
+ content: [
1527
+ {
1528
+ type: "text",
1529
+ text: result.response
1530
+ }
1531
+ ]
1532
+ };
1533
+ } catch (error) {
1534
+ return {
1535
+ content: [
1536
+ {
1537
+ type: "text",
1538
+ text: `API Error: ${error.message}`
1539
+ }
1540
+ ]
1541
+ };
105
1542
  }
106
- });
107
- export { server };
108
- // Settings implementation - updated for multi-user support
109
- const main = async () => {
110
- await launchMCPServer(join(dirname(fileURLToPath(import.meta.url)), 'server-config.json'), serverModule);
1543
+ }
1544
+ );
1545
+ var main = async () => {
1546
+ await launchMCPServer(
1547
+ join2(dirname(fileURLToPath(import.meta.url)), "server-config.json"),
1548
+ serverModule
1549
+ );
111
1550
  };
112
1551
  main().catch((error) => {
113
- console.error('Fatal error in main():', error);
114
- process.exit(1);
1552
+ console.error("Fatal error in main():", error);
1553
+ process.exit(1);
115
1554
  });
116
- //# sourceMappingURL=index.js.map
1555
+ export {
1556
+ server
1557
+ };