snow-flow 10.0.196 → 10.0.198

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/package.json +2 -1
  2. package/src/cli/cmd/tui/component/dialog-auth.tsx +18 -14
  3. package/src/servicenow/servicenow-mcp-unified/tools/automation/snow_execute_script.ts +67 -35
  4. package/src/servicenow/servicenow-mcp-unified/tools/index.ts +0 -18
  5. package/src/servicenow/servicenow-mcp-unified/tools/platform/snow_create_ui_policy.ts +25 -4
  6. package/src/servicenow/servicenow-mcp-unified/tools/security/snow_analyze_threat_intelligence.ts +2 -4
  7. package/src/servicenow/servicenow-mcp-unified/tools/security/snow_audit_trail_analysis.ts +1 -3
  8. package/src/servicenow/servicenow-mcp-unified/tools/security/snow_automate_threat_response.ts +2 -4
  9. package/src/servicenow/servicenow-mcp-unified/tools/security/snow_create_access_control.ts +2 -4
  10. package/src/servicenow/servicenow-mcp-unified/tools/security/snow_create_audit_rule.ts +1 -3
  11. package/src/servicenow/servicenow-mcp-unified/tools/ui-policies/link-ui-policy.ts +84 -0
  12. package/src/servicenow/servicenow-mcp-unified/tools/ui-policies/snow_create_ui_policy_action.ts +68 -31
  13. package/src/servicenow/shared/mcp-prompt-manager.ts +7 -7
  14. package/tsconfig.servicenow.json +20 -0
  15. package/src/servicenow/base-mcp-server.ts +0 -732
  16. package/src/servicenow/cli/auth.ts +0 -669
  17. package/src/servicenow/cli/deploy-artifact.ts +0 -304
  18. package/src/servicenow/cli/enterprise-refresh.ts +0 -93
  19. package/src/servicenow/cli/enterprise.ts +0 -446
  20. package/src/servicenow/cli/session.ts +0 -45
  21. package/src/servicenow/config/snow-code-config.ts +0 -154
  22. package/src/servicenow/index.ts +0 -126
  23. package/src/servicenow/mcp-config.ts +0 -157
  24. package/src/servicenow/servicenow-automation-mcp.ts +0 -2895
  25. package/src/servicenow/servicenow-change-virtualagent-pa-mcp-enhanced.ts +0 -974
  26. package/src/servicenow/servicenow-change-virtualagent-pa-mcp.ts +0 -1466
  27. package/src/servicenow/servicenow-cmdb-event-hr-csm-devops-mcp-enhanced.ts +0 -1311
  28. package/src/servicenow/servicenow-cmdb-event-hr-csm-devops-mcp.ts +0 -1616
  29. package/src/servicenow/servicenow-deployment-mcp.ts +0 -10306
  30. package/src/servicenow/servicenow-development-assistant-mcp.ts +0 -4925
  31. package/src/servicenow/servicenow-flow-workspace-mobile-mcp-enhanced.ts +0 -1038
  32. package/src/servicenow/servicenow-flow-workspace-mobile-mcp.ts +0 -4311
  33. package/src/servicenow/servicenow-integration-mcp.ts +0 -906
  34. package/src/servicenow/servicenow-itam-mcp.ts +0 -673
  35. package/src/servicenow/servicenow-knowledge-catalog-mcp-enhanced.ts +0 -836
  36. package/src/servicenow/servicenow-knowledge-catalog-mcp.ts +0 -1898
  37. package/src/servicenow/servicenow-local-development-mcp.ts +0 -629
  38. package/src/servicenow/servicenow-machine-learning-mcp.ts +0 -4095
  39. package/src/servicenow/servicenow-mcp-server.ts +0 -736
  40. package/src/servicenow/servicenow-mcp-unified/tools/ai-ml-MIGRATED/index.ts +0 -5
  41. package/src/servicenow/servicenow-mcp-unified/tools/ai-ml-MIGRATED/snow_predict.ts +0 -44
  42. package/src/servicenow/servicenow-mcp-unified/tools/ai-ml-MIGRATED/snow_train_classifier.ts +0 -46
  43. package/src/servicenow/servicenow-mcp-unified/tools/machine-learning-MIGRATED/README.md +0 -149
  44. package/src/servicenow/servicenow-mcp-unified/tools/machine-learning-MIGRATED/index.ts +0 -48
  45. package/src/servicenow/servicenow-mcp-unified/tools/machine-learning-MIGRATED/ml_classify_incident.ts +0 -197
  46. package/src/servicenow/servicenow-mcp-unified/tools/machine-learning-MIGRATED/ml_detect_anomalies.ts +0 -191
  47. package/src/servicenow/servicenow-mcp-unified/tools/machine-learning-MIGRATED/ml_forecast_incidents.ts +0 -273
  48. package/src/servicenow/servicenow-mcp-unified/tools/machine-learning-MIGRATED/ml_hybrid_recommendation.ts +0 -346
  49. package/src/servicenow/servicenow-mcp-unified/tools/machine-learning-MIGRATED/ml_performance_analytics.ts +0 -232
  50. package/src/servicenow/servicenow-mcp-unified/tools/machine-learning-MIGRATED/ml_predict_change_risk.ts +0 -186
  51. package/src/servicenow/servicenow-mcp-unified/tools/machine-learning-MIGRATED/ml_train_anomaly_detector.ts +0 -298
  52. package/src/servicenow/servicenow-mcp-unified/tools/machine-learning-MIGRATED/ml_train_change_risk.ts +0 -267
  53. package/src/servicenow/servicenow-mcp-unified/tools/machine-learning-MIGRATED/ml_train_incident_classifier.ts +0 -386
  54. package/src/servicenow/servicenow-mcp-unified/tools/script-includes/index.ts +0 -4
  55. package/src/servicenow/servicenow-mcp-unified/tools/ui-actions/index.ts +0 -4
  56. package/src/servicenow/servicenow-notifications-mcp.ts +0 -413
  57. package/src/servicenow/servicenow-operations-mcp.ts +0 -4041
  58. package/src/servicenow/servicenow-platform-development-mcp.ts +0 -1081
  59. package/src/servicenow/servicenow-progressive-indexer.ts +0 -366
  60. package/src/servicenow/servicenow-reporting-analytics-mcp.ts +0 -1485
  61. package/src/servicenow/servicenow-secops-mcp.ts +0 -690
  62. package/src/servicenow/servicenow-security-compliance-mcp.ts +0 -1267
  63. package/src/servicenow/servicenow-system-properties-mcp.ts +0 -1339
  64. package/src/servicenow/servicenow-update-set-mcp.ts +0 -964
  65. package/src/servicenow/shared/MCP-PROMPTS.md +0 -226
  66. package/src/servicenow/shared/agent-context-provider.ts +0 -354
  67. package/src/servicenow/shared/base-mcp-server.ts +0 -2570
  68. package/src/servicenow/shared/enhanced-base-mcp-server.ts +0 -387
  69. package/src/servicenow/shared/mcp-logger.ts +0 -269
  70. package/src/servicenow/shared/mcp-memory-manager.ts +0 -567
  71. package/src/servicenow/shared/mcp-resource-manager.ts +0 -367
  72. package/src/servicenow/shared/mcp-types.ts +0 -58
  73. package/src/servicenow/shared/reliable-memory-manager.ts +0 -315
  74. package/src/servicenow/shared/response-limiter.ts +0 -129
  75. package/src/servicenow/utils/dynamic-models.ts +0 -101
  76. package/src/servicenow/utils/logger.ts +0 -99
  77. package/src/servicenow/utils/memory-safe-collections.ts +0 -235
  78. package/src/servicenow/utils/servicenow-client.ts +0 -3530
  79. package/src/servicenow/utils/snow-oauth.ts +0 -1164
  80. package/src/servicenow/utils/sync-mcp-configs.ts +0 -114
  81. package/src/servicenow/utils/timer-registry.ts +0 -346
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "10.0.196",
3
+ "version": "10.0.198",
4
4
  "name": "snow-flow",
