@chkp/harmony-email-mcp 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -41,8 +41,8 @@ This server puts that behind an MCP interface, with a SOC-analyst persona and a
41
41
 
42
42
  **Anti-Phishing exceptions**
43
43
 
44
- 20. **list_ap_exceptions** - the whitelist, blacklist or spam whitelist
45
- 21. **get_ap_exception** - one entry by id
44
+ 20. **list_ap_exceptions** - the whitelist, blacklist or spam whitelist; each entry gives `id`, `type`, `match` (the criteria that are set, with their matching mode), `comment`, `actionNeeded`, `ignoringSpfCheck`, `actor` and `updatedAt`
45
+ 21. **get_ap_exception** - one entry by id, same fields
46
46
 
47
47
  ### 4 prompts and a glossary
48
48
 
package/dist/index.js CHANGED
@@ -369,6 +369,79 @@ var init_ui_dialog = __esm({
369
369
  function booleanOptionDefault(envValue, optionDefault) {
370
370
  return envValue === "true" || optionDefault === "true";
371
371
  }
372
+ function resolveTransportType(transportOption, env = process.env) {
373
+ return (transportOption || env.MCP_TRANSPORT_TYPE || "stdio").toLowerCase() === "http" ? "http" : "stdio";
374
+ }
375
+ function optionKey(flag) {
376
+ const long = flag.split(/[,\s]+/).find((part) => part.startsWith("--"));
377
+ if (!long)
378
+ return void 0;
379
+ const negated = long.startsWith("--no-");
380
+ return {
381
+ key: long.replace(/^--(no-)?/, "").replace(/-([a-z])/g, (_match, char) => char.toUpperCase()),
382
+ negated
383
+ };
384
+ }
385
+ function operatorValues(options, parsed, env = process.env) {
386
+ const values = { ...env };
387
+ for (const option of options) {
388
+ const derived = option.env ? optionKey(option.flag) : void 0;
389
+ if (!derived || derived.negated)
390
+ continue;
391
+ const value = parsed[derived.key];
392
+ if (value !== void 0)
393
+ values[option.env] = value;
394
+ }
395
+ return values;
396
+ }
397
+
398
+ // ../mcp-utils/dist/debug-view.js
399
+ import { createHash } from "node:crypto";
400
+ var BUILTIN_LOGGABLE_KEYS = [
401
+ "accept",
402
+ "accept-encoding",
403
+ "accept-language",
404
+ "connection",
405
+ "content-length",
406
+ "content-type",
407
+ "host",
408
+ "mcp-protocol-version",
409
+ "traceparent",
410
+ "user-agent",
411
+ "x-correlation-id",
412
+ "x-gw-auth-method",
413
+ "x-request-id",
414
+ // Launcher options
415
+ "debug",
416
+ "telemetry",
417
+ "telemetry-url",
418
+ "transport",
419
+ "transport-port"
420
+ ];
421
+ function normalizeDebugKey(key) {
422
+ const split = /[-_]/.test(key) ? key : key.replace(/([a-z][0-9]*)([A-Z])/g, "$1-$2");
423
+ return split.replace(/_/g, "-").toLowerCase();
424
+ }
425
+ function debugLoggableKeys(extra = []) {
426
+ return new Set([...BUILTIN_LOGGABLE_KEYS, ...extra].map(normalizeDebugKey));
427
+ }
428
+ function describe(key, value, loggable) {
429
+ if (value === void 0 || value === null || value === "")
430
+ return "(unset)";
431
+ if (loggable.has(normalizeDebugKey(key))) {
432
+ return typeof value === "string" ? value : JSON.stringify(value);
433
+ }
434
+ const text = typeof value === "string" ? value : Array.isArray(value) ? value.join(", ") : void 0;
435
+ return text === void 0 ? "(hidden)" : `(hidden, ${text.length} chars)`;
436
+ }
437
+ function debugView(record, loggable = debugLoggableKeys()) {
438
+ return Object.fromEntries(Object.entries(record ?? {}).map(([key, value]) => [key, describe(key, value, loggable)]));
439
+ }
440
+ function sessionLogLabel(sessionId) {
441
+ if (!sessionId || sessionId === "default")
442
+ return "default";
443
+ return `session#${createHash("sha256").update(sessionId).digest("hex").slice(0, 8)}`;
444
+ }
372
445
 
373
446
  // ../mcp-utils/dist/launcher.js
374
447
  import { Command } from "commander";
@@ -378,6 +451,89 @@ import fs from "fs";
378
451
  import http from "http";
379
452
  import { randomUUID } from "crypto";
380
453
 
454
+ // ../mcp-utils/dist/connection-source.js
455
+ function hasValue(value) {
456
+ return value !== void 0 && value !== null && value !== "" && !(Array.isArray(value) && value.length === 0);
457
+ }
458
+ function headersRead(fromHeaders, headers) {
459
+ const read = /* @__PURE__ */ new Set();
460
+ const recording = new Proxy(headers, {
461
+ get(target, prop, receiver) {
462
+ const value = Reflect.get(target, prop, receiver);
463
+ if (typeof prop === "string" && hasValue(value))
464
+ read.add(prop);
465
+ return value;
466
+ }
467
+ });
468
+ try {
469
+ fromHeaders(recording);
470
+ } catch {
471
+ }
472
+ return read;
473
+ }
474
+ function keySet(keys = []) {
475
+ return new Set(keys.map(normalizeDebugKey));
476
+ }
477
+ function chooseConnectionSource(read, basicKeys) {
478
+ for (const key of read) {
479
+ if (!basicKeys.has(normalizeDebugKey(key)))
480
+ return "caller";
481
+ }
482
+ return "operator";
483
+ }
484
+ function basicOnly(headers, basicKeys) {
485
+ return Object.fromEntries(Object.entries(headers).filter(([key]) => basicKeys.has(normalizeDebugKey(key))));
486
+ }
487
+ function mergeHeaders(base, overrides) {
488
+ const merged = {};
489
+ const index = /* @__PURE__ */ new Map();
490
+ for (const [key, value] of [...Object.entries(base), ...Object.entries(overrides)]) {
491
+ const id = normalizeDebugKey(key);
492
+ const previous = index.get(id);
493
+ if (previous !== void 0)
494
+ delete merged[previous];
495
+ index.set(id, key);
496
+ merged[key] = value;
497
+ }
498
+ return merged;
499
+ }
500
+ function operatorHeaders(values) {
501
+ const headers = {};
502
+ for (const [name, value] of Object.entries(values)) {
503
+ if (!hasValue(value))
504
+ continue;
505
+ headers[name.replace(/_/g, "-")] = Array.isArray(value) ? value.map(String) : String(value);
506
+ }
507
+ return headers;
508
+ }
509
+ function canonicalizeAliases(headers, aliases) {
510
+ if (aliases.size === 0)
511
+ return headers;
512
+ const canonical = new Set([...aliases.values()].map(normalizeDebugKey));
513
+ const present = new Set(Object.keys(headers).map(normalizeDebugKey).filter((key) => canonical.has(key)));
514
+ const result = {};
515
+ for (const [key, value] of Object.entries(headers)) {
516
+ const target = aliases.get(normalizeDebugKey(key));
517
+ if (target === void 0) {
518
+ result[key] = value;
519
+ } else if (!present.has(normalizeDebugKey(target))) {
520
+ result[target] = value;
521
+ present.add(normalizeDebugKey(target));
522
+ }
523
+ }
524
+ return result;
525
+ }
526
+ function aliasMap(aliases = {}) {
527
+ return new Map(Object.entries(aliases).map(([alias, target]) => [normalizeDebugKey(alias), target]));
528
+ }
529
+ function sessionHeaders(source, callerHeaders, operator, basicKeys, operatorSettingsOverHttp) {
530
+ if (source === "caller") {
531
+ return mergeHeaders(basicOnly(operator, basicKeys), callerHeaders);
532
+ }
533
+ const base = operatorSettingsOverHttp ? operator : basicOnly(operator, basicKeys);
534
+ return mergeHeaders(base, basicOnly(callerHeaders, basicKeys));
535
+ }
536
+
381
537
  // ../mcp-utils/dist/settings-manager.js
382
538
  var SettingsManager = class _SettingsManager {
383
539
  /**
@@ -387,7 +543,13 @@ var SettingsManager = class _SettingsManager {
387
543
  constructor(settingsClass) {
388
544
  this.settingsMap = /* @__PURE__ */ new Map();
389
545
  this.defaultSessionId = "default";
546
+ this.operatorValues = {};
547
+ this.sessionSources = /* @__PURE__ */ new Map();
390
548
  this.settingsClass = settingsClass;
549
+ this.loggableKeys = debugLoggableKeys(settingsClass?.debugLoggableKeys ?? []);
550
+ this.basicKeys = keySet(settingsClass?.basicKeys ?? []);
551
+ this.headerAliases = aliasMap(settingsClass?.headerAliases);
552
+ this.operatorSettingsOverHttp = settingsClass?.operatorSettingsOverHttp !== false;
391
553
  }
392
554
  /**
393
555
  * Get settings for a specific session
@@ -414,12 +576,15 @@ var SettingsManager = class _SettingsManager {
414
576
  * Injects debug settings from source into settings object
415
577
  * @param settings The settings object to update
416
578
  * @param source Source object containing debug information
579
+ * @param scope 'process' when the operator set debug (CLI/env), which also
580
+ * updates the process-wide state; 'session' when a caller set it through a
581
+ * header, which affects only that session's settings
417
582
  * @private
418
583
  */
419
- injectDebug(settings, source) {
584
+ injectDebug(settings, source, scope) {
420
585
  const debug = source?.debug ?? _SettingsManager.globalDebugState ?? process.env.DEBUG;
421
586
  if (typeof debug !== "undefined") {
422
- if (source?.debug !== void 0) {
587
+ if (scope === "process" && source?.debug !== void 0) {
423
588
  _SettingsManager.globalDebugState = source.debug;
424
589
  }
425
590
  if (typeof settings.set === "function") {
@@ -428,8 +593,8 @@ var SettingsManager = class _SettingsManager {
428
593
  settings.debug = debug;
429
594
  }
430
595
  if (debug) {
431
- console.error("Debug enabled. Source object contents:");
432
- console.error(JSON.stringify(source, null, 2));
596
+ console.error("Debug enabled. Source:");
597
+ this.printDebugView(source);
433
598
  }
434
599
  }
435
600
  }
@@ -442,19 +607,21 @@ var SettingsManager = class _SettingsManager {
442
607
  if (typeof settings.get === "function") {
443
608
  console.error("Settings (using get method):");
444
609
  if (settings.data && typeof settings.data === "object") {
445
- Object.entries(settings.data).forEach(([key, value]) => {
446
- console.error(` ${key}: ${JSON.stringify(value)}`);
447
- });
610
+ this.printDebugView(settings.data);
448
611
  } else {
449
612
  console.error(" Unable to enumerate settings properties - no accessible data structure");
450
613
  }
451
614
  } else {
452
615
  console.error("Settings (plain object):");
453
- Object.entries(settings).forEach(([key, value]) => {
454
- console.error(` ${key}: ${JSON.stringify(value)}`);
455
- });
616
+ this.printDebugView(settings);
456
617
  }
457
618
  }
619
+ /** Print allowlisted values; everything else as "(hidden, N chars)". */
620
+ printDebugView(record) {
621
+ Object.entries(debugView(record, this.loggableKeys)).forEach(([key, value]) => {
622
+ console.error(` ${key}: ${value}`);
623
+ });
624
+ }
458
625
  /**
459
626
  * Create settings from command-line arguments
460
627
  * @param args Command line arguments
@@ -463,10 +630,19 @@ var SettingsManager = class _SettingsManager {
463
630
  */
464
631
  createFromArgs(args, sessionId) {
465
632
  const settings = this.settingsClass.fromArgs(args);
466
- this.injectDebug(settings, args);
633
+ this.injectDebug(settings, args, "process");
467
634
  this.setSettings(settings, sessionId);
468
635
  return settings;
469
636
  }
637
+ /**
638
+ * Record the operator's values (environment variables and parsed CLI
639
+ * options, keyed by environment-variable name). HTTP sessions take basic
640
+ * keys from them when the caller doesn't send its own, and their whole
641
+ * connection set when the caller sends none of it.
642
+ */
643
+ setOperatorValues(values) {
644
+ this.operatorValues = canonicalizeAliases(operatorHeaders(values), this.headerAliases);
645
+ }
470
646
  /**
471
647
  * Create settings from HTTP headers
472
648
  * @param headers HTTP headers
@@ -476,13 +652,13 @@ var SettingsManager = class _SettingsManager {
476
652
  createFromHeaders(headers, sessionId) {
477
653
  const verbose = _SettingsManager.globalDebugState;
478
654
  if (verbose) {
479
- console.error("[SettingsManager.createFromHeaders] Verbose: Starting with sessionId:", sessionId || "(default)");
655
+ console.error("[SettingsManager.createFromHeaders] Verbose: Starting with session:", sessionLogLabel(sessionId));
480
656
  console.error("[SettingsManager.createFromHeaders] Verbose: Incoming headers count:", Object.keys(headers).length);
481
657
  }
482
658
  if (_SettingsManager.globalDebugState) {
483
659
  console.error("=== createFromHeaders Debug Info ===");
484
660
  console.error("Incoming headers:");
485
- console.error(JSON.stringify(headers, null, 2));
661
+ this.printDebugView(headers);
486
662
  }
487
663
  if (verbose && (!headers || Object.keys(headers).length === 0)) {
488
664
  console.error("[SettingsManager.createFromHeaders] Verbose: WARNING - Headers object is empty or undefined");
@@ -499,26 +675,32 @@ var SettingsManager = class _SettingsManager {
499
675
  console.error("[SettingsManager.createFromHeaders] Verbose: Normalized headers count:", Object.keys(normalizedHeaders).length);
500
676
  }
501
677
  if (_SettingsManager.globalDebugState) {
502
- console.error("Normalized headers:");
503
- console.error(JSON.stringify(normalizedHeaders, null, 2));
678
+ console.error("Normalized header names:", Object.keys(normalizedHeaders));
504
679
  }
505
680
  const debugHeader = normalizedHeaders["debug"] || normalizedHeaders["Debug"] || normalizedHeaders["DEBUG"];
506
- const debugSource = { debug: debugHeader !== void 0 ? debugHeader : _SettingsManager.globalDebugState };
681
+ const requestedDebug = Array.isArray(debugHeader) ? debugHeader[0] : debugHeader;
682
+ const debugSource = {
683
+ debug: requestedDebug !== void 0 ? requestedDebug.toLowerCase() === "true" : _SettingsManager.globalDebugState
684
+ };
685
+ const callerHeaders = canonicalizeAliases(normalizedHeaders, this.headerAliases);
686
+ const source = this.connectionSource(callerHeaders, sessionId);
687
+ const inputHeaders = sessionHeaders(source, callerHeaders, this.operatorValues, this.basicKeys, this.operatorSettingsOverHttp);
507
688
  if (verbose) {
689
+ console.error("[SettingsManager.createFromHeaders] Verbose: Connection settings source:", source);
508
690
  console.error("[SettingsManager.createFromHeaders] Verbose: Calling settingsClass.fromHeaders");
509
691
  }
510
- const settings = this.settingsClass.fromHeaders(normalizedHeaders);
692
+ const settings = this.settingsClass.fromHeaders(inputHeaders);
511
693
  if (verbose) {
512
694
  console.error("[SettingsManager.createFromHeaders] Verbose: Settings object created");
513
695
  }
514
- this.injectDebug(settings, debugSource);
696
+ this.injectDebug(settings, debugSource, "session");
515
697
  if (_SettingsManager.globalDebugState) {
516
- console.error("Final settings object for session:", sessionId || "(default)");
698
+ console.error("Final settings object for session:", sessionLogLabel(sessionId));
517
699
  this.printSettingsDebug(settings);
518
700
  console.error("=== End createFromHeaders Debug Info ===");
519
701
  }
520
702
  if (verbose) {
521
- console.error("[SettingsManager.createFromHeaders] Verbose: Storing settings for session:", sessionId || "(default)");
703
+ console.error("[SettingsManager.createFromHeaders] Verbose: Storing settings for session:", sessionLogLabel(sessionId));
522
704
  }
523
705
  this.setSettings(settings, sessionId);
524
706
  return settings;
@@ -530,14 +712,28 @@ var SettingsManager = class _SettingsManager {
530
712
  clearSession(sessionId) {
531
713
  if (sessionId !== this.defaultSessionId) {
532
714
  this.settingsMap.delete(sessionId);
715
+ this.sessionSources.delete(sessionId);
533
716
  }
534
717
  }
718
+ /**
719
+ * The session's connection source: decided by the request that creates the
720
+ * session and kept for its lifetime, so a later request cannot switch it.
721
+ */
722
+ connectionSource(headers, sessionId) {
723
+ const known = sessionId ? this.sessionSources.get(sessionId) : void 0;
724
+ if (known)
725
+ return known;
726
+ const source = chooseConnectionSource(headersRead((h) => this.settingsClass.fromHeaders(h), headers), this.basicKeys);
727
+ if (sessionId)
728
+ this.sessionSources.set(sessionId, source);
729
+ return source;
730
+ }
535
731
  };
536
732
  SettingsManager.globalDebugState = void 0;
537
733
 
538
734
  // ../mcp-utils/dist/telemetry.js
539
735
  import machineIdPkg from "node-machine-id";
540
- import { createHash } from "crypto";
736
+ import { createHash as createHash2 } from "crypto";
541
737
  var { machineIdSync } = machineIdPkg;
542
738
  var machineId = null;
543
739
  var hashedMachineId = null;
@@ -552,7 +748,7 @@ function getTelemetryUrl() {
552
748
  return process.env.TELEMETRY_URL || "https://metrics.security.ai.checkpoint.com/api/v1/metrics/collect";
553
749
  }
554
750
  function hashString(input) {
555
- return createHash("sha256").update(input).digest("hex");
751
+ return createHash2("sha256").update(input).digest("hex");
556
752
  }
557
753
  function getMachineId() {
558
754
  if (!machineId) {
@@ -600,16 +796,6 @@ async function trackToolCall(mcpName, toolName, clientVersion, extra) {
600
796
  }
601
797
 
602
798
  // ../mcp-utils/dist/launcher.js
603
- function optionKey(flag) {
604
- const long = flag.split(/[,\s]+/).find((part) => part.startsWith("--"));
605
- if (!long)
606
- return void 0;
607
- const negated = long.startsWith("--no-");
608
- return {
609
- key: long.replace(/^--(no-)?/, "").replace(/-([a-z])/g, (_match, char) => char.toUpperCase()),
610
- negated
611
- };
612
- }
613
799
  function mirrorBooleanFlagsToEnv(config, options) {
614
800
  for (const option of config.options) {
615
801
  if (option.type !== "boolean" || !option.env)
@@ -660,17 +846,23 @@ async function launchMCPServer(configPath, serverModule2) {
660
846
  process.env.TELEMETRY_URL = options.telemetryUrl;
661
847
  }
662
848
  mirrorBooleanFlagsToEnv(config, options);
849
+ const transportType2 = resolveTransportType(options.transport);
850
+ process.env.MCP_TRANSPORT_TYPE = transportType2;
663
851
  if (!serverModule2.settingsManager) {
664
852
  throw new Error("ServerModule must have a settingsManager. Create it with createServerModule.");
665
853
  }
666
854
  const settings = serverModule2.settingsManager.createFromArgs(options);
855
+ serverModule2.settingsManager.setOperatorValues?.(operatorValues(config.options, options));
667
856
  if (typeof serverModule2.server.applyToolPolicy === "function") {
668
857
  console.error("[launchMCPServer] Applying tool policy before connecting");
669
858
  serverModule2.server.applyToolPolicy();
670
859
  }
671
- const transportType2 = (options.transport || process.env.MCP_TRANSPORT_TYPE || "stdio").toLowerCase() === "http" ? "http" : "stdio";
672
860
  const transportPort = options.transportPort ? parseInt(options.transportPort, 10) : process.env.MCP_TRANSPORT_PORT ? parseInt(process.env.MCP_TRANSPORT_PORT, 10) : 3e3;
673
861
  if (transportType2 === "http") {
862
+ const refusal = serverModule2.httpStartupCheck?.();
863
+ if (refusal) {
864
+ throw new Error(refusal);
865
+ }
674
866
  setTransportType("http");
675
867
  await launchHTTPServer(config, serverModule2, transportPort);
676
868
  } else {
@@ -719,7 +911,7 @@ async function launchHTTPServer(config, serverModule2, port) {
719
911
  if (sessionId && transports[sessionId]) {
720
912
  const verbose = SettingsManager.globalDebugState;
721
913
  if (verbose) {
722
- console.error("[launchHTTPServer] Verbose: Reusing existing transport for session:", sessionId);
914
+ console.error("[launchHTTPServer] Verbose: Reusing existing transport for session:", sessionLogLabel(sessionId));
723
915
  }
724
916
  transport = transports[sessionId];
725
917
  if (!serverModule2.settingsManager) {
@@ -739,7 +931,7 @@ async function launchHTTPServer(config, serverModule2, port) {
739
931
  onsessioninitialized: (sid) => {
740
932
  const verbose = SettingsManager.globalDebugState;
741
933
  if (verbose) {
742
- console.error("[launchHTTPServer] Verbose: New session initialized:", sid);
934
+ console.error("[launchHTTPServer] Verbose: New session initialized:", sessionLogLabel(sid));
743
935
  }
744
936
  transports[sid] = transport;
745
937
  if (verbose) {
@@ -942,7 +1134,6 @@ function headersToEnvVars(headers, config) {
942
1134
  }
943
1135
  if (verbose) {
944
1136
  console.error("[headersToEnvVars] Verbose: Final result keys:", Object.keys(result));
945
- 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])));
946
1137
  }
947
1138
  return result;
948
1139
  }
@@ -969,7 +1160,7 @@ var APIManagerFactory = class {
969
1160
  const verbose = SettingsManager.globalDebugState;
970
1161
  const sid = sessionId || this.defaultSessionId;
971
1162
  if (verbose) {
972
- console.error("[APIManagerFactory.getAPIManager] Verbose: Getting API manager for session:", sid);
1163
+ console.error("[APIManagerFactory.getAPIManager] Verbose: Getting API manager for session:", sessionLogLabel(sid));
973
1164
  }
974
1165
  if (!this.apiManagerMap.has(sid)) {
975
1166
  if (verbose) {
@@ -1067,16 +1258,15 @@ var SessionContext = class {
1067
1258
  /**
1068
1259
  * Get the current session ID from the MCP extra context
1069
1260
  * @param extra Extra context passed to MCP tool callbacks
1070
- * @returns The session ID or DEFAULT_SESSION_ID if not available
1261
+ * @returns The session ID, or DEFAULT_SESSION_ID under stdio
1262
+ * @throws Under HTTP transport when the context carries no session ID
1071
1263
  */
1072
1264
  static getSessionId(extra) {
1073
- if (!extra)
1074
- return this.DEFAULT_SESSION_ID;
1075
- if (extra.transport && extra.transport.sessionId) {
1076
- return extra.transport.sessionId;
1077
- }
1078
- if (extra.sessionId) {
1079
- return extra.sessionId;
1265
+ const sessionId = extra?.transport?.sessionId || extra?.sessionId;
1266
+ if (sessionId)
1267
+ return sessionId;
1268
+ if (process.env.MCP_TRANSPORT_TYPE === "http") {
1269
+ throw new Error("No MCP session in this request context; HTTP transport requires one");
1080
1270
  }
1081
1271
  return this.DEFAULT_SESSION_ID;
1082
1272
  }
@@ -1193,10 +1383,10 @@ var SessionContext = class {
1193
1383
  }
1194
1384
  }
1195
1385
  }
1196
- console.error(`Using cached user data for session: ${sessionId}, key: ${options.cacheKey}`);
1386
+ console.error(`Using cached user data for ${sessionLogLabel(sessionId)}, key: ${options.cacheKey}`);
1197
1387
  return { cancelled: false, data: dataToReturn2 };
1198
1388
  }
1199
- console.error(`Prompting user for data for session: ${sessionId}, key: ${options.cacheKey}`);
1389
+ console.error(`Prompting user for data for ${sessionLogLabel(sessionId)}, key: ${options.cacheKey}`);
1200
1390
  let result;
1201
1391
  if (options.showLoginDialog) {
1202
1392
  const { showLoginDialog: showLoginDialog2 } = await Promise.resolve().then(() => (init_ui_dialog(), ui_dialog_exports));
@@ -1850,7 +2040,7 @@ function unwrapSingleton(data, where) {
1850
2040
  }
1851
2041
 
1852
2042
  // src/core/providers/avanan.ts
1853
- import { createHash as createHash2 } from "node:crypto";
2043
+ import { createHash as createHash3 } from "node:crypto";
1854
2044
  var V1_PREFIX = "/v1.0";
1855
2045
  var AUTH_PATH = "/v1.0/auth";
1856
2046
  var REGION_HOSTS = {
@@ -1873,7 +2063,7 @@ function avananSignature(reqId, appId, date, secret, requestPath) {
1873
2063
  if (requestPath !== null) parts.push(requestPath);
1874
2064
  parts.push(secret);
1875
2065
  const base64 = Buffer.from(parts.join(""), "utf8").toString("base64");
1876
- return createHash2("sha256").update(base64, "utf8").digest("hex");
2066
+ return createHash3("sha256").update(base64, "utf8").digest("hex");
1877
2067
  }
1878
2068
  function formatAvananDate(now) {
1879
2069
  return `${now.toISOString().replace("Z", "")}000`;
@@ -2766,6 +2956,251 @@ function neverReachedUpstream(error) {
2766
2956
  return code !== null && PRE_FLIGHT_ERROR_CODES.has(code);
2767
2957
  }
2768
2958
 
2959
+ // src/tools/shared/schemas.ts
2960
+ import { z as z2 } from "zod";
2961
+ function orNull(value) {
2962
+ return value ?? null;
2963
+ }
2964
+ function compact(obj) {
2965
+ return Object.fromEntries(
2966
+ Object.entries(obj).filter(
2967
+ ([, value]) => value !== null && value !== void 0
2968
+ )
2969
+ );
2970
+ }
2971
+ var looseString = z2.unknown().transform((v) => typeof v === "string" ? v : null);
2972
+ var looseRecord = z2.unknown().transform(
2973
+ (v) => v !== null && typeof v === "object" && !Array.isArray(v) ? v : null
2974
+ );
2975
+ var SEVERITY_BY_DIGIT = {
2976
+ "1": "lowest",
2977
+ "2": "low",
2978
+ "3": "medium",
2979
+ "4": "high",
2980
+ "5": "critical"
2981
+ };
2982
+ function normalizeSeverity(value) {
2983
+ if (typeof value !== "string") return null;
2984
+ return SEVERITY_BY_DIGIT[value] ?? (value || null);
2985
+ }
2986
+ var eventSchema = z2.object({
2987
+ eventId: z2.unknown(),
2988
+ type: looseString,
2989
+ state: looseString,
2990
+ severity: z2.unknown(),
2991
+ saas: looseString,
2992
+ description: looseString,
2993
+ entityId: looseString,
2994
+ eventCreated: looseString,
2995
+ confidenceIndicator: looseString
2996
+ }).passthrough().transform((raw) => ({
2997
+ eventId: typeof raw.eventId === "string" ? raw.eventId : String(raw.eventId ?? ""),
2998
+ type: raw.type,
2999
+ state: raw.state,
3000
+ severity: normalizeSeverity(raw.severity),
3001
+ saas: raw.saas,
3002
+ description: raw.description,
3003
+ entityId: raw.entityId,
3004
+ eventCreated: raw.eventCreated,
3005
+ confidenceIndicator: raw.confidenceIndicator
3006
+ }));
3007
+ function toEvent(raw) {
3008
+ return eventSchema.parse(raw);
3009
+ }
3010
+ var sectoolResultSchema = z2.object({
3011
+ entityId: looseString,
3012
+ entityType: looseString,
3013
+ payload: looseRecord,
3014
+ score: looseString,
3015
+ securityResultEntityId: looseString,
3016
+ securityResultEntityType: looseString,
3017
+ statusCode: looseString,
3018
+ statusDescription: looseString,
3019
+ verdict: z2.unknown().transform((v) => typeof v === "string" ? v : "unknown")
3020
+ }).passthrough().transform((raw) => ({
3021
+ entityId: raw.entityId,
3022
+ entityType: raw.entityType,
3023
+ payload: raw.payload,
3024
+ score: raw.score,
3025
+ securityResultEntityId: raw.securityResultEntityId,
3026
+ securityResultEntityType: raw.securityResultEntityType,
3027
+ statusCode: raw.statusCode,
3028
+ statusDescription: raw.statusDescription,
3029
+ verdict: raw.verdict
3030
+ }));
3031
+ var engineResultsSchema = z2.array(sectoolResultSchema).nullish().transform((v) => orNull(v));
3032
+ var entitySecurityResultSchema = z2.object({
3033
+ combinedVerdict: looseRecord,
3034
+ ap: engineResultsSchema,
3035
+ dlp: engineResultsSchema,
3036
+ clicktimeProtection: engineResultsSchema,
3037
+ shadowIt: engineResultsSchema,
3038
+ av: engineResultsSchema
3039
+ }).passthrough().transform((raw) => ({
3040
+ combinedVerdict: raw.combinedVerdict,
3041
+ ap: raw.ap,
3042
+ dlp: raw.dlp,
3043
+ clicktimeProtection: raw.clicktimeProtection,
3044
+ shadowIt: raw.shadowIt,
3045
+ av: raw.av
3046
+ }));
3047
+ var entityActionSchema = z2.object({
3048
+ entityActionName: z2.string(),
3049
+ entityActionDate: looseString,
3050
+ entityActionResponseCode: looseString,
3051
+ entityActionResponseText: looseString,
3052
+ entityActionState: looseString
3053
+ }).passthrough().transform((raw) => ({
3054
+ entityActionName: raw.entityActionName,
3055
+ entityActionDate: raw.entityActionDate,
3056
+ entityActionResponseCode: raw.entityActionResponseCode,
3057
+ entityActionResponseText: raw.entityActionResponseText,
3058
+ entityActionState: raw.entityActionState
3059
+ }));
3060
+ var entityInfoSchema = z2.object({
3061
+ entityId: z2.string(),
3062
+ customerId: looseString,
3063
+ saas: looseString,
3064
+ saasEntityType: looseString,
3065
+ entityCreated: looseString,
3066
+ entityUpdated: looseString,
3067
+ entityActionState: looseString
3068
+ }).passthrough().transform((raw) => ({
3069
+ entityId: raw.entityId,
3070
+ customerId: raw.customerId,
3071
+ saas: raw.saas,
3072
+ saasEntityType: raw.saasEntityType,
3073
+ entityCreated: raw.entityCreated,
3074
+ entityUpdated: raw.entityUpdated,
3075
+ entityActionState: raw.entityActionState
3076
+ }));
3077
+ var entitySchema = z2.object({
3078
+ entityInfo: entityInfoSchema,
3079
+ saasInfo: looseRecord,
3080
+ entityPayload: looseRecord,
3081
+ entitySecurityResult: entitySecurityResultSchema.nullish().transform((v) => orNull(v)),
3082
+ entityActions: z2.array(entityActionSchema).nullish(),
3083
+ entityAvailableActions: z2.array(z2.string()).nullish()
3084
+ }).passthrough().transform((raw) => ({
3085
+ entityInfo: raw.entityInfo,
3086
+ saasInfo: raw.saasInfo,
3087
+ entityPayload: raw.entityPayload,
3088
+ entitySecurityResult: raw.entitySecurityResult,
3089
+ entityActions: raw.entityActions ?? [],
3090
+ entityAvailableActions: raw.entityAvailableActions ?? []
3091
+ }));
3092
+ function toEntity(raw) {
3093
+ return entitySchema.parse(raw);
3094
+ }
3095
+ function toEntitySummary(raw) {
3096
+ const {
3097
+ entityPayload: _payload,
3098
+ saasInfo: _saasInfo,
3099
+ ...rest
3100
+ } = toEntity(raw);
3101
+ return rest;
3102
+ }
3103
+ var TASK_STATUSES = [
3104
+ "init",
3105
+ "inprogress",
3106
+ "completed",
3107
+ "failed",
3108
+ "stopped",
3109
+ "paused"
3110
+ ];
3111
+ var taskSchema = z2.object({
3112
+ taskId: z2.string(),
3113
+ status: z2.enum(TASK_STATUSES),
3114
+ actor: looseString,
3115
+ startedAt: looseString,
3116
+ finishedAt: looseString
3117
+ }).passthrough().transform((raw) => ({
3118
+ taskId: raw.taskId,
3119
+ status: raw.status,
3120
+ actor: raw.actor,
3121
+ startedAt: raw.startedAt,
3122
+ finishedAt: raw.finishedAt
3123
+ }));
3124
+ function toTask(raw) {
3125
+ return taskSchema.parse(raw);
3126
+ }
3127
+ var EXCEPTION_TYPES = [
3128
+ "whitelist",
3129
+ "blacklist",
3130
+ "spam_whitelist"
3131
+ ];
3132
+ var AP_EXCEPTION_CRITERIA = [
3133
+ ["senderEmail", "senderEmailMatching"],
3134
+ ["senderName", "senderNameMatching"],
3135
+ ["senderDomain", "senderDomainMatching"],
3136
+ ["senderIp", null],
3137
+ ["senderClientIp", null],
3138
+ ["recipient", "recipientMatching"],
3139
+ ["domain", null],
3140
+ ["linkDomains", "linkDomainMatching"],
3141
+ ["subject", "subjectMatching"],
3142
+ ["attachmentMd5", null]
3143
+ ];
3144
+ var nonEmpty = (v) => typeof v === "string" && v !== "";
3145
+ function exceptionIdOf(row) {
3146
+ if (!row || typeof row !== "object" || Array.isArray(row)) return null;
3147
+ const { id, entityId } = row;
3148
+ for (const v of [id, entityId]) {
3149
+ if (nonEmpty(v)) return v;
3150
+ if (typeof v === "number") return String(v);
3151
+ }
3152
+ return null;
3153
+ }
3154
+ function withExceptionId(raw) {
3155
+ const id = exceptionIdOf(raw);
3156
+ return id === null ? raw : { ...raw, id };
3157
+ }
3158
+ var apExceptionRowSchema = z2.preprocess(
3159
+ withExceptionId,
3160
+ z2.object({
3161
+ id: z2.string(),
3162
+ comment: looseString,
3163
+ actionNeeded: looseString,
3164
+ ignoringSpfCheck: z2.unknown().transform((v) => {
3165
+ if (typeof v === "boolean") return v;
3166
+ if (v === 1 || v === "true") return true;
3167
+ if (v === 0 || v === "false") return false;
3168
+ return null;
3169
+ }),
3170
+ editedBy: looseString,
3171
+ addedBy: looseString,
3172
+ updateTime: looseString
3173
+ }).passthrough()
3174
+ );
3175
+ function criteriaOf(row) {
3176
+ const match = {};
3177
+ for (const [field, modeField] of AP_EXCEPTION_CRITERIA) {
3178
+ const value = row[field];
3179
+ if (value === null || value === void 0 || value === "" || Array.isArray(value) && value.length === 0) {
3180
+ continue;
3181
+ }
3182
+ const mode = modeField ? row[modeField] : null;
3183
+ match[field] = {
3184
+ value,
3185
+ matching: typeof mode === "string" ? mode : null
3186
+ };
3187
+ }
3188
+ return match;
3189
+ }
3190
+ function toApException(raw, type) {
3191
+ const row = apExceptionRowSchema.parse(raw);
3192
+ return {
3193
+ id: row.id,
3194
+ type,
3195
+ match: criteriaOf(row),
3196
+ comment: row.comment,
3197
+ actionNeeded: row.actionNeeded,
3198
+ ignoringSpfCheck: row.ignoringSpfCheck,
3199
+ actor: nonEmpty(row.editedBy) ? row.editedBy : row.addedBy,
3200
+ updatedAt: row.updateTime
3201
+ };
3202
+ }
3203
+
2769
3204
  // src/check.ts
2770
3205
  function maskId(value) {
2771
3206
  return value.length <= 8 ? `${value.slice(0, 2)}\u2026` : `${value.slice(0, 6)}\u2026`;
@@ -2790,8 +3225,8 @@ function firstExceptionId(whitelist, blacklist) {
2790
3225
  ["blacklist", blacklist]
2791
3226
  ];
2792
3227
  for (const [excType, rows] of candidates) {
2793
- const value = rows?.[0]?.id ?? rows?.[0]?.exceptionId;
2794
- if (typeof value === "string") return [excType, value];
3228
+ const value = exceptionIdOf(rows?.[0]);
3229
+ if (value !== null) return [excType, value];
2795
3230
  }
2796
3231
  return [null, null];
2797
3232
  }
@@ -3119,7 +3554,7 @@ query tools.
3119
3554
  `;
3120
3555
 
3121
3556
  // src/prompts/index.ts
3122
- import { z as z3 } from "zod";
3557
+ import { z as z4 } from "zod";
3123
3558
 
3124
3559
  // src/content/glossary.ts
3125
3560
  var GLOSSARY = {
@@ -3493,7 +3928,7 @@ var GLOSSARY = {
3493
3928
  };
3494
3929
 
3495
3930
  // src/tools/shared/result.ts
3496
- import { z as z2 } from "zod";
3931
+ import { z as z3 } from "zod";
3497
3932
  function jsonResult(payload) {
3498
3933
  return { content: [{ type: "text", text: JSON.stringify(payload) }] };
3499
3934
  }
@@ -3507,7 +3942,7 @@ function errorResult(tool, error) {
3507
3942
  isError: true
3508
3943
  };
3509
3944
  }
3510
- if (error instanceof z2.ZodError) {
3945
+ if (error instanceof z3.ZodError) {
3511
3946
  const detail = error.issues.map(
3512
3947
  (issue) => `${issue.path.join(".") || "input"}: ${issue.message}`
3513
3948
  ).join("; ");
@@ -3797,7 +4232,7 @@ function registerPrompts(server2) {
3797
4232
  "security_activity_summary",
3798
4233
  ACTIVITY_DESCRIPTION,
3799
4234
  {
3800
- time_window: z3.string().optional().describe(
4235
+ time_window: z4.string().optional().describe(
3801
4236
  'Rolling window, e.g. "last 24 hours" or "this week".'
3802
4237
  )
3803
4238
  },
@@ -3810,8 +4245,8 @@ function registerPrompts(server2) {
3810
4245
  {
3811
4246
  // Deliberately free-form, so model-invented synonyms ("open",
3812
4247
  // "active") still land on the pending branch.
3813
- mode: z3.string().optional().describe("pending, resolved, or trend."),
3814
- time_window: z3.string().optional().describe("Rolling window for the resolved and trend modes.")
4248
+ mode: z4.string().optional().describe("pending, resolved, or trend."),
4249
+ time_window: z4.string().optional().describe("Rolling window for the resolved and trend modes.")
3815
4250
  },
3816
4251
  (args) => promptMessage(
3817
4252
  restoreTemplate(
@@ -3825,7 +4260,7 @@ function registerPrompts(server2) {
3825
4260
  "single_email_investigation",
3826
4261
  SINGLE_DESCRIPTION,
3827
4262
  {
3828
- entity_id: z3.string().describe("The HEC entity id to investigate.")
4263
+ entity_id: z4.string().describe("The HEC entity id to investigate.")
3829
4264
  },
3830
4265
  (args) => promptMessage(singleTemplate(args.entity_id ?? ""))
3831
4266
  );
@@ -3912,48 +4347,19 @@ function firstOf(...values) {
3912
4347
  return values.find((v) => v !== void 0 && v !== "");
3913
4348
  }
3914
4349
  var Settings = class _Settings {
4350
+ // Takes only what it is given; fromArgs reads the environment.
3915
4351
  constructor({
3916
- domain = firstOf(
3917
- process.env.HEC_DOMAIN,
3918
- process.env.SMARTAPI_MCP_DOMAIN
3919
- ),
3920
- clientId = firstOf(
3921
- process.env.HEC_CLIENT_ID,
3922
- process.env.SMARTAPI_MCP_CLIENT_ID
3923
- ),
3924
- secret = firstOf(
3925
- process.env.HEC_SECRET,
3926
- process.env.SMARTAPI_MCP_SECRET
3927
- ),
3928
- authMethod = firstOf(
3929
- process.env.HEC_AUTH_METHOD,
3930
- process.env.SMARTAPI_MCP_AUTH_METHOD
3931
- ),
3932
- region = firstOf(
3933
- process.env.HEC_REGION,
3934
- process.env.SMARTAPI_MCP_REGION
3935
- ),
3936
- scope = firstOf(process.env.HEC_SCOPE, process.env.SMARTAPI_MCP_SCOPE),
3937
- requestTimeout = firstOf(
3938
- process.env.HEC_REQUEST_TIMEOUT,
3939
- process.env.SMARTAPI_MCP_REQUEST_TIMEOUT
3940
- ),
3941
- maxRetries = firstOf(
3942
- process.env.HEC_MAX_RETRIES,
3943
- process.env.SMARTAPI_MCP_MAX_RETRIES
3944
- ),
3945
- retryBaseSeconds = firstOf(
3946
- process.env.HEC_RETRY_BASE_SECONDS,
3947
- process.env.SMARTAPI_MCP_RETRY_BASE_SECONDS
3948
- ),
3949
- maxConcurrency = firstOf(
3950
- process.env.HEC_MAX_CONCURRENCY,
3951
- process.env.SMARTAPI_MCP_MAX_CONCURRENCY
3952
- ),
3953
- actionBatchLimit = firstOf(
3954
- process.env.HEC_ACTION_BATCH_LIMIT,
3955
- process.env.SMARTAPI_MCP_ACTION_BATCH_LIMIT
3956
- )
4352
+ domain,
4353
+ clientId,
4354
+ secret,
4355
+ authMethod,
4356
+ region,
4357
+ scope,
4358
+ requestTimeout,
4359
+ maxRetries,
4360
+ retryBaseSeconds,
4361
+ maxConcurrency,
4362
+ actionBatchLimit
3957
4363
  } = {}) {
3958
4364
  this.domain = "";
3959
4365
  this.clientId = "";
@@ -3978,6 +4384,67 @@ var Settings = class _Settings {
3978
4384
  "actionBatchLimit"
3979
4385
  );
3980
4386
  }
4387
+ static {
4388
+ /**
4389
+ * Keys whose values debug output may print (see debugView in mcp-utils).
4390
+ * Anything not listed, including every credential, is shown hidden.
4391
+ * Lists both the header/CLI names (hec-*) and the property names.
4392
+ */
4393
+ this.debugLoggableKeys = [
4394
+ "hec-domain",
4395
+ "domain",
4396
+ "hec-region",
4397
+ "region",
4398
+ "hec-scope",
4399
+ "scope",
4400
+ "hec-auth-method",
4401
+ "auth-method",
4402
+ "hec-request-timeout",
4403
+ "request-timeout",
4404
+ "hec-max-retries",
4405
+ "max-retries",
4406
+ "hec-retry-base-seconds",
4407
+ "retry-base-seconds",
4408
+ "hec-max-concurrency",
4409
+ "max-concurrency",
4410
+ "hec-action-batch-limit",
4411
+ "action-batch-limit"
4412
+ ];
4413
+ }
4414
+ static {
4415
+ /**
4416
+ * Headers an HTTP session may mix with the operator's values (see
4417
+ * connection-source in mcp-utils): the numeric tunables, which are
4418
+ * deployment-wide rather than per tenant, under both spellings.
4419
+ */
4420
+ this.basicKeys = [
4421
+ "HEC-REQUEST-TIMEOUT",
4422
+ "HEC-MAX-RETRIES",
4423
+ "HEC-RETRY-BASE-SECONDS",
4424
+ "HEC-MAX-CONCURRENCY",
4425
+ "HEC-ACTION-BATCH-LIMIT"
4426
+ ];
4427
+ }
4428
+ static {
4429
+ /**
4430
+ * The Python server's names for the tunables (alias -> canonical), so a
4431
+ * caller's SMARTAPI-MCP-* header overrides the operator's HEC_* value.
4432
+ */
4433
+ this.headerAliases = {
4434
+ "SMARTAPI-MCP-REQUEST-TIMEOUT": "HEC-REQUEST-TIMEOUT",
4435
+ "SMARTAPI-MCP-MAX-RETRIES": "HEC-MAX-RETRIES",
4436
+ "SMARTAPI-MCP-RETRY-BASE-SECONDS": "HEC-RETRY-BASE-SECONDS",
4437
+ "SMARTAPI-MCP-MAX-CONCURRENCY": "HEC-MAX-CONCURRENCY",
4438
+ "SMARTAPI-MCP-ACTION-BATCH-LIMIT": "HEC-ACTION-BATCH-LIMIT"
4439
+ };
4440
+ }
4441
+ static {
4442
+ /**
4443
+ * An HTTP session never uses the operator's tenant: a client must not be
4444
+ * able to act as whichever tenant the operator configured.
4445
+ */
4446
+ this.operatorSettingsOverHttp = false;
4447
+ }
3981
4448
  /**
3982
4449
  * Under HTTP transport credentials arrive per request as headers, so the
3983
4450
  * process starts with none and validating at boot would be wrong.
@@ -3994,30 +4461,27 @@ var Settings = class _Settings {
3994
4461
  return true;
3995
4462
  }
3996
4463
  static fromArgs(options) {
4464
+ const env = process.env;
3997
4465
  return new _Settings({
3998
- domain: options.hecDomain,
3999
- clientId: options.hecClientId,
4000
- secret: options.hecSecret,
4001
- authMethod: options.hecAuthMethod,
4002
- region: options.hecRegion,
4003
- scope: options.hecScope,
4004
- requestTimeout: options.hecRequestTimeout,
4005
- maxRetries: options.hecMaxRetries,
4006
- retryBaseSeconds: options.hecRetryBaseSeconds,
4007
- maxConcurrency: options.hecMaxConcurrency,
4008
- actionBatchLimit: options.hecActionBatchLimit
4466
+ domain: options.hecDomain ?? firstOf(env.HEC_DOMAIN, env.SMARTAPI_MCP_DOMAIN),
4467
+ clientId: options.hecClientId ?? firstOf(env.HEC_CLIENT_ID, env.SMARTAPI_MCP_CLIENT_ID),
4468
+ secret: options.hecSecret ?? firstOf(env.HEC_SECRET, env.SMARTAPI_MCP_SECRET),
4469
+ authMethod: options.hecAuthMethod ?? firstOf(env.HEC_AUTH_METHOD, env.SMARTAPI_MCP_AUTH_METHOD),
4470
+ region: options.hecRegion ?? firstOf(env.HEC_REGION, env.SMARTAPI_MCP_REGION),
4471
+ scope: options.hecScope ?? firstOf(env.HEC_SCOPE, env.SMARTAPI_MCP_SCOPE),
4472
+ requestTimeout: options.hecRequestTimeout ?? firstOf(env.HEC_REQUEST_TIMEOUT, env.SMARTAPI_MCP_REQUEST_TIMEOUT),
4473
+ maxRetries: options.hecMaxRetries ?? firstOf(env.HEC_MAX_RETRIES, env.SMARTAPI_MCP_MAX_RETRIES),
4474
+ retryBaseSeconds: options.hecRetryBaseSeconds ?? firstOf(env.HEC_RETRY_BASE_SECONDS, env.SMARTAPI_MCP_RETRY_BASE_SECONDS),
4475
+ maxConcurrency: options.hecMaxConcurrency ?? firstOf(env.HEC_MAX_CONCURRENCY, env.SMARTAPI_MCP_MAX_CONCURRENCY),
4476
+ actionBatchLimit: options.hecActionBatchLimit ?? firstOf(env.HEC_ACTION_BATCH_LIMIT, env.SMARTAPI_MCP_ACTION_BATCH_LIMIT)
4009
4477
  });
4010
4478
  }
4011
4479
  /**
4012
- * Per-request settings, built from headers alone.
4013
- *
4014
- * Every tenant-scoped field is passed as an explicit empty string when its
4015
- * header is absent, because `undefined` would hand the field back to the
4016
- * constructor's env default. Under HTTP transport that would let a request
4017
- * with no credentials inherit the server process's own tenant and act as
4018
- * it, so the empty string is what makes a header-less request fail closed.
4019
- * The numeric tunables are deployment-wide, not per tenant, so they keep
4020
- * their defaults.
4480
+ * Per-request settings, built from headers alone. A missing tenant-scoped
4481
+ * header leaves its field empty, so a request without credentials fails
4482
+ * closed. The numeric tunables are deployment-wide, not per tenant: they
4483
+ * are basic keys, so the operator's values apply when the caller sends
4484
+ * none.
4021
4485
  */
4022
4486
  static fromHeaders(headers) {
4023
4487
  return new _Settings({
@@ -4027,11 +4491,26 @@ var Settings = class _Settings {
4027
4491
  authMethod: getHeaderValue(headers, "HEC-AUTH-METHOD") ?? "",
4028
4492
  region: getHeaderValue(headers, "HEC-REGION") ?? "",
4029
4493
  scope: getHeaderValue(headers, "HEC-SCOPE") ?? "",
4030
- requestTimeout: getHeaderValue(headers, "HEC-REQUEST-TIMEOUT"),
4031
- maxRetries: getHeaderValue(headers, "HEC-MAX-RETRIES"),
4032
- retryBaseSeconds: getHeaderValue(headers, "HEC-RETRY-BASE-SECONDS"),
4033
- maxConcurrency: getHeaderValue(headers, "HEC-MAX-CONCURRENCY"),
4034
- actionBatchLimit: getHeaderValue(headers, "HEC-ACTION-BATCH-LIMIT")
4494
+ requestTimeout: firstOf(
4495
+ getHeaderValue(headers, "HEC-REQUEST-TIMEOUT"),
4496
+ getHeaderValue(headers, "SMARTAPI-MCP-REQUEST-TIMEOUT")
4497
+ ),
4498
+ maxRetries: firstOf(
4499
+ getHeaderValue(headers, "HEC-MAX-RETRIES"),
4500
+ getHeaderValue(headers, "SMARTAPI-MCP-MAX-RETRIES")
4501
+ ),
4502
+ retryBaseSeconds: firstOf(
4503
+ getHeaderValue(headers, "HEC-RETRY-BASE-SECONDS"),
4504
+ getHeaderValue(headers, "SMARTAPI-MCP-RETRY-BASE-SECONDS")
4505
+ ),
4506
+ maxConcurrency: firstOf(
4507
+ getHeaderValue(headers, "HEC-MAX-CONCURRENCY"),
4508
+ getHeaderValue(headers, "SMARTAPI-MCP-MAX-CONCURRENCY")
4509
+ ),
4510
+ actionBatchLimit: firstOf(
4511
+ getHeaderValue(headers, "HEC-ACTION-BATCH-LIMIT"),
4512
+ getHeaderValue(headers, "SMARTAPI-MCP-ACTION-BATCH-LIMIT")
4513
+ )
4035
4514
  });
4036
4515
  }
4037
4516
  };
@@ -4039,198 +4518,6 @@ var Settings = class _Settings {
4039
4518
  // src/tools/actions.ts
4040
4519
  import { z as z5 } from "zod";
4041
4520
 
4042
- // src/tools/shared/schemas.ts
4043
- import { z as z4 } from "zod";
4044
- function orNull(value) {
4045
- return value ?? null;
4046
- }
4047
- function compact(obj) {
4048
- return Object.fromEntries(
4049
- Object.entries(obj).filter(
4050
- ([, value]) => value !== null && value !== void 0
4051
- )
4052
- );
4053
- }
4054
- var looseString = z4.unknown().transform((v) => typeof v === "string" ? v : null);
4055
- var looseRecord = z4.unknown().transform(
4056
- (v) => v !== null && typeof v === "object" && !Array.isArray(v) ? v : null
4057
- );
4058
- var SEVERITY_BY_DIGIT = {
4059
- "1": "lowest",
4060
- "2": "low",
4061
- "3": "medium",
4062
- "4": "high",
4063
- "5": "critical"
4064
- };
4065
- function normalizeSeverity(value) {
4066
- if (typeof value !== "string") return null;
4067
- return SEVERITY_BY_DIGIT[value] ?? (value || null);
4068
- }
4069
- var eventSchema = z4.object({
4070
- eventId: z4.unknown(),
4071
- type: looseString,
4072
- state: looseString,
4073
- severity: z4.unknown(),
4074
- saas: looseString,
4075
- description: looseString,
4076
- entityId: looseString,
4077
- eventCreated: looseString,
4078
- confidenceIndicator: looseString
4079
- }).passthrough().transform((raw) => ({
4080
- eventId: typeof raw.eventId === "string" ? raw.eventId : String(raw.eventId ?? ""),
4081
- type: raw.type,
4082
- state: raw.state,
4083
- severity: normalizeSeverity(raw.severity),
4084
- saas: raw.saas,
4085
- description: raw.description,
4086
- entityId: raw.entityId,
4087
- eventCreated: raw.eventCreated,
4088
- confidenceIndicator: raw.confidenceIndicator
4089
- }));
4090
- function toEvent(raw) {
4091
- return eventSchema.parse(raw);
4092
- }
4093
- var sectoolResultSchema = z4.object({
4094
- entityId: looseString,
4095
- entityType: looseString,
4096
- payload: looseRecord,
4097
- score: looseString,
4098
- securityResultEntityId: looseString,
4099
- securityResultEntityType: looseString,
4100
- statusCode: looseString,
4101
- statusDescription: looseString,
4102
- verdict: z4.unknown().transform((v) => typeof v === "string" ? v : "unknown")
4103
- }).passthrough().transform((raw) => ({
4104
- entityId: raw.entityId,
4105
- entityType: raw.entityType,
4106
- payload: raw.payload,
4107
- score: raw.score,
4108
- securityResultEntityId: raw.securityResultEntityId,
4109
- securityResultEntityType: raw.securityResultEntityType,
4110
- statusCode: raw.statusCode,
4111
- statusDescription: raw.statusDescription,
4112
- verdict: raw.verdict
4113
- }));
4114
- var engineResultsSchema = z4.array(sectoolResultSchema).nullish().transform((v) => orNull(v));
4115
- var entitySecurityResultSchema = z4.object({
4116
- combinedVerdict: looseRecord,
4117
- ap: engineResultsSchema,
4118
- dlp: engineResultsSchema,
4119
- clicktimeProtection: engineResultsSchema,
4120
- shadowIt: engineResultsSchema,
4121
- av: engineResultsSchema
4122
- }).passthrough().transform((raw) => ({
4123
- combinedVerdict: raw.combinedVerdict,
4124
- ap: raw.ap,
4125
- dlp: raw.dlp,
4126
- clicktimeProtection: raw.clicktimeProtection,
4127
- shadowIt: raw.shadowIt,
4128
- av: raw.av
4129
- }));
4130
- var entityActionSchema = z4.object({
4131
- entityActionName: z4.string(),
4132
- entityActionDate: looseString,
4133
- entityActionResponseCode: looseString,
4134
- entityActionResponseText: looseString,
4135
- entityActionState: looseString
4136
- }).passthrough().transform((raw) => ({
4137
- entityActionName: raw.entityActionName,
4138
- entityActionDate: raw.entityActionDate,
4139
- entityActionResponseCode: raw.entityActionResponseCode,
4140
- entityActionResponseText: raw.entityActionResponseText,
4141
- entityActionState: raw.entityActionState
4142
- }));
4143
- var entityInfoSchema = z4.object({
4144
- entityId: z4.string(),
4145
- customerId: looseString,
4146
- saas: looseString,
4147
- saasEntityType: looseString,
4148
- entityCreated: looseString,
4149
- entityUpdated: looseString,
4150
- entityActionState: looseString
4151
- }).passthrough().transform((raw) => ({
4152
- entityId: raw.entityId,
4153
- customerId: raw.customerId,
4154
- saas: raw.saas,
4155
- saasEntityType: raw.saasEntityType,
4156
- entityCreated: raw.entityCreated,
4157
- entityUpdated: raw.entityUpdated,
4158
- entityActionState: raw.entityActionState
4159
- }));
4160
- var entitySchema = z4.object({
4161
- entityInfo: entityInfoSchema,
4162
- saasInfo: looseRecord,
4163
- entityPayload: looseRecord,
4164
- entitySecurityResult: entitySecurityResultSchema.nullish().transform((v) => orNull(v)),
4165
- entityActions: z4.array(entityActionSchema).nullish(),
4166
- entityAvailableActions: z4.array(z4.string()).nullish()
4167
- }).passthrough().transform((raw) => ({
4168
- entityInfo: raw.entityInfo,
4169
- saasInfo: raw.saasInfo,
4170
- entityPayload: raw.entityPayload,
4171
- entitySecurityResult: raw.entitySecurityResult,
4172
- entityActions: raw.entityActions ?? [],
4173
- entityAvailableActions: raw.entityAvailableActions ?? []
4174
- }));
4175
- function toEntity(raw) {
4176
- return entitySchema.parse(raw);
4177
- }
4178
- function toEntitySummary(raw) {
4179
- const {
4180
- entityPayload: _payload,
4181
- saasInfo: _saasInfo,
4182
- ...rest
4183
- } = toEntity(raw);
4184
- return rest;
4185
- }
4186
- var TASK_STATUSES = [
4187
- "init",
4188
- "inprogress",
4189
- "completed",
4190
- "failed",
4191
- "stopped",
4192
- "paused"
4193
- ];
4194
- var taskSchema = z4.object({
4195
- taskId: z4.string(),
4196
- status: z4.enum(TASK_STATUSES),
4197
- actor: looseString,
4198
- startedAt: looseString,
4199
- finishedAt: looseString
4200
- }).passthrough().transform((raw) => ({
4201
- taskId: raw.taskId,
4202
- status: raw.status,
4203
- actor: raw.actor,
4204
- startedAt: raw.startedAt,
4205
- finishedAt: raw.finishedAt
4206
- }));
4207
- function toTask(raw) {
4208
- return taskSchema.parse(raw);
4209
- }
4210
- var EXCEPTION_TYPES = [
4211
- "whitelist",
4212
- "blacklist",
4213
- "spam_whitelist"
4214
- ];
4215
- var apExceptionSchema = z4.object({
4216
- id: z4.string(),
4217
- type: z4.enum(EXCEPTION_TYPES).nullish().transform((v) => orNull(v)),
4218
- value: looseString,
4219
- actor: looseString,
4220
- createdAt: looseString,
4221
- updatedAt: looseString
4222
- }).passthrough().transform((raw) => ({
4223
- id: raw.id,
4224
- type: raw.type,
4225
- value: raw.value,
4226
- actor: raw.actor,
4227
- createdAt: raw.createdAt,
4228
- updatedAt: raw.updatedAt
4229
- }));
4230
- function toApException(raw) {
4231
- return apExceptionSchema.parse(raw);
4232
- }
4233
-
4234
4521
  // src/tools/shared/session.ts
4235
4522
  function apiFor(serverModule2, extra) {
4236
4523
  return SessionContext.getAPIManager(
@@ -5299,6 +5586,7 @@ WHEN TO USE:
5299
5586
  PURPOSE:
5300
5587
  - \`whitelist\` always allows, \`blacklist\` always blocks, \`spam_whitelist\` allows through the spam filter only
5301
5588
  - Each entry can match by sender email, domain or IP, recipient, subject, link domain, or attachment hash
5589
+ - Each entry returns \`id\`, \`type\`, \`match\` (only the criteria that are set, each as {value, matching}; matching is exact, contains, endswith...), \`comment\`, \`actionNeeded\` (the verdict the entry applies, e.g. phishing), \`ignoringSpfCheck\`, \`actor\` (who last edited it) and \`updatedAt\`
5302
5590
  - Read-only`;
5303
5591
  var GET_DESCRIPTION = `Fetch one Anti-Phishing exception entry by id.
5304
5592
 
@@ -5306,7 +5594,8 @@ WHEN TO USE:
5306
5594
  - Drilling into a specific entry surfaced by \`list_ap_exceptions\`
5307
5595
 
5308
5596
  PURPOSE:
5309
- - \`exc_id\` is the entry id from \`list_ap_exceptions\`; \`exc_type\` must match the list it came from
5597
+ - \`exc_id\` is the entry \`id\` from \`list_ap_exceptions\`; \`exc_type\` must match the list it came from
5598
+ - Returns the same fields as a \`list_ap_exceptions\` entry
5310
5599
  - Read-only`;
5311
5600
  var excTypeSchema = z11.enum(EXCEPTION_TYPES).describe(
5312
5601
  "Which exception list to read: whitelist, blacklist or spam_whitelist."
@@ -5324,7 +5613,11 @@ function registerExceptionTools(server2, serverModule2) {
5324
5613
  args.exc_type,
5325
5614
  args.scope
5326
5615
  );
5327
- return { exceptions: rows.map(toApException) };
5616
+ return {
5617
+ exceptions: rows.map(
5618
+ (row) => toApException(row, args.exc_type)
5619
+ )
5620
+ };
5328
5621
  })
5329
5622
  );
5330
5623
  registerTool(
@@ -5343,7 +5636,8 @@ function registerExceptionTools(server2, serverModule2) {
5343
5636
  args.exc_type,
5344
5637
  args.exc_id,
5345
5638
  args.scope
5346
- )
5639
+ ),
5640
+ args.exc_type
5347
5641
  );
5348
5642
  })
5349
5643
  );
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chkp/harmony-email-mcp",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Email Security MCP Server - investigate email security events, entities and restore requests via the HEC SmartAPI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chkp/harmony-email-mcp",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Email Security MCP Server - investigate email security events, entities and restore requests via the HEC SmartAPI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json.bak CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chkp/harmony-email-mcp",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Email Security MCP Server - investigate email security events, entities and restore requests via the HEC SmartAPI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",