@lexq/cli 0.1.58 → 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 +376 -367
- package/dist/mcp/register.d.ts +1 -1
- package/dist/mcp/register.js +374 -365
- package/package.json +7 -4
package/dist/index.js
CHANGED
|
@@ -3317,8 +3317,8 @@ import dedent17 from "dedent";
|
|
|
3317
3317
|
import { readFileSync as readFileSync3 } from "fs";
|
|
3318
3318
|
import { dirname, join as join2 } from "path";
|
|
3319
3319
|
import { fileURLToPath } from "url";
|
|
3320
|
-
import {
|
|
3321
|
-
import {
|
|
3320
|
+
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
3321
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
3322
3322
|
|
|
3323
3323
|
// src/mcp/tools/_shared.ts
|
|
3324
3324
|
function createCallApiFromConfig() {
|
|
@@ -3402,27 +3402,28 @@ function formatUnregisteredFactWarning(meta) {
|
|
|
3402
3402
|
}
|
|
3403
3403
|
|
|
3404
3404
|
// src/mcp/tools/status.ts
|
|
3405
|
+
import { z } from "zod";
|
|
3405
3406
|
function registerStatusTools(server, callApi) {
|
|
3406
3407
|
server.registerTool(
|
|
3407
3408
|
"lexq_whoami",
|
|
3408
3409
|
{
|
|
3409
3410
|
title: "Who Am I",
|
|
3410
3411
|
description: "Show current authentication info (tenant ID, user ID, role).",
|
|
3411
|
-
inputSchema: {}
|
|
3412
|
+
inputSchema: z.object({})
|
|
3412
3413
|
},
|
|
3413
3414
|
async () => callApi("GET", "whoami")
|
|
3414
3415
|
);
|
|
3415
3416
|
}
|
|
3416
3417
|
|
|
3417
3418
|
// src/mcp/tools/groups.ts
|
|
3418
|
-
import { z } from "zod";
|
|
3419
|
+
import { z as z2 } from "zod";
|
|
3419
3420
|
function registerGroupTools(server, callApi) {
|
|
3420
3421
|
server.registerTool(
|
|
3421
3422
|
"lexq_groups_list",
|
|
3422
3423
|
{
|
|
3423
3424
|
title: "List Policy Groups",
|
|
3424
3425
|
description: "List all policy groups (tenant-wide, priority ASC).",
|
|
3425
|
-
inputSchema: {}
|
|
3426
|
+
inputSchema: z2.object({})
|
|
3426
3427
|
},
|
|
3427
3428
|
async () => callApi("GET", "policy-groups")
|
|
3428
3429
|
);
|
|
@@ -3431,9 +3432,9 @@ function registerGroupTools(server, callApi) {
|
|
|
3431
3432
|
{
|
|
3432
3433
|
title: "Get Policy Group",
|
|
3433
3434
|
description: "Get a single policy group by ID.",
|
|
3434
|
-
inputSchema: {
|
|
3435
|
-
groupId:
|
|
3436
|
-
}
|
|
3435
|
+
inputSchema: z2.object({
|
|
3436
|
+
groupId: z2.string().uuid().describe("Policy group ID")
|
|
3437
|
+
})
|
|
3437
3438
|
},
|
|
3438
3439
|
async ({ groupId }) => callApi("GET", `policy-groups/${groupId}`)
|
|
3439
3440
|
);
|
|
@@ -3441,15 +3442,19 @@ function registerGroupTools(server, callApi) {
|
|
|
3441
3442
|
"lexq_groups_create",
|
|
3442
3443
|
{
|
|
3443
3444
|
title: "Create Policy Group",
|
|
3444
|
-
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.
|
|
3445
|
-
inputSchema: {
|
|
3446
|
-
name:
|
|
3447
|
-
description:
|
|
3448
|
-
activationMode:
|
|
3449
|
-
activationStrategy:
|
|
3450
|
-
executionLimit:
|
|
3451
|
-
|
|
3452
|
-
|
|
3445
|
+
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.",
|
|
3446
|
+
inputSchema: z2.object({
|
|
3447
|
+
name: z2.string().describe("Group name (unique among non-ARCHIVED)"),
|
|
3448
|
+
description: z2.string().optional().describe("Group description"),
|
|
3449
|
+
activationMode: z2.enum(ConflictResolutionMode).optional().describe("Conflict resolution mode"),
|
|
3450
|
+
activationStrategy: z2.enum(ConflictResolutionStrategy).optional().describe("Ranking used to pick the winning groups when mode is EXCLUSIVE or MAX_N"),
|
|
3451
|
+
executionLimit: z2.number().int().min(1).optional().describe(
|
|
3452
|
+
"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."
|
|
3453
|
+
),
|
|
3454
|
+
activationGroup: z2.string().optional().describe(
|
|
3455
|
+
"Activation group (Execution Group) cluster key. Policy groups sharing this key compete, and group priority picks the winners."
|
|
3456
|
+
)
|
|
3457
|
+
})
|
|
3453
3458
|
},
|
|
3454
3459
|
async (args) => {
|
|
3455
3460
|
const body = {
|
|
@@ -3468,16 +3473,20 @@ function registerGroupTools(server, callApi) {
|
|
|
3468
3473
|
{
|
|
3469
3474
|
title: "Update Policy Group",
|
|
3470
3475
|
description: "Update a policy group. Only provided fields are updated; omitted fields remain unchanged.",
|
|
3471
|
-
inputSchema: {
|
|
3472
|
-
groupId:
|
|
3473
|
-
name:
|
|
3474
|
-
description:
|
|
3475
|
-
status:
|
|
3476
|
-
activationGroup:
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3476
|
+
inputSchema: z2.object({
|
|
3477
|
+
groupId: z2.string().uuid().describe("Policy group ID"),
|
|
3478
|
+
name: z2.string().optional().describe("New name"),
|
|
3479
|
+
description: z2.string().optional().describe("New description"),
|
|
3480
|
+
status: z2.enum(["ACTIVE", "DISABLED"]).optional().describe("Status (DISABLED = emergency stop)"),
|
|
3481
|
+
activationGroup: z2.string().optional().describe(
|
|
3482
|
+
"Activation group (Execution Group) cluster key. Policy groups sharing this key compete, and group priority picks the winners."
|
|
3483
|
+
),
|
|
3484
|
+
activationMode: z2.enum(ConflictResolutionMode).optional().describe("Conflict resolution mode"),
|
|
3485
|
+
activationStrategy: z2.enum(ConflictResolutionStrategy).optional().describe("Ranking used to pick the winning groups"),
|
|
3486
|
+
executionLimit: z2.number().int().min(1).optional().describe(
|
|
3487
|
+
"How many policy groups sharing this activationGroup may run. Counts groups, not rules."
|
|
3488
|
+
)
|
|
3489
|
+
})
|
|
3481
3490
|
},
|
|
3482
3491
|
async ({ groupId, ...body }) => callApi("PUT", `policy-groups/${groupId}`, { body })
|
|
3483
3492
|
);
|
|
@@ -3486,9 +3495,9 @@ function registerGroupTools(server, callApi) {
|
|
|
3486
3495
|
{
|
|
3487
3496
|
title: "Delete Policy Group",
|
|
3488
3497
|
description: "Archive a policy group. Only non-live groups can be deleted. This is irreversible.",
|
|
3489
|
-
inputSchema: {
|
|
3490
|
-
groupId:
|
|
3491
|
-
}
|
|
3498
|
+
inputSchema: z2.object({
|
|
3499
|
+
groupId: z2.string().uuid().describe("Policy group ID")
|
|
3500
|
+
})
|
|
3492
3501
|
},
|
|
3493
3502
|
async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}`)
|
|
3494
3503
|
);
|
|
@@ -3497,9 +3506,9 @@ function registerGroupTools(server, callApi) {
|
|
|
3497
3506
|
{
|
|
3498
3507
|
title: "Reorder Policy Groups",
|
|
3499
3508
|
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.",
|
|
3500
|
-
inputSchema: {
|
|
3501
|
-
groupIds:
|
|
3502
|
-
}
|
|
3509
|
+
inputSchema: z2.object({
|
|
3510
|
+
groupIds: z2.array(z2.string().uuid()).describe("Group IDs in desired priority order (index 0 = priority 1)")
|
|
3511
|
+
})
|
|
3503
3512
|
},
|
|
3504
3513
|
async ({ groupIds }) => {
|
|
3505
3514
|
const groups = groupIds.map((groupId, index) => ({
|
|
@@ -3514,11 +3523,11 @@ function registerGroupTools(server, callApi) {
|
|
|
3514
3523
|
{
|
|
3515
3524
|
title: "Start A/B Test",
|
|
3516
3525
|
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%.",
|
|
3517
|
-
inputSchema: {
|
|
3518
|
-
groupId:
|
|
3519
|
-
testVersionId:
|
|
3520
|
-
trafficRate:
|
|
3521
|
-
}
|
|
3526
|
+
inputSchema: z2.object({
|
|
3527
|
+
groupId: z2.string().uuid().describe("Policy group ID"),
|
|
3528
|
+
testVersionId: z2.string().uuid().describe("Challenger version ID to test"),
|
|
3529
|
+
trafficRate: z2.number().int().min(1).max(99).describe("Traffic percentage routed to challenger (1-99)")
|
|
3530
|
+
})
|
|
3522
3531
|
},
|
|
3523
3532
|
async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test`, { body })
|
|
3524
3533
|
);
|
|
@@ -3527,9 +3536,9 @@ function registerGroupTools(server, callApi) {
|
|
|
3527
3536
|
{
|
|
3528
3537
|
title: "Stop A/B Test",
|
|
3529
3538
|
description: "Stop a running A/B test. All traffic is restored to the control (current) version.",
|
|
3530
|
-
inputSchema: {
|
|
3531
|
-
groupId:
|
|
3532
|
-
}
|
|
3539
|
+
inputSchema: z2.object({
|
|
3540
|
+
groupId: z2.string().uuid().describe("Policy group ID")
|
|
3541
|
+
})
|
|
3533
3542
|
},
|
|
3534
3543
|
async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}/ab-test`)
|
|
3535
3544
|
);
|
|
@@ -3538,28 +3547,28 @@ function registerGroupTools(server, callApi) {
|
|
|
3538
3547
|
{
|
|
3539
3548
|
title: "Adjust A/B Test",
|
|
3540
3549
|
description: "Adjust traffic rate of a running A/B test.",
|
|
3541
|
-
inputSchema: {
|
|
3542
|
-
groupId:
|
|
3543
|
-
trafficRate:
|
|
3544
|
-
}
|
|
3550
|
+
inputSchema: z2.object({
|
|
3551
|
+
groupId: z2.string().uuid().describe("Policy group ID"),
|
|
3552
|
+
trafficRate: z2.number().int().min(1).max(99).describe("New traffic percentage for challenger (1-99)")
|
|
3553
|
+
})
|
|
3545
3554
|
},
|
|
3546
3555
|
async ({ groupId, ...body }) => callApi("PATCH", `policy-groups/${groupId}/ab-test/traffic-rate`, { body })
|
|
3547
3556
|
);
|
|
3548
3557
|
}
|
|
3549
3558
|
|
|
3550
3559
|
// src/mcp/tools/versions.ts
|
|
3551
|
-
import { z as
|
|
3560
|
+
import { z as z3 } from "zod";
|
|
3552
3561
|
function registerVersionTools(server, callApi) {
|
|
3553
3562
|
server.registerTool(
|
|
3554
3563
|
"lexq_versions_list",
|
|
3555
3564
|
{
|
|
3556
3565
|
title: "List Policy Versions",
|
|
3557
3566
|
description: "List all versions of a policy group.",
|
|
3558
|
-
inputSchema: {
|
|
3559
|
-
groupId:
|
|
3560
|
-
page:
|
|
3561
|
-
size:
|
|
3562
|
-
}
|
|
3567
|
+
inputSchema: z3.object({
|
|
3568
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
3569
|
+
page: z3.number().int().min(0).default(0).describe("Page number"),
|
|
3570
|
+
size: z3.number().int().min(1).max(100).default(20).describe("Page size")
|
|
3571
|
+
})
|
|
3563
3572
|
},
|
|
3564
3573
|
async ({ groupId, page, size }) => callApi("GET", `policy-groups/${groupId}/versions`, {
|
|
3565
3574
|
params: paginationParams(page, size)
|
|
@@ -3570,10 +3579,10 @@ function registerVersionTools(server, callApi) {
|
|
|
3570
3579
|
{
|
|
3571
3580
|
title: "Get Policy Version",
|
|
3572
3581
|
description: "Get a single version by ID, including its rules and fact requirements.",
|
|
3573
|
-
inputSchema: {
|
|
3574
|
-
groupId:
|
|
3575
|
-
versionId:
|
|
3576
|
-
}
|
|
3582
|
+
inputSchema: z3.object({
|
|
3583
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
3584
|
+
versionId: z3.string().uuid().describe("Version ID")
|
|
3585
|
+
})
|
|
3577
3586
|
},
|
|
3578
3587
|
async ({ groupId, versionId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}`)
|
|
3579
3588
|
);
|
|
@@ -3582,12 +3591,12 @@ function registerVersionTools(server, callApi) {
|
|
|
3582
3591
|
{
|
|
3583
3592
|
title: "Create Policy Version",
|
|
3584
3593
|
description: "Create a new DRAFT version in a policy group. Optionally provide a commit message and effective date range.",
|
|
3585
|
-
inputSchema: {
|
|
3586
|
-
groupId:
|
|
3587
|
-
commitMessage:
|
|
3588
|
-
effectiveFrom:
|
|
3589
|
-
effectiveTo:
|
|
3590
|
-
}
|
|
3594
|
+
inputSchema: z3.object({
|
|
3595
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
3596
|
+
commitMessage: z3.string().optional().describe("Commit message describing this version"),
|
|
3597
|
+
effectiveFrom: z3.string().optional().describe("Effective start date (ISO 8601)"),
|
|
3598
|
+
effectiveTo: z3.string().optional().describe("Effective end date (ISO 8601)")
|
|
3599
|
+
})
|
|
3591
3600
|
},
|
|
3592
3601
|
async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/versions`, { body })
|
|
3593
3602
|
);
|
|
@@ -3596,13 +3605,13 @@ function registerVersionTools(server, callApi) {
|
|
|
3596
3605
|
{
|
|
3597
3606
|
title: "Update Policy Version",
|
|
3598
3607
|
description: "Update a DRAFT version. Only DRAFT versions can be modified. Only provided fields are changed.",
|
|
3599
|
-
inputSchema: {
|
|
3600
|
-
groupId:
|
|
3601
|
-
versionId:
|
|
3602
|
-
commitMessage:
|
|
3603
|
-
effectiveFrom:
|
|
3604
|
-
effectiveTo:
|
|
3605
|
-
}
|
|
3608
|
+
inputSchema: z3.object({
|
|
3609
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
3610
|
+
versionId: z3.string().uuid().describe("Version ID"),
|
|
3611
|
+
commitMessage: z3.string().optional().describe("New commit message"),
|
|
3612
|
+
effectiveFrom: z3.string().optional().describe("New effective start date"),
|
|
3613
|
+
effectiveTo: z3.string().optional().describe("New effective end date")
|
|
3614
|
+
})
|
|
3606
3615
|
},
|
|
3607
3616
|
async ({ groupId, versionId, ...body }) => callApi("PUT", `policy-groups/${groupId}/versions/${versionId}`, { body })
|
|
3608
3617
|
);
|
|
@@ -3611,10 +3620,10 @@ function registerVersionTools(server, callApi) {
|
|
|
3611
3620
|
{
|
|
3612
3621
|
title: "Delete Policy Version",
|
|
3613
3622
|
description: "Delete a DRAFT version. Only DRAFT versions can be deleted.",
|
|
3614
|
-
inputSchema: {
|
|
3615
|
-
groupId:
|
|
3616
|
-
versionId:
|
|
3617
|
-
}
|
|
3623
|
+
inputSchema: z3.object({
|
|
3624
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
3625
|
+
versionId: z3.string().uuid().describe("Version ID")
|
|
3626
|
+
})
|
|
3618
3627
|
},
|
|
3619
3628
|
async ({ groupId, versionId }) => callApi("DELETE", `policy-groups/${groupId}/versions/${versionId}`)
|
|
3620
3629
|
);
|
|
@@ -3623,10 +3632,10 @@ function registerVersionTools(server, callApi) {
|
|
|
3623
3632
|
{
|
|
3624
3633
|
title: "Clone Policy Version",
|
|
3625
3634
|
description: "Clone an existing version to create a new DRAFT. Useful when the source version is already published.",
|
|
3626
|
-
inputSchema: {
|
|
3627
|
-
groupId:
|
|
3628
|
-
versionId:
|
|
3629
|
-
}
|
|
3635
|
+
inputSchema: z3.object({
|
|
3636
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
3637
|
+
versionId: z3.string().uuid().describe("Source version ID to clone")
|
|
3638
|
+
})
|
|
3630
3639
|
},
|
|
3631
3640
|
async ({ groupId, versionId }) => {
|
|
3632
3641
|
return callApi("POST", `policy-groups/${groupId}/versions/${versionId}/clone`, {
|
|
@@ -3637,7 +3646,7 @@ function registerVersionTools(server, callApi) {
|
|
|
3637
3646
|
}
|
|
3638
3647
|
|
|
3639
3648
|
// src/mcp/tools/rules.ts
|
|
3640
|
-
import { z as
|
|
3649
|
+
import { z as z4 } from "zod";
|
|
3641
3650
|
import dedent15 from "dedent";
|
|
3642
3651
|
function registerRuleTools(server, callApi) {
|
|
3643
3652
|
server.registerTool(
|
|
@@ -3645,10 +3654,10 @@ function registerRuleTools(server, callApi) {
|
|
|
3645
3654
|
{
|
|
3646
3655
|
title: "List Rules",
|
|
3647
3656
|
description: "List all rules in a version (priority ASC). Returns summary with conditionSummary and actionSummary.",
|
|
3648
|
-
inputSchema: {
|
|
3649
|
-
groupId:
|
|
3650
|
-
versionId:
|
|
3651
|
-
}
|
|
3657
|
+
inputSchema: z4.object({
|
|
3658
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
3659
|
+
versionId: z4.string().uuid().describe("Version ID")
|
|
3660
|
+
})
|
|
3652
3661
|
},
|
|
3653
3662
|
async ({ groupId, versionId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules`)
|
|
3654
3663
|
);
|
|
@@ -3657,11 +3666,11 @@ function registerRuleTools(server, callApi) {
|
|
|
3657
3666
|
{
|
|
3658
3667
|
title: "Get Rule Detail",
|
|
3659
3668
|
description: "Get full rule detail including condition tree and action definitions.",
|
|
3660
|
-
inputSchema: {
|
|
3661
|
-
groupId:
|
|
3662
|
-
versionId:
|
|
3663
|
-
ruleId:
|
|
3664
|
-
}
|
|
3669
|
+
inputSchema: z4.object({
|
|
3670
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
3671
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
3672
|
+
ruleId: z4.string().uuid().describe("Rule ID")
|
|
3673
|
+
})
|
|
3665
3674
|
},
|
|
3666
3675
|
async ({ groupId, versionId, ruleId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`)
|
|
3667
3676
|
);
|
|
@@ -3730,13 +3739,13 @@ function registerRuleTools(server, callApi) {
|
|
|
3730
3739
|
|
|
3731
3740
|
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).
|
|
3732
3741
|
`,
|
|
3733
|
-
inputSchema: {
|
|
3734
|
-
groupId:
|
|
3735
|
-
versionId:
|
|
3736
|
-
rule:
|
|
3742
|
+
inputSchema: z4.object({
|
|
3743
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
3744
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
3745
|
+
rule: z4.string().describe(
|
|
3737
3746
|
"JSON string of CreateRuleRequest: { name, condition, actions, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
|
|
3738
3747
|
)
|
|
3739
|
-
}
|
|
3748
|
+
})
|
|
3740
3749
|
},
|
|
3741
3750
|
async ({ groupId, versionId, rule }) => {
|
|
3742
3751
|
const body = parseJson(rule);
|
|
@@ -3748,14 +3757,14 @@ function registerRuleTools(server, callApi) {
|
|
|
3748
3757
|
{
|
|
3749
3758
|
title: "Update Rule",
|
|
3750
3759
|
description: "Update an existing rule in a DRAFT version. Only provided fields are changed.",
|
|
3751
|
-
inputSchema: {
|
|
3752
|
-
groupId:
|
|
3753
|
-
versionId:
|
|
3754
|
-
ruleId:
|
|
3755
|
-
rule:
|
|
3760
|
+
inputSchema: z4.object({
|
|
3761
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
3762
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
3763
|
+
ruleId: z4.string().uuid().describe("Rule ID"),
|
|
3764
|
+
rule: z4.string().describe(
|
|
3756
3765
|
"JSON string of UpdateRuleRequest: { name?, condition?, actions?, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
|
|
3757
3766
|
)
|
|
3758
|
-
}
|
|
3767
|
+
})
|
|
3759
3768
|
},
|
|
3760
3769
|
async ({ groupId, versionId, ruleId, rule }) => {
|
|
3761
3770
|
const body = parseJson(rule);
|
|
@@ -3769,12 +3778,12 @@ function registerRuleTools(server, callApi) {
|
|
|
3769
3778
|
{
|
|
3770
3779
|
title: "Delete Rule",
|
|
3771
3780
|
description: "Delete a rule from a DRAFT version.",
|
|
3772
|
-
inputSchema: {
|
|
3773
|
-
groupId:
|
|
3774
|
-
versionId:
|
|
3775
|
-
ruleId:
|
|
3776
|
-
force:
|
|
3777
|
-
}
|
|
3781
|
+
inputSchema: z4.object({
|
|
3782
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
3783
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
3784
|
+
ruleId: z4.string().uuid().describe("Rule ID"),
|
|
3785
|
+
force: z4.boolean().default(false).describe("Skip confirmation (for the last rule in a version)")
|
|
3786
|
+
})
|
|
3778
3787
|
},
|
|
3779
3788
|
async ({ groupId, versionId, ruleId, force }) => {
|
|
3780
3789
|
const params = {};
|
|
@@ -3789,11 +3798,11 @@ function registerRuleTools(server, callApi) {
|
|
|
3789
3798
|
{
|
|
3790
3799
|
title: "Reorder Rules",
|
|
3791
3800
|
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).",
|
|
3792
|
-
inputSchema: {
|
|
3793
|
-
groupId:
|
|
3794
|
-
versionId:
|
|
3795
|
-
ruleIds:
|
|
3796
|
-
}
|
|
3801
|
+
inputSchema: z4.object({
|
|
3802
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
3803
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
3804
|
+
ruleIds: z4.array(z4.string().uuid()).describe("Rule IDs in desired priority order")
|
|
3805
|
+
})
|
|
3797
3806
|
},
|
|
3798
3807
|
async ({ groupId, versionId, ruleIds }) => {
|
|
3799
3808
|
const rules = ruleIds.map((ruleId, index) => ({
|
|
@@ -3810,12 +3819,12 @@ function registerRuleTools(server, callApi) {
|
|
|
3810
3819
|
{
|
|
3811
3820
|
title: "Toggle Rule",
|
|
3812
3821
|
description: "Enable or disable a rule without deleting it.",
|
|
3813
|
-
inputSchema: {
|
|
3814
|
-
groupId:
|
|
3815
|
-
versionId:
|
|
3816
|
-
ruleId:
|
|
3817
|
-
isEnabled:
|
|
3818
|
-
}
|
|
3822
|
+
inputSchema: z4.object({
|
|
3823
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
3824
|
+
versionId: z4.string().uuid().describe("Version ID"),
|
|
3825
|
+
ruleId: z4.string().uuid().describe("Rule ID"),
|
|
3826
|
+
isEnabled: z4.boolean().describe("true to enable, false to disable")
|
|
3827
|
+
})
|
|
3819
3828
|
},
|
|
3820
3829
|
async ({ groupId, versionId, ruleId, isEnabled }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/enabled`, {
|
|
3821
3830
|
body: { isEnabled }
|
|
@@ -3824,7 +3833,7 @@ function registerRuleTools(server, callApi) {
|
|
|
3824
3833
|
}
|
|
3825
3834
|
|
|
3826
3835
|
// src/mcp/tools/facts.ts
|
|
3827
|
-
import { z as
|
|
3836
|
+
import { z as z5 } from "zod";
|
|
3828
3837
|
|
|
3829
3838
|
// src/types/facts.ts
|
|
3830
3839
|
var FACT_KEY_PATTERN = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
|
@@ -3837,11 +3846,11 @@ function registerFactTools(server, callApi) {
|
|
|
3837
3846
|
{
|
|
3838
3847
|
title: "List Fact Definitions",
|
|
3839
3848
|
description: "List all fact definitions (input variable schema). Shows key, type, required, and PII status. Always check this before creating rules.",
|
|
3840
|
-
inputSchema: {
|
|
3841
|
-
page:
|
|
3842
|
-
size:
|
|
3843
|
-
keyword:
|
|
3844
|
-
}
|
|
3849
|
+
inputSchema: z5.object({
|
|
3850
|
+
page: z5.number().int().min(0).default(0).describe("Page number"),
|
|
3851
|
+
size: z5.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
3852
|
+
keyword: z5.string().optional().describe("Search keyword")
|
|
3853
|
+
})
|
|
3845
3854
|
},
|
|
3846
3855
|
async ({ page, size, keyword }) => {
|
|
3847
3856
|
const params = paginationParams(page, size);
|
|
@@ -3854,16 +3863,16 @@ function registerFactTools(server, callApi) {
|
|
|
3854
3863
|
{
|
|
3855
3864
|
title: "Create Fact Definition",
|
|
3856
3865
|
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.",
|
|
3857
|
-
inputSchema: {
|
|
3858
|
-
key:
|
|
3859
|
-
name:
|
|
3860
|
-
type:
|
|
3861
|
-
description:
|
|
3862
|
-
isRequired:
|
|
3863
|
-
isPii:
|
|
3866
|
+
inputSchema: z5.object({
|
|
3867
|
+
key: z5.string().regex(FACT_KEY_PATTERN).describe("Variable key. Any casing; must start with a letter."),
|
|
3868
|
+
name: z5.string().describe("Display name"),
|
|
3869
|
+
type: z5.enum(VALUE_TYPES).describe("Value type"),
|
|
3870
|
+
description: z5.string().optional().describe("Description"),
|
|
3871
|
+
isRequired: z5.boolean().default(false).describe("Whether this fact is required for rule evaluation"),
|
|
3872
|
+
isPii: z5.boolean().default(false).describe(
|
|
3864
3873
|
"Mark as PII \u2014 masked on every read surface, revealable only in the console (audited)"
|
|
3865
3874
|
)
|
|
3866
|
-
}
|
|
3875
|
+
})
|
|
3867
3876
|
},
|
|
3868
3877
|
async (args) => callApi("POST", "schema/facts", { body: args })
|
|
3869
3878
|
);
|
|
@@ -3872,16 +3881,16 @@ function registerFactTools(server, callApi) {
|
|
|
3872
3881
|
{
|
|
3873
3882
|
title: "Update Fact Definition",
|
|
3874
3883
|
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.",
|
|
3875
|
-
inputSchema: {
|
|
3876
|
-
factId:
|
|
3877
|
-
name:
|
|
3878
|
-
description:
|
|
3879
|
-
type:
|
|
3884
|
+
inputSchema: z5.object({
|
|
3885
|
+
factId: z5.string().uuid().describe("Fact definition ID"),
|
|
3886
|
+
name: z5.string().optional().describe("Display name"),
|
|
3887
|
+
description: z5.string().optional().describe("Description"),
|
|
3888
|
+
type: z5.enum(VALUE_TYPES).optional().describe(
|
|
3880
3889
|
"Value type. Omit to leave it unchanged. Changing it fails with FD-007 while any rule references the fact."
|
|
3881
3890
|
),
|
|
3882
|
-
isRequired:
|
|
3883
|
-
isPii:
|
|
3884
|
-
}
|
|
3891
|
+
isRequired: z5.boolean().optional().describe("Required flag"),
|
|
3892
|
+
isPii: z5.boolean().optional().describe("PII flag \u2014 enables/disables masking (changeable even on system facts)")
|
|
3893
|
+
})
|
|
3885
3894
|
},
|
|
3886
3895
|
async ({ factId, ...body }) => callApi("PUT", `schema/facts/${factId}`, { body })
|
|
3887
3896
|
);
|
|
@@ -3890,9 +3899,9 @@ function registerFactTools(server, callApi) {
|
|
|
3890
3899
|
{
|
|
3891
3900
|
title: "Delete Fact Definition",
|
|
3892
3901
|
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.",
|
|
3893
|
-
inputSchema: {
|
|
3894
|
-
factId:
|
|
3895
|
-
}
|
|
3902
|
+
inputSchema: z5.object({
|
|
3903
|
+
factId: z5.string().uuid().describe("Fact definition ID")
|
|
3904
|
+
})
|
|
3896
3905
|
},
|
|
3897
3906
|
async ({ factId }) => callApi("DELETE", `schema/facts/${factId}`)
|
|
3898
3907
|
);
|
|
@@ -3901,7 +3910,7 @@ function registerFactTools(server, callApi) {
|
|
|
3901
3910
|
{
|
|
3902
3911
|
title: "Get Action Runtime Fact Metadata",
|
|
3903
3912
|
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.",
|
|
3904
|
-
inputSchema: {}
|
|
3913
|
+
inputSchema: z5.object({})
|
|
3905
3914
|
},
|
|
3906
3915
|
async () => callApi("GET", "schema/action-metadata")
|
|
3907
3916
|
);
|
|
@@ -3910,10 +3919,10 @@ function registerFactTools(server, callApi) {
|
|
|
3910
3919
|
{
|
|
3911
3920
|
title: "List Unregistered Facts",
|
|
3912
3921
|
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.",
|
|
3913
|
-
inputSchema: {
|
|
3914
|
-
groupId:
|
|
3915
|
-
versionId:
|
|
3916
|
-
}
|
|
3922
|
+
inputSchema: z5.object({
|
|
3923
|
+
groupId: z5.string().uuid().describe("Policy group ID"),
|
|
3924
|
+
versionId: z5.string().uuid().describe("Version ID")
|
|
3925
|
+
})
|
|
3917
3926
|
},
|
|
3918
3927
|
async ({ groupId, versionId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/unregistered-facts`)
|
|
3919
3928
|
);
|
|
@@ -3922,10 +3931,10 @@ function registerFactTools(server, callApi) {
|
|
|
3922
3931
|
{
|
|
3923
3932
|
title: "Export Fact Catalog",
|
|
3924
3933
|
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.",
|
|
3925
|
-
inputSchema: {
|
|
3926
|
-
format:
|
|
3927
|
-
keyword:
|
|
3928
|
-
}
|
|
3934
|
+
inputSchema: z5.object({
|
|
3935
|
+
format: z5.enum(EXPORT_FORMATS).default("csv").describe("Export format"),
|
|
3936
|
+
keyword: z5.string().optional().describe("Filter by key or name")
|
|
3937
|
+
})
|
|
3929
3938
|
},
|
|
3930
3939
|
async ({ format, keyword }) => callApi("GET", "schema/facts/export", {
|
|
3931
3940
|
params: keyword ? { format, keyword } : { format }
|
|
@@ -3934,18 +3943,18 @@ function registerFactTools(server, callApi) {
|
|
|
3934
3943
|
}
|
|
3935
3944
|
|
|
3936
3945
|
// src/mcp/tools/deploy.ts
|
|
3937
|
-
import { z as
|
|
3946
|
+
import { z as z6 } from "zod";
|
|
3938
3947
|
function registerDeployTools(server, callApi) {
|
|
3939
3948
|
server.registerTool(
|
|
3940
3949
|
"lexq_deploy_publish",
|
|
3941
3950
|
{
|
|
3942
3951
|
title: "Publish Version",
|
|
3943
3952
|
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.",
|
|
3944
|
-
inputSchema: {
|
|
3945
|
-
groupId:
|
|
3946
|
-
versionId:
|
|
3947
|
-
memo:
|
|
3948
|
-
}
|
|
3953
|
+
inputSchema: z6.object({
|
|
3954
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
3955
|
+
versionId: z6.string().uuid().describe("Version ID to publish"),
|
|
3956
|
+
memo: z6.string().min(1).describe("Publish memo (required)")
|
|
3957
|
+
})
|
|
3949
3958
|
},
|
|
3950
3959
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/versions/${versionId}/publish`, { body: { memo } })
|
|
3951
3960
|
);
|
|
@@ -3954,11 +3963,11 @@ function registerDeployTools(server, callApi) {
|
|
|
3954
3963
|
{
|
|
3955
3964
|
title: "Deploy to Live",
|
|
3956
3965
|
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.",
|
|
3957
|
-
inputSchema: {
|
|
3958
|
-
groupId:
|
|
3959
|
-
versionId:
|
|
3960
|
-
memo:
|
|
3961
|
-
}
|
|
3966
|
+
inputSchema: z6.object({
|
|
3967
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
3968
|
+
versionId: z6.string().uuid().describe("Version ID to deploy"),
|
|
3969
|
+
memo: z6.string().min(1).describe("Deployment memo (required)")
|
|
3970
|
+
})
|
|
3962
3971
|
},
|
|
3963
3972
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/deploy`, {
|
|
3964
3973
|
body: { versionId, memo }
|
|
@@ -3969,10 +3978,10 @@ function registerDeployTools(server, callApi) {
|
|
|
3969
3978
|
{
|
|
3970
3979
|
title: "Rollback Deployment",
|
|
3971
3980
|
description: "Rollback to the previous deployed version. Only available if there is a previous version.",
|
|
3972
|
-
inputSchema: {
|
|
3973
|
-
groupId:
|
|
3974
|
-
memo:
|
|
3975
|
-
}
|
|
3981
|
+
inputSchema: z6.object({
|
|
3982
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
3983
|
+
memo: z6.string().min(1).describe("Rollback reason (required)")
|
|
3984
|
+
})
|
|
3976
3985
|
},
|
|
3977
3986
|
async ({ groupId, memo }) => callApi("POST", `policy-groups/${groupId}/rollback`, {
|
|
3978
3987
|
body: { memo }
|
|
@@ -3983,10 +3992,10 @@ function registerDeployTools(server, callApi) {
|
|
|
3983
3992
|
{
|
|
3984
3993
|
title: "Undeploy",
|
|
3985
3994
|
description: "Remove the live version from traffic. The version stays ACTIVE but no longer serves requests.",
|
|
3986
|
-
inputSchema: {
|
|
3987
|
-
groupId:
|
|
3988
|
-
memo:
|
|
3989
|
-
}
|
|
3995
|
+
inputSchema: z6.object({
|
|
3996
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
3997
|
+
memo: z6.string().min(1).describe("Undeploy reason (required)")
|
|
3998
|
+
})
|
|
3990
3999
|
},
|
|
3991
4000
|
async ({ groupId, memo }) => callApi("POST", `policy-groups/${groupId}/undeploy`, {
|
|
3992
4001
|
body: { memo }
|
|
@@ -3997,11 +4006,11 @@ function registerDeployTools(server, callApi) {
|
|
|
3997
4006
|
{
|
|
3998
4007
|
title: "Schedule Deployment",
|
|
3999
4008
|
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).",
|
|
4000
|
-
inputSchema: {
|
|
4001
|
-
groupId:
|
|
4002
|
-
versionId:
|
|
4003
|
-
memo:
|
|
4004
|
-
}
|
|
4009
|
+
inputSchema: z6.object({
|
|
4010
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
4011
|
+
versionId: z6.string().uuid().describe("ACTIVE version ID with a future effective start date"),
|
|
4012
|
+
memo: z6.string().min(1).describe("Schedule memo (required)")
|
|
4013
|
+
})
|
|
4005
4014
|
},
|
|
4006
4015
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/schedule`, {
|
|
4007
4016
|
body: { versionId, memo }
|
|
@@ -4012,9 +4021,9 @@ function registerDeployTools(server, callApi) {
|
|
|
4012
4021
|
{
|
|
4013
4022
|
title: "Cancel Scheduled Deployment",
|
|
4014
4023
|
description: "Cancel the pending scheduled deployment for a group. The version itself is not affected. Fails with P-039 if no pending schedule exists.",
|
|
4015
|
-
inputSchema: {
|
|
4016
|
-
groupId:
|
|
4017
|
-
}
|
|
4024
|
+
inputSchema: z6.object({
|
|
4025
|
+
groupId: z6.string().uuid().describe("Policy group ID")
|
|
4026
|
+
})
|
|
4018
4027
|
},
|
|
4019
4028
|
async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}/schedule`)
|
|
4020
4029
|
);
|
|
@@ -4023,10 +4032,10 @@ function registerDeployTools(server, callApi) {
|
|
|
4023
4032
|
{
|
|
4024
4033
|
title: "List Scheduled Deployments",
|
|
4025
4034
|
description: "List scheduled deployments across all groups (all statuses: PENDING, EXECUTED, CANCELED, FAILED), newest first.",
|
|
4026
|
-
inputSchema: {
|
|
4027
|
-
page:
|
|
4028
|
-
size:
|
|
4029
|
-
}
|
|
4035
|
+
inputSchema: z6.object({
|
|
4036
|
+
page: z6.number().int().min(0).default(0).describe("Page number"),
|
|
4037
|
+
size: z6.number().int().min(1).max(100).default(20).describe("Page size")
|
|
4038
|
+
})
|
|
4030
4039
|
},
|
|
4031
4040
|
async ({ page, size }) => callApi("GET", "policy-groups/schedules", { params: paginationParams(page, size) })
|
|
4032
4041
|
);
|
|
@@ -4035,14 +4044,14 @@ function registerDeployTools(server, callApi) {
|
|
|
4035
4044
|
{
|
|
4036
4045
|
title: "Deployment History",
|
|
4037
4046
|
description: "List deployment history across all groups.",
|
|
4038
|
-
inputSchema: {
|
|
4039
|
-
page:
|
|
4040
|
-
size:
|
|
4041
|
-
groupId:
|
|
4042
|
-
types:
|
|
4043
|
-
startDate:
|
|
4044
|
-
endDate:
|
|
4045
|
-
}
|
|
4047
|
+
inputSchema: z6.object({
|
|
4048
|
+
page: z6.number().int().min(0).default(0).describe("Page number"),
|
|
4049
|
+
size: z6.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
4050
|
+
groupId: z6.string().uuid().optional().describe("Filter by group ID"),
|
|
4051
|
+
types: z6.string().optional().describe("Filter by deployment types (comma-separated: DEPLOY,ROLLBACK,UNDEPLOY)"),
|
|
4052
|
+
startDate: z6.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
4053
|
+
endDate: z6.string().optional().describe("End date (yyyy-MM-dd)")
|
|
4054
|
+
})
|
|
4046
4055
|
},
|
|
4047
4056
|
async ({ page, size, groupId, types, startDate, endDate }) => {
|
|
4048
4057
|
const params = paginationParams(page, size);
|
|
@@ -4058,9 +4067,9 @@ function registerDeployTools(server, callApi) {
|
|
|
4058
4067
|
{
|
|
4059
4068
|
title: "Deployment Detail",
|
|
4060
4069
|
description: "Get detailed info about a specific deployment including snapshot hash and integrity check.",
|
|
4061
|
-
inputSchema: {
|
|
4062
|
-
deploymentId:
|
|
4063
|
-
}
|
|
4070
|
+
inputSchema: z6.object({
|
|
4071
|
+
deploymentId: z6.string().uuid().describe("Deployment ID")
|
|
4072
|
+
})
|
|
4064
4073
|
},
|
|
4065
4074
|
async ({ deploymentId }) => callApi("GET", `deployments/${deploymentId}`)
|
|
4066
4075
|
);
|
|
@@ -4069,7 +4078,7 @@ function registerDeployTools(server, callApi) {
|
|
|
4069
4078
|
{
|
|
4070
4079
|
title: "Deployment Overview",
|
|
4071
4080
|
description: "Show current deployment status of all groups \u2014 which version is live, last deployment type, and deployer.",
|
|
4072
|
-
inputSchema: {}
|
|
4081
|
+
inputSchema: z6.object({})
|
|
4073
4082
|
},
|
|
4074
4083
|
async () => callApi("GET", "deployments/overview")
|
|
4075
4084
|
);
|
|
@@ -4078,9 +4087,9 @@ function registerDeployTools(server, callApi) {
|
|
|
4078
4087
|
{
|
|
4079
4088
|
title: "List Deployable Versions",
|
|
4080
4089
|
description: "List ACTIVE (published) versions that can be deployed for a group. Use this to find which versions are available before calling deploy live.",
|
|
4081
|
-
inputSchema: {
|
|
4082
|
-
groupId:
|
|
4083
|
-
}
|
|
4090
|
+
inputSchema: z6.object({
|
|
4091
|
+
groupId: z6.string().uuid().describe("Policy group ID")
|
|
4092
|
+
})
|
|
4084
4093
|
},
|
|
4085
4094
|
async ({ groupId }) => callApi("GET", `deployments/groups/${groupId}/deployable-versions`)
|
|
4086
4095
|
);
|
|
@@ -4089,10 +4098,10 @@ function registerDeployTools(server, callApi) {
|
|
|
4089
4098
|
{
|
|
4090
4099
|
title: "Deployment Diff",
|
|
4091
4100
|
description: "Compare rule snapshots between two versions. Shows added, removed, and modified rules. Useful for reviewing changes before deploying a new version.",
|
|
4092
|
-
inputSchema: {
|
|
4093
|
-
baseVersionId:
|
|
4094
|
-
targetVersionId:
|
|
4095
|
-
}
|
|
4101
|
+
inputSchema: z6.object({
|
|
4102
|
+
baseVersionId: z6.string().uuid().describe("Base version ID (typically the current live)"),
|
|
4103
|
+
targetVersionId: z6.string().uuid().describe("Target version ID (the one you want to deploy)")
|
|
4104
|
+
})
|
|
4096
4105
|
},
|
|
4097
4106
|
async ({ baseVersionId, targetVersionId }) => callApi("GET", "deployments/diff", {
|
|
4098
4107
|
params: { baseVersionId, targetVersionId }
|
|
@@ -4101,7 +4110,7 @@ function registerDeployTools(server, callApi) {
|
|
|
4101
4110
|
}
|
|
4102
4111
|
|
|
4103
4112
|
// src/mcp/tools/analytics.ts
|
|
4104
|
-
import { z as
|
|
4113
|
+
import { z as z7 } from "zod";
|
|
4105
4114
|
import dedent16 from "dedent";
|
|
4106
4115
|
function registerAnalyticsTools(server, callApi) {
|
|
4107
4116
|
server.registerTool(
|
|
@@ -4120,11 +4129,11 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4120
4129
|
|
|
4121
4130
|
Example input: { "facts": { "paymentAmount": 100000, "customerTier": "VIP" } }
|
|
4122
4131
|
Always dry-run before publishing to validate rule behavior.`,
|
|
4123
|
-
inputSchema: {
|
|
4124
|
-
versionId:
|
|
4125
|
-
facts:
|
|
4126
|
-
includeDebugInfo:
|
|
4127
|
-
}
|
|
4132
|
+
inputSchema: z7.object({
|
|
4133
|
+
versionId: z7.string().uuid().describe("Policy version ID to test against"),
|
|
4134
|
+
facts: z7.string().describe('JSON string of facts object, e.g. {"paymentAmount":100000}'),
|
|
4135
|
+
includeDebugInfo: z7.boolean().default(true).describe("Include execution and decision traces")
|
|
4136
|
+
})
|
|
4128
4137
|
},
|
|
4129
4138
|
async ({ versionId, facts, includeDebugInfo }) => {
|
|
4130
4139
|
const parsedFacts = parseJson(facts);
|
|
@@ -4144,11 +4153,11 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4144
4153
|
resultA / resultB — full DryRunResponse for each version
|
|
4145
4154
|
diff.mutatedDiff — changes in mutatedFacts between A and B (key → {before, after})
|
|
4146
4155
|
diff.generatedDiff — changes in generatedVariables between A and B`,
|
|
4147
|
-
inputSchema: {
|
|
4148
|
-
versionIdA:
|
|
4149
|
-
versionIdB:
|
|
4150
|
-
facts:
|
|
4151
|
-
}
|
|
4156
|
+
inputSchema: z7.object({
|
|
4157
|
+
versionIdA: z7.string().uuid().describe("Baseline version ID"),
|
|
4158
|
+
versionIdB: z7.string().uuid().describe("Candidate version ID"),
|
|
4159
|
+
facts: z7.string().describe("JSON string of facts object")
|
|
4160
|
+
})
|
|
4152
4161
|
},
|
|
4153
4162
|
async ({ versionIdA, versionIdB, facts }) => {
|
|
4154
4163
|
const parsedFacts = parseJson(facts);
|
|
@@ -4162,10 +4171,10 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4162
4171
|
{
|
|
4163
4172
|
title: "Analyze Requirements",
|
|
4164
4173
|
description: "Analyze which input facts a version requires. Returns required keys, types, and an example request body.",
|
|
4165
|
-
inputSchema: {
|
|
4166
|
-
groupId:
|
|
4167
|
-
versionId:
|
|
4168
|
-
}
|
|
4174
|
+
inputSchema: z7.object({
|
|
4175
|
+
groupId: z7.string().uuid().describe("Policy group ID"),
|
|
4176
|
+
versionId: z7.string().uuid().describe("Version ID")
|
|
4177
|
+
})
|
|
4169
4178
|
},
|
|
4170
4179
|
async ({ groupId, versionId }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/requirements`)
|
|
4171
4180
|
);
|
|
@@ -4201,9 +4210,9 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4201
4210
|
"options": { "baselinePolicyVersionId": "<uuid>", "includeRuleStats": true }
|
|
4202
4211
|
}
|
|
4203
4212
|
`,
|
|
4204
|
-
inputSchema: {
|
|
4205
|
-
body:
|
|
4206
|
-
}
|
|
4213
|
+
inputSchema: z7.object({
|
|
4214
|
+
body: z7.string().describe("JSON string of SimulationRequest")
|
|
4215
|
+
})
|
|
4207
4216
|
},
|
|
4208
4217
|
async ({ body }) => {
|
|
4209
4218
|
const parsed = parseJson(body);
|
|
@@ -4215,9 +4224,9 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4215
4224
|
{
|
|
4216
4225
|
title: "Simulation Status",
|
|
4217
4226
|
description: "Get simulation status and results. Poll until status is COMPLETED or FAILED.",
|
|
4218
|
-
inputSchema: {
|
|
4219
|
-
simulationId:
|
|
4220
|
-
}
|
|
4227
|
+
inputSchema: z7.object({
|
|
4228
|
+
simulationId: z7.string().uuid().describe("Simulation ID")
|
|
4229
|
+
})
|
|
4221
4230
|
},
|
|
4222
4231
|
async ({ simulationId }) => callApi("GET", `analytics/simulations/${simulationId}`)
|
|
4223
4232
|
);
|
|
@@ -4226,13 +4235,13 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4226
4235
|
{
|
|
4227
4236
|
title: "List Simulations",
|
|
4228
4237
|
description: "List simulation history with optional filters.",
|
|
4229
|
-
inputSchema: {
|
|
4230
|
-
page:
|
|
4231
|
-
size:
|
|
4232
|
-
status:
|
|
4233
|
-
from:
|
|
4234
|
-
to:
|
|
4235
|
-
}
|
|
4238
|
+
inputSchema: z7.object({
|
|
4239
|
+
page: z7.number().int().min(0).default(0).describe("Page number"),
|
|
4240
|
+
size: z7.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
4241
|
+
status: z7.enum(["PENDING", "RUNNING", "COMPLETED", "FAILED", "CANCELED"]).optional().describe("Filter by status"),
|
|
4242
|
+
from: z7.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
4243
|
+
to: z7.string().optional().describe("End date (yyyy-MM-dd)")
|
|
4244
|
+
})
|
|
4236
4245
|
},
|
|
4237
4246
|
async ({ page, size, status, from, to }) => {
|
|
4238
4247
|
const params = paginationParams(page, size);
|
|
@@ -4247,9 +4256,9 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4247
4256
|
{
|
|
4248
4257
|
title: "Cancel Simulation",
|
|
4249
4258
|
description: "Cancel a running or pending simulation.",
|
|
4250
|
-
inputSchema: {
|
|
4251
|
-
simulationId:
|
|
4252
|
-
}
|
|
4259
|
+
inputSchema: z7.object({
|
|
4260
|
+
simulationId: z7.string().uuid().describe("Simulation ID")
|
|
4261
|
+
})
|
|
4253
4262
|
},
|
|
4254
4263
|
async ({ simulationId }) => callApi("DELETE", `analytics/simulations/${simulationId}`)
|
|
4255
4264
|
);
|
|
@@ -4258,10 +4267,10 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4258
4267
|
{
|
|
4259
4268
|
title: "Export Simulation",
|
|
4260
4269
|
description: "Export simulation results as JSON or CSV. Returns the raw data.",
|
|
4261
|
-
inputSchema: {
|
|
4262
|
-
simulationId:
|
|
4263
|
-
format:
|
|
4264
|
-
}
|
|
4270
|
+
inputSchema: z7.object({
|
|
4271
|
+
simulationId: z7.string().uuid().describe("Simulation ID"),
|
|
4272
|
+
format: z7.enum(EXPORT_FORMATS).default("json").describe("Export format")
|
|
4273
|
+
})
|
|
4265
4274
|
},
|
|
4266
4275
|
async ({ simulationId, format }) => callApi("GET", `analytics/simulations/${simulationId}/export`, {
|
|
4267
4276
|
params: { format }
|
|
@@ -4285,10 +4294,10 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4285
4294
|
|
|
4286
4295
|
JSON example: [{"userId":"user_001","paymentAmount":150000}, {"userId":"user_002","paymentAmount":50000}]
|
|
4287
4296
|
`,
|
|
4288
|
-
inputSchema: {
|
|
4289
|
-
content:
|
|
4290
|
-
filename:
|
|
4291
|
-
}
|
|
4297
|
+
inputSchema: z7.object({
|
|
4298
|
+
content: z7.string().describe("CSV or JSON content as string"),
|
|
4299
|
+
filename: z7.string().default("dataset.csv").describe("Filename with extension (.csv or .json)")
|
|
4300
|
+
})
|
|
4292
4301
|
},
|
|
4293
4302
|
async ({ content, filename }) => {
|
|
4294
4303
|
const result = await callApi("POST", "analytics/datasets/upload", {
|
|
@@ -4315,11 +4324,11 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4315
4324
|
{
|
|
4316
4325
|
title: "Download Dataset Template",
|
|
4317
4326
|
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.",
|
|
4318
|
-
inputSchema: {
|
|
4319
|
-
groupId:
|
|
4320
|
-
versionId:
|
|
4321
|
-
format:
|
|
4322
|
-
}
|
|
4327
|
+
inputSchema: z7.object({
|
|
4328
|
+
groupId: z7.string().uuid().describe("Policy group ID"),
|
|
4329
|
+
versionId: z7.string().uuid().describe("Version ID"),
|
|
4330
|
+
format: z7.enum(EXPORT_FORMATS).default("csv").describe("Template format")
|
|
4331
|
+
})
|
|
4323
4332
|
},
|
|
4324
4333
|
async ({ groupId, versionId, format }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/dataset-template`, {
|
|
4325
4334
|
params: { format }
|
|
@@ -4328,7 +4337,7 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4328
4337
|
}
|
|
4329
4338
|
|
|
4330
4339
|
// src/mcp/tools/profile.ts
|
|
4331
|
-
import { z as
|
|
4340
|
+
import { z as z8 } from "zod";
|
|
4332
4341
|
var RELATIVE_THRESHOLD = `flagged = p50 \u2265 ${SLOW_MULTIPLIER}\xD7 median of per-rule p50s within the group; absolute thresholds are intentionally not supported.`;
|
|
4333
4342
|
function profileParams(opts) {
|
|
4334
4343
|
const params = {};
|
|
@@ -4344,15 +4353,15 @@ function registerProfileTools(server, callApi) {
|
|
|
4344
4353
|
{
|
|
4345
4354
|
title: "Group Latency Profile",
|
|
4346
4355
|
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.`,
|
|
4347
|
-
inputSchema: {
|
|
4348
|
-
groupId:
|
|
4349
|
-
versionId:
|
|
4350
|
-
from:
|
|
4356
|
+
inputSchema: z8.object({
|
|
4357
|
+
groupId: z8.string().uuid().describe("Policy group ID"),
|
|
4358
|
+
versionId: z8.string().uuid().optional().describe("Version to inspect (default: live version)"),
|
|
4359
|
+
from: z8.string().optional().describe(
|
|
4351
4360
|
`Window start, ISO-8601 instant (e.g. 2026-07-01T00:00:00Z). Default: ${PROFILE_DEFAULT_WINDOW_HOURS}h ago`
|
|
4352
4361
|
),
|
|
4353
|
-
to:
|
|
4354
|
-
cacheState:
|
|
4355
|
-
}
|
|
4362
|
+
to: z8.string().optional().describe("Window end, ISO-8601 instant. Default: now"),
|
|
4363
|
+
cacheState: z8.enum(["HIT", "MISS"]).optional().describe("Cache dimension for the rule table and judgment (default: HIT)")
|
|
4364
|
+
})
|
|
4356
4365
|
},
|
|
4357
4366
|
async ({ groupId, versionId, from, to, cacheState }) => callApi("GET", `policy-groups/${groupId}/profile`, {
|
|
4358
4367
|
params: profileParams({ versionId, from, to, cacheState })
|
|
@@ -4363,15 +4372,15 @@ function registerProfileTools(server, callApi) {
|
|
|
4363
4372
|
{
|
|
4364
4373
|
title: "Rule Latency Detail",
|
|
4365
4374
|
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,
|
|
4366
|
-
inputSchema: {
|
|
4367
|
-
groupId:
|
|
4368
|
-
ruleId:
|
|
4369
|
-
versionId:
|
|
4370
|
-
from:
|
|
4375
|
+
inputSchema: z8.object({
|
|
4376
|
+
groupId: z8.string().uuid().describe("Policy group ID"),
|
|
4377
|
+
ruleId: z8.string().uuid().describe("Rule ID (from lexq_profile_overview)"),
|
|
4378
|
+
versionId: z8.string().uuid().optional().describe("Version to inspect (default: live version)"),
|
|
4379
|
+
from: z8.string().optional().describe(
|
|
4371
4380
|
`Window start, ISO-8601 instant. Default: ${PROFILE_DEFAULT_WINDOW_HOURS}h ago`
|
|
4372
4381
|
),
|
|
4373
|
-
to:
|
|
4374
|
-
}
|
|
4382
|
+
to: z8.string().optional().describe("Window end, ISO-8601 instant. Default: now")
|
|
4383
|
+
})
|
|
4375
4384
|
},
|
|
4376
4385
|
async ({ groupId, ruleId, versionId, from, to }) => callApi("GET", `policy-groups/${groupId}/profile/rules/${ruleId}`, {
|
|
4377
4386
|
params: profileParams({ versionId, from, to })
|
|
@@ -4380,17 +4389,17 @@ function registerProfileTools(server, callApi) {
|
|
|
4380
4389
|
}
|
|
4381
4390
|
|
|
4382
4391
|
// src/mcp/tools/replay.ts
|
|
4383
|
-
import { z as
|
|
4392
|
+
import { z as z9 } from "zod";
|
|
4384
4393
|
function registerReplayTools(server, callApi) {
|
|
4385
4394
|
server.registerTool(
|
|
4386
4395
|
"lexq_replay_decision",
|
|
4387
4396
|
{
|
|
4388
4397
|
title: "Replay a Decision",
|
|
4389
4398
|
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.",
|
|
4390
|
-
inputSchema: {
|
|
4391
|
-
traceId:
|
|
4392
|
-
candidateVersionId:
|
|
4393
|
-
}
|
|
4399
|
+
inputSchema: z9.object({
|
|
4400
|
+
traceId: z9.string().describe("Trace ID of the past execution to replay"),
|
|
4401
|
+
candidateVersionId: z9.string().uuid().describe("Version to re-evaluate against")
|
|
4402
|
+
})
|
|
4394
4403
|
},
|
|
4395
4404
|
async ({ traceId, candidateVersionId }) => callApi("POST", "replay/decisions", { body: { traceId, candidateVersionId } })
|
|
4396
4405
|
);
|
|
@@ -4399,14 +4408,14 @@ function registerReplayTools(server, callApi) {
|
|
|
4399
4408
|
{
|
|
4400
4409
|
title: "Start Window Replay (Blast Radius)",
|
|
4401
4410
|
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.",
|
|
4402
|
-
inputSchema: {
|
|
4403
|
-
candidateVersionId:
|
|
4404
|
-
from:
|
|
4405
|
-
to:
|
|
4406
|
-
maxRecords:
|
|
4411
|
+
inputSchema: z9.object({
|
|
4412
|
+
candidateVersionId: z9.string().uuid().describe("Version to re-evaluate against"),
|
|
4413
|
+
from: z9.string().describe("Window start date (yyyy-MM-dd)"),
|
|
4414
|
+
to: z9.string().describe("Window end date (yyyy-MM-dd)"),
|
|
4415
|
+
maxRecords: z9.number().int().min(1).optional().describe(
|
|
4407
4416
|
`Sample cap (server default applies; hard cap ${REPLAY_WINDOW_MAX_RECORDS / 1e3}k)`
|
|
4408
4417
|
)
|
|
4409
|
-
}
|
|
4418
|
+
})
|
|
4410
4419
|
},
|
|
4411
4420
|
async ({ candidateVersionId, from, to, maxRecords }) => callApi("POST", "replay/jobs", { body: { candidateVersionId, from, to, maxRecords } })
|
|
4412
4421
|
);
|
|
@@ -4415,9 +4424,9 @@ function registerReplayTools(server, callApi) {
|
|
|
4415
4424
|
{
|
|
4416
4425
|
title: "Get Replay Job Status",
|
|
4417
4426
|
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.",
|
|
4418
|
-
inputSchema: {
|
|
4419
|
-
jobId:
|
|
4420
|
-
}
|
|
4427
|
+
inputSchema: z9.object({
|
|
4428
|
+
jobId: z9.string().describe("Replay job ID from lexq_replay_start")
|
|
4429
|
+
})
|
|
4421
4430
|
},
|
|
4422
4431
|
async ({ jobId }) => callApi("GET", `replay/jobs/${jobId}`)
|
|
4423
4432
|
);
|
|
@@ -4426,10 +4435,10 @@ function registerReplayTools(server, callApi) {
|
|
|
4426
4435
|
{
|
|
4427
4436
|
title: "List Replay Jobs",
|
|
4428
4437
|
description: "List window replay job history (reverse-chronological). Lightweight items \u2014 use lexq_replay_status for summary and changed samples.",
|
|
4429
|
-
inputSchema: {
|
|
4430
|
-
page:
|
|
4431
|
-
size:
|
|
4432
|
-
}
|
|
4438
|
+
inputSchema: z9.object({
|
|
4439
|
+
page: z9.number().int().min(0).default(0).describe("Page number"),
|
|
4440
|
+
size: z9.number().int().min(1).max(100).default(20).describe("Page size")
|
|
4441
|
+
})
|
|
4433
4442
|
},
|
|
4434
4443
|
async ({ page, size }) => callApi("GET", "replay/jobs", { params: paginationParams(page, size) })
|
|
4435
4444
|
);
|
|
@@ -4438,9 +4447,9 @@ function registerReplayTools(server, callApi) {
|
|
|
4438
4447
|
{
|
|
4439
4448
|
title: "Cancel Replay Job",
|
|
4440
4449
|
description: "Cooperatively cancel a PENDING or RUNNING window replay job. Other states are rejected. VIEWER role cannot cancel.",
|
|
4441
|
-
inputSchema: {
|
|
4442
|
-
jobId:
|
|
4443
|
-
}
|
|
4450
|
+
inputSchema: z9.object({
|
|
4451
|
+
jobId: z9.string().describe("Replay job ID")
|
|
4452
|
+
})
|
|
4444
4453
|
},
|
|
4445
4454
|
async ({ jobId }) => callApi("POST", `replay/jobs/${jobId}/cancel`)
|
|
4446
4455
|
);
|
|
@@ -4449,33 +4458,33 @@ function registerReplayTools(server, callApi) {
|
|
|
4449
4458
|
{
|
|
4450
4459
|
title: "Export Replay Result",
|
|
4451
4460
|
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.",
|
|
4452
|
-
inputSchema: {
|
|
4453
|
-
jobId:
|
|
4454
|
-
format:
|
|
4455
|
-
}
|
|
4461
|
+
inputSchema: z9.object({
|
|
4462
|
+
jobId: z9.string().describe("Replay job ID"),
|
|
4463
|
+
format: z9.enum(EXPORT_FORMATS).default("json").describe("Export format")
|
|
4464
|
+
})
|
|
4456
4465
|
},
|
|
4457
4466
|
async ({ jobId, format }) => callApi("GET", `replay/jobs/${jobId}/export`, { params: { format } })
|
|
4458
4467
|
);
|
|
4459
4468
|
}
|
|
4460
4469
|
|
|
4461
4470
|
// src/mcp/tools/history.ts
|
|
4462
|
-
import { z as
|
|
4471
|
+
import { z as z10 } from "zod";
|
|
4463
4472
|
function registerHistoryTools(server, callApi) {
|
|
4464
4473
|
server.registerTool(
|
|
4465
4474
|
"lexq_history_list",
|
|
4466
4475
|
{
|
|
4467
4476
|
title: "List Execution History",
|
|
4468
4477
|
description: "List policy execution history. Shows trace ID, group, version, status, match result, and latency.",
|
|
4469
|
-
inputSchema: {
|
|
4470
|
-
page:
|
|
4471
|
-
size:
|
|
4472
|
-
traceId:
|
|
4473
|
-
groupId:
|
|
4474
|
-
versionId:
|
|
4475
|
-
status:
|
|
4476
|
-
startDate:
|
|
4477
|
-
endDate:
|
|
4478
|
-
}
|
|
4478
|
+
inputSchema: z10.object({
|
|
4479
|
+
page: z10.number().int().min(0).default(0).describe("Page number"),
|
|
4480
|
+
size: z10.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
4481
|
+
traceId: z10.string().optional().describe("Filter by trace ID"),
|
|
4482
|
+
groupId: z10.string().uuid().optional().describe("Filter by policy group"),
|
|
4483
|
+
versionId: z10.string().uuid().optional().describe("Filter by version"),
|
|
4484
|
+
status: z10.enum(["SUCCESS", "NO_MATCH", "ERROR", "TIMEOUT"]).optional().describe("Filter by execution status"),
|
|
4485
|
+
startDate: z10.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
4486
|
+
endDate: z10.string().optional().describe("End date (yyyy-MM-dd)")
|
|
4487
|
+
})
|
|
4479
4488
|
},
|
|
4480
4489
|
async ({ page, size, traceId, groupId, versionId, status, startDate, endDate }) => {
|
|
4481
4490
|
const params = paginationParams(page, size);
|
|
@@ -4493,9 +4502,9 @@ function registerHistoryTools(server, callApi) {
|
|
|
4493
4502
|
{
|
|
4494
4503
|
title: "Get Execution Detail",
|
|
4495
4504
|
description: "Get full execution detail including inputFacts, mutatedFacts, generatedVariables, executionTraces, and decisionTraces.",
|
|
4496
|
-
inputSchema: {
|
|
4497
|
-
traceId:
|
|
4498
|
-
}
|
|
4505
|
+
inputSchema: z10.object({
|
|
4506
|
+
traceId: z10.string().describe("Trace ID from execution history")
|
|
4507
|
+
})
|
|
4499
4508
|
},
|
|
4500
4509
|
async ({ traceId }) => callApi("GET", `execution/history/${traceId}`)
|
|
4501
4510
|
);
|
|
@@ -4504,11 +4513,11 @@ function registerHistoryTools(server, callApi) {
|
|
|
4504
4513
|
{
|
|
4505
4514
|
title: "Execution Statistics",
|
|
4506
4515
|
description: "Get execution KPIs: total executions, success/failure counts, success rate, and average latency.",
|
|
4507
|
-
inputSchema: {
|
|
4508
|
-
groupId:
|
|
4509
|
-
startDate:
|
|
4510
|
-
endDate:
|
|
4511
|
-
}
|
|
4516
|
+
inputSchema: z10.object({
|
|
4517
|
+
groupId: z10.string().uuid().optional().describe("Filter by policy group"),
|
|
4518
|
+
startDate: z10.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
4519
|
+
endDate: z10.string().optional().describe("End date (yyyy-MM-dd)")
|
|
4520
|
+
})
|
|
4512
4521
|
},
|
|
4513
4522
|
async ({ groupId, startDate, endDate }) => {
|
|
4514
4523
|
const params = {};
|
|
@@ -4521,16 +4530,16 @@ function registerHistoryTools(server, callApi) {
|
|
|
4521
4530
|
}
|
|
4522
4531
|
|
|
4523
4532
|
// src/mcp/tools/provenance.ts
|
|
4524
|
-
import { z as
|
|
4533
|
+
import { z as z11 } from "zod";
|
|
4525
4534
|
function registerProvenanceTools(server, callApi) {
|
|
4526
4535
|
server.registerTool(
|
|
4527
4536
|
"lexq_provenance_get",
|
|
4528
4537
|
{
|
|
4529
4538
|
title: "Get Decision Provenance",
|
|
4530
4539
|
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.",
|
|
4531
|
-
inputSchema: {
|
|
4532
|
-
traceId:
|
|
4533
|
-
}
|
|
4540
|
+
inputSchema: z11.object({
|
|
4541
|
+
traceId: z11.string().describe("Trace ID of the execution")
|
|
4542
|
+
})
|
|
4534
4543
|
},
|
|
4535
4544
|
async ({ traceId }) => callApi("GET", `provenance/${traceId}`)
|
|
4536
4545
|
);
|
|
@@ -4539,15 +4548,15 @@ function registerProvenanceTools(server, callApi) {
|
|
|
4539
4548
|
{
|
|
4540
4549
|
title: "List PII Reveal Audits",
|
|
4541
4550
|
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.",
|
|
4542
|
-
inputSchema: {
|
|
4543
|
-
page:
|
|
4544
|
-
size:
|
|
4545
|
-
traceId:
|
|
4546
|
-
revealedBy:
|
|
4547
|
-
factKey:
|
|
4548
|
-
startDate:
|
|
4549
|
-
endDate:
|
|
4550
|
-
}
|
|
4551
|
+
inputSchema: z11.object({
|
|
4552
|
+
page: z11.number().int().min(0).default(0).describe("Page number"),
|
|
4553
|
+
size: z11.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
4554
|
+
traceId: z11.string().optional().describe("Filter by trace ID (exact match)"),
|
|
4555
|
+
revealedBy: z11.string().optional().describe("Filter by operator ID (exact match)"),
|
|
4556
|
+
factKey: z11.string().optional().describe("Filter by fact key (partial match, case-insensitive)"),
|
|
4557
|
+
startDate: z11.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
4558
|
+
endDate: z11.string().optional().describe("End date (yyyy-MM-dd)")
|
|
4559
|
+
})
|
|
4551
4560
|
},
|
|
4552
4561
|
async ({ page, size, traceId, revealedBy, factKey, startDate, endDate }) => {
|
|
4553
4562
|
const params = paginationParams(page, size);
|
|
@@ -4562,22 +4571,22 @@ function registerProvenanceTools(server, callApi) {
|
|
|
4562
4571
|
}
|
|
4563
4572
|
|
|
4564
4573
|
// src/mcp/tools/logs.ts
|
|
4565
|
-
import { z as
|
|
4574
|
+
import { z as z12 } from "zod";
|
|
4566
4575
|
function registerLogTools(server, callApi) {
|
|
4567
4576
|
server.registerTool(
|
|
4568
4577
|
"lexq_logs_list",
|
|
4569
4578
|
{
|
|
4570
4579
|
title: "List Failure Logs",
|
|
4571
4580
|
description: "List system failure logs from background tasks (platform event webhooks, scheduled deployments).",
|
|
4572
|
-
inputSchema: {
|
|
4573
|
-
page:
|
|
4574
|
-
size:
|
|
4575
|
-
taskType:
|
|
4576
|
-
status:
|
|
4577
|
-
keyword:
|
|
4578
|
-
startDate:
|
|
4579
|
-
endDate:
|
|
4580
|
-
}
|
|
4581
|
+
inputSchema: z12.object({
|
|
4582
|
+
page: z12.number().int().min(0).default(0).describe("Page number"),
|
|
4583
|
+
size: z12.number().int().min(1).max(100).default(20).describe("Page size"),
|
|
4584
|
+
taskType: z12.enum(TaskType).optional().describe("Task type"),
|
|
4585
|
+
status: z12.enum(FailureStatus).optional().describe("Log status"),
|
|
4586
|
+
keyword: z12.string().optional().describe("Search in refId, refSubId, errorMessage"),
|
|
4587
|
+
startDate: z12.string().optional().describe("Start date (yyyy-MM-dd)"),
|
|
4588
|
+
endDate: z12.string().optional().describe("End date (yyyy-MM-dd)")
|
|
4589
|
+
})
|
|
4581
4590
|
},
|
|
4582
4591
|
async ({ page, size, taskType, status, keyword, startDate, endDate }) => {
|
|
4583
4592
|
const params = paginationParams(page, size);
|
|
@@ -4594,9 +4603,9 @@ function registerLogTools(server, callApi) {
|
|
|
4594
4603
|
{
|
|
4595
4604
|
title: "Get Failure Log",
|
|
4596
4605
|
description: "Get failure log detail by ID.",
|
|
4597
|
-
inputSchema: {
|
|
4598
|
-
logId:
|
|
4599
|
-
}
|
|
4606
|
+
inputSchema: z12.object({
|
|
4607
|
+
logId: z12.string().uuid().describe("Failure log ID")
|
|
4608
|
+
})
|
|
4600
4609
|
},
|
|
4601
4610
|
async ({ logId }) => callApi("GET", `failure-logs/${logId}`)
|
|
4602
4611
|
);
|
|
@@ -4605,10 +4614,10 @@ function registerLogTools(server, callApi) {
|
|
|
4605
4614
|
{
|
|
4606
4615
|
title: "Process Failure Log",
|
|
4607
4616
|
description: "Process a single failure log: RESOLVE (mark as manually fixed) or IGNORE (skip intentionally).",
|
|
4608
|
-
inputSchema: {
|
|
4609
|
-
logId:
|
|
4610
|
-
action:
|
|
4611
|
-
}
|
|
4617
|
+
inputSchema: z12.object({
|
|
4618
|
+
logId: z12.string().uuid().describe("Failure log ID"),
|
|
4619
|
+
action: z12.enum(FailureAction).describe("Action to take")
|
|
4620
|
+
})
|
|
4612
4621
|
},
|
|
4613
4622
|
async ({ logId, action }) => callApi("POST", `failure-logs/${logId}/actions`, {
|
|
4614
4623
|
params: { action }
|
|
@@ -4619,10 +4628,10 @@ function registerLogTools(server, callApi) {
|
|
|
4619
4628
|
{
|
|
4620
4629
|
title: "Bulk Process Failure Logs",
|
|
4621
4630
|
description: "Process multiple failure logs at once. Provide an array of log IDs and the action.",
|
|
4622
|
-
inputSchema: {
|
|
4623
|
-
logIds:
|
|
4624
|
-
action:
|
|
4625
|
-
}
|
|
4631
|
+
inputSchema: z12.object({
|
|
4632
|
+
logIds: z12.array(z12.string().uuid()).describe("Array of failure log IDs"),
|
|
4633
|
+
action: z12.enum(FailureAction).describe("Action to apply to all logs")
|
|
4634
|
+
})
|
|
4626
4635
|
},
|
|
4627
4636
|
async ({ logIds, action }) => callApi("POST", "failure-logs/bulk-actions", {
|
|
4628
4637
|
body: { logIds, action }
|
|
@@ -4631,17 +4640,17 @@ function registerLogTools(server, callApi) {
|
|
|
4631
4640
|
}
|
|
4632
4641
|
|
|
4633
4642
|
// src/mcp/tools/webhook-subscriptions.ts
|
|
4634
|
-
import { z as
|
|
4643
|
+
import { z as z13 } from "zod";
|
|
4635
4644
|
function registerWebhookSubscriptionTools(server, callApi) {
|
|
4636
4645
|
server.registerTool(
|
|
4637
4646
|
"lexq_webhook_subscriptions_list",
|
|
4638
4647
|
{
|
|
4639
4648
|
title: "List Webhook Subscriptions",
|
|
4640
4649
|
description: "List platform event webhook subscriptions. These receive deployment lifecycle notifications (publish, deploy, rollback, undeploy).",
|
|
4641
|
-
inputSchema: {
|
|
4642
|
-
page:
|
|
4643
|
-
size:
|
|
4644
|
-
}
|
|
4650
|
+
inputSchema: z13.object({
|
|
4651
|
+
page: z13.number().int().min(0).default(0).describe("Page number"),
|
|
4652
|
+
size: z13.number().int().min(1).max(100).default(20).describe("Page size")
|
|
4653
|
+
})
|
|
4645
4654
|
},
|
|
4646
4655
|
async ({ page, size }) => {
|
|
4647
4656
|
const params = paginationParams(page, size);
|
|
@@ -4653,9 +4662,9 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4653
4662
|
{
|
|
4654
4663
|
title: "Get Webhook Subscription",
|
|
4655
4664
|
description: "Get webhook subscription detail by ID.",
|
|
4656
|
-
inputSchema: {
|
|
4657
|
-
id:
|
|
4658
|
-
}
|
|
4665
|
+
inputSchema: z13.object({
|
|
4666
|
+
id: z13.string().uuid().describe("Webhook subscription ID")
|
|
4667
|
+
})
|
|
4659
4668
|
},
|
|
4660
4669
|
async ({ id }) => callApi("GET", `webhook-subscriptions/${id}`)
|
|
4661
4670
|
);
|
|
@@ -4664,15 +4673,15 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4664
4673
|
{
|
|
4665
4674
|
title: "Save Webhook Subscription",
|
|
4666
4675
|
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": "..."}).',
|
|
4667
|
-
inputSchema: {
|
|
4668
|
-
id:
|
|
4669
|
-
name:
|
|
4670
|
-
webhookUrl:
|
|
4671
|
-
subscribedEvents:
|
|
4672
|
-
payloadFormat:
|
|
4673
|
-
secret:
|
|
4674
|
-
isActive:
|
|
4675
|
-
}
|
|
4676
|
+
inputSchema: z13.object({
|
|
4677
|
+
id: z13.string().uuid().optional().describe("Subscription ID (omit to create, provide to update)"),
|
|
4678
|
+
name: z13.string().min(1).describe("Subscription name (unique per tenant)"),
|
|
4679
|
+
webhookUrl: z13.string().url().describe("Webhook endpoint URL"),
|
|
4680
|
+
subscribedEvents: z13.array(z13.enum(PlatformEventType)).min(1).describe("Events to subscribe to"),
|
|
4681
|
+
payloadFormat: z13.enum(WebhookPayloadFormat).optional().default("GENERIC").describe("Payload format"),
|
|
4682
|
+
secret: z13.string().optional().describe("HMAC-SHA256 signing secret"),
|
|
4683
|
+
isActive: z13.boolean().optional().default(true).describe("Whether the subscription is active")
|
|
4684
|
+
})
|
|
4676
4685
|
},
|
|
4677
4686
|
async ({ ...body }) => callApi("POST", "webhook-subscriptions", { body })
|
|
4678
4687
|
);
|
|
@@ -4681,9 +4690,9 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4681
4690
|
{
|
|
4682
4691
|
title: "Delete Webhook Subscription",
|
|
4683
4692
|
description: "Delete a webhook subscription by ID.",
|
|
4684
|
-
inputSchema: {
|
|
4685
|
-
id:
|
|
4686
|
-
}
|
|
4693
|
+
inputSchema: z13.object({
|
|
4694
|
+
id: z13.string().uuid().describe("Webhook subscription ID")
|
|
4695
|
+
})
|
|
4687
4696
|
},
|
|
4688
4697
|
async ({ id }) => callApi("DELETE", `webhook-subscriptions/${id}`)
|
|
4689
4698
|
);
|
|
@@ -4692,23 +4701,23 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4692
4701
|
{
|
|
4693
4702
|
title: "Test Webhook Subscription",
|
|
4694
4703
|
description: "Send a test event to verify webhook connectivity. Returns the HTTP status code and success/failure message.",
|
|
4695
|
-
inputSchema: {
|
|
4696
|
-
id:
|
|
4697
|
-
}
|
|
4704
|
+
inputSchema: z13.object({
|
|
4705
|
+
id: z13.string().uuid().describe("Webhook subscription ID")
|
|
4706
|
+
})
|
|
4698
4707
|
},
|
|
4699
4708
|
async ({ id }) => callApi("POST", `webhook-subscriptions/${id}/test`)
|
|
4700
4709
|
);
|
|
4701
4710
|
}
|
|
4702
4711
|
|
|
4703
4712
|
// src/mcp/tools/domain-templates.ts
|
|
4704
|
-
import { z as
|
|
4713
|
+
import { z as z14 } from "zod";
|
|
4705
4714
|
function registerDomainTemplateTools(server, callApi) {
|
|
4706
4715
|
server.registerTool(
|
|
4707
4716
|
"lexq_domain_templates_list",
|
|
4708
4717
|
{
|
|
4709
4718
|
title: "List Domain Templates",
|
|
4710
4719
|
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.",
|
|
4711
|
-
inputSchema: {}
|
|
4720
|
+
inputSchema: z14.object({})
|
|
4712
4721
|
},
|
|
4713
4722
|
async () => callApi("GET", "domain-templates")
|
|
4714
4723
|
);
|
|
@@ -4717,11 +4726,11 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
4717
4726
|
{
|
|
4718
4727
|
title: "Preview Domain Template",
|
|
4719
4728
|
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.",
|
|
4720
|
-
inputSchema: {
|
|
4721
|
-
template:
|
|
4729
|
+
inputSchema: z14.object({
|
|
4730
|
+
template: z14.string().describe(
|
|
4722
4731
|
"Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see available keys \u2014 currently only ECOMMERCE is ACTIVE."
|
|
4723
4732
|
)
|
|
4724
|
-
}
|
|
4733
|
+
})
|
|
4725
4734
|
},
|
|
4726
4735
|
async ({ template }) => callApi("GET", `domain-templates/${template}/preview`)
|
|
4727
4736
|
);
|
|
@@ -4730,12 +4739,12 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
4730
4739
|
{
|
|
4731
4740
|
title: "Apply Domain Template",
|
|
4732
4741
|
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.",
|
|
4733
|
-
inputSchema: {
|
|
4734
|
-
template:
|
|
4735
|
-
customName:
|
|
4742
|
+
inputSchema: z14.object({
|
|
4743
|
+
template: z14.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
|
|
4744
|
+
customName: z14.string().optional().describe(
|
|
4736
4745
|
"Optional custom name for the policy group that gets created. If omitted, the template's default name is used."
|
|
4737
4746
|
)
|
|
4738
|
-
}
|
|
4747
|
+
})
|
|
4739
4748
|
},
|
|
4740
4749
|
async ({ template, customName }) => {
|
|
4741
4750
|
const body = {};
|