5
5
  "description": "Snow-Flow - ServiceNow Multi-Agent Development Framework powered by AI",
6
6
  "license": "Elastic-2.0",
7
7
  "private": false,
8
8
  "scripts": {
9
9
  "typecheck": "tsgo --noEmit",
10
+ "typecheck:servicenow": "tsgo --project tsconfig.servicenow.json --noEmit",
10
11
  "test": "bun test",
11
12
  "build": "bun run script/build.ts",
12
13
  "dev": "bun run --conditions=browser ./src/index.ts",
@@ -1105,31 +1105,35 @@ function DialogAuthEnterprise() {
1105
1105
  }),
1106
1106
  })
1107
1107
 
1108
- if (response.ok) {
1109
- data = await response.json()
1110
- break
1108
+ const responseData = await response.json().catch(() => ({}))
1109
+
1110
+ // 202 = pending approval, or explicit pending status
1111
+ const isPending = response.status === 202 || responseData.status === "pending" || responseData.error === "pending"
1112
+ if (isPending && attempt < maxAttempts) {
1113
+ toast.show({ variant: "info", message: `Waiting for browser approval... (${attempt}/${maxAttempts})`, duration: 2000 })
1114
+ await new Promise(r => setTimeout(r, 2000))
1115
+ continue
1111
1116
  }
1112
1117
 
1113
- const err = await response.json().catch(() => ({}))
1118
+ if (response.ok && !isPending) {
1119
+ data = responseData
1120
+ break
1121
+ }
1114
1122
 
1115
1123
  // Billing redirect — not retryable
1116
- if (err.billingUrl) {
1117
- toast.show({ variant: "error", message: err.message || err.error || "Subscription required", duration: 8000 })
1124
+ if (responseData.billingUrl) {
1125
+ toast.show({ variant: "error", message: responseData.message || responseData.error || "Subscription required", duration: 8000 })
1118
1126
  toast.show({ variant: "info", message: "Opening billing page...", duration: 4000 })
1119
- tryOpenBrowser(err.billingUrl)
1127
+ tryOpenBrowser(responseData.billingUrl)
1120
1128
  setStep("code")
1121
1129
  return
1122
1130
  }
1123
1131
 
1124
- // Pending approval — retry with status message
1125
- const isPending = err.error === "pending" || err.error === "Session not yet approved" || err.status === "pending"
1126
- if (isPending && attempt < maxAttempts) {
1127
- toast.show({ variant: "info", message: `Waiting for browser approval... (${attempt}/${maxAttempts})`, duration: 2000 })
1128
- await new Promise(r => setTimeout(r, 2000))
1129
- continue
1132
+ if (isPending) {
1133
+ throw new Error("Verification timed out please approve in your browser and try again")
1130
1134
  }
1131
1135
 
1132
- throw new Error(err.error || "Verification failed")
1136
+ throw new Error(responseData.error || "Verification failed")
1133
1137
  }
1134
1138
 
1135
1139
  if (!data) {
@@ -8,15 +8,15 @@
8
8
  * ES5 only! ServiceNow runs on Rhino engine.
9
9
  */
10
10
 
11
- import { MCPToolDefinition, ServiceNowContext, ToolResult } from "../../shared/types.js"
11
+ import type { MCPToolDefinition, ServiceNowContext, ToolResult } from "../../shared/types.js"
12
12
  import { getAuthenticatedClient } from "../../shared/auth.js"
13
13
  import { createSuccessResult, createErrorResult, SnowFlowError, ErrorType } from "../../shared/error-handler.js"
14
- import crypto from "crypto"
14
+ import { randomBytes } from "crypto"
15
15
 
16
16
  const ENDPOINT_SERVICE_ID = "snow_flow_exec"
17
17
  const ENDPOINT_PATH = "/execute"
18
18
 
19
- const deployed = new Map<string, boolean>()
19
+ const endpointCache = new Map<string, { namespace: string }>()
20
20
 
21
21
  const OPERATION_SCRIPT = `(function process(request, response) {
22
22
  var body = request.body.data;
@@ -213,53 +213,85 @@ export async function execute(args: Record<string, unknown>, context: ServiceNow
213
213
  }
214
214
  }
215
215
 
216
+ function getEndpointUrl(context: ServiceNowContext): string {
217
+ const cached = endpointCache.get(context.instanceUrl)
218
+ if (cached) return `/api/${cached.namespace}/${ENDPOINT_SERVICE_ID}${ENDPOINT_PATH}`
219
+ return `/api/${ENDPOINT_SERVICE_ID}${ENDPOINT_PATH}`
220
+ }
221
+
216
222
  async function ensureEndpoint(context: ServiceNowContext): Promise<boolean> {
217
- if (deployed.get(context.instanceUrl)) return true
223
+ if (endpointCache.has(context.instanceUrl)) return true
218
224
 
219
225
  const client = await getAuthenticatedClient(context)
220
226
 
221
227
  const check = await client.get("/api/now/table/sys_ws_definition", {
222
228
  params: {
223
229
  sysparm_query: `service_id=${ENDPOINT_SERVICE_ID}`,
224
- sysparm_fields: "sys_id",
230
+ sysparm_fields: "sys_id,namespace,base_uri",
225
231
  sysparm_limit: 1,
226
232
  },
227
233
  })
228
234
 
229
235
  const existing = check.data?.result?.[0]
230
- if (!existing) {
231
- const svc = await client.post("/api/now/table/sys_ws_definition", {
232
- name: "Snow-Flow Script Executor",
233
- service_id: ENDPOINT_SERVICE_ID,
234
- short_description: "Synchronous script execution endpoint for Snow-Flow",
235
- active: true,
236
- })
236
+ const svcId =
237
+ existing?.sys_id ||
238
+ (await (async () => {
239
+ const svc = await client.post("/api/now/table/sys_ws_definition", {
240
+ name: "Snow-Flow Script Executor",
241
+ service_id: ENDPOINT_SERVICE_ID,
242
+ short_description: "Synchronous script execution endpoint for Snow-Flow",
243
+ active: true,
244
+ })
237
245
 
238
- const svcId = svc.data?.result?.sys_id
239
- if (!svcId) return false
246
+ const id = svc.data?.result?.sys_id
247
+ if (!id) return null
240
248
 
241
- const res = await client.post("/api/now/table/sys_ws_operation", {
242
- name: "Execute Script",
243
- web_service_definition: svcId,
244
- http_method: "POST",
245
- relative_path: ENDPOINT_PATH,
246
- operation_script: OPERATION_SCRIPT,
247
- active: true,
248
- })
249
+ await client.post("/api/now/table/sys_ws_operation", {
250
+ name: "Execute Script",
251
+ web_service_definition: id,
252
+ http_method: "POST",
253
+ relative_path: ENDPOINT_PATH,
254
+ operation_script: OPERATION_SCRIPT,
255
+ active: true,
256
+ })
257
+
258
+ return id
259
+ })())
260
+
261
+ if (!svcId) return false
249
262
 
250
- if (!res.data?.result?.sys_id) return false
263
+ const svcRecord =
264
+ existing ||
265
+ (
266
+ await client
267
+ .get("/api/now/table/sys_ws_definition/" + svcId, {
268
+ params: { sysparm_fields: "namespace,base_uri" },
269
+ })
270
+ .catch(() => null)
271
+ )?.data?.result
272
+
273
+ const ns = svcRecord?.namespace || ""
274
+
275
+ const candidates = ns
276
+ ? [`/api/${ns}/${ENDPOINT_SERVICE_ID}${ENDPOINT_PATH}`, `/api/${ENDPOINT_SERVICE_ID}${ENDPOINT_PATH}`]
277
+ : [`/api/${ENDPOINT_SERVICE_ID}${ENDPOINT_PATH}`]
278
+
279
+ for (const url of candidates) {
280
+ const ping = await client.post(url, { script: "'pong'", execution_id: "deploy_verify" }).catch(() => null)
281
+
282
+ if (ping?.data?.result?.success === true) {
283
+ const parts = url.replace(`/${ENDPOINT_SERVICE_ID}${ENDPOINT_PATH}`, "").replace("/api/", "")
284
+ endpointCache.set(context.instanceUrl, { namespace: parts || ENDPOINT_SERVICE_ID })
285
+ return true
286
+ }
251
287
  }
252
288
 
253
- const ping = await client
254
- .post(`/api/${ENDPOINT_SERVICE_ID}${ENDPOINT_PATH}`, {
255
- script: "'pong'",
256
- execution_id: "deploy_verify",
257
- })
258
- .catch(() => null)
289
+ if (ns) {
290
+ endpointCache.set(context.instanceUrl, { namespace: ns })
291
+ return true
292
+ }
259
293
 
260
- const ok = ping?.data?.result?.success === true
261
- if (ok) deployed.set(context.instanceUrl, true)
262
- return ok
294
+ return false
263
295
  }
264
296
 
265
297
  async function executeViaSyncApi(
@@ -276,7 +308,7 @@ async function executeViaSyncApi(
276
308
  const client = await getAuthenticatedClient(context)
277
309
 
278
310
  const response = await client
279
- .post(`/api/${ENDPOINT_SERVICE_ID}${ENDPOINT_PATH}`, {
311
+ .post(getEndpointUrl(context), {
280
312
  script: params.script,
281
313
  execution_id: params.executionId,
282
314
  })
@@ -346,7 +378,7 @@ async function executeViaScheduler(
346
378
  const escape = (str: string) =>
347
379
  str.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r")
348
380
 
349
- const executionId = `exec_${Date.now()}_${crypto.randomBytes(6).toString("hex")}`
381
+ const executionId = `exec_${Date.now()}_${randomBytes(6).toString("hex")}`
350
382
  const marker = `SNOW_FLOW_EXEC_${executionId}`
351
383
 
352
384
  const wrapped = `
@@ -561,7 +593,7 @@ async function executeScript(
561
593
  },
562
594
  context: ServiceNowContext,
563
595
  ): Promise<ToolResult> {
564
- const executionId = `exec_${Date.now()}_${crypto.randomBytes(6).toString("hex")}`
596
+ const executionId = `exec_${Date.now()}_${randomBytes(6).toString("hex")}`
565
597
 
566
598
  const syncResult = await executeViaSyncApi({ ...params, executionId }, context)
567
599
  if (syncResult) return syncResult
@@ -56,9 +56,6 @@ export * from "./lists/index.js"
56
56
  // Business Rules (2 tools)
57
57
  export * from "./business-rules/index.js"
58
58
 
59
- // Script Includes (1 tool)
60
- export * from "./script-includes/index.js"
61
-
62
59
  // REST API tools moved to Integration folder (see snow_rest_message_manage, snow_create_rest_message)
63
60
 
64
61
  // SLA (2 tools)
@@ -94,9 +91,6 @@ export * from "./journals/index.js"
94
91
  // Data Policies (2 tools)
95
92
  export * from "./data-policies/index.js"
96
93
 
97
- // UI Actions (1 tool)
98
- export * from "./ui-actions/index.js"
99
-
100
94
  // Workspace (10 tools)
101
95
  export * from "./workspace/index.js"
102
96
 
@@ -187,9 +181,6 @@ export * from "./project/index.js"
187
181
  // Performance Analytics (3 tools)
188
182
  export * from "./performance-analytics/index.js"
189
183
 
190
- // Predictive Intelligence (5 tools)
191
- export * from "./predictive-intelligence/index.js"
192
-
193
184
  // Service Portal (3 tools)
194
185
  export * from "./service-portal/index.js"
195
186
 
@@ -217,12 +208,6 @@ export * from "./notifications/index.js"
217
208
  // Mobile (3 tools)
218
209
  export * from "./mobile/index.js"
219
210
 
220
- // AI & ML (3 tools)
221
- export * from "./ai-ml/index.js"
222
-
223
- // Machine Learning - TensorFlow.js Neural Networks (9 tools)
224
- export * from "./machine-learning/index.js"
225
-
226
211
  // ATF (Automated Test Framework) (6 tools)
227
212
  export * from "./atf/index.js"
228
213
 
@@ -244,9 +229,6 @@ export * from "./integration/index.js"
244
229
  // Platform (8 tools)
245
230
  export * from "./platform/index.js"
246
231
 
247
- // Monitoring (1 tool)
248
- export * from "./monitoring/index.js"
249
-
250
232
  // Blast Radius (5 tools)
251
233
  export * from "./blast-radius/index.js"
252
234
 
@@ -8,6 +8,7 @@
8
8
  import { MCPToolDefinition, ServiceNowContext, ToolResult } from "../../shared/types.js"
9
9
  import { getAuthenticatedClient } from "../../shared/auth.js"
10
10
  import { createSuccessResult, createErrorResult } from "../../shared/error-handler.js"
11
+ import { linkUiPolicyReference, verifyUiPolicyLink } from "../ui-policies/link-ui-policy.js"
11
12
 
12
13
  /**
13
14
  * Extract sys_id from API response - handles both string and object formats
@@ -129,6 +130,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
129
130
 
130
131
  // Create UI Policy Actions
131
132
  const createdActions = []
133
+ const unlinkableActions: string[] = []
132
134
  for (const action of actions) {
133
135
  const actionData: any = {
134
136
  ui_policy: policySysId,
@@ -140,10 +142,20 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
140
142
  }
141
143
 
142
144
  const actionResponse = await client.post("/api/now/table/sys_ui_policy_action", actionData)
143
- createdActions.push(actionResponse.data.result)
145
+ const actionResult = actionResponse.data.result
146
+ const actionSysId = extractSysId(actionResult.sys_id)
147
+
148
+ // Verify ui_policy link; if POST didn't set it, use fallback chain
149
+ const alreadyLinked = await verifyUiPolicyLink(client, actionSysId, policySysId)
150
+ if (!alreadyLinked) {
151
+ const linked = await linkUiPolicyReference(client, actionSysId, policySysId)
152
+ if (!linked) unlinkableActions.push(action.field_name)
153
+ }
154
+
155
+ createdActions.push(actionResult)
144
156
  }
145
157
 
146
- return createSuccessResult({
158
+ const result: Record<string, any> = {
147
159
  created: true,
148
160
  ui_policy: {
149
161
  sys_id: policySysId,
@@ -161,7 +173,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
161
173
  mandatory: action.mandatory === "true",
162
174
  readonly: action.readonly === "true",
163
175
  cleared: action.cleared === "true",
164
- ui_policy_reference: policySysId,
176
+ ui_policy_linked: !unlinkableActions.includes(action.field),
165
177
  })),
166
178
  total_actions: createdActions.length,
167
179
  best_practices: [
@@ -171,7 +183,16 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
171
183
  "Order matters when multiple policies affect same field",
172
184
  "Test with different user roles and data",
173
185
  ],
174
- })
186
+ }
187
+
188
+ if (unlinkableActions.length > 0) {
189
+ result.warning =
190
+ "Some actions could not be linked to the UI policy: " +
191
+ unlinkableActions.join(", ") +
192
+ ". Link them manually in the ServiceNow UI."
193
+ }
194
+
195
+ return createSuccessResult(result)
175
196
  } catch (error: any) {
176
197
  return createErrorResult(error.message)
177
198
  }
@@ -1,6 +1,4 @@
1
1
  import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js"
2
- import type { ServiceNowClient } from "../../../../utils/servicenow-client.js"
3
- import type { MCPLogger } from "../../../shared/mcp-logger.js"
4
2
  import { MCPToolDefinition, ToolResult } from "../../shared/types.js"
5
3
  import { ServiceNowContext } from "../../shared/types.js"
6
4
 
@@ -66,8 +64,8 @@ export interface AnalyzeThreatIntelligenceArgs {
66
64
 
67
65
  export async function analyzeThreatIntelligence(
68
66
  args: AnalyzeThreatIntelligenceArgs,
69
- client: ServiceNowClient,
70
- logger: MCPLogger,
67
+ client: any,
68
+ logger: any,
71
69
  ) {
72
70
  try {
73
71
  const { ioc_value, ioc_type, threat_feed_sources = [], correlation_timeframe = "24_hours" } = args
@@ -1,6 +1,4 @@
1
1
  import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js"
2
- import type { ServiceNowClient } from "../../../../utils/servicenow-client.js"
3
- import type { MCPLogger } from "../../../shared/mcp-logger.js"
4
2
  import { MCPToolDefinition, ToolResult, ServiceNowContext } from "../../shared/types.js"
5
3
 
6
4
  export const toolDefinition: MCPToolDefinition = {
@@ -63,7 +61,7 @@ export interface AuditTrailAnalysisArgs {
63
61
  exportFormat?: "json" | "csv" | "pdf"
64
62
  }
65
63
 
66
- export async function auditTrailAnalysis(args: AuditTrailAnalysisArgs, client: ServiceNowClient, logger: MCPLogger) {
64
+ export async function auditTrailAnalysis(args: AuditTrailAnalysisArgs, client: any, logger: any) {
67
65
  try {
68
66
  const timeframe = args.timeframe || "24h"
69
67
  let query = ""
@@ -1,6 +1,4 @@
1
1
  import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js"
2
- import type { ServiceNowClient } from "../../../../utils/servicenow-client.js"
3
- import type { MCPLogger } from "../../../shared/mcp-logger.js"
4
2
  import { MCPToolDefinition, ToolResult, ServiceNowContext } from "../../shared/types.js"
5
3
 
6
4
  export const toolDefinition: MCPToolDefinition = {
@@ -64,8 +62,8 @@ export interface AutomateThreatResponseArgs {
64
62
 
65
63
  export async function automateThreatResponse(
66
64
  args: AutomateThreatResponseArgs,
67
- client: ServiceNowClient,
68
- logger: MCPLogger,
65
+ client: any,
66
+ logger: any,
69
67
  ) {
70
68
  try {
71
69
  const { threat_id, response_level, automated_actions = false, notification_groups = [] } = args
@@ -1,6 +1,4 @@
1
1
  import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js"
2
- import type { ServiceNowClient } from "../../../../utils/servicenow-client.js"
3
- import type { MCPLogger } from "../../../shared/mcp-logger.js"
4
2
  import { MCPToolDefinition, ToolResult, ServiceNowContext } from "../../shared/types.js"
5
3
 
6
4
  export const toolDefinition: MCPToolDefinition = {
@@ -76,7 +74,7 @@ export interface CreateAccessControlArgs {
76
74
  active?: boolean
77
75
  }
78
76
 
79
- export async function createAccessControl(args: CreateAccessControlArgs, client: ServiceNowClient, logger: MCPLogger) {
77
+ export async function createAccessControl(args: CreateAccessControlArgs, client: any, logger: any) {
80
78
  try {
81
79
  logger.info("Creating Access Control...")
82
80
 
@@ -118,7 +116,7 @@ export async function createAccessControl(args: CreateAccessControlArgs, client:
118
116
 
119
117
  async function getTableInfo(
120
118
  tableName: string,
121
- client: ServiceNowClient,
119
+ client: any,
122
120
  ): Promise<{ name: string; label: string } | null> {
123
121
  try {
124
122
  const tableResponse = await client.searchRecords("sys_db_object", `name=${tableName}`, 1)
@@ -1,6 +1,4 @@
1
1
  import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js"
2
- import type { ServiceNowClient } from "../../../../utils/servicenow-client.js"
3
- import type { MCPLogger } from "../../../shared/mcp-logger.js"
4
2
  import { MCPToolDefinition, ToolResult, ServiceNowContext } from "../../shared/types.js"
5
3
 
6
4
  export const toolDefinition: MCPToolDefinition = {
@@ -79,7 +77,7 @@ export interface CreateAuditRuleArgs {
79
77
  active?: boolean
80
78
  }
81
79
 
82
- export async function createAuditRule(args: CreateAuditRuleArgs, client: ServiceNowClient, logger: MCPLogger) {
80
+ export async function createAuditRule(args: CreateAuditRuleArgs, client: any, logger: any) {
83
81
  try {
84
82
  logger.info("Creating Audit Rule...")
85
83
 
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Shared helper to link a sys_ui_policy_action record to its parent UI policy.
3
+ *
4
+ * ServiceNow's REST Table API POST silently ignores the "ui_policy" reference
5
+ * field on sys_ui_policy_action during creation. This module provides a
6
+ * cascading fallback (PATCH → PUT → GlideRecord) to set the reference after
7
+ * the record has been created.
8
+ */
9
+
10
+ import type { AxiosInstance } from "axios"
11
+
12
+ /**
13
+ * Verify that the ui_policy reference field is set on a sys_ui_policy_action record.
14
+ */
15
+ export async function verifyUiPolicyLink(
16
+ client: AxiosInstance,
17
+ actionSysId: string,
18
+ expectedSysId: string,
19
+ ): Promise<boolean> {
20
+ try {
21
+ const res = await client.get(
22
+ "/api/now/table/sys_ui_policy_action/" + actionSysId + "?sysparm_fields=ui_policy",
23
+ )
24
+ const ref = res.data.result?.ui_policy
25
+ const val = typeof ref === "object" && ref !== null ? ref.value : ref
26
+ return !!val && val !== "" && val === expectedSysId
27
+ } catch {
28
+ return false
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Attempt to link a sys_ui_policy_action record to its parent UI policy using
34
+ * a cascading fallback chain:
35
+ * Tier 1 — PATCH (standard Table API update)
36
+ * Tier 2 — PUT (full record update)
37
+ * Tier 3 — GlideRecord via Scripted REST endpoint (last resort)
38
+ *
39
+ * Returns true if the link was successfully set and verified.
40
+ */
41
+ export async function linkUiPolicyReference(
42
+ client: AxiosInstance,
43
+ actionSysId: string,
44
+ uiPolicySysId: string,
45
+ ): Promise<boolean> {
46
+ const url = "/api/now/table/sys_ui_policy_action/" + actionSysId
47
+ const body = { ui_policy: uiPolicySysId }
48
+
49
+ // Tier 1: PATCH
50
+ try {
51
+ await client.patch(url, body)
52
+ if (await verifyUiPolicyLink(client, actionSysId, uiPolicySysId)) return true
53
+ } catch {
54
+ // fall through
55
+ }
56
+
57
+ // Tier 2: PUT
58
+ try {
59
+ await client.put(url, body)
60
+ if (await verifyUiPolicyLink(client, actionSysId, uiPolicySysId)) return true
61
+ } catch {
62
+ // fall through
63
+ }
64
+
65
+ // Tier 3: GlideRecord via Scripted REST endpoint
66
+ try {
67
+ const script =
68
+ "var gr = new GlideRecord('sys_ui_policy_action');\n" +
69
+ "gr.get('" + actionSysId + "');\n" +
70
+ "gr.setValue('ui_policy', '" + uiPolicySysId + "');\n" +
71
+ "gr.update();\n" +
72
+ "gs.print(gr.getValue('ui_policy'));"
73
+
74
+ await client.post("/api/snow_flow_exec/execute", {
75
+ script,
76
+ execution_id: "link_ui_policy_" + actionSysId,
77
+ })
78
+ if (await verifyUiPolicyLink(client, actionSysId, uiPolicySysId)) return true
79
+ } catch {
80
+ // all tiers exhausted
81
+ }
82
+
83
+ return false
84
+ }