@lexq/cli 0.1.59 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +5 -0
- package/README.md +1 -1
- package/dist/index.js +367 -366
- package/dist/mcp/register.d.ts +1 -1
- package/dist/mcp/register.js +365 -364
- package/package.json +7 -4
package/dist/mcp/register.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
// src/mcp/tools/status.ts
|
|
2
|
+
import { z } from "zod";
|
|
2
3
|
function registerStatusTools(server, callApi) {
|
|
3
4
|
server.registerTool(
|
|
4
5
|
"lexq_whoami",
|
|
5
6
|
{
|
|
6
7
|
title: "Who Am I",
|
|
7
8
|
description: "Show current authentication info (tenant ID, user ID, role).",
|
|
8
|
-
inputSchema: {}
|
|
9
|
+
inputSchema: z.object({})
|
|
9
10
|
},
|
|
10
11
|
async () => callApi("GET", "whoami")
|
|
11
12
|
);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
// src/mcp/tools/groups.ts
|
|
15
|
-
import { z } from "zod";
|
|
16
|
+
import { z as z2 } from "zod";
|
|
16
17
|
|
|
17
18
|
// src/types/enums.ts
|
|
18
19
|
var ValueType = ["STRING", "NUMBER", "BOOLEAN", "LIST_STRING", "LIST_NUMBER"];
|
|
@@ -39,7 +40,7 @@ function registerGroupTools(server, callApi) {
|
|
|
39
40
|
{
|
|
40
41
|
title: "List Policy Groups",
|
|
41
42
|
description: "List all policy groups (tenant-wide, priority ASC).",
|
|
42
|
-
inputSchema: {}
|
|
43
|
+
inputSchema: z2.object({})
|
|
43
44
|
},
|
|
44
45
|
async () => callApi("GET", "policy-groups")
|
|
45
46
|
);
|
|
@@ -48,9 +49,9 @@ function registerGroupTools(server, callApi) {
|
|
|
48
49
|
{
|
|
49
50
|
title: "Get Policy Group",
|
|
50
51
|
description: "Get a single policy group by ID.",
|
|
51
|
-
inputSchema: {
|
|
52
|
-
groupId:
|
|
53
|
-
}
|
|
52
|
+
inputSchema: z2.object({
|
|
53
|
+
groupId: z2.string().uuid().describe("Policy group ID")
|
|
54
|
+
})
|
|
54
55
|
},
|
|
55
56
|
async ({ groupId }) => callApi("GET", `policy-groups/${groupId}`)
|
|
56
57
|
);
|
|
@@ -59,18 +60,18 @@ function registerGroupTools(server, callApi) {
|
|
|
59
60
|
{
|
|
60
61
|
title: "Create Policy Group",
|
|
61
62
|
description: "Create a new policy group. Requires name. Priority is auto-assigned (appended last, tenant-wide); use lexq_groups_reorder to change order. Optionally set conflict resolution, activation group, and description. Policy groups that share an activationGroup form a cluster and must share the same activationMode / activationStrategy / executionLimit; executionLimit is how many of those groups run, not how many rules.",
|
|
62
|
-
inputSchema: {
|
|
63
|
-
name:
|
|
64
|
-
description:
|
|
65
|
-
activationMode:
|
|
66
|
-
activationStrategy:
|
|
67
|
-
executionLimit:
|
|
63
|
+
inputSchema: z2.object({
|
|
64
|
+
name: z2.string().describe("Group name (unique among non-ARCHIVED)"),
|
|
65
|
+
description: z2.string().optional().describe("Group description"),
|
|
66
|
+
activationMode: z2.enum(ConflictResolutionMode).optional().describe("Conflict resolution mode"),
|
|
67
|
+
activationStrategy: z2.enum(ConflictResolutionStrategy).optional().describe("Ranking used to pick the winning groups when mode is EXCLUSIVE or MAX_N"),
|
|
68
|
+
executionLimit: z2.number().int().min(1).optional().describe(
|
|
68
69
|
"How many policy groups sharing this activationGroup may run (required when mode is MAX_N). Counts groups, not rules: every rule of a winning group runs."
|
|
69
70
|
),
|
|
70
|
-
activationGroup:
|
|
71
|
+
activationGroup: z2.string().optional().describe(
|
|
71
72
|
"Activation group (Execution Group) cluster key. Policy groups sharing this key compete, and group priority picks the winners."
|
|
72
73
|
)
|
|
73
|
-
}
|
|
74
|
+
})
|
|
74
75
|
},
|
|
75
76
|
async (args) => {
|
|
76
77
|
const body = {
|
|
@@ -89,20 +90,20 @@ function registerGroupTools(server, callApi) {
|
|
|
89
90
|
{
|
|
90
91
|
title: "Update Policy Group",
|
|
91
92
|
description: "Update a policy group. Only provided fields are updated; omitted fields remain unchanged.",
|
|
92
|
-
inputSchema: {
|
|
93
|
-
groupId:
|
|
94
|
-
name:
|
|
95
|
-
description:
|
|
96
|
-
status:
|
|
97
|
-
activationGroup:
|
|
93
|
+
inputSchema: z2.object({
|
|
94
|
+
groupId: z2.string().uuid().describe("Policy group ID"),
|
|
95
|
+
name: z2.string().optional().describe("New name"),
|
|
96
|
+
description: z2.string().optional().describe("New description"),
|
|
97
|
+
status: z2.enum(["ACTIVE", "DISABLED"]).optional().describe("Status (DISABLED = emergency stop)"),
|
|
98
|
+
activationGroup: z2.string().optional().describe(
|
|
98
99
|
"Activation group (Execution Group) cluster key. Policy groups sharing this key compete, and group priority picks the winners."
|
|
99
100
|
),
|
|
100
|
-
activationMode:
|
|
101
|
-
activationStrategy:
|
|
102
|
-
executionLimit:
|
|
101
|
+
activationMode: z2.enum(ConflictResolutionMode).optional().describe("Conflict resolution mode"),
|
|
102
|
+
activationStrategy: z2.enum(ConflictResolutionStrategy).optional().describe("Ranking used to pick the winning groups"),
|
|
103
|
+
executionLimit: z2.number().int().min(1).optional().describe(
|
|
103
104
|
"How many policy groups sharing this activationGroup may run. Counts groups, not rules."
|
|
104
105
|
)
|
|
105
|
-
}
|
|
106
|
+
})
|
|
106
107
|
},
|
|
107
108
|
async ({ groupId, ...body }) => callApi("PUT", `policy-groups/${groupId}`, { body })
|
|
108
109
|
);
|
|
@@ -111,9 +112,9 @@ function registerGroupTools(server, callApi) {
|
|
|
111
112
|
{
|
|
112
113
|
title: "Delete Policy Group",
|
|
113
114
|
description: "Archive a policy group. Only non-live groups can be deleted. This is irreversible.",
|
|
114
|
-
inputSchema: {
|
|
115
|
-
groupId:
|
|
116
|
-
}
|
|
115
|
+
inputSchema: z2.object({
|
|
116
|
+
groupId: z2.string().uuid().describe("Policy group ID")
|
|
117
|
+
})
|
|
117
118
|
},
|
|
118
119
|
async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}`)
|
|
119
120
|
);
|
|
@@ -122,9 +123,9 @@ function registerGroupTools(server, callApi) {
|
|
|
122
123
|
{
|
|
123
124
|
title: "Reorder Policy Groups",
|
|
124
125
|
description: "Reorder policy groups by priority. Priority is tenant-wide and flat (1...N continuous); array index 0 = priority 1 (highest precedence). activationGroup is not affected \u2014 this only changes priority.",
|
|
125
|
-
inputSchema: {
|
|
126
|
-
groupIds:
|
|
127
|
-
}
|
|
126
|
+
inputSchema: z2.object({
|
|
127
|
+
groupIds: z2.array(z2.string().uuid()).describe("Group IDs in desired priority order (index 0 = priority 1)")
|
|
128
|
+
})
|
|
128
129
|
},
|
|
129
130
|
async ({ groupIds }) => {
|
|
130
131
|
const groups = groupIds.map((groupId, index) => ({
|
|
@@ -139,11 +140,11 @@ function registerGroupTools(server, callApi) {
|
|
|
139
140
|
{
|
|
140
141
|
title: "Start A/B Test",
|
|
141
142
|
description: "Start an A/B test on a policy group. Requires a challenger version ID and traffic rate. The split is computed from context.trafficKey on each execution request; requests that omit it never reach the challenger and the test stays at 0%.",
|
|
142
|
-
inputSchema: {
|
|
143
|
-
groupId:
|
|
144
|
-
testVersionId:
|
|
145
|
-
trafficRate:
|
|
146
|
-
}
|
|
143
|
+
inputSchema: z2.object({
|
|
144
|
+
groupId: z2.string().uuid().describe("Policy group ID"),
|
|
145
|
+
testVersionId: z2.string().uuid().describe("Challenger version ID to test"),
|
|
146
|
+
trafficRate: z2.number().int().min(1).max(99).describe("Traffic percentage routed to challenger (1-99)")
|
|
147
|
+
})
|
|
147
148
|
},
|
|
148
149
|
async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test`, { body })
|
|
149
150
|
);
|
|
@@ -152,9 +153,9 @@ function registerGroupTools(server, callApi) {
|
|
|
152
153
|
{
|
|
153
154
|
title: "Stop A/B Test",
|
|
154
155
|
description: "Stop a running A/B test. All traffic is restored to the control (current) version.",
|
|
155
|
-
inputSchema: {
|
|
156
|
-
groupId:
|
|
157
|
-
}
|
|
156
|
+
inputSchema: z2.object({
|
|
157
|
+
groupId: z2.string().uuid().describe("Policy group ID")
|
|
158
|
+
})
|
|
158
159
|
},
|
|
159
160
|
async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}/ab-test`)
|
|
160
161
|
);
|
|
@@ -163,17 +164,17 @@ function registerGroupTools(server, callApi) {
|
|
|
163
164
|
{
|
|
164
165
|
title: "Adjust A/B Test",
|
|
165
166
|
description: "Adjust traffic rate of a running A/B test.",
|
|
166
|
-
inputSchema: {
|
|
167
|
-
groupId:
|
|
168
|
-
trafficRate:
|
|
169
|
-
}
|
|
167
|
+
inputSchema: z2.object({
|
|
168
|
+
groupId: z2.string().uuid().describe("Policy group ID"),
|
|
169
|
+
trafficRate: z2.number().int().min(1).max(99).describe("New traffic percentage for challenger (1-99)")
|
|
170
|
+
})
|
|
170
171
|
},
|
|
171
172
|
async ({ groupId, ...body }) => callApi("PATCH", `policy-groups/${groupId}/ab-test/traffic-rate`, { body })
|
|
172
173
|
);
|
|
173
174
|
}
|
|
174
175
|
|
|
175
176
|
// src/mcp/tools/versions.ts
|
|
176
|
-
import { z as
|
|
177
|
+
import { z as z3 } from "zod";
|
|
177
178
|
|
|
178
179
|
// src/lib/config.ts
|
|
179
180
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
@@ -238,11 +239,11 @@ function registerVersionTools(server, callApi) {
|
|
|
238
239
|
{
|
|
239
240
|
title: "List Policy Versions",
|
|
240
241
|
description: "List all versions of a policy group.",
|
|
241
|
-
inputSchema: {
|
|
242
|
-
groupId:
|
|
243
|
-
page:
|
|
244
|
-
size:
|
|
245
|
-
}
|
|
242
|
+
inputSchema: z3.object({
|
|
243
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
244
|
+
page: z3.number().int().min(0).default(0).describe("Page number"),
|
|
245
|
+
size: z3.number().int().min(1).max(100).default(20).describe("Page size")
|
|
246
|
+
})
|
|
246
247
|
},
|
|
247
248
|
async ({ groupId, page, size }) => callApi("GET", `policy-groups/${groupId}/versions`, {
|
|
248
249
|
params: paginationParams(page, size)
|
|
@@ -253,10 +254,10 @@ function registerVersionTools(server, callApi) {
|
|
|
253
254
|
{
|
|
254
255
|
title: "Get Policy Version",
|
|
255
256
|
description: "Get a single version by ID, including its rules and fact requirements.",
|
|
256
|
-
inputSchema: {
|
|
257
|
-
groupId:
|
|
258
|
-
versionId:
|
|
259
|
-
}
|
|
257
|
+
inputSchema: z3.object({
|
|
258
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
259
|
+
versionId: z3.string().uuid().describe("Version ID")
|
|
260
|
+
})
|
|
260
261
|
},
|
|
261
262
|
async ({ groupId, versionId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}`)
|
|
262
263
|
);
|
|
@@ -265,12 +266,12 @@ function registerVersionTools(server, callApi) {
|
|
|
265
266
|
{
|
|
266
267
|
title: "Create Policy Version",
|
|
267
268
|
description: "Create a new DRAFT version in a policy group. Optionally provide a commit message and effective date range.",
|
|
268
|
-
inputSchema: {
|
|
269
|
-
groupId:
|
|
270
|
-
commitMessage:
|
|
271
|
-
effectiveFrom:
|
|
272
|
-
effectiveTo:
|
|
273
|
-
}
|
|
269
|
+
inputSchema: z3.object({
|
|
270
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
271
|
+
commitMessage: z3.string().optional().describe("Commit message describing this version"),
|
|
272
|
+
effectiveFrom: z3.string().optional().describe("Effective start date (ISO 8601)"),
|
|
273
|
+
effectiveTo: z3.string().optional().describe("Effective end date (ISO 8601)")
|
|
274
|
+
})
|
|
274
275
|
},
|
|
275
276
|
async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/versions`, { body })
|
|
276
277
|
);
|
|
@@ -279,13 +280,13 @@ function registerVersionTools(server, callApi) {
|
|
|
279
280
|
{
|
|
280
281
|
title: "Update Policy Version",
|
|
281
282
|
description: "Update a DRAFT version. Only DRAFT versions can be modified. Only provided fields are changed.",
|
|
282
|
-
inputSchema: {
|
|
283
|
-
groupId:
|
|
284
|
-
versionId:
|
|
285
|
-
commitMessage:
|
|
286
|
-
effectiveFrom:
|
|
287
|
-
effectiveTo:
|
|
288
|
-
}
|
|
283
|
+
inputSchema: z3.object({
|
|
284
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
285
|
+
versionId: z3.string().uuid().describe("Version ID"),
|
|
286
|
+
commitMessage: z3.string().optional().describe("New commit message"),
|
|
287
|
+
effectiveFrom: z3.string().optional().describe("New effective start date"),
|
|
288
|
+
effectiveTo: z3.string().optional().describe("New effective end date")
|
|
289
|
+
})
|
|
289
290
|
},
|
|
290
291
|
async ({ groupId, versionId, ...body }) => callApi("PUT", `policy-groups/${groupId}/versions/${versionId}`, { body })
|
|
291
292
|
);
|
|
@@ -294,10 +295,10 @@ function registerVersionTools(server, callApi) {
|
|
|
294
295
|
{
|
|
295
296
|
title: "Delete Policy Version",
|
|
296
297
|
description: "Delete a DRAFT version. Only DRAFT versions can be deleted.",
|
|
297
|
-
inputSchema: {
|
|
298
|
-
groupId:
|
|
299
|
-
versionId:
|
|
300
|
-
}
|
|
298
|
+
inputSchema: z3.object({
|
|
299
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
300
|
+
versionId: z3.string().uuid().describe("Version ID")
|
|
301
|
+
})
|
|
301
302
|
},
|
|
302
303
|
async ({ groupId, versionId }) => callApi("DELETE", `policy-groups/${groupId}/versions/${versionId}`)
|
|
303
304
|
);
|
|
@@ -306,10 +307,10 @@ function registerVersionTools(server, callApi) {
|
|
|
306
307
|
{
|
|
307
308
|
title: "Clone Policy Version",
|
|
308
309
|
description: "Clone an existing version to create a new DRAFT. Useful when the source version is already published.",
|
|
309
|
-
inputSchema: {
|
|
310
|
-
groupId:
|
|
311
|
-
versionId:
|
|
312
|
-
}
|
|
310
|
+
inputSchema: z3.object({
|
|
311
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
312
|
+
versionId: z3.string().uuid().describe("Source version ID to clone")
|
|
313
|
+
})
|
|
313
314
|
},
|
|
314
315
|
async ({ groupId, versionId }) => {
|
|
315
316
|
return callApi("POST", `policy-groups/${groupId}/versions/${versionId}/clone`, {
|
|
@@ -331,7 +332,7 @@ var MIN_COHORT_SIZE = 3;
|
|
|
331
332
|
var PROFILE_DEFAULT_WINDOW_HOURS = 24;
|
|
332
333
|
|
|
333
334
|
// src/mcp/tools/rules.ts
|
|
334
|
-
import { z as
|
|
335
|
+
import { z as z4 } from "zod";
|
|
335
336
|
import dedent from "dedent";
|
|
336
337
|
function registerRuleTools(server, callApi) {
|
|
337
338
|
server.registerTool(
|
|
@@ -339,10 +340,10 @@ function registerRuleTools(server, callApi) {
|
|
|
339
340
|
{
|
|
340
341
|
title: "List Rules",
|
|
341
342
|
description: "List all rules in a version (priority ASC). Returns summary with conditionSummary and actionSummary.",
|
|
342
|
-
inputSchema: {
|
|
343
|
-
groupId:
|
|
344
|
-
versionId:
|
|
345
|
-
}
|
|
343
|
+
inputSchema: z4.object({
|
|
344
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
345
|
+
versionId: z4.string().uuid().describe("Version ID")
|
|
346
|
+
})
|
|
346
347
|
},
|
|
347
348
|
async ({ groupId, versionId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules`)
|
|
348
349
|
);
|
|
@@ -351,11 +352,11 @@ function registerRuleTools(server, callApi) {
|
|
|
351
352
|
{
|
|
352
353
|
title: "Get Rule Detail",
|
|
353
354
|
description: "Get full rule detail including condition tree and action definitions.",
|
|
354
|
-
inputSchema: {
|
|
355
|
-
groupId:
|
|
356
|
-
versionId:
|
|
357
|
-
ruleId:
|
|
358
|
-
}
|
|
355
|
+
inputSchema: z4.object({
|
|
356
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
357
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
358
|
+
ruleId: z4.string().uuid().describe("Rule ID")
|
|
359
|
+
})
|
|
359
360
|
},
|
|
360
361
|
async ({ groupId, versionId, ruleId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`)
|
|
361
362
|
);
|
|
@@ -424,13 +425,13 @@ function registerRuleTools(server, callApi) {
|
|
|
424
425
|
|
|
425
426
|
RoundingOption (optional, MUTATE_FACT only): { scale: integer (0..${MAX_ROUNDING_SCALE}), mode?: "HALF_UP"|"HALF_DOWN"|"HALF_EVEN"|"FLOOR"|"CEILING"|"DOWN"|"UP" } mode defaults to HALF_UP. When omitted, calculator output is preserved at full precision (lossless).
|
|
426
427
|
`,
|
|
427
|
-
inputSchema: {
|
|
428
|
-
groupId:
|
|
429
|
-
versionId:
|
|
430
|
-
rule:
|
|
428
|
+
inputSchema: z4.object({
|
|
429
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
430
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
431
|
+
rule: z4.string().describe(
|
|
431
432
|
"JSON string of CreateRuleRequest: { name, condition, actions, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
|
|
432
433
|
)
|
|
433
|
-
}
|
|
434
|
+
})
|
|
434
435
|
},
|
|
435
436
|
async ({ groupId, versionId, rule }) => {
|
|
436
437
|
const body = parseJson(rule);
|
|
@@ -442,14 +443,14 @@ function registerRuleTools(server, callApi) {
|
|
|
442
443
|
{
|
|
443
444
|
title: "Update Rule",
|
|
444
445
|
description: "Update an existing rule in a DRAFT version. Only provided fields are changed.",
|
|
445
|
-
inputSchema: {
|
|
446
|
-
groupId:
|
|
447
|
-
versionId:
|
|
448
|
-
ruleId:
|
|
449
|
-
rule:
|
|
446
|
+
inputSchema: z4.object({
|
|
447
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
448
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
449
|
+
ruleId: z4.string().uuid().describe("Rule ID"),
|
|
450
|
+
rule: z4.string().describe(
|
|
450
451
|
"JSON string of UpdateRuleRequest: { name?, condition?, actions?, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
|
|
451
452
|
)
|
|
452
|
-
}
|
|
453
|
+
})
|
|
453
454
|
},
|
|
454
455
|
async ({ groupId, versionId, ruleId, rule }) => {
|
|
455
456
|
const body = parseJson(rule);
|
|
@@ -463,12 +464,12 @@ function registerRuleTools(server, callApi) {
|
|
|
463
464
|
{
|
|
464
465
|
title: "Delete Rule",
|
|
465
466
|
description: "Delete a rule from a DRAFT version.",
|
|
466
|
-
inputSchema: {
|
|
467
|
-
groupId:
|
|
468
|
-
versionId:
|
|
469
|
-
ruleId:
|
|
470
|
-
force:
|
|
471
|
-
}
|
|
467
|
+
inputSchema: z4.object({
|
|
468
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
469
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
470
|
+
ruleId: z4.string().uuid().describe("Rule ID"),
|
|
471
|
+
force: z4.boolean().default(false).describe("Skip confirmation (for the last rule in a version)")
|
|
472
|
+
})
|
|
472
473
|
},
|
|
473
474
|
async ({ groupId, versionId, ruleId, force }) => {
|
|
474
475
|
const params = {};
|
|
@@ -483,11 +484,11 @@ function registerRuleTools(server, callApi) {
|
|
|
483
484
|
{
|
|
484
485
|
title: "Reorder Rules",
|
|
485
486
|
description: "Reorder rules by specifying rule IDs in desired order. Priorities are assigned 1...N (1-based, continuous); array index 0 = priority 1 (highest precedence).",
|
|
486
|
-
inputSchema: {
|
|
487
|
-
groupId:
|
|
488
|
-
versionId:
|
|
489
|
-
ruleIds:
|
|
490
|
-
}
|
|
487
|
+
inputSchema: z4.object({
|
|
488
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
489
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
490
|
+
ruleIds: z4.array(z4.string().uuid()).describe("Rule IDs in desired priority order")
|
|
491
|
+
})
|
|
491
492
|
},
|
|
492
493
|
async ({ groupId, versionId, ruleIds }) => {
|
|
493
494
|
const rules = ruleIds.map((ruleId, index) => ({
|
|
@@ -504,12 +505,12 @@ function registerRuleTools(server, callApi) {
|
|
|
504
505
|
{
|
|
505
506
|
title: "Toggle Rule",
|
|
506
507
|
description: "Enable or disable a rule without deleting it.",
|
|
507
|
-
inputSchema: {
|
|
508
|
-
groupId:
|
|
509
|
-
versionId:
|
|
510
|
-
ruleId:
|
|
511
|
-
isEnabled:
|
|
512
|
-
}
|
|
508
|
+
inputSchema: z4.object({
|
|
509
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
510
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
511
|
+
ruleId: z4.string().uuid().describe("Rule ID"),
|
|
512
|
+
isEnabled: z4.boolean().describe("true to enable, false to disable")
|
|
513
|
+
})
|
|
513
514
|
},
|
|
514
515
|
async ({ groupId, versionId, ruleId, isEnabled }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/enabled`, {
|
|
515
516
|
body: { isEnabled }
|
|
@@ -518,7 +519,7 @@ function registerRuleTools(server, callApi) {
|
|
|
518
519
|
}
|
|
519
520
|
|
|
520
521
|
// src/mcp/tools/facts.ts
|
|
521
|
-
import { z as
|
|
522
|
+
import { z as z5 } from "zod";
|
|
522
523
|
|
|
523
524
|
// src/types/facts.ts
|
|
524
525
|
var FACT_KEY_PATTERN = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
|
@@ -535,11 +536,11 @@ function registerFactTools(server, callApi) {
|
|
|
535
536
|
{
|
|
536
537
|
title: "List Fact Definitions",
|
|
537
538
|
description: "List all fact definitions (input variable schema). Shows key, type, required, and PII status. Always check this before creating rules.",
|
|
538
|
-
inputSchema: {
|
|
539
|
-
page:
|
|
540
|
-
size:
|
|
541
|
-
keyword:
|
|
542
|
-
}
|
|
539
|
+
inputSchema: z5.object({
|
|
540
|
+
page: z5.number().int().min(0).default(0).describe("Page number"),
|
|
541
|
+
size: z5.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
542
|
+
keyword: z5.string().optional().describe("Search keyword")
|
|
543
|
+
})
|
|
543
544
|
},
|
|
544
545
|
async ({ page, size, keyword }) => {
|
|
545
546
|
const params = paginationParams(page, size);
|
|
@@ -552,16 +553,16 @@ function registerFactTools(server, callApi) {
|
|
|
552
553
|
{
|
|
553
554
|
title: "Create Fact Definition",
|
|
554
555
|
description: "Register a new input variable. Key starts with a letter, then letters, numbers, and underscores (e.g. paymentAmount). Casing is not enforced. Types: STRING, NUMBER, BOOLEAN, LIST_STRING, LIST_NUMBER.",
|
|
555
|
-
inputSchema: {
|
|
556
|
-
key:
|
|
557
|
-
name:
|
|
558
|
-
type:
|
|
559
|
-
description:
|
|
560
|
-
isRequired:
|
|
561
|
-
isPii:
|
|
556
|
+
inputSchema: z5.object({
|
|
557
|
+
key: z5.string().regex(FACT_KEY_PATTERN).describe("Variable key. Any casing; must start with a letter."),
|
|
558
|
+
name: z5.string().describe("Display name"),
|
|
559
|
+
type: z5.enum(VALUE_TYPES).describe("Value type"),
|
|
560
|
+
description: z5.string().optional().describe("Description"),
|
|
561
|
+
isRequired: z5.boolean().default(false).describe("Whether this fact is required for rule evaluation"),
|
|
562
|
+
isPii: z5.boolean().default(false).describe(
|
|
562
563
|
"Mark as PII \u2014 masked on every read surface, revealable only in the console (audited)"
|
|
563
564
|
)
|
|
564
|
-
}
|
|
565
|
+
})
|
|
565
566
|
},
|
|
566
567
|
async (args) => callApi("POST", "schema/facts", { body: args })
|
|
567
568
|
);
|
|
@@ -570,16 +571,16 @@ function registerFactTools(server, callApi) {
|
|
|
570
571
|
{
|
|
571
572
|
title: "Update Fact Definition",
|
|
572
573
|
description: "Update a fact definition. The key is immutable. The type can change only while no rule references the fact; if any does, the call fails with FD-007 and reports the count. Only the fields you send are changed. System facts accept name, description, and PII only.",
|
|
573
|
-
inputSchema: {
|
|
574
|
-
factId:
|
|
575
|
-
name:
|
|
576
|
-
description:
|
|
577
|
-
type:
|
|
574
|
+
inputSchema: z5.object({
|
|
575
|
+
factId: z5.string().uuid().describe("Fact definition ID"),
|
|
576
|
+
name: z5.string().optional().describe("Display name"),
|
|
577
|
+
description: z5.string().optional().describe("Description"),
|
|
578
|
+
type: z5.enum(VALUE_TYPES).optional().describe(
|
|
578
579
|
"Value type. Omit to leave it unchanged. Changing it fails with FD-007 while any rule references the fact."
|
|
579
580
|
),
|
|
580
|
-
isRequired:
|
|
581
|
-
isPii:
|
|
582
|
-
}
|
|
581
|
+
isRequired: z5.boolean().optional().describe("Required flag"),
|
|
582
|
+
isPii: z5.boolean().optional().describe("PII flag \u2014 enables/disables masking (changeable even on system facts)")
|
|
583
|
+
})
|
|
583
584
|
},
|
|
584
585
|
async ({ factId, ...body }) => callApi("PUT", `schema/facts/${factId}`, { body })
|
|
585
586
|
);
|
|
@@ -588,9 +589,9 @@ function registerFactTools(server, callApi) {
|
|
|
588
589
|
{
|
|
589
590
|
title: "Delete Fact Definition",
|
|
590
591
|
description: "Delete a fact definition. System facts cannot be deleted. Neither can a fact that any rule references: that call fails with FD-006 and reports the count. Remove the references first.",
|
|
591
|
-
inputSchema: {
|
|
592
|
-
factId:
|
|
593
|
-
}
|
|
592
|
+
inputSchema: z5.object({
|
|
593
|
+
factId: z5.string().uuid().describe("Fact definition ID")
|
|
594
|
+
})
|
|
594
595
|
},
|
|
595
596
|
async ({ factId }) => callApi("DELETE", `schema/facts/${factId}`)
|
|
596
597
|
);
|
|
@@ -599,7 +600,7 @@ function registerFactTools(server, callApi) {
|
|
|
599
600
|
{
|
|
600
601
|
title: "Get Action Runtime Fact Metadata",
|
|
601
602
|
description: "Retrieve runtime fact requirements per Action type. For each Action, shows which input facts must be present in the execution payload \u2014 e.g. MUTATE_FACT always requires its targetVar fact, plus refVar when one is specified. The factRequired flag describes the FACT, not the parameter: refVar is an optional parameter, but if you specify it the named fact must exist. A required fact absent at runtime throws \u2014 the engine never defaults to 0. Facts are supplied as input or written by a prior action in the same rule; only SET_FACT creates a fact from nothing. Static data, safe to cache in-session.",
|
|
602
|
-
inputSchema: {}
|
|
603
|
+
inputSchema: z5.object({})
|
|
603
604
|
},
|
|
604
605
|
async () => callApi("GET", "schema/action-metadata")
|
|
605
606
|
);
|
|
@@ -608,10 +609,10 @@ function registerFactTools(server, callApi) {
|
|
|
608
609
|
{
|
|
609
610
|
title: "List Unregistered Facts",
|
|
610
611
|
description: "List facts referenced by a version's rules but not yet defined (read-only \u2014 does not block publish/deploy, INV-4). Version-wide: covers every rule in the version. Each entry carries the inferred type, suggested name, and where it is referenced (condition/action). Register them with lexq_facts_create to enable type validation and the dry-run requirements analyzer.",
|
|
611
|
-
inputSchema: {
|
|
612
|
-
groupId:
|
|
613
|
-
versionId:
|
|
614
|
-
}
|
|
612
|
+
inputSchema: z5.object({
|
|
613
|
+
groupId: z5.string().uuid().describe("Policy group ID"),
|
|
614
|
+
versionId: z5.string().uuid().describe("Version ID")
|
|
615
|
+
})
|
|
615
616
|
},
|
|
616
617
|
async ({ groupId, versionId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/unregistered-facts`)
|
|
617
618
|
);
|
|
@@ -620,10 +621,10 @@ function registerFactTools(server, callApi) {
|
|
|
620
621
|
{
|
|
621
622
|
title: "Export Fact Catalog",
|
|
622
623
|
description: "Export the fact catalog. The two formats carry different things: CSV is the catalog as it stands, system facts included, for reading in a spreadsheet; JSON matches the shape that batch create accepts, so it can be fed straight back in, which is why it leaves out the fields that endpoint does not take. Returns the file contents as text.",
|
|
623
|
-
inputSchema: {
|
|
624
|
-
format:
|
|
625
|
-
keyword:
|
|
626
|
-
}
|
|
624
|
+
inputSchema: z5.object({
|
|
625
|
+
format: z5.enum(EXPORT_FORMATS).default("csv").describe("Export format"),
|
|
626
|
+
keyword: z5.string().optional().describe("Filter by key or name")
|
|
627
|
+
})
|
|
627
628
|
},
|
|
628
629
|
async ({ format, keyword }) => callApi("GET", "schema/facts/export", {
|
|
629
630
|
params: keyword ? { format, keyword } : { format }
|
|
@@ -632,18 +633,18 @@ function registerFactTools(server, callApi) {
|
|
|
632
633
|
}
|
|
633
634
|
|
|
634
635
|
// src/mcp/tools/deploy.ts
|
|
635
|
-
import { z as
|
|
636
|
+
import { z as z6 } from "zod";
|
|
636
637
|
function registerDeployTools(server, callApi) {
|
|
637
638
|
server.registerTool(
|
|
638
639
|
"lexq_deploy_publish",
|
|
639
640
|
{
|
|
640
641
|
title: "Publish Version",
|
|
641
642
|
description: "Publish a DRAFT version (DRAFT \u2192 ACTIVE). Locks the version from further edits. Must have at least one rule. Undefined facts referenced by rules do not block publishing (INV-4); call lexq_facts_unregistered first to review them.",
|
|
642
|
-
inputSchema: {
|
|
643
|
-
groupId:
|
|
644
|
-
versionId:
|
|
645
|
-
memo:
|
|
646
|
-
}
|
|
643
|
+
inputSchema: z6.object({
|
|
644
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
645
|
+
versionId: z6.string().uuid().describe("Version ID to publish"),
|
|
646
|
+
memo: z6.string().min(1).describe("Publish memo (required)")
|
|
647
|
+
})
|
|
647
648
|
},
|
|
648
649
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/versions/${versionId}/publish`, { body: { memo } })
|
|
649
650
|
);
|
|
@@ -652,11 +653,11 @@ function registerDeployTools(server, callApi) {
|
|
|
652
653
|
{
|
|
653
654
|
title: "Deploy to Live",
|
|
654
655
|
description: "Deploy an ACTIVE (published) version to live traffic. Takes effect immediately. Versions whose effective start date has not arrived are rejected (P-037) \u2014 use lexq_deploy_schedule for those. Undefined facts do not block deployment (INV-4); use lexq_facts_unregistered to review what the version references but has not defined.",
|
|
655
|
-
inputSchema: {
|
|
656
|
-
groupId:
|
|
657
|
-
versionId:
|
|
658
|
-
memo:
|
|
659
|
-
}
|
|
656
|
+
inputSchema: z6.object({
|
|
657
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
658
|
+
versionId: z6.string().uuid().describe("Version ID to deploy"),
|
|
659
|
+
memo: z6.string().min(1).describe("Deployment memo (required)")
|
|
660
|
+
})
|
|
660
661
|
},
|
|
661
662
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/deploy`, {
|
|
662
663
|
body: { versionId, memo }
|
|
@@ -667,10 +668,10 @@ function registerDeployTools(server, callApi) {
|
|
|
667
668
|
{
|
|
668
669
|
title: "Rollback Deployment",
|
|
669
670
|
description: "Rollback to the previous deployed version. Only available if there is a previous version.",
|
|
670
|
-
inputSchema: {
|
|
671
|
-
groupId:
|
|
672
|
-
memo:
|
|
673
|
-
}
|
|
671
|
+
inputSchema: z6.object({
|
|
672
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
673
|
+
memo: z6.string().min(1).describe("Rollback reason (required)")
|
|
674
|
+
})
|
|
674
675
|
},
|
|
675
676
|
async ({ groupId, memo }) => callApi("POST", `policy-groups/${groupId}/rollback`, {
|
|
676
677
|
body: { memo }
|
|
@@ -681,10 +682,10 @@ function registerDeployTools(server, callApi) {
|
|
|
681
682
|
{
|
|
682
683
|
title: "Undeploy",
|
|
683
684
|
description: "Remove the live version from traffic. The version stays ACTIVE but no longer serves requests.",
|
|
684
|
-
inputSchema: {
|
|
685
|
-
groupId:
|
|
686
|
-
memo:
|
|
687
|
-
}
|
|
685
|
+
inputSchema: z6.object({
|
|
686
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
687
|
+
memo: z6.string().min(1).describe("Undeploy reason (required)")
|
|
688
|
+
})
|
|
688
689
|
},
|
|
689
690
|
async ({ groupId, memo }) => callApi("POST", `policy-groups/${groupId}/undeploy`, {
|
|
690
691
|
body: { memo }
|
|
@@ -695,11 +696,11 @@ function registerDeployTools(server, callApi) {
|
|
|
695
696
|
{
|
|
696
697
|
title: "Schedule Deployment",
|
|
697
698
|
description: "Schedule an ACTIVE version with a future effective start date to auto-deploy at that time (Scheduled Deployment). One pending schedule per group; manual deploy/rollback/undeploy, starting an A/B test, or archiving the group cancels it. The snapshot hash is sealed at scheduling and re-verified at execution (fail-closed).",
|
|
698
|
-
inputSchema: {
|
|
699
|
-
groupId:
|
|
700
|
-
versionId:
|
|
701
|
-
memo:
|
|
702
|
-
}
|
|
699
|
+
inputSchema: z6.object({
|
|
700
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
701
|
+
versionId: z6.string().uuid().describe("ACTIVE version ID with a future effective start date"),
|
|
702
|
+
memo: z6.string().min(1).describe("Schedule memo (required)")
|
|
703
|
+
})
|
|
703
704
|
},
|
|
704
705
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/schedule`, {
|
|
705
706
|
body: { versionId, memo }
|
|
@@ -710,9 +711,9 @@ function registerDeployTools(server, callApi) {
|
|
|
710
711
|
{
|
|
711
712
|
title: "Cancel Scheduled Deployment",
|
|
712
713
|
description: "Cancel the pending scheduled deployment for a group. The version itself is not affected. Fails with P-039 if no pending schedule exists.",
|
|
713
|
-
inputSchema: {
|
|
714
|
-
groupId:
|
|
715
|
-
}
|
|
714
|
+
inputSchema: z6.object({
|
|
715
|
+
groupId: z6.string().uuid().describe("Policy group ID")
|
|
716
|
+
})
|
|
716
717
|
},
|
|
717
718
|
async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}/schedule`)
|
|
718
719
|
);
|
|
@@ -721,10 +722,10 @@ function registerDeployTools(server, callApi) {
|
|
|
721
722
|
{
|
|
722
723
|
title: "List Scheduled Deployments",
|
|
723
724
|
description: "List scheduled deployments across all groups (all statuses: PENDING, EXECUTED, CANCELED, FAILED), newest first.",
|
|
724
|
-
inputSchema: {
|
|
725
|
-
page:
|
|
726
|
-
size:
|
|
727
|
-
}
|
|
725
|
+
inputSchema: z6.object({
|
|
726
|
+
page: z6.number().int().min(0).default(0).describe("Page number"),
|
|
727
|
+
size: z6.number().int().min(1).max(100).default(20).describe("Page size")
|
|
728
|
+
})
|
|
728
729
|
},
|
|
729
730
|
async ({ page, size }) => callApi("GET", "policy-groups/schedules", { params: paginationParams(page, size) })
|
|
730
731
|
);
|
|
@@ -733,14 +734,14 @@ function registerDeployTools(server, callApi) {
|
|
|
733
734
|
{
|
|
734
735
|
title: "Deployment History",
|
|
735
736
|
description: "List deployment history across all groups.",
|
|
736
|
-
inputSchema: {
|
|
737
|
-
page:
|
|
738
|
-
size:
|
|
739
|
-
groupId:
|
|
740
|
-
types:
|
|
741
|
-
startDate:
|
|
742
|
-
endDate:
|
|
743
|
-
}
|
|
737
|
+
inputSchema: z6.object({
|
|
738
|
+
page: z6.number().int().min(0).default(0).describe("Page number"),
|
|
739
|
+
size: z6.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
740
|
+
groupId: z6.string().uuid().optional().describe("Filter by group ID"),
|
|
741
|
+
types: z6.string().optional().describe("Filter by deployment types (comma-separated: DEPLOY,ROLLBACK,UNDEPLOY)"),
|
|
742
|
+
startDate: z6.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
743
|
+
endDate: z6.string().optional().describe("End date (yyyy-MM-dd)")
|
|
744
|
+
})
|
|
744
745
|
},
|
|
745
746
|
async ({ page, size, groupId, types, startDate, endDate }) => {
|
|
746
747
|
const params = paginationParams(page, size);
|
|
@@ -756,9 +757,9 @@ function registerDeployTools(server, callApi) {
|
|
|
756
757
|
{
|
|
757
758
|
title: "Deployment Detail",
|
|
758
759
|
description: "Get detailed info about a specific deployment including snapshot hash and integrity check.",
|
|
759
|
-
inputSchema: {
|
|
760
|
-
deploymentId:
|
|
761
|
-
}
|
|
760
|
+
inputSchema: z6.object({
|
|
761
|
+
deploymentId: z6.string().uuid().describe("Deployment ID")
|
|
762
|
+
})
|
|
762
763
|
},
|
|
763
764
|
async ({ deploymentId }) => callApi("GET", `deployments/${deploymentId}`)
|
|
764
765
|
);
|
|
@@ -767,7 +768,7 @@ function registerDeployTools(server, callApi) {
|
|
|
767
768
|
{
|
|
768
769
|
title: "Deployment Overview",
|
|
769
770
|
description: "Show current deployment status of all groups \u2014 which version is live, last deployment type, and deployer.",
|
|
770
|
-
inputSchema: {}
|
|
771
|
+
inputSchema: z6.object({})
|
|
771
772
|
},
|
|
772
773
|
async () => callApi("GET", "deployments/overview")
|
|
773
774
|
);
|
|
@@ -776,9 +777,9 @@ function registerDeployTools(server, callApi) {
|
|
|
776
777
|
{
|
|
777
778
|
title: "List Deployable Versions",
|
|
778
779
|
description: "List ACTIVE (published) versions that can be deployed for a group. Use this to find which versions are available before calling deploy live.",
|
|
779
|
-
inputSchema: {
|
|
780
|
-
groupId:
|
|
781
|
-
}
|
|
780
|
+
inputSchema: z6.object({
|
|
781
|
+
groupId: z6.string().uuid().describe("Policy group ID")
|
|
782
|
+
})
|
|
782
783
|
},
|
|
783
784
|
async ({ groupId }) => callApi("GET", `deployments/groups/${groupId}/deployable-versions`)
|
|
784
785
|
);
|
|
@@ -787,10 +788,10 @@ function registerDeployTools(server, callApi) {
|
|
|
787
788
|
{
|
|
788
789
|
title: "Deployment Diff",
|
|
789
790
|
description: "Compare rule snapshots between two versions. Shows added, removed, and modified rules. Useful for reviewing changes before deploying a new version.",
|
|
790
|
-
inputSchema: {
|
|
791
|
-
baseVersionId:
|
|
792
|
-
targetVersionId:
|
|
793
|
-
}
|
|
791
|
+
inputSchema: z6.object({
|
|
792
|
+
baseVersionId: z6.string().uuid().describe("Base version ID (typically the current live)"),
|
|
793
|
+
targetVersionId: z6.string().uuid().describe("Target version ID (the one you want to deploy)")
|
|
794
|
+
})
|
|
794
795
|
},
|
|
795
796
|
async ({ baseVersionId, targetVersionId }) => callApi("GET", "deployments/diff", {
|
|
796
797
|
params: { baseVersionId, targetVersionId }
|
|
@@ -799,7 +800,7 @@ function registerDeployTools(server, callApi) {
|
|
|
799
800
|
}
|
|
800
801
|
|
|
801
802
|
// src/mcp/tools/analytics.ts
|
|
802
|
-
import { z as
|
|
803
|
+
import { z as z7 } from "zod";
|
|
803
804
|
import dedent2 from "dedent";
|
|
804
805
|
function registerAnalyticsTools(server, callApi) {
|
|
805
806
|
server.registerTool(
|
|
@@ -818,11 +819,11 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
818
819
|
|
|
819
820
|
Example input: { "facts": { "paymentAmount": 100000, "customerTier": "VIP" } }
|
|
820
821
|
Always dry-run before publishing to validate rule behavior.`,
|
|
821
|
-
inputSchema: {
|
|
822
|
-
versionId:
|
|
823
|
-
facts:
|
|
824
|
-
includeDebugInfo:
|
|
825
|
-
}
|
|
822
|
+
inputSchema: z7.object({
|
|
823
|
+
versionId: z7.string().uuid().describe("Policy version ID to test against"),
|
|
824
|
+
facts: z7.string().describe('JSON string of facts object, e.g. {"paymentAmount":100000}'),
|
|
825
|
+
includeDebugInfo: z7.boolean().default(true).describe("Include execution and decision traces")
|
|
826
|
+
})
|
|
826
827
|
},
|
|
827
828
|
async ({ versionId, facts, includeDebugInfo }) => {
|
|
828
829
|
const parsedFacts = parseJson(facts);
|
|
@@ -842,11 +843,11 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
842
843
|
resultA / resultB — full DryRunResponse for each version
|
|
843
844
|
diff.mutatedDiff — changes in mutatedFacts between A and B (key → {before, after})
|
|
844
845
|
diff.generatedDiff — changes in generatedVariables between A and B`,
|
|
845
|
-
inputSchema: {
|
|
846
|
-
versionIdA:
|
|
847
|
-
versionIdB:
|
|
848
|
-
facts:
|
|
849
|
-
}
|
|
846
|
+
inputSchema: z7.object({
|
|
847
|
+
versionIdA: z7.string().uuid().describe("Baseline version ID"),
|
|
848
|
+
versionIdB: z7.string().uuid().describe("Candidate version ID"),
|
|
849
|
+
facts: z7.string().describe("JSON string of facts object")
|
|
850
|
+
})
|
|
850
851
|
},
|
|
851
852
|
async ({ versionIdA, versionIdB, facts }) => {
|
|
852
853
|
const parsedFacts = parseJson(facts);
|
|
@@ -860,10 +861,10 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
860
861
|
{
|
|
861
862
|
title: "Analyze Requirements",
|
|
862
863
|
description: "Analyze which input facts a version requires. Returns required keys, types, and an example request body.",
|
|
863
|
-
inputSchema: {
|
|
864
|
-
groupId:
|
|
865
|
-
versionId:
|
|
866
|
-
}
|
|
864
|
+
inputSchema: z7.object({
|
|
865
|
+
groupId: z7.string().uuid().describe("Policy group ID"),
|
|
866
|
+
versionId: z7.string().uuid().describe("Version ID")
|
|
867
|
+
})
|
|
867
868
|
},
|
|
868
869
|
async ({ groupId, versionId }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/requirements`)
|
|
869
870
|
);
|
|
@@ -899,9 +900,9 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
899
900
|
"options": { "baselinePolicyVersionId": "<uuid>", "includeRuleStats": true }
|
|
900
901
|
}
|
|
901
902
|
`,
|
|
902
|
-
inputSchema: {
|
|
903
|
-
body:
|
|
904
|
-
}
|
|
903
|
+
inputSchema: z7.object({
|
|
904
|
+
body: z7.string().describe("JSON string of SimulationRequest")
|
|
905
|
+
})
|
|
905
906
|
},
|
|
906
907
|
async ({ body }) => {
|
|
907
908
|
const parsed = parseJson(body);
|
|
@@ -913,9 +914,9 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
913
914
|
{
|
|
914
915
|
title: "Simulation Status",
|
|
915
916
|
description: "Get simulation status and results. Poll until status is COMPLETED or FAILED.",
|
|
916
|
-
inputSchema: {
|
|
917
|
-
simulationId:
|
|
918
|
-
}
|
|
917
|
+
inputSchema: z7.object({
|
|
918
|
+
simulationId: z7.string().uuid().describe("Simulation ID")
|
|
919
|
+
})
|
|
919
920
|
},
|
|
920
921
|
async ({ simulationId }) => callApi("GET", `analytics/simulations/${simulationId}`)
|
|
921
922
|
);
|
|
@@ -924,13 +925,13 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
924
925
|
{
|
|
925
926
|
title: "List Simulations",
|
|
926
927
|
description: "List simulation history with optional filters.",
|
|
927
|
-
inputSchema: {
|
|
928
|
-
page:
|
|
929
|
-
size:
|
|
930
|
-
status:
|
|
931
|
-
from:
|
|
932
|
-
to:
|
|
933
|
-
}
|
|
928
|
+
inputSchema: z7.object({
|
|
929
|
+
page: z7.number().int().min(0).default(0).describe("Page number"),
|
|
930
|
+
size: z7.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
931
|
+
status: z7.enum(["PENDING", "RUNNING", "COMPLETED", "FAILED", "CANCELED"]).optional().describe("Filter by status"),
|
|
932
|
+
from: z7.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
933
|
+
to: z7.string().optional().describe("End date (yyyy-MM-dd)")
|
|
934
|
+
})
|
|
934
935
|
},
|
|
935
936
|
async ({ page, size, status, from, to }) => {
|
|
936
937
|
const params = paginationParams(page, size);
|
|
@@ -945,9 +946,9 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
945
946
|
{
|
|
946
947
|
title: "Cancel Simulation",
|
|
947
948
|
description: "Cancel a running or pending simulation.",
|
|
948
|
-
inputSchema: {
|
|
949
|
-
simulationId:
|
|
950
|
-
}
|
|
949
|
+
inputSchema: z7.object({
|
|
950
|
+
simulationId: z7.string().uuid().describe("Simulation ID")
|
|
951
|
+
})
|
|
951
952
|
},
|
|
952
953
|
async ({ simulationId }) => callApi("DELETE", `analytics/simulations/${simulationId}`)
|
|
953
954
|
);
|
|
@@ -956,10 +957,10 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
956
957
|
{
|
|
957
958
|
title: "Export Simulation",
|
|
958
959
|
description: "Export simulation results as JSON or CSV. Returns the raw data.",
|
|
959
|
-
inputSchema: {
|
|
960
|
-
simulationId:
|
|
961
|
-
format:
|
|
962
|
-
}
|
|
960
|
+
inputSchema: z7.object({
|
|
961
|
+
simulationId: z7.string().uuid().describe("Simulation ID"),
|
|
962
|
+
format: z7.enum(EXPORT_FORMATS).default("json").describe("Export format")
|
|
963
|
+
})
|
|
963
964
|
},
|
|
964
965
|
async ({ simulationId, format }) => callApi("GET", `analytics/simulations/${simulationId}/export`, {
|
|
965
966
|
params: { format }
|
|
@@ -983,10 +984,10 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
983
984
|
|
|
984
985
|
JSON example: [{"userId":"user_001","paymentAmount":150000}, {"userId":"user_002","paymentAmount":50000}]
|
|
985
986
|
`,
|
|
986
|
-
inputSchema: {
|
|
987
|
-
content:
|
|
988
|
-
filename:
|
|
989
|
-
}
|
|
987
|
+
inputSchema: z7.object({
|
|
988
|
+
content: z7.string().describe("CSV or JSON content as string"),
|
|
989
|
+
filename: z7.string().default("dataset.csv").describe("Filename with extension (.csv or .json)")
|
|
990
|
+
})
|
|
990
991
|
},
|
|
991
992
|
async ({ content, filename }) => {
|
|
992
993
|
const result = await callApi("POST", "analytics/datasets/upload", {
|
|
@@ -1013,11 +1014,11 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
1013
1014
|
{
|
|
1014
1015
|
title: "Download Dataset Template",
|
|
1015
1016
|
description: "Generate a sample CSV or JSON template based on the required facts of a version. Use this to understand the expected data format before uploading a dataset.",
|
|
1016
|
-
inputSchema: {
|
|
1017
|
-
groupId:
|
|
1018
|
-
versionId:
|
|
1019
|
-
format:
|
|
1020
|
-
}
|
|
1017
|
+
inputSchema: z7.object({
|
|
1018
|
+
groupId: z7.string().uuid().describe("Policy group ID"),
|
|
1019
|
+
versionId: z7.string().uuid().describe("Version ID"),
|
|
1020
|
+
format: z7.enum(EXPORT_FORMATS).default("csv").describe("Template format")
|
|
1021
|
+
})
|
|
1021
1022
|
},
|
|
1022
1023
|
async ({ groupId, versionId, format }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/dataset-template`, {
|
|
1023
1024
|
params: { format }
|
|
@@ -1026,7 +1027,7 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
1026
1027
|
}
|
|
1027
1028
|
|
|
1028
1029
|
// src/mcp/tools/profile.ts
|
|
1029
|
-
import { z as
|
|
1030
|
+
import { z as z8 } from "zod";
|
|
1030
1031
|
var RELATIVE_THRESHOLD = `flagged = p50 \u2265 ${SLOW_MULTIPLIER}\xD7 median of per-rule p50s within the group; absolute thresholds are intentionally not supported.`;
|
|
1031
1032
|
function profileParams(opts) {
|
|
1032
1033
|
const params = {};
|
|
@@ -1042,15 +1043,15 @@ function registerProfileTools(server, callApi) {
|
|
|
1042
1043
|
{
|
|
1043
1044
|
title: "Group Latency Profile",
|
|
1044
1045
|
description: "Per-rule latency profile of a policy group over a time window: group TOTAL distribution split by cache state (HIT = compiled ruleset cache hit, MISS = deep-load + compile), a per-rule CONDITION/ACTION percentile table, and slow-rule flags. " + RELATIVE_THRESHOLD + ` Every percentile is accompanied by its sample count n; a percentile is withheld (null) unless n\xD7(1\u2212q) \u2265 ${TAIL_MIN_OBS} (p50 needs n \u2265 6, p95 n \u2265 60, p99 n \u2265 300 \u2014 display gate, separate from the n \u2265 ${MIN_SAMPLES} judgment gate). Baselines report INSUFFICIENT_COHORT when fewer than ${MIN_COHORT_SIZE} rules qualify. Rule detail comes from a deterministic ${PROFILE_SAMPLE_PERMILLE / 10}% sample of calls; TOTAL is recorded for every call. Defaults: last ${PROFILE_DEFAULT_WINDOW_HOURS}h, live version, cacheState HIT.`,
|
|
1045
|
-
inputSchema: {
|
|
1046
|
-
groupId:
|
|
1047
|
-
versionId:
|
|
1048
|
-
from:
|
|
1046
|
+
inputSchema: z8.object({
|
|
1047
|
+
groupId: z8.string().uuid().describe("Policy group ID"),
|
|
1048
|
+
versionId: z8.string().uuid().optional().describe("Version to inspect (default: live version)"),
|
|
1049
|
+
from: z8.string().optional().describe(
|
|
1049
1050
|
`Window start, ISO-8601 instant (e.g. 2026-07-01T00:00:00Z). Default: ${PROFILE_DEFAULT_WINDOW_HOURS}h ago`
|
|
1050
1051
|
),
|
|
1051
|
-
to:
|
|
1052
|
-
cacheState:
|
|
1053
|
-
}
|
|
1052
|
+
to: z8.string().optional().describe("Window end, ISO-8601 instant. Default: now"),
|
|
1053
|
+
cacheState: z8.enum(["HIT", "MISS"]).optional().describe("Cache dimension for the rule table and judgment (default: HIT)")
|
|
1054
|
+
})
|
|
1054
1055
|
},
|
|
1055
1056
|
async ({ groupId, versionId, from, to, cacheState }) => callApi("GET", `policy-groups/${groupId}/profile`, {
|
|
1056
1057
|
params: profileParams({ versionId, from, to, cacheState })
|
|
@@ -1061,15 +1062,15 @@ function registerProfileTools(server, callApi) {
|
|
|
1061
1062
|
{
|
|
1062
1063
|
title: "Rule Latency Detail",
|
|
1063
1064
|
description: `Single-rule latency detail: merged phase \xD7 cacheState distributions plus a per-window time series (${LATENCY_WINDOW_MILLIS / 1e3}s windows). Missing windows are genuine gaps \u2014 never interpolated. Series points carry each window's own values; percentiles in merged distributions are withheld (null) unless n\xD7(1\u2212q) \u2265 ${TAIL_MIN_OBS} (p50 n \u2265 6, p95 n \u2265 60, p99 n \u2265 300). ` + RELATIVE_THRESHOLD,
|
|
1064
|
-
inputSchema: {
|
|
1065
|
-
groupId:
|
|
1066
|
-
ruleId:
|
|
1067
|
-
versionId:
|
|
1068
|
-
from:
|
|
1065
|
+
inputSchema: z8.object({
|
|
1066
|
+
groupId: z8.string().uuid().describe("Policy group ID"),
|
|
1067
|
+
ruleId: z8.string().uuid().describe("Rule ID (from lexq_profile_overview)"),
|
|
1068
|
+
versionId: z8.string().uuid().optional().describe("Version to inspect (default: live version)"),
|
|
1069
|
+
from: z8.string().optional().describe(
|
|
1069
1070
|
`Window start, ISO-8601 instant. Default: ${PROFILE_DEFAULT_WINDOW_HOURS}h ago`
|
|
1070
1071
|
),
|
|
1071
|
-
to:
|
|
1072
|
-
}
|
|
1072
|
+
to: z8.string().optional().describe("Window end, ISO-8601 instant. Default: now")
|
|
1073
|
+
})
|
|
1073
1074
|
},
|
|
1074
1075
|
async ({ groupId, ruleId, versionId, from, to }) => callApi("GET", `policy-groups/${groupId}/profile/rules/${ruleId}`, {
|
|
1075
1076
|
params: profileParams({ versionId, from, to })
|
|
@@ -1078,17 +1079,17 @@ function registerProfileTools(server, callApi) {
|
|
|
1078
1079
|
}
|
|
1079
1080
|
|
|
1080
1081
|
// src/mcp/tools/replay.ts
|
|
1081
|
-
import { z as
|
|
1082
|
+
import { z as z9 } from "zod";
|
|
1082
1083
|
function registerReplayTools(server, callApi) {
|
|
1083
1084
|
server.registerTool(
|
|
1084
1085
|
"lexq_replay_decision",
|
|
1085
1086
|
{
|
|
1086
1087
|
title: "Replay a Decision",
|
|
1087
1088
|
description: "Re-evaluate a past execution (traceId) against a candidate version and return the decision diff (decisionChanged, effect changes, fired rules) plus a determinism verdict. Synchronous and free of charge (TPS throttle only). A replay sends no webhook, notification, or event: rule actions produce no outward effects.",
|
|
1088
|
-
inputSchema: {
|
|
1089
|
-
traceId:
|
|
1090
|
-
candidateVersionId:
|
|
1091
|
-
}
|
|
1089
|
+
inputSchema: z9.object({
|
|
1090
|
+
traceId: z9.string().describe("Trace ID of the past execution to replay"),
|
|
1091
|
+
candidateVersionId: z9.string().uuid().describe("Version to re-evaluate against")
|
|
1092
|
+
})
|
|
1092
1093
|
},
|
|
1093
1094
|
async ({ traceId, candidateVersionId }) => callApi("POST", "replay/decisions", { body: { traceId, candidateVersionId } })
|
|
1094
1095
|
);
|
|
@@ -1097,14 +1098,14 @@ function registerReplayTools(server, callApi) {
|
|
|
1097
1098
|
{
|
|
1098
1099
|
title: "Start Window Replay (Blast Radius)",
|
|
1099
1100
|
description: "Submit an async job that replays a date window of past executions against a candidate version and measures the blast radius (how many decisions change). Billed per replayed record (REPLAY metric); VIEWER role cannot submit. Poll with lexq_replay_status.",
|
|
1100
|
-
inputSchema: {
|
|
1101
|
-
candidateVersionId:
|
|
1102
|
-
from:
|
|
1103
|
-
to:
|
|
1104
|
-
maxRecords:
|
|
1101
|
+
inputSchema: z9.object({
|
|
1102
|
+
candidateVersionId: z9.string().uuid().describe("Version to re-evaluate against"),
|
|
1103
|
+
from: z9.string().describe("Window start date (yyyy-MM-dd)"),
|
|
1104
|
+
to: z9.string().describe("Window end date (yyyy-MM-dd)"),
|
|
1105
|
+
maxRecords: z9.number().int().min(1).optional().describe(
|
|
1105
1106
|
`Sample cap (server default applies; hard cap ${REPLAY_WINDOW_MAX_RECORDS / 1e3}k)`
|
|
1106
1107
|
)
|
|
1107
|
-
}
|
|
1108
|
+
})
|
|
1108
1109
|
},
|
|
1109
1110
|
async ({ candidateVersionId, from, to, maxRecords }) => callApi("POST", "replay/jobs", { body: { candidateVersionId, from, to, maxRecords } })
|
|
1110
1111
|
);
|
|
@@ -1113,9 +1114,9 @@ function registerReplayTools(server, callApi) {
|
|
|
1113
1114
|
{
|
|
1114
1115
|
title: "Get Replay Job Status",
|
|
1115
1116
|
description: "Poll a window replay job. RUNNING shows progress 0\u2013100; COMPLETED fills summary and changedSamples; FAILED carries errorMessage. capped=true means the window exceeded the sample cap and only part was replayed.",
|
|
1116
|
-
inputSchema: {
|
|
1117
|
-
jobId:
|
|
1118
|
-
}
|
|
1117
|
+
inputSchema: z9.object({
|
|
1118
|
+
jobId: z9.string().describe("Replay job ID from lexq_replay_start")
|
|
1119
|
+
})
|
|
1119
1120
|
},
|
|
1120
1121
|
async ({ jobId }) => callApi("GET", `replay/jobs/${jobId}`)
|
|
1121
1122
|
);
|
|
@@ -1124,10 +1125,10 @@ function registerReplayTools(server, callApi) {
|
|
|
1124
1125
|
{
|
|
1125
1126
|
title: "List Replay Jobs",
|
|
1126
1127
|
description: "List window replay job history (reverse-chronological). Lightweight items \u2014 use lexq_replay_status for summary and changed samples.",
|
|
1127
|
-
inputSchema: {
|
|
1128
|
-
page:
|
|
1129
|
-
size:
|
|
1130
|
-
}
|
|
1128
|
+
inputSchema: z9.object({
|
|
1129
|
+
page: z9.number().int().min(0).default(0).describe("Page number"),
|
|
1130
|
+
size: z9.number().int().min(1).max(100).default(20).describe("Page size")
|
|
1131
|
+
})
|
|
1131
1132
|
},
|
|
1132
1133
|
async ({ page, size }) => callApi("GET", "replay/jobs", { params: paginationParams(page, size) })
|
|
1133
1134
|
);
|
|
@@ -1136,9 +1137,9 @@ function registerReplayTools(server, callApi) {
|
|
|
1136
1137
|
{
|
|
1137
1138
|
title: "Cancel Replay Job",
|
|
1138
1139
|
description: "Cooperatively cancel a PENDING or RUNNING window replay job. Other states are rejected. VIEWER role cannot cancel.",
|
|
1139
|
-
inputSchema: {
|
|
1140
|
-
jobId:
|
|
1141
|
-
}
|
|
1140
|
+
inputSchema: z9.object({
|
|
1141
|
+
jobId: z9.string().describe("Replay job ID")
|
|
1142
|
+
})
|
|
1142
1143
|
},
|
|
1143
1144
|
async ({ jobId }) => callApi("POST", `replay/jobs/${jobId}/cancel`)
|
|
1144
1145
|
);
|
|
@@ -1147,33 +1148,33 @@ function registerReplayTools(server, callApi) {
|
|
|
1147
1148
|
{
|
|
1148
1149
|
title: "Export Replay Result",
|
|
1149
1150
|
description: "Export a COMPLETED window replay job. A running job is rejected \u2014 a partial result reads as the whole thing on the receiving end. The two formats carry different things: CSV holds the effect blast radius, whose columns are fixed; JSON holds the changed samples and action parameters, which nest and whose keys differ per tenant. JSON is not a superset of CSV. Returns the file contents as text.",
|
|
1150
|
-
inputSchema: {
|
|
1151
|
-
jobId:
|
|
1152
|
-
format:
|
|
1153
|
-
}
|
|
1151
|
+
inputSchema: z9.object({
|
|
1152
|
+
jobId: z9.string().describe("Replay job ID"),
|
|
1153
|
+
format: z9.enum(EXPORT_FORMATS).default("json").describe("Export format")
|
|
1154
|
+
})
|
|
1154
1155
|
},
|
|
1155
1156
|
async ({ jobId, format }) => callApi("GET", `replay/jobs/${jobId}/export`, { params: { format } })
|
|
1156
1157
|
);
|
|
1157
1158
|
}
|
|
1158
1159
|
|
|
1159
1160
|
// src/mcp/tools/history.ts
|
|
1160
|
-
import { z as
|
|
1161
|
+
import { z as z10 } from "zod";
|
|
1161
1162
|
function registerHistoryTools(server, callApi) {
|
|
1162
1163
|
server.registerTool(
|
|
1163
1164
|
"lexq_history_list",
|
|
1164
1165
|
{
|
|
1165
1166
|
title: "List Execution History",
|
|
1166
1167
|
description: "List policy execution history. Shows trace ID, group, version, status, match result, and latency.",
|
|
1167
|
-
inputSchema: {
|
|
1168
|
-
page:
|
|
1169
|
-
size:
|
|
1170
|
-
traceId:
|
|
1171
|
-
groupId:
|
|
1172
|
-
versionId:
|
|
1173
|
-
status:
|
|
1174
|
-
startDate:
|
|
1175
|
-
endDate:
|
|
1176
|
-
}
|
|
1168
|
+
inputSchema: z10.object({
|
|
1169
|
+
page: z10.number().int().min(0).default(0).describe("Page number"),
|
|
1170
|
+
size: z10.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
1171
|
+
traceId: z10.string().optional().describe("Filter by trace ID"),
|
|
1172
|
+
groupId: z10.string().uuid().optional().describe("Filter by policy group"),
|
|
1173
|
+
versionId: z10.string().uuid().optional().describe("Filter by version"),
|
|
1174
|
+
status: z10.enum(["SUCCESS", "NO_MATCH", "ERROR", "TIMEOUT"]).optional().describe("Filter by execution status"),
|
|
1175
|
+
startDate: z10.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
1176
|
+
endDate: z10.string().optional().describe("End date (yyyy-MM-dd)")
|
|
1177
|
+
})
|
|
1177
1178
|
},
|
|
1178
1179
|
async ({ page, size, traceId, groupId, versionId, status, startDate, endDate }) => {
|
|
1179
1180
|
const params = paginationParams(page, size);
|
|
@@ -1191,9 +1192,9 @@ function registerHistoryTools(server, callApi) {
|
|
|
1191
1192
|
{
|
|
1192
1193
|
title: "Get Execution Detail",
|
|
1193
1194
|
description: "Get full execution detail including inputFacts, mutatedFacts, generatedVariables, executionTraces, and decisionTraces.",
|
|
1194
|
-
inputSchema: {
|
|
1195
|
-
traceId:
|
|
1196
|
-
}
|
|
1195
|
+
inputSchema: z10.object({
|
|
1196
|
+
traceId: z10.string().describe("Trace ID from execution history")
|
|
1197
|
+
})
|
|
1197
1198
|
},
|
|
1198
1199
|
async ({ traceId }) => callApi("GET", `execution/history/${traceId}`)
|
|
1199
1200
|
);
|
|
@@ -1202,11 +1203,11 @@ function registerHistoryTools(server, callApi) {
|
|
|
1202
1203
|
{
|
|
1203
1204
|
title: "Execution Statistics",
|
|
1204
1205
|
description: "Get execution KPIs: total executions, success/failure counts, success rate, and average latency.",
|
|
1205
|
-
inputSchema: {
|
|
1206
|
-
groupId:
|
|
1207
|
-
startDate:
|
|
1208
|
-
endDate:
|
|
1209
|
-
}
|
|
1206
|
+
inputSchema: z10.object({
|
|
1207
|
+
groupId: z10.string().uuid().optional().describe("Filter by policy group"),
|
|
1208
|
+
startDate: z10.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
1209
|
+
endDate: z10.string().optional().describe("End date (yyyy-MM-dd)")
|
|
1210
|
+
})
|
|
1210
1211
|
},
|
|
1211
1212
|
async ({ groupId, startDate, endDate }) => {
|
|
1212
1213
|
const params = {};
|
|
@@ -1219,16 +1220,16 @@ function registerHistoryTools(server, callApi) {
|
|
|
1219
1220
|
}
|
|
1220
1221
|
|
|
1221
1222
|
// src/mcp/tools/provenance.ts
|
|
1222
|
-
import { z as
|
|
1223
|
+
import { z as z11 } from "zod";
|
|
1223
1224
|
function registerProvenanceTools(server, callApi) {
|
|
1224
1225
|
server.registerTool(
|
|
1225
1226
|
"lexq_provenance_get",
|
|
1226
1227
|
{
|
|
1227
1228
|
title: "Get Decision Provenance",
|
|
1228
1229
|
description: "Get the lineage of a single decision: what was decided, deterministic why per rule, input facts (PII facts are masked as \u2022\u2022\u2022\u2022\u2022\u2022 with maskedKeys listing them \u2014 values are revealable only in the console, audited), the authored/published/deployed responsibility chain, and the rule snapshot fingerprint.",
|
|
1229
|
-
inputSchema: {
|
|
1230
|
-
traceId:
|
|
1231
|
-
}
|
|
1230
|
+
inputSchema: z11.object({
|
|
1231
|
+
traceId: z11.string().describe("Trace ID of the execution")
|
|
1232
|
+
})
|
|
1232
1233
|
},
|
|
1233
1234
|
async ({ traceId }) => callApi("GET", `provenance/${traceId}`)
|
|
1234
1235
|
);
|
|
@@ -1237,15 +1238,15 @@ function registerProvenanceTools(server, callApi) {
|
|
|
1237
1238
|
{
|
|
1238
1239
|
title: "List PII Reveal Audits",
|
|
1239
1240
|
description: "List the PII reveal audit ledger \u2014 who revealed which fact of which trace, and when. Metadata only; revealed values are never stored or returned. Use for monthly access-log inspection and SIEM collection.",
|
|
1240
|
-
inputSchema: {
|
|
1241
|
-
page:
|
|
1242
|
-
size:
|
|
1243
|
-
traceId:
|
|
1244
|
-
revealedBy:
|
|
1245
|
-
factKey:
|
|
1246
|
-
startDate:
|
|
1247
|
-
endDate:
|
|
1248
|
-
}
|
|
1241
|
+
inputSchema: z11.object({
|
|
1242
|
+
page: z11.number().int().min(0).default(0).describe("Page number"),
|
|
1243
|
+
size: z11.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
1244
|
+
traceId: z11.string().optional().describe("Filter by trace ID (exact match)"),
|
|
1245
|
+
revealedBy: z11.string().optional().describe("Filter by operator ID (exact match)"),
|
|
1246
|
+
factKey: z11.string().optional().describe("Filter by fact key (partial match, case-insensitive)"),
|
|
1247
|
+
startDate: z11.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
1248
|
+
endDate: z11.string().optional().describe("End date (yyyy-MM-dd)")
|
|
1249
|
+
})
|
|
1249
1250
|
},
|
|
1250
1251
|
async ({ page, size, traceId, revealedBy, factKey, startDate, endDate }) => {
|
|
1251
1252
|
const params = paginationParams(page, size);
|
|
@@ -1260,22 +1261,22 @@ function registerProvenanceTools(server, callApi) {
|
|
|
1260
1261
|
}
|
|
1261
1262
|
|
|
1262
1263
|
// src/mcp/tools/logs.ts
|
|
1263
|
-
import { z as
|
|
1264
|
+
import { z as z12 } from "zod";
|
|
1264
1265
|
function registerLogTools(server, callApi) {
|
|
1265
1266
|
server.registerTool(
|
|
1266
1267
|
"lexq_logs_list",
|
|
1267
1268
|
{
|
|
1268
1269
|
title: "List Failure Logs",
|
|
1269
1270
|
description: "List system failure logs from background tasks (platform event webhooks, scheduled deployments).",
|
|
1270
|
-
inputSchema: {
|
|
1271
|
-
page:
|
|
1272
|
-
size:
|
|
1273
|
-
taskType:
|
|
1274
|
-
status:
|
|
1275
|
-
keyword:
|
|
1276
|
-
startDate:
|
|
1277
|
-
endDate:
|
|
1278
|
-
}
|
|
1271
|
+
inputSchema: z12.object({
|
|
1272
|
+
page: z12.number().int().min(0).default(0).describe("Page number"),
|
|
1273
|
+
size: z12.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
1274
|
+
taskType: z12.enum(TaskType).optional().describe("Task type"),
|
|
1275
|
+
status: z12.enum(FailureStatus).optional().describe("Log status"),
|
|
1276
|
+
keyword: z12.string().optional().describe("Search in refId, refSubId, errorMessage"),
|
|
1277
|
+
startDate: z12.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
1278
|
+
endDate: z12.string().optional().describe("End date (yyyy-MM-dd)")
|
|
1279
|
+
})
|
|
1279
1280
|
},
|
|
1280
1281
|
async ({ page, size, taskType, status, keyword, startDate, endDate }) => {
|
|
1281
1282
|
const params = paginationParams(page, size);
|
|
@@ -1292,9 +1293,9 @@ function registerLogTools(server, callApi) {
|
|
|
1292
1293
|
{
|
|
1293
1294
|
title: "Get Failure Log",
|
|
1294
1295
|
description: "Get failure log detail by ID.",
|
|
1295
|
-
inputSchema: {
|
|
1296
|
-
logId:
|
|
1297
|
-
}
|
|
1296
|
+
inputSchema: z12.object({
|
|
1297
|
+
logId: z12.string().uuid().describe("Failure log ID")
|
|
1298
|
+
})
|
|
1298
1299
|
},
|
|
1299
1300
|
async ({ logId }) => callApi("GET", `failure-logs/${logId}`)
|
|
1300
1301
|
);
|
|
@@ -1303,10 +1304,10 @@ function registerLogTools(server, callApi) {
|
|
|
1303
1304
|
{
|
|
1304
1305
|
title: "Process Failure Log",
|
|
1305
1306
|
description: "Process a single failure log: RESOLVE (mark as manually fixed) or IGNORE (skip intentionally).",
|
|
1306
|
-
inputSchema: {
|
|
1307
|
-
logId:
|
|
1308
|
-
action:
|
|
1309
|
-
}
|
|
1307
|
+
inputSchema: z12.object({
|
|
1308
|
+
logId: z12.string().uuid().describe("Failure log ID"),
|
|
1309
|
+
action: z12.enum(FailureAction).describe("Action to take")
|
|
1310
|
+
})
|
|
1310
1311
|
},
|
|
1311
1312
|
async ({ logId, action }) => callApi("POST", `failure-logs/${logId}/actions`, {
|
|
1312
1313
|
params: { action }
|
|
@@ -1317,10 +1318,10 @@ function registerLogTools(server, callApi) {
|
|
|
1317
1318
|
{
|
|
1318
1319
|
title: "Bulk Process Failure Logs",
|
|
1319
1320
|
description: "Process multiple failure logs at once. Provide an array of log IDs and the action.",
|
|
1320
|
-
inputSchema: {
|
|
1321
|
-
logIds:
|
|
1322
|
-
action:
|
|
1323
|
-
}
|
|
1321
|
+
inputSchema: z12.object({
|
|
1322
|
+
logIds: z12.array(z12.string().uuid()).describe("Array of failure log IDs"),
|
|
1323
|
+
action: z12.enum(FailureAction).describe("Action to apply to all logs")
|
|
1324
|
+
})
|
|
1324
1325
|
},
|
|
1325
1326
|
async ({ logIds, action }) => callApi("POST", "failure-logs/bulk-actions", {
|
|
1326
1327
|
body: { logIds, action }
|
|
@@ -1329,17 +1330,17 @@ function registerLogTools(server, callApi) {
|
|
|
1329
1330
|
}
|
|
1330
1331
|
|
|
1331
1332
|
// src/mcp/tools/webhook-subscriptions.ts
|
|
1332
|
-
import { z as
|
|
1333
|
+
import { z as z13 } from "zod";
|
|
1333
1334
|
function registerWebhookSubscriptionTools(server, callApi) {
|
|
1334
1335
|
server.registerTool(
|
|
1335
1336
|
"lexq_webhook_subscriptions_list",
|
|
1336
1337
|
{
|
|
1337
1338
|
title: "List Webhook Subscriptions",
|
|
1338
1339
|
description: "List platform event webhook subscriptions. These receive deployment lifecycle notifications (publish, deploy, rollback, undeploy).",
|
|
1339
|
-
inputSchema: {
|
|
1340
|
-
page:
|
|
1341
|
-
size:
|
|
1342
|
-
}
|
|
1340
|
+
inputSchema: z13.object({
|
|
1341
|
+
page: z13.number().int().min(0).default(0).describe("Page number"),
|
|
1342
|
+
size: z13.number().int().min(1).max(100).default(20).describe("Page size")
|
|
1343
|
+
})
|
|
1343
1344
|
},
|
|
1344
1345
|
async ({ page, size }) => {
|
|
1345
1346
|
const params = paginationParams(page, size);
|
|
@@ -1351,9 +1352,9 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
1351
1352
|
{
|
|
1352
1353
|
title: "Get Webhook Subscription",
|
|
1353
1354
|
description: "Get webhook subscription detail by ID.",
|
|
1354
|
-
inputSchema: {
|
|
1355
|
-
id:
|
|
1356
|
-
}
|
|
1355
|
+
inputSchema: z13.object({
|
|
1356
|
+
id: z13.string().uuid().describe("Webhook subscription ID")
|
|
1357
|
+
})
|
|
1357
1358
|
},
|
|
1358
1359
|
async ({ id }) => callApi("GET", `webhook-subscriptions/${id}`)
|
|
1359
1360
|
);
|
|
@@ -1362,15 +1363,15 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
1362
1363
|
{
|
|
1363
1364
|
title: "Save Webhook Subscription",
|
|
1364
1365
|
description: 'Create or update a webhook subscription. Omit id to create, provide id to update. Events: VERSION_PUBLISHED, DEPLOYED, ROLLED_BACK, UNDEPLOYED. Formats: GENERIC (full JSON), SLACK ({"text": "..."}).',
|
|
1365
|
-
inputSchema: {
|
|
1366
|
-
id:
|
|
1367
|
-
name:
|
|
1368
|
-
webhookUrl:
|
|
1369
|
-
subscribedEvents:
|
|
1370
|
-
payloadFormat:
|
|
1371
|
-
secret:
|
|
1372
|
-
isActive:
|
|
1373
|
-
}
|
|
1366
|
+
inputSchema: z13.object({
|
|
1367
|
+
id: z13.string().uuid().optional().describe("Subscription ID (omit to create, provide to update)"),
|
|
1368
|
+
name: z13.string().min(1).describe("Subscription name (unique per tenant)"),
|
|
1369
|
+
webhookUrl: z13.string().url().describe("Webhook endpoint URL"),
|
|
1370
|
+
subscribedEvents: z13.array(z13.enum(PlatformEventType)).min(1).describe("Events to subscribe to"),
|
|
1371
|
+
payloadFormat: z13.enum(WebhookPayloadFormat).optional().default("GENERIC").describe("Payload format"),
|
|
1372
|
+
secret: z13.string().optional().describe("HMAC-SHA256 signing secret"),
|
|
1373
|
+
isActive: z13.boolean().optional().default(true).describe("Whether the subscription is active")
|
|
1374
|
+
})
|
|
1374
1375
|
},
|
|
1375
1376
|
async ({ ...body }) => callApi("POST", "webhook-subscriptions", { body })
|
|
1376
1377
|
);
|
|
@@ -1379,9 +1380,9 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
1379
1380
|
{
|
|
1380
1381
|
title: "Delete Webhook Subscription",
|
|
1381
1382
|
description: "Delete a webhook subscription by ID.",
|
|
1382
|
-
inputSchema: {
|
|
1383
|
-
id:
|
|
1384
|
-
}
|
|
1383
|
+
inputSchema: z13.object({
|
|
1384
|
+
id: z13.string().uuid().describe("Webhook subscription ID")
|
|
1385
|
+
})
|
|
1385
1386
|
},
|
|
1386
1387
|
async ({ id }) => callApi("DELETE", `webhook-subscriptions/${id}`)
|
|
1387
1388
|
);
|
|
@@ -1390,23 +1391,23 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
1390
1391
|
{
|
|
1391
1392
|
title: "Test Webhook Subscription",
|
|
1392
1393
|
description: "Send a test event to verify webhook connectivity. Returns the HTTP status code and success/failure message.",
|
|
1393
|
-
inputSchema: {
|
|
1394
|
-
id:
|
|
1395
|
-
}
|
|
1394
|
+
inputSchema: z13.object({
|
|
1395
|
+
id: z13.string().uuid().describe("Webhook subscription ID")
|
|
1396
|
+
})
|
|
1396
1397
|
},
|
|
1397
1398
|
async ({ id }) => callApi("POST", `webhook-subscriptions/${id}/test`)
|
|
1398
1399
|
);
|
|
1399
1400
|
}
|
|
1400
1401
|
|
|
1401
1402
|
// src/mcp/tools/domain-templates.ts
|
|
1402
|
-
import { z as
|
|
1403
|
+
import { z as z14 } from "zod";
|
|
1403
1404
|
function registerDomainTemplateTools(server, callApi) {
|
|
1404
1405
|
server.registerTool(
|
|
1405
1406
|
"lexq_domain_templates_list",
|
|
1406
1407
|
{
|
|
1407
1408
|
title: "List Domain Templates",
|
|
1408
1409
|
description: "List all domain templates. A domain template is a curated, industry-specific starter pack of fact definitions and sample rules (e.g. ECOMMERCE). Each entry reports its key, status (ACTIVE or COMING_SOON), and a summary of what it provisions. Call this before preview or apply to discover which templates can currently be applied.",
|
|
1409
|
-
inputSchema: {}
|
|
1410
|
+
inputSchema: z14.object({})
|
|
1410
1411
|
},
|
|
1411
1412
|
async () => callApi("GET", "domain-templates")
|
|
1412
1413
|
);
|
|
@@ -1415,11 +1416,11 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
1415
1416
|
{
|
|
1416
1417
|
title: "Preview Domain Template",
|
|
1417
1418
|
description: "Preview exactly what a domain template will provision before applying it: the fact definitions it registers, the sample rules it creates, and an apply plan. This is a read-only dry run \u2014 nothing is created. Only ACTIVE templates can be previewed.",
|
|
1418
|
-
inputSchema: {
|
|
1419
|
-
template:
|
|
1419
|
+
inputSchema: z14.object({
|
|
1420
|
+
template: z14.string().describe(
|
|
1420
1421
|
"Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see available keys \u2014 currently only ECOMMERCE is ACTIVE."
|
|
1421
1422
|
)
|
|
1422
|
-
}
|
|
1423
|
+
})
|
|
1423
1424
|
},
|
|
1424
1425
|
async ({ template }) => callApi("GET", `domain-templates/${template}/preview`)
|
|
1425
1426
|
);
|
|
@@ -1428,12 +1429,12 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
1428
1429
|
{
|
|
1429
1430
|
title: "Apply Domain Template",
|
|
1430
1431
|
description: "Apply a domain template to the current tenant. Creates the template's fact definitions and a new policy group pre-populated with its sample rules as a DRAFT version. Existing facts are skipped \u2014 apply is additive and never overwrites existing schema. Run lexq_domain_templates_preview first to review what will be created. Only ACTIVE templates can be applied.",
|
|
1431
|
-
inputSchema: {
|
|
1432
|
-
template:
|
|
1433
|
-
customName:
|
|
1432
|
+
inputSchema: z14.object({
|
|
1433
|
+
template: z14.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
|
|
1434
|
+
customName: z14.string().optional().describe(
|
|
1434
1435
|
"Optional custom name for the policy group that gets created. If omitted, the template's default name is used."
|
|
1435
1436
|
)
|
|
1436
|
-
}
|
|
1437
|
+
})
|
|
1437
1438
|
},
|
|
1438
1439
|
async ({ template, customName }) => {
|
|
1439
1440
|
const body = {};
|