@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/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
|
);
|
|
@@ -3442,18 +3443,18 @@ function registerGroupTools(server, callApi) {
|
|
|
3442
3443
|
{
|
|
3443
3444
|
title: "Create Policy Group",
|
|
3444
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.",
|
|
3445
|
-
inputSchema: {
|
|
3446
|
-
name:
|
|
3447
|
-
description:
|
|
3448
|
-
activationMode:
|
|
3449
|
-
activationStrategy:
|
|
3450
|
-
executionLimit:
|
|
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(
|
|
3451
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."
|
|
3452
3453
|
),
|
|
3453
|
-
activationGroup:
|
|
3454
|
+
activationGroup: z2.string().optional().describe(
|
|
3454
3455
|
"Activation group (Execution Group) cluster key. Policy groups sharing this key compete, and group priority picks the winners."
|
|
3455
3456
|
)
|
|
3456
|
-
}
|
|
3457
|
+
})
|
|
3457
3458
|
},
|
|
3458
3459
|
async (args) => {
|
|
3459
3460
|
const body = {
|
|
@@ -3472,20 +3473,20 @@ function registerGroupTools(server, callApi) {
|
|
|
3472
3473
|
{
|
|
3473
3474
|
title: "Update Policy Group",
|
|
3474
3475
|
description: "Update a policy group. Only provided fields are updated; omitted fields remain unchanged.",
|
|
3475
|
-
inputSchema: {
|
|
3476
|
-
groupId:
|
|
3477
|
-
name:
|
|
3478
|
-
description:
|
|
3479
|
-
status:
|
|
3480
|
-
activationGroup:
|
|
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(
|
|
3481
3482
|
"Activation group (Execution Group) cluster key. Policy groups sharing this key compete, and group priority picks the winners."
|
|
3482
3483
|
),
|
|
3483
|
-
activationMode:
|
|
3484
|
-
activationStrategy:
|
|
3485
|
-
executionLimit:
|
|
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(
|
|
3486
3487
|
"How many policy groups sharing this activationGroup may run. Counts groups, not rules."
|
|
3487
3488
|
)
|
|
3488
|
-
}
|
|
3489
|
+
})
|
|
3489
3490
|
},
|
|
3490
3491
|
async ({ groupId, ...body }) => callApi("PUT", `policy-groups/${groupId}`, { body })
|
|
3491
3492
|
);
|
|
@@ -3494,9 +3495,9 @@ function registerGroupTools(server, callApi) {
|
|
|
3494
3495
|
{
|
|
3495
3496
|
title: "Delete Policy Group",
|
|
3496
3497
|
description: "Archive a policy group. Only non-live groups can be deleted. This is irreversible.",
|
|
3497
|
-
inputSchema: {
|
|
3498
|
-
groupId:
|
|
3499
|
-
}
|
|
3498
|
+
inputSchema: z2.object({
|
|
3499
|
+
groupId: z2.string().uuid().describe("Policy group ID")
|
|
3500
|
+
})
|
|
3500
3501
|
},
|
|
3501
3502
|
async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}`)
|
|
3502
3503
|
);
|
|
@@ -3505,9 +3506,9 @@ function registerGroupTools(server, callApi) {
|
|
|
3505
3506
|
{
|
|
3506
3507
|
title: "Reorder Policy Groups",
|
|
3507
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.",
|
|
3508
|
-
inputSchema: {
|
|
3509
|
-
groupIds:
|
|
3510
|
-
}
|
|
3509
|
+
inputSchema: z2.object({
|
|
3510
|
+
groupIds: z2.array(z2.string().uuid()).describe("Group IDs in desired priority order (index 0 = priority 1)")
|
|
3511
|
+
})
|
|
3511
3512
|
},
|
|
3512
3513
|
async ({ groupIds }) => {
|
|
3513
3514
|
const groups = groupIds.map((groupId, index) => ({
|
|
@@ -3522,11 +3523,11 @@ function registerGroupTools(server, callApi) {
|
|
|
3522
3523
|
{
|
|
3523
3524
|
title: "Start A/B Test",
|
|
3524
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%.",
|
|
3525
|
-
inputSchema: {
|
|
3526
|
-
groupId:
|
|
3527
|
-
testVersionId:
|
|
3528
|
-
trafficRate:
|
|
3529
|
-
}
|
|
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
|
+
})
|
|
3530
3531
|
},
|
|
3531
3532
|
async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/ab-test`, { body })
|
|
3532
3533
|
);
|
|
@@ -3535,9 +3536,9 @@ function registerGroupTools(server, callApi) {
|
|
|
3535
3536
|
{
|
|
3536
3537
|
title: "Stop A/B Test",
|
|
3537
3538
|
description: "Stop a running A/B test. All traffic is restored to the control (current) version.",
|
|
3538
|
-
inputSchema: {
|
|
3539
|
-
groupId:
|
|
3540
|
-
}
|
|
3539
|
+
inputSchema: z2.object({
|
|
3540
|
+
groupId: z2.string().uuid().describe("Policy group ID")
|
|
3541
|
+
})
|
|
3541
3542
|
},
|
|
3542
3543
|
async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}/ab-test`)
|
|
3543
3544
|
);
|
|
@@ -3546,28 +3547,28 @@ function registerGroupTools(server, callApi) {
|
|
|
3546
3547
|
{
|
|
3547
3548
|
title: "Adjust A/B Test",
|
|
3548
3549
|
description: "Adjust traffic rate of a running A/B test.",
|
|
3549
|
-
inputSchema: {
|
|
3550
|
-
groupId:
|
|
3551
|
-
trafficRate:
|
|
3552
|
-
}
|
|
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
|
+
})
|
|
3553
3554
|
},
|
|
3554
3555
|
async ({ groupId, ...body }) => callApi("PATCH", `policy-groups/${groupId}/ab-test/traffic-rate`, { body })
|
|
3555
3556
|
);
|
|
3556
3557
|
}
|
|
3557
3558
|
|
|
3558
3559
|
// src/mcp/tools/versions.ts
|
|
3559
|
-
import { z as
|
|
3560
|
+
import { z as z3 } from "zod";
|
|
3560
3561
|
function registerVersionTools(server, callApi) {
|
|
3561
3562
|
server.registerTool(
|
|
3562
3563
|
"lexq_versions_list",
|
|
3563
3564
|
{
|
|
3564
3565
|
title: "List Policy Versions",
|
|
3565
3566
|
description: "List all versions of a policy group.",
|
|
3566
|
-
inputSchema: {
|
|
3567
|
-
groupId:
|
|
3568
|
-
page:
|
|
3569
|
-
size:
|
|
3570
|
-
}
|
|
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
|
+
})
|
|
3571
3572
|
},
|
|
3572
3573
|
async ({ groupId, page, size }) => callApi("GET", `policy-groups/${groupId}/versions`, {
|
|
3573
3574
|
params: paginationParams(page, size)
|
|
@@ -3578,10 +3579,10 @@ function registerVersionTools(server, callApi) {
|
|
|
3578
3579
|
{
|
|
3579
3580
|
title: "Get Policy Version",
|
|
3580
3581
|
description: "Get a single version by ID, including its rules and fact requirements.",
|
|
3581
|
-
inputSchema: {
|
|
3582
|
-
groupId:
|
|
3583
|
-
versionId:
|
|
3584
|
-
}
|
|
3582
|
+
inputSchema: z3.object({
|
|
3583
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
3584
|
+
versionId: z3.string().uuid().describe("Version ID")
|
|
3585
|
+
})
|
|
3585
3586
|
},
|
|
3586
3587
|
async ({ groupId, versionId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}`)
|
|
3587
3588
|
);
|
|
@@ -3590,12 +3591,12 @@ function registerVersionTools(server, callApi) {
|
|
|
3590
3591
|
{
|
|
3591
3592
|
title: "Create Policy Version",
|
|
3592
3593
|
description: "Create a new DRAFT version in a policy group. Optionally provide a commit message and effective date range.",
|
|
3593
|
-
inputSchema: {
|
|
3594
|
-
groupId:
|
|
3595
|
-
commitMessage:
|
|
3596
|
-
effectiveFrom:
|
|
3597
|
-
effectiveTo:
|
|
3598
|
-
}
|
|
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
|
+
})
|
|
3599
3600
|
},
|
|
3600
3601
|
async ({ groupId, ...body }) => callApi("POST", `policy-groups/${groupId}/versions`, { body })
|
|
3601
3602
|
);
|
|
@@ -3604,13 +3605,13 @@ function registerVersionTools(server, callApi) {
|
|
|
3604
3605
|
{
|
|
3605
3606
|
title: "Update Policy Version",
|
|
3606
3607
|
description: "Update a DRAFT version. Only DRAFT versions can be modified. Only provided fields are changed.",
|
|
3607
|
-
inputSchema: {
|
|
3608
|
-
groupId:
|
|
3609
|
-
versionId:
|
|
3610
|
-
commitMessage:
|
|
3611
|
-
effectiveFrom:
|
|
3612
|
-
effectiveTo:
|
|
3613
|
-
}
|
|
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
|
+
})
|
|
3614
3615
|
},
|
|
3615
3616
|
async ({ groupId, versionId, ...body }) => callApi("PUT", `policy-groups/${groupId}/versions/${versionId}`, { body })
|
|
3616
3617
|
);
|
|
@@ -3619,10 +3620,10 @@ function registerVersionTools(server, callApi) {
|
|
|
3619
3620
|
{
|
|
3620
3621
|
title: "Delete Policy Version",
|
|
3621
3622
|
description: "Delete a DRAFT version. Only DRAFT versions can be deleted.",
|
|
3622
|
-
inputSchema: {
|
|
3623
|
-
groupId:
|
|
3624
|
-
versionId:
|
|
3625
|
-
}
|
|
3623
|
+
inputSchema: z3.object({
|
|
3624
|
+
groupId: z3.string().uuid().describe("Policy group ID"),
|
|
3625
|
+
versionId: z3.string().uuid().describe("Version ID")
|
|
3626
|
+
})
|
|
3626
3627
|
},
|
|
3627
3628
|
async ({ groupId, versionId }) => callApi("DELETE", `policy-groups/${groupId}/versions/${versionId}`)
|
|
3628
3629
|
);
|
|
@@ -3631,10 +3632,10 @@ function registerVersionTools(server, callApi) {
|
|
|
3631
3632
|
{
|
|
3632
3633
|
title: "Clone Policy Version",
|
|
3633
3634
|
description: "Clone an existing version to create a new DRAFT. Useful when the source version is already published.",
|
|
3634
|
-
inputSchema: {
|
|
3635
|
-
groupId:
|
|
3636
|
-
versionId:
|
|
3637
|
-
}
|
|
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
|
+
})
|
|
3638
3639
|
},
|
|
3639
3640
|
async ({ groupId, versionId }) => {
|
|
3640
3641
|
return callApi("POST", `policy-groups/${groupId}/versions/${versionId}/clone`, {
|
|
@@ -3645,7 +3646,7 @@ function registerVersionTools(server, callApi) {
|
|
|
3645
3646
|
}
|
|
3646
3647
|
|
|
3647
3648
|
// src/mcp/tools/rules.ts
|
|
3648
|
-
import { z as
|
|
3649
|
+
import { z as z4 } from "zod";
|
|
3649
3650
|
import dedent15 from "dedent";
|
|
3650
3651
|
function registerRuleTools(server, callApi) {
|
|
3651
3652
|
server.registerTool(
|
|
@@ -3653,10 +3654,10 @@ function registerRuleTools(server, callApi) {
|
|
|
3653
3654
|
{
|
|
3654
3655
|
title: "List Rules",
|
|
3655
3656
|
description: "List all rules in a version (priority ASC). Returns summary with conditionSummary and actionSummary.",
|
|
3656
|
-
inputSchema: {
|
|
3657
|
-
groupId:
|
|
3658
|
-
versionId:
|
|
3659
|
-
}
|
|
3657
|
+
inputSchema: z4.object({
|
|
3658
|
+
groupId: z4.string().uuid().describe("Policy group ID"),
|
|
3659
|
+
versionId: z4.string().uuid().describe("Version ID")
|
|
3660
|
+
})
|
|
3660
3661
|
},
|
|
3661
3662
|
async ({ groupId, versionId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules`)
|
|
3662
3663
|
);
|
|
@@ -3665,11 +3666,11 @@ function registerRuleTools(server, callApi) {
|
|
|
3665
3666
|
{
|
|
3666
3667
|
title: "Get Rule Detail",
|
|
3667
3668
|
description: "Get full rule detail including condition tree and action definitions.",
|
|
3668
|
-
inputSchema: {
|
|
3669
|
-
groupId:
|
|
3670
|
-
versionId:
|
|
3671
|
-
ruleId:
|
|
3672
|
-
}
|
|
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
|
+
})
|
|
3673
3674
|
},
|
|
3674
3675
|
async ({ groupId, versionId, ruleId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}`)
|
|
3675
3676
|
);
|
|
@@ -3738,13 +3739,13 @@ function registerRuleTools(server, callApi) {
|
|
|
3738
3739
|
|
|
3739
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).
|
|
3740
3741
|
`,
|
|
3741
|
-
inputSchema: {
|
|
3742
|
-
groupId:
|
|
3743
|
-
versionId:
|
|
3744
|
-
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(
|
|
3745
3746
|
"JSON string of CreateRuleRequest: { name, condition, actions, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
|
|
3746
3747
|
)
|
|
3747
|
-
}
|
|
3748
|
+
})
|
|
3748
3749
|
},
|
|
3749
3750
|
async ({ groupId, versionId, rule }) => {
|
|
3750
3751
|
const body = parseJson(rule);
|
|
@@ -3756,14 +3757,14 @@ function registerRuleTools(server, callApi) {
|
|
|
3756
3757
|
{
|
|
3757
3758
|
title: "Update Rule",
|
|
3758
3759
|
description: "Update an existing rule in a DRAFT version. Only provided fields are changed.",
|
|
3759
|
-
inputSchema: {
|
|
3760
|
-
groupId:
|
|
3761
|
-
versionId:
|
|
3762
|
-
ruleId:
|
|
3763
|
-
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(
|
|
3764
3765
|
"JSON string of UpdateRuleRequest: { name?, condition?, actions?, mutexGroup?, mutexMode?, mutexStrategy?, mutexLimit?, isEnabled? }"
|
|
3765
3766
|
)
|
|
3766
|
-
}
|
|
3767
|
+
})
|
|
3767
3768
|
},
|
|
3768
3769
|
async ({ groupId, versionId, ruleId, rule }) => {
|
|
3769
3770
|
const body = parseJson(rule);
|
|
@@ -3777,12 +3778,12 @@ function registerRuleTools(server, callApi) {
|
|
|
3777
3778
|
{
|
|
3778
3779
|
title: "Delete Rule",
|
|
3779
3780
|
description: "Delete a rule from a DRAFT version.",
|
|
3780
|
-
inputSchema: {
|
|
3781
|
-
groupId:
|
|
3782
|
-
versionId:
|
|
3783
|
-
ruleId:
|
|
3784
|
-
force:
|
|
3785
|
-
}
|
|
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
|
+
})
|
|
3786
3787
|
},
|
|
3787
3788
|
async ({ groupId, versionId, ruleId, force }) => {
|
|
3788
3789
|
const params = {};
|
|
@@ -3797,11 +3798,11 @@ function registerRuleTools(server, callApi) {
|
|
|
3797
3798
|
{
|
|
3798
3799
|
title: "Reorder Rules",
|
|
3799
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).",
|
|
3800
|
-
inputSchema: {
|
|
3801
|
-
groupId:
|
|
3802
|
-
versionId:
|
|
3803
|
-
ruleIds:
|
|
3804
|
-
}
|
|
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
|
+
})
|
|
3805
3806
|
},
|
|
3806
3807
|
async ({ groupId, versionId, ruleIds }) => {
|
|
3807
3808
|
const rules = ruleIds.map((ruleId, index) => ({
|
|
@@ -3818,12 +3819,12 @@ function registerRuleTools(server, callApi) {
|
|
|
3818
3819
|
{
|
|
3819
3820
|
title: "Toggle Rule",
|
|
3820
3821
|
description: "Enable or disable a rule without deleting it.",
|
|
3821
|
-
inputSchema: {
|
|
3822
|
-
groupId:
|
|
3823
|
-
versionId:
|
|
3824
|
-
ruleId:
|
|
3825
|
-
isEnabled:
|
|
3826
|
-
}
|
|
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
|
+
})
|
|
3827
3828
|
},
|
|
3828
3829
|
async ({ groupId, versionId, ruleId, isEnabled }) => callApi("PATCH", `policy-groups/${groupId}/versions/${versionId}/rules/${ruleId}/enabled`, {
|
|
3829
3830
|
body: { isEnabled }
|
|
@@ -3832,7 +3833,7 @@ function registerRuleTools(server, callApi) {
|
|
|
3832
3833
|
}
|
|
3833
3834
|
|
|
3834
3835
|
// src/mcp/tools/facts.ts
|
|
3835
|
-
import { z as
|
|
3836
|
+
import { z as z5 } from "zod";
|
|
3836
3837
|
|
|
3837
3838
|
// src/types/facts.ts
|
|
3838
3839
|
var FACT_KEY_PATTERN = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
|
@@ -3845,11 +3846,11 @@ function registerFactTools(server, callApi) {
|
|
|
3845
3846
|
{
|
|
3846
3847
|
title: "List Fact Definitions",
|
|
3847
3848
|
description: "List all fact definitions (input variable schema). Shows key, type, required, and PII status. Always check this before creating rules.",
|
|
3848
|
-
inputSchema: {
|
|
3849
|
-
page:
|
|
3850
|
-
size:
|
|
3851
|
-
keyword:
|
|
3852
|
-
}
|
|
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
|
+
})
|
|
3853
3854
|
},
|
|
3854
3855
|
async ({ page, size, keyword }) => {
|
|
3855
3856
|
const params = paginationParams(page, size);
|
|
@@ -3862,16 +3863,16 @@ function registerFactTools(server, callApi) {
|
|
|
3862
3863
|
{
|
|
3863
3864
|
title: "Create Fact Definition",
|
|
3864
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.",
|
|
3865
|
-
inputSchema: {
|
|
3866
|
-
key:
|
|
3867
|
-
name:
|
|
3868
|
-
type:
|
|
3869
|
-
description:
|
|
3870
|
-
isRequired:
|
|
3871
|
-
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(
|
|
3872
3873
|
"Mark as PII \u2014 masked on every read surface, revealable only in the console (audited)"
|
|
3873
3874
|
)
|
|
3874
|
-
}
|
|
3875
|
+
})
|
|
3875
3876
|
},
|
|
3876
3877
|
async (args) => callApi("POST", "schema/facts", { body: args })
|
|
3877
3878
|
);
|
|
@@ -3880,16 +3881,16 @@ function registerFactTools(server, callApi) {
|
|
|
3880
3881
|
{
|
|
3881
3882
|
title: "Update Fact Definition",
|
|
3882
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.",
|
|
3883
|
-
inputSchema: {
|
|
3884
|
-
factId:
|
|
3885
|
-
name:
|
|
3886
|
-
description:
|
|
3887
|
-
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(
|
|
3888
3889
|
"Value type. Omit to leave it unchanged. Changing it fails with FD-007 while any rule references the fact."
|
|
3889
3890
|
),
|
|
3890
|
-
isRequired:
|
|
3891
|
-
isPii:
|
|
3892
|
-
}
|
|
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
|
+
})
|
|
3893
3894
|
},
|
|
3894
3895
|
async ({ factId, ...body }) => callApi("PUT", `schema/facts/${factId}`, { body })
|
|
3895
3896
|
);
|
|
@@ -3898,9 +3899,9 @@ function registerFactTools(server, callApi) {
|
|
|
3898
3899
|
{
|
|
3899
3900
|
title: "Delete Fact Definition",
|
|
3900
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.",
|
|
3901
|
-
inputSchema: {
|
|
3902
|
-
factId:
|
|
3903
|
-
}
|
|
3902
|
+
inputSchema: z5.object({
|
|
3903
|
+
factId: z5.string().uuid().describe("Fact definition ID")
|
|
3904
|
+
})
|
|
3904
3905
|
},
|
|
3905
3906
|
async ({ factId }) => callApi("DELETE", `schema/facts/${factId}`)
|
|
3906
3907
|
);
|
|
@@ -3909,7 +3910,7 @@ function registerFactTools(server, callApi) {
|
|
|
3909
3910
|
{
|
|
3910
3911
|
title: "Get Action Runtime Fact Metadata",
|
|
3911
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.",
|
|
3912
|
-
inputSchema: {}
|
|
3913
|
+
inputSchema: z5.object({})
|
|
3913
3914
|
},
|
|
3914
3915
|
async () => callApi("GET", "schema/action-metadata")
|
|
3915
3916
|
);
|
|
@@ -3918,10 +3919,10 @@ function registerFactTools(server, callApi) {
|
|
|
3918
3919
|
{
|
|
3919
3920
|
title: "List Unregistered Facts",
|
|
3920
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.",
|
|
3921
|
-
inputSchema: {
|
|
3922
|
-
groupId:
|
|
3923
|
-
versionId:
|
|
3924
|
-
}
|
|
3922
|
+
inputSchema: z5.object({
|
|
3923
|
+
groupId: z5.string().uuid().describe("Policy group ID"),
|
|
3924
|
+
versionId: z5.string().uuid().describe("Version ID")
|
|
3925
|
+
})
|
|
3925
3926
|
},
|
|
3926
3927
|
async ({ groupId, versionId }) => callApi("GET", `policy-groups/${groupId}/versions/${versionId}/unregistered-facts`)
|
|
3927
3928
|
);
|
|
@@ -3930,10 +3931,10 @@ function registerFactTools(server, callApi) {
|
|
|
3930
3931
|
{
|
|
3931
3932
|
title: "Export Fact Catalog",
|
|
3932
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.",
|
|
3933
|
-
inputSchema: {
|
|
3934
|
-
format:
|
|
3935
|
-
keyword:
|
|
3936
|
-
}
|
|
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
|
+
})
|
|
3937
3938
|
},
|
|
3938
3939
|
async ({ format, keyword }) => callApi("GET", "schema/facts/export", {
|
|
3939
3940
|
params: keyword ? { format, keyword } : { format }
|
|
@@ -3942,18 +3943,18 @@ function registerFactTools(server, callApi) {
|
|
|
3942
3943
|
}
|
|
3943
3944
|
|
|
3944
3945
|
// src/mcp/tools/deploy.ts
|
|
3945
|
-
import { z as
|
|
3946
|
+
import { z as z6 } from "zod";
|
|
3946
3947
|
function registerDeployTools(server, callApi) {
|
|
3947
3948
|
server.registerTool(
|
|
3948
3949
|
"lexq_deploy_publish",
|
|
3949
3950
|
{
|
|
3950
3951
|
title: "Publish Version",
|
|
3951
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.",
|
|
3952
|
-
inputSchema: {
|
|
3953
|
-
groupId:
|
|
3954
|
-
versionId:
|
|
3955
|
-
memo:
|
|
3956
|
-
}
|
|
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
|
+
})
|
|
3957
3958
|
},
|
|
3958
3959
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/versions/${versionId}/publish`, { body: { memo } })
|
|
3959
3960
|
);
|
|
@@ -3962,11 +3963,11 @@ function registerDeployTools(server, callApi) {
|
|
|
3962
3963
|
{
|
|
3963
3964
|
title: "Deploy to Live",
|
|
3964
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.",
|
|
3965
|
-
inputSchema: {
|
|
3966
|
-
groupId:
|
|
3967
|
-
versionId:
|
|
3968
|
-
memo:
|
|
3969
|
-
}
|
|
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
|
+
})
|
|
3970
3971
|
},
|
|
3971
3972
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/deploy`, {
|
|
3972
3973
|
body: { versionId, memo }
|
|
@@ -3977,10 +3978,10 @@ function registerDeployTools(server, callApi) {
|
|
|
3977
3978
|
{
|
|
3978
3979
|
title: "Rollback Deployment",
|
|
3979
3980
|
description: "Rollback to the previous deployed version. Only available if there is a previous version.",
|
|
3980
|
-
inputSchema: {
|
|
3981
|
-
groupId:
|
|
3982
|
-
memo:
|
|
3983
|
-
}
|
|
3981
|
+
inputSchema: z6.object({
|
|
3982
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
3983
|
+
memo: z6.string().min(1).describe("Rollback reason (required)")
|
|
3984
|
+
})
|
|
3984
3985
|
},
|
|
3985
3986
|
async ({ groupId, memo }) => callApi("POST", `policy-groups/${groupId}/rollback`, {
|
|
3986
3987
|
body: { memo }
|
|
@@ -3991,10 +3992,10 @@ function registerDeployTools(server, callApi) {
|
|
|
3991
3992
|
{
|
|
3992
3993
|
title: "Undeploy",
|
|
3993
3994
|
description: "Remove the live version from traffic. The version stays ACTIVE but no longer serves requests.",
|
|
3994
|
-
inputSchema: {
|
|
3995
|
-
groupId:
|
|
3996
|
-
memo:
|
|
3997
|
-
}
|
|
3995
|
+
inputSchema: z6.object({
|
|
3996
|
+
groupId: z6.string().uuid().describe("Policy group ID"),
|
|
3997
|
+
memo: z6.string().min(1).describe("Undeploy reason (required)")
|
|
3998
|
+
})
|
|
3998
3999
|
},
|
|
3999
4000
|
async ({ groupId, memo }) => callApi("POST", `policy-groups/${groupId}/undeploy`, {
|
|
4000
4001
|
body: { memo }
|
|
@@ -4005,11 +4006,11 @@ function registerDeployTools(server, callApi) {
|
|
|
4005
4006
|
{
|
|
4006
4007
|
title: "Schedule Deployment",
|
|
4007
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).",
|
|
4008
|
-
inputSchema: {
|
|
4009
|
-
groupId:
|
|
4010
|
-
versionId:
|
|
4011
|
-
memo:
|
|
4012
|
-
}
|
|
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
|
+
})
|
|
4013
4014
|
},
|
|
4014
4015
|
async ({ groupId, versionId, memo }) => callApi("POST", `policy-groups/${groupId}/schedule`, {
|
|
4015
4016
|
body: { versionId, memo }
|
|
@@ -4020,9 +4021,9 @@ function registerDeployTools(server, callApi) {
|
|
|
4020
4021
|
{
|
|
4021
4022
|
title: "Cancel Scheduled Deployment",
|
|
4022
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.",
|
|
4023
|
-
inputSchema: {
|
|
4024
|
-
groupId:
|
|
4025
|
-
}
|
|
4024
|
+
inputSchema: z6.object({
|
|
4025
|
+
groupId: z6.string().uuid().describe("Policy group ID")
|
|
4026
|
+
})
|
|
4026
4027
|
},
|
|
4027
4028
|
async ({ groupId }) => callApi("DELETE", `policy-groups/${groupId}/schedule`)
|
|
4028
4029
|
);
|
|
@@ -4031,10 +4032,10 @@ function registerDeployTools(server, callApi) {
|
|
|
4031
4032
|
{
|
|
4032
4033
|
title: "List Scheduled Deployments",
|
|
4033
4034
|
description: "List scheduled deployments across all groups (all statuses: PENDING, EXECUTED, CANCELED, FAILED), newest first.",
|
|
4034
|
-
inputSchema: {
|
|
4035
|
-
page:
|
|
4036
|
-
size:
|
|
4037
|
-
}
|
|
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
|
+
})
|
|
4038
4039
|
},
|
|
4039
4040
|
async ({ page, size }) => callApi("GET", "policy-groups/schedules", { params: paginationParams(page, size) })
|
|
4040
4041
|
);
|
|
@@ -4043,14 +4044,14 @@ function registerDeployTools(server, callApi) {
|
|
|
4043
4044
|
{
|
|
4044
4045
|
title: "Deployment History",
|
|
4045
4046
|
description: "List deployment history across all groups.",
|
|
4046
|
-
inputSchema: {
|
|
4047
|
-
page:
|
|
4048
|
-
size:
|
|
4049
|
-
groupId:
|
|
4050
|
-
types:
|
|
4051
|
-
startDate:
|
|
4052
|
-
endDate:
|
|
4053
|
-
}
|
|
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
|
+
})
|
|
4054
4055
|
},
|
|
4055
4056
|
async ({ page, size, groupId, types, startDate, endDate }) => {
|
|
4056
4057
|
const params = paginationParams(page, size);
|
|
@@ -4066,9 +4067,9 @@ function registerDeployTools(server, callApi) {
|
|
|
4066
4067
|
{
|
|
4067
4068
|
title: "Deployment Detail",
|
|
4068
4069
|
description: "Get detailed info about a specific deployment including snapshot hash and integrity check.",
|
|
4069
|
-
inputSchema: {
|
|
4070
|
-
deploymentId:
|
|
4071
|
-
}
|
|
4070
|
+
inputSchema: z6.object({
|
|
4071
|
+
deploymentId: z6.string().uuid().describe("Deployment ID")
|
|
4072
|
+
})
|
|
4072
4073
|
},
|
|
4073
4074
|
async ({ deploymentId }) => callApi("GET", `deployments/${deploymentId}`)
|
|
4074
4075
|
);
|
|
@@ -4077,7 +4078,7 @@ function registerDeployTools(server, callApi) {
|
|
|
4077
4078
|
{
|
|
4078
4079
|
title: "Deployment Overview",
|
|
4079
4080
|
description: "Show current deployment status of all groups \u2014 which version is live, last deployment type, and deployer.",
|
|
4080
|
-
inputSchema: {}
|
|
4081
|
+
inputSchema: z6.object({})
|
|
4081
4082
|
},
|
|
4082
4083
|
async () => callApi("GET", "deployments/overview")
|
|
4083
4084
|
);
|
|
@@ -4086,9 +4087,9 @@ function registerDeployTools(server, callApi) {
|
|
|
4086
4087
|
{
|
|
4087
4088
|
title: "List Deployable Versions",
|
|
4088
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.",
|
|
4089
|
-
inputSchema: {
|
|
4090
|
-
groupId:
|
|
4091
|
-
}
|
|
4090
|
+
inputSchema: z6.object({
|
|
4091
|
+
groupId: z6.string().uuid().describe("Policy group ID")
|
|
4092
|
+
})
|
|
4092
4093
|
},
|
|
4093
4094
|
async ({ groupId }) => callApi("GET", `deployments/groups/${groupId}/deployable-versions`)
|
|
4094
4095
|
);
|
|
@@ -4097,10 +4098,10 @@ function registerDeployTools(server, callApi) {
|
|
|
4097
4098
|
{
|
|
4098
4099
|
title: "Deployment Diff",
|
|
4099
4100
|
description: "Compare rule snapshots between two versions. Shows added, removed, and modified rules. Useful for reviewing changes before deploying a new version.",
|
|
4100
|
-
inputSchema: {
|
|
4101
|
-
baseVersionId:
|
|
4102
|
-
targetVersionId:
|
|
4103
|
-
}
|
|
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
|
+
})
|
|
4104
4105
|
},
|
|
4105
4106
|
async ({ baseVersionId, targetVersionId }) => callApi("GET", "deployments/diff", {
|
|
4106
4107
|
params: { baseVersionId, targetVersionId }
|
|
@@ -4109,7 +4110,7 @@ function registerDeployTools(server, callApi) {
|
|
|
4109
4110
|
}
|
|
4110
4111
|
|
|
4111
4112
|
// src/mcp/tools/analytics.ts
|
|
4112
|
-
import { z as
|
|
4113
|
+
import { z as z7 } from "zod";
|
|
4113
4114
|
import dedent16 from "dedent";
|
|
4114
4115
|
function registerAnalyticsTools(server, callApi) {
|
|
4115
4116
|
server.registerTool(
|
|
@@ -4128,11 +4129,11 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4128
4129
|
|
|
4129
4130
|
Example input: { "facts": { "paymentAmount": 100000, "customerTier": "VIP" } }
|
|
4130
4131
|
Always dry-run before publishing to validate rule behavior.`,
|
|
4131
|
-
inputSchema: {
|
|
4132
|
-
versionId:
|
|
4133
|
-
facts:
|
|
4134
|
-
includeDebugInfo:
|
|
4135
|
-
}
|
|
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
|
+
})
|
|
4136
4137
|
},
|
|
4137
4138
|
async ({ versionId, facts, includeDebugInfo }) => {
|
|
4138
4139
|
const parsedFacts = parseJson(facts);
|
|
@@ -4152,11 +4153,11 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4152
4153
|
resultA / resultB — full DryRunResponse for each version
|
|
4153
4154
|
diff.mutatedDiff — changes in mutatedFacts between A and B (key → {before, after})
|
|
4154
4155
|
diff.generatedDiff — changes in generatedVariables between A and B`,
|
|
4155
|
-
inputSchema: {
|
|
4156
|
-
versionIdA:
|
|
4157
|
-
versionIdB:
|
|
4158
|
-
facts:
|
|
4159
|
-
}
|
|
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
|
+
})
|
|
4160
4161
|
},
|
|
4161
4162
|
async ({ versionIdA, versionIdB, facts }) => {
|
|
4162
4163
|
const parsedFacts = parseJson(facts);
|
|
@@ -4170,10 +4171,10 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4170
4171
|
{
|
|
4171
4172
|
title: "Analyze Requirements",
|
|
4172
4173
|
description: "Analyze which input facts a version requires. Returns required keys, types, and an example request body.",
|
|
4173
|
-
inputSchema: {
|
|
4174
|
-
groupId:
|
|
4175
|
-
versionId:
|
|
4176
|
-
}
|
|
4174
|
+
inputSchema: z7.object({
|
|
4175
|
+
groupId: z7.string().uuid().describe("Policy group ID"),
|
|
4176
|
+
versionId: z7.string().uuid().describe("Version ID")
|
|
4177
|
+
})
|
|
4177
4178
|
},
|
|
4178
4179
|
async ({ groupId, versionId }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/requirements`)
|
|
4179
4180
|
);
|
|
@@ -4209,9 +4210,9 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4209
4210
|
"options": { "baselinePolicyVersionId": "<uuid>", "includeRuleStats": true }
|
|
4210
4211
|
}
|
|
4211
4212
|
`,
|
|
4212
|
-
inputSchema: {
|
|
4213
|
-
body:
|
|
4214
|
-
}
|
|
4213
|
+
inputSchema: z7.object({
|
|
4214
|
+
body: z7.string().describe("JSON string of SimulationRequest")
|
|
4215
|
+
})
|
|
4215
4216
|
},
|
|
4216
4217
|
async ({ body }) => {
|
|
4217
4218
|
const parsed = parseJson(body);
|
|
@@ -4223,9 +4224,9 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4223
4224
|
{
|
|
4224
4225
|
title: "Simulation Status",
|
|
4225
4226
|
description: "Get simulation status and results. Poll until status is COMPLETED or FAILED.",
|
|
4226
|
-
inputSchema: {
|
|
4227
|
-
simulationId:
|
|
4228
|
-
}
|
|
4227
|
+
inputSchema: z7.object({
|
|
4228
|
+
simulationId: z7.string().uuid().describe("Simulation ID")
|
|
4229
|
+
})
|
|
4229
4230
|
},
|
|
4230
4231
|
async ({ simulationId }) => callApi("GET", `analytics/simulations/${simulationId}`)
|
|
4231
4232
|
);
|
|
@@ -4234,13 +4235,13 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4234
4235
|
{
|
|
4235
4236
|
title: "List Simulations",
|
|
4236
4237
|
description: "List simulation history with optional filters.",
|
|
4237
|
-
inputSchema: {
|
|
4238
|
-
page:
|
|
4239
|
-
size:
|
|
4240
|
-
status:
|
|
4241
|
-
from:
|
|
4242
|
-
to:
|
|
4243
|
-
}
|
|
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
|
+
})
|
|
4244
4245
|
},
|
|
4245
4246
|
async ({ page, size, status, from, to }) => {
|
|
4246
4247
|
const params = paginationParams(page, size);
|
|
@@ -4255,9 +4256,9 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4255
4256
|
{
|
|
4256
4257
|
title: "Cancel Simulation",
|
|
4257
4258
|
description: "Cancel a running or pending simulation.",
|
|
4258
|
-
inputSchema: {
|
|
4259
|
-
simulationId:
|
|
4260
|
-
}
|
|
4259
|
+
inputSchema: z7.object({
|
|
4260
|
+
simulationId: z7.string().uuid().describe("Simulation ID")
|
|
4261
|
+
})
|
|
4261
4262
|
},
|
|
4262
4263
|
async ({ simulationId }) => callApi("DELETE", `analytics/simulations/${simulationId}`)
|
|
4263
4264
|
);
|
|
@@ -4266,10 +4267,10 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4266
4267
|
{
|
|
4267
4268
|
title: "Export Simulation",
|
|
4268
4269
|
description: "Export simulation results as JSON or CSV. Returns the raw data.",
|
|
4269
|
-
inputSchema: {
|
|
4270
|
-
simulationId:
|
|
4271
|
-
format:
|
|
4272
|
-
}
|
|
4270
|
+
inputSchema: z7.object({
|
|
4271
|
+
simulationId: z7.string().uuid().describe("Simulation ID"),
|
|
4272
|
+
format: z7.enum(EXPORT_FORMATS).default("json").describe("Export format")
|
|
4273
|
+
})
|
|
4273
4274
|
},
|
|
4274
4275
|
async ({ simulationId, format }) => callApi("GET", `analytics/simulations/${simulationId}/export`, {
|
|
4275
4276
|
params: { format }
|
|
@@ -4293,10 +4294,10 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4293
4294
|
|
|
4294
4295
|
JSON example: [{"userId":"user_001","paymentAmount":150000}, {"userId":"user_002","paymentAmount":50000}]
|
|
4295
4296
|
`,
|
|
4296
|
-
inputSchema: {
|
|
4297
|
-
content:
|
|
4298
|
-
filename:
|
|
4299
|
-
}
|
|
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
|
+
})
|
|
4300
4301
|
},
|
|
4301
4302
|
async ({ content, filename }) => {
|
|
4302
4303
|
const result = await callApi("POST", "analytics/datasets/upload", {
|
|
@@ -4323,11 +4324,11 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4323
4324
|
{
|
|
4324
4325
|
title: "Download Dataset Template",
|
|
4325
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.",
|
|
4326
|
-
inputSchema: {
|
|
4327
|
-
groupId:
|
|
4328
|
-
versionId:
|
|
4329
|
-
format:
|
|
4330
|
-
}
|
|
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
|
+
})
|
|
4331
4332
|
},
|
|
4332
4333
|
async ({ groupId, versionId, format }) => callApi("GET", `analytics/groups/${groupId}/versions/${versionId}/dataset-template`, {
|
|
4333
4334
|
params: { format }
|
|
@@ -4336,7 +4337,7 @@ function registerAnalyticsTools(server, callApi) {
|
|
|
4336
4337
|
}
|
|
4337
4338
|
|
|
4338
4339
|
// src/mcp/tools/profile.ts
|
|
4339
|
-
import { z as
|
|
4340
|
+
import { z as z8 } from "zod";
|
|
4340
4341
|
var RELATIVE_THRESHOLD = `flagged = p50 \u2265 ${SLOW_MULTIPLIER}\xD7 median of per-rule p50s within the group; absolute thresholds are intentionally not supported.`;
|
|
4341
4342
|
function profileParams(opts) {
|
|
4342
4343
|
const params = {};
|
|
@@ -4352,15 +4353,15 @@ function registerProfileTools(server, callApi) {
|
|
|
4352
4353
|
{
|
|
4353
4354
|
title: "Group Latency Profile",
|
|
4354
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.`,
|
|
4355
|
-
inputSchema: {
|
|
4356
|
-
groupId:
|
|
4357
|
-
versionId:
|
|
4358
|
-
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(
|
|
4359
4360
|
`Window start, ISO-8601 instant (e.g. 2026-07-01T00:00:00Z). Default: ${PROFILE_DEFAULT_WINDOW_HOURS}h ago`
|
|
4360
4361
|
),
|
|
4361
|
-
to:
|
|
4362
|
-
cacheState:
|
|
4363
|
-
}
|
|
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
|
+
})
|
|
4364
4365
|
},
|
|
4365
4366
|
async ({ groupId, versionId, from, to, cacheState }) => callApi("GET", `policy-groups/${groupId}/profile`, {
|
|
4366
4367
|
params: profileParams({ versionId, from, to, cacheState })
|
|
@@ -4371,15 +4372,15 @@ function registerProfileTools(server, callApi) {
|
|
|
4371
4372
|
{
|
|
4372
4373
|
title: "Rule Latency Detail",
|
|
4373
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,
|
|
4374
|
-
inputSchema: {
|
|
4375
|
-
groupId:
|
|
4376
|
-
ruleId:
|
|
4377
|
-
versionId:
|
|
4378
|
-
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(
|
|
4379
4380
|
`Window start, ISO-8601 instant. Default: ${PROFILE_DEFAULT_WINDOW_HOURS}h ago`
|
|
4380
4381
|
),
|
|
4381
|
-
to:
|
|
4382
|
-
}
|
|
4382
|
+
to: z8.string().optional().describe("Window end, ISO-8601 instant. Default: now")
|
|
4383
|
+
})
|
|
4383
4384
|
},
|
|
4384
4385
|
async ({ groupId, ruleId, versionId, from, to }) => callApi("GET", `policy-groups/${groupId}/profile/rules/${ruleId}`, {
|
|
4385
4386
|
params: profileParams({ versionId, from, to })
|
|
@@ -4388,17 +4389,17 @@ function registerProfileTools(server, callApi) {
|
|
|
4388
4389
|
}
|
|
4389
4390
|
|
|
4390
4391
|
// src/mcp/tools/replay.ts
|
|
4391
|
-
import { z as
|
|
4392
|
+
import { z as z9 } from "zod";
|
|
4392
4393
|
function registerReplayTools(server, callApi) {
|
|
4393
4394
|
server.registerTool(
|
|
4394
4395
|
"lexq_replay_decision",
|
|
4395
4396
|
{
|
|
4396
4397
|
title: "Replay a Decision",
|
|
4397
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.",
|
|
4398
|
-
inputSchema: {
|
|
4399
|
-
traceId:
|
|
4400
|
-
candidateVersionId:
|
|
4401
|
-
}
|
|
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
|
+
})
|
|
4402
4403
|
},
|
|
4403
4404
|
async ({ traceId, candidateVersionId }) => callApi("POST", "replay/decisions", { body: { traceId, candidateVersionId } })
|
|
4404
4405
|
);
|
|
@@ -4407,14 +4408,14 @@ function registerReplayTools(server, callApi) {
|
|
|
4407
4408
|
{
|
|
4408
4409
|
title: "Start Window Replay (Blast Radius)",
|
|
4409
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.",
|
|
4410
|
-
inputSchema: {
|
|
4411
|
-
candidateVersionId:
|
|
4412
|
-
from:
|
|
4413
|
-
to:
|
|
4414
|
-
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(
|
|
4415
4416
|
`Sample cap (server default applies; hard cap ${REPLAY_WINDOW_MAX_RECORDS / 1e3}k)`
|
|
4416
4417
|
)
|
|
4417
|
-
}
|
|
4418
|
+
})
|
|
4418
4419
|
},
|
|
4419
4420
|
async ({ candidateVersionId, from, to, maxRecords }) => callApi("POST", "replay/jobs", { body: { candidateVersionId, from, to, maxRecords } })
|
|
4420
4421
|
);
|
|
@@ -4423,9 +4424,9 @@ function registerReplayTools(server, callApi) {
|
|
|
4423
4424
|
{
|
|
4424
4425
|
title: "Get Replay Job Status",
|
|
4425
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.",
|
|
4426
|
-
inputSchema: {
|
|
4427
|
-
jobId:
|
|
4428
|
-
}
|
|
4427
|
+
inputSchema: z9.object({
|
|
4428
|
+
jobId: z9.string().describe("Replay job ID from lexq_replay_start")
|
|
4429
|
+
})
|
|
4429
4430
|
},
|
|
4430
4431
|
async ({ jobId }) => callApi("GET", `replay/jobs/${jobId}`)
|
|
4431
4432
|
);
|
|
@@ -4434,10 +4435,10 @@ function registerReplayTools(server, callApi) {
|
|
|
4434
4435
|
{
|
|
4435
4436
|
title: "List Replay Jobs",
|
|
4436
4437
|
description: "List window replay job history (reverse-chronological). Lightweight items \u2014 use lexq_replay_status for summary and changed samples.",
|
|
4437
|
-
inputSchema: {
|
|
4438
|
-
page:
|
|
4439
|
-
size:
|
|
4440
|
-
}
|
|
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
|
+
})
|
|
4441
4442
|
},
|
|
4442
4443
|
async ({ page, size }) => callApi("GET", "replay/jobs", { params: paginationParams(page, size) })
|
|
4443
4444
|
);
|
|
@@ -4446,9 +4447,9 @@ function registerReplayTools(server, callApi) {
|
|
|
4446
4447
|
{
|
|
4447
4448
|
title: "Cancel Replay Job",
|
|
4448
4449
|
description: "Cooperatively cancel a PENDING or RUNNING window replay job. Other states are rejected. VIEWER role cannot cancel.",
|
|
4449
|
-
inputSchema: {
|
|
4450
|
-
jobId:
|
|
4451
|
-
}
|
|
4450
|
+
inputSchema: z9.object({
|
|
4451
|
+
jobId: z9.string().describe("Replay job ID")
|
|
4452
|
+
})
|
|
4452
4453
|
},
|
|
4453
4454
|
async ({ jobId }) => callApi("POST", `replay/jobs/${jobId}/cancel`)
|
|
4454
4455
|
);
|
|
@@ -4457,33 +4458,33 @@ function registerReplayTools(server, callApi) {
|
|
|
4457
4458
|
{
|
|
4458
4459
|
title: "Export Replay Result",
|
|
4459
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.",
|
|
4460
|
-
inputSchema: {
|
|
4461
|
-
jobId:
|
|
4462
|
-
format:
|
|
4463
|
-
}
|
|
4461
|
+
inputSchema: z9.object({
|
|
4462
|
+
jobId: z9.string().describe("Replay job ID"),
|
|
4463
|
+
format: z9.enum(EXPORT_FORMATS).default("json").describe("Export format")
|
|
4464
|
+
})
|
|
4464
4465
|
},
|
|
4465
4466
|
async ({ jobId, format }) => callApi("GET", `replay/jobs/${jobId}/export`, { params: { format } })
|
|
4466
4467
|
);
|
|
4467
4468
|
}
|
|
4468
4469
|
|
|
4469
4470
|
// src/mcp/tools/history.ts
|
|
4470
|
-
import { z as
|
|
4471
|
+
import { z as z10 } from "zod";
|
|
4471
4472
|
function registerHistoryTools(server, callApi) {
|
|
4472
4473
|
server.registerTool(
|
|
4473
4474
|
"lexq_history_list",
|
|
4474
4475
|
{
|
|
4475
4476
|
title: "List Execution History",
|
|
4476
4477
|
description: "List policy execution history. Shows trace ID, group, version, status, match result, and latency.",
|
|
4477
|
-
inputSchema: {
|
|
4478
|
-
page:
|
|
4479
|
-
size:
|
|
4480
|
-
traceId:
|
|
4481
|
-
groupId:
|
|
4482
|
-
versionId:
|
|
4483
|
-
status:
|
|
4484
|
-
startDate:
|
|
4485
|
-
endDate:
|
|
4486
|
-
}
|
|
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
|
+
})
|
|
4487
4488
|
},
|
|
4488
4489
|
async ({ page, size, traceId, groupId, versionId, status, startDate, endDate }) => {
|
|
4489
4490
|
const params = paginationParams(page, size);
|
|
@@ -4501,9 +4502,9 @@ function registerHistoryTools(server, callApi) {
|
|
|
4501
4502
|
{
|
|
4502
4503
|
title: "Get Execution Detail",
|
|
4503
4504
|
description: "Get full execution detail including inputFacts, mutatedFacts, generatedVariables, executionTraces, and decisionTraces.",
|
|
4504
|
-
inputSchema: {
|
|
4505
|
-
traceId:
|
|
4506
|
-
}
|
|
4505
|
+
inputSchema: z10.object({
|
|
4506
|
+
traceId: z10.string().describe("Trace ID from execution history")
|
|
4507
|
+
})
|
|
4507
4508
|
},
|
|
4508
4509
|
async ({ traceId }) => callApi("GET", `execution/history/${traceId}`)
|
|
4509
4510
|
);
|
|
@@ -4512,11 +4513,11 @@ function registerHistoryTools(server, callApi) {
|
|
|
4512
4513
|
{
|
|
4513
4514
|
title: "Execution Statistics",
|
|
4514
4515
|
description: "Get execution KPIs: total executions, success/failure counts, success rate, and average latency.",
|
|
4515
|
-
inputSchema: {
|
|
4516
|
-
groupId:
|
|
4517
|
-
startDate:
|
|
4518
|
-
endDate:
|
|
4519
|
-
}
|
|
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
|
+
})
|
|
4520
4521
|
},
|
|
4521
4522
|
async ({ groupId, startDate, endDate }) => {
|
|
4522
4523
|
const params = {};
|
|
@@ -4529,16 +4530,16 @@ function registerHistoryTools(server, callApi) {
|
|
|
4529
4530
|
}
|
|
4530
4531
|
|
|
4531
4532
|
// src/mcp/tools/provenance.ts
|
|
4532
|
-
import { z as
|
|
4533
|
+
import { z as z11 } from "zod";
|
|
4533
4534
|
function registerProvenanceTools(server, callApi) {
|
|
4534
4535
|
server.registerTool(
|
|
4535
4536
|
"lexq_provenance_get",
|
|
4536
4537
|
{
|
|
4537
4538
|
title: "Get Decision Provenance",
|
|
4538
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.",
|
|
4539
|
-
inputSchema: {
|
|
4540
|
-
traceId:
|
|
4541
|
-
}
|
|
4540
|
+
inputSchema: z11.object({
|
|
4541
|
+
traceId: z11.string().describe("Trace ID of the execution")
|
|
4542
|
+
})
|
|
4542
4543
|
},
|
|
4543
4544
|
async ({ traceId }) => callApi("GET", `provenance/${traceId}`)
|
|
4544
4545
|
);
|
|
@@ -4547,15 +4548,15 @@ function registerProvenanceTools(server, callApi) {
|
|
|
4547
4548
|
{
|
|
4548
4549
|
title: "List PII Reveal Audits",
|
|
4549
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.",
|
|
4550
|
-
inputSchema: {
|
|
4551
|
-
page:
|
|
4552
|
-
size:
|
|
4553
|
-
traceId:
|
|
4554
|
-
revealedBy:
|
|
4555
|
-
factKey:
|
|
4556
|
-
startDate:
|
|
4557
|
-
endDate:
|
|
4558
|
-
}
|
|
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
|
+
})
|
|
4559
4560
|
},
|
|
4560
4561
|
async ({ page, size, traceId, revealedBy, factKey, startDate, endDate }) => {
|
|
4561
4562
|
const params = paginationParams(page, size);
|
|
@@ -4570,22 +4571,22 @@ function registerProvenanceTools(server, callApi) {
|
|
|
4570
4571
|
}
|
|
4571
4572
|
|
|
4572
4573
|
// src/mcp/tools/logs.ts
|
|
4573
|
-
import { z as
|
|
4574
|
+
import { z as z12 } from "zod";
|
|
4574
4575
|
function registerLogTools(server, callApi) {
|
|
4575
4576
|
server.registerTool(
|
|
4576
4577
|
"lexq_logs_list",
|
|
4577
4578
|
{
|
|
4578
4579
|
title: "List Failure Logs",
|
|
4579
4580
|
description: "List system failure logs from background tasks (platform event webhooks, scheduled deployments).",
|
|
4580
|
-
inputSchema: {
|
|
4581
|
-
page:
|
|
4582
|
-
size:
|
|
4583
|
-
taskType:
|
|
4584
|
-
status:
|
|
4585
|
-
keyword:
|
|
4586
|
-
startDate:
|
|
4587
|
-
endDate:
|
|
4588
|
-
}
|
|
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
|
+
})
|
|
4589
4590
|
},
|
|
4590
4591
|
async ({ page, size, taskType, status, keyword, startDate, endDate }) => {
|
|
4591
4592
|
const params = paginationParams(page, size);
|
|
@@ -4602,9 +4603,9 @@ function registerLogTools(server, callApi) {
|
|
|
4602
4603
|
{
|
|
4603
4604
|
title: "Get Failure Log",
|
|
4604
4605
|
description: "Get failure log detail by ID.",
|
|
4605
|
-
inputSchema: {
|
|
4606
|
-
logId:
|
|
4607
|
-
}
|
|
4606
|
+
inputSchema: z12.object({
|
|
4607
|
+
logId: z12.string().uuid().describe("Failure log ID")
|
|
4608
|
+
})
|
|
4608
4609
|
},
|
|
4609
4610
|
async ({ logId }) => callApi("GET", `failure-logs/${logId}`)
|
|
4610
4611
|
);
|
|
@@ -4613,10 +4614,10 @@ function registerLogTools(server, callApi) {
|
|
|
4613
4614
|
{
|
|
4614
4615
|
title: "Process Failure Log",
|
|
4615
4616
|
description: "Process a single failure log: RESOLVE (mark as manually fixed) or IGNORE (skip intentionally).",
|
|
4616
|
-
inputSchema: {
|
|
4617
|
-
logId:
|
|
4618
|
-
action:
|
|
4619
|
-
}
|
|
4617
|
+
inputSchema: z12.object({
|
|
4618
|
+
logId: z12.string().uuid().describe("Failure log ID"),
|
|
4619
|
+
action: z12.enum(FailureAction).describe("Action to take")
|
|
4620
|
+
})
|
|
4620
4621
|
},
|
|
4621
4622
|
async ({ logId, action }) => callApi("POST", `failure-logs/${logId}/actions`, {
|
|
4622
4623
|
params: { action }
|
|
@@ -4627,10 +4628,10 @@ function registerLogTools(server, callApi) {
|
|
|
4627
4628
|
{
|
|
4628
4629
|
title: "Bulk Process Failure Logs",
|
|
4629
4630
|
description: "Process multiple failure logs at once. Provide an array of log IDs and the action.",
|
|
4630
|
-
inputSchema: {
|
|
4631
|
-
logIds:
|
|
4632
|
-
action:
|
|
4633
|
-
}
|
|
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
|
+
})
|
|
4634
4635
|
},
|
|
4635
4636
|
async ({ logIds, action }) => callApi("POST", "failure-logs/bulk-actions", {
|
|
4636
4637
|
body: { logIds, action }
|
|
@@ -4639,17 +4640,17 @@ function registerLogTools(server, callApi) {
|
|
|
4639
4640
|
}
|
|
4640
4641
|
|
|
4641
4642
|
// src/mcp/tools/webhook-subscriptions.ts
|
|
4642
|
-
import { z as
|
|
4643
|
+
import { z as z13 } from "zod";
|
|
4643
4644
|
function registerWebhookSubscriptionTools(server, callApi) {
|
|
4644
4645
|
server.registerTool(
|
|
4645
4646
|
"lexq_webhook_subscriptions_list",
|
|
4646
4647
|
{
|
|
4647
4648
|
title: "List Webhook Subscriptions",
|
|
4648
4649
|
description: "List platform event webhook subscriptions. These receive deployment lifecycle notifications (publish, deploy, rollback, undeploy).",
|
|
4649
|
-
inputSchema: {
|
|
4650
|
-
page:
|
|
4651
|
-
size:
|
|
4652
|
-
}
|
|
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
|
+
})
|
|
4653
4654
|
},
|
|
4654
4655
|
async ({ page, size }) => {
|
|
4655
4656
|
const params = paginationParams(page, size);
|
|
@@ -4661,9 +4662,9 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4661
4662
|
{
|
|
4662
4663
|
title: "Get Webhook Subscription",
|
|
4663
4664
|
description: "Get webhook subscription detail by ID.",
|
|
4664
|
-
inputSchema: {
|
|
4665
|
-
id:
|
|
4666
|
-
}
|
|
4665
|
+
inputSchema: z13.object({
|
|
4666
|
+
id: z13.string().uuid().describe("Webhook subscription ID")
|
|
4667
|
+
})
|
|
4667
4668
|
},
|
|
4668
4669
|
async ({ id }) => callApi("GET", `webhook-subscriptions/${id}`)
|
|
4669
4670
|
);
|
|
@@ -4672,15 +4673,15 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4672
4673
|
{
|
|
4673
4674
|
title: "Save Webhook Subscription",
|
|
4674
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": "..."}).',
|
|
4675
|
-
inputSchema: {
|
|
4676
|
-
id:
|
|
4677
|
-
name:
|
|
4678
|
-
webhookUrl:
|
|
4679
|
-
subscribedEvents:
|
|
4680
|
-
payloadFormat:
|
|
4681
|
-
secret:
|
|
4682
|
-
isActive:
|
|
4683
|
-
}
|
|
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
|
+
})
|
|
4684
4685
|
},
|
|
4685
4686
|
async ({ ...body }) => callApi("POST", "webhook-subscriptions", { body })
|
|
4686
4687
|
);
|
|
@@ -4689,9 +4690,9 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4689
4690
|
{
|
|
4690
4691
|
title: "Delete Webhook Subscription",
|
|
4691
4692
|
description: "Delete a webhook subscription by ID.",
|
|
4692
|
-
inputSchema: {
|
|
4693
|
-
id:
|
|
4694
|
-
}
|
|
4693
|
+
inputSchema: z13.object({
|
|
4694
|
+
id: z13.string().uuid().describe("Webhook subscription ID")
|
|
4695
|
+
})
|
|
4695
4696
|
},
|
|
4696
4697
|
async ({ id }) => callApi("DELETE", `webhook-subscriptions/${id}`)
|
|
4697
4698
|
);
|
|
@@ -4700,23 +4701,23 @@ function registerWebhookSubscriptionTools(server, callApi) {
|
|
|
4700
4701
|
{
|
|
4701
4702
|
title: "Test Webhook Subscription",
|
|
4702
4703
|
description: "Send a test event to verify webhook connectivity. Returns the HTTP status code and success/failure message.",
|
|
4703
|
-
inputSchema: {
|
|
4704
|
-
id:
|
|
4705
|
-
}
|
|
4704
|
+
inputSchema: z13.object({
|
|
4705
|
+
id: z13.string().uuid().describe("Webhook subscription ID")
|
|
4706
|
+
})
|
|
4706
4707
|
},
|
|
4707
4708
|
async ({ id }) => callApi("POST", `webhook-subscriptions/${id}/test`)
|
|
4708
4709
|
);
|
|
4709
4710
|
}
|
|
4710
4711
|
|
|
4711
4712
|
// src/mcp/tools/domain-templates.ts
|
|
4712
|
-
import { z as
|
|
4713
|
+
import { z as z14 } from "zod";
|
|
4713
4714
|
function registerDomainTemplateTools(server, callApi) {
|
|
4714
4715
|
server.registerTool(
|
|
4715
4716
|
"lexq_domain_templates_list",
|
|
4716
4717
|
{
|
|
4717
4718
|
title: "List Domain Templates",
|
|
4718
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.",
|
|
4719
|
-
inputSchema: {}
|
|
4720
|
+
inputSchema: z14.object({})
|
|
4720
4721
|
},
|
|
4721
4722
|
async () => callApi("GET", "domain-templates")
|
|
4722
4723
|
);
|
|
@@ -4725,11 +4726,11 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
4725
4726
|
{
|
|
4726
4727
|
title: "Preview Domain Template",
|
|
4727
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.",
|
|
4728
|
-
inputSchema: {
|
|
4729
|
-
template:
|
|
4729
|
+
inputSchema: z14.object({
|
|
4730
|
+
template: z14.string().describe(
|
|
4730
4731
|
"Domain template key (e.g. ECOMMERCE). Use lexq_domain_templates_list to see available keys \u2014 currently only ECOMMERCE is ACTIVE."
|
|
4731
4732
|
)
|
|
4732
|
-
}
|
|
4733
|
+
})
|
|
4733
4734
|
},
|
|
4734
4735
|
async ({ template }) => callApi("GET", `domain-templates/${template}/preview`)
|
|
4735
4736
|
);
|
|
@@ -4738,12 +4739,12 @@ function registerDomainTemplateTools(server, callApi) {
|
|
|
4738
4739
|
{
|
|
4739
4740
|
title: "Apply Domain Template",
|
|
4740
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.",
|
|
4741
|
-
inputSchema: {
|
|
4742
|
-
template:
|
|
4743
|
-
customName:
|
|
4742
|
+
inputSchema: z14.object({
|
|
4743
|
+
template: z14.string().describe("Domain template key to apply (e.g. ECOMMERCE)."),
|
|
4744
|
+
customName: z14.string().optional().describe(
|
|
4744
4745
|
"Optional custom name for the policy group that gets created. If omitted, the template's default name is used."
|
|
4745
4746
|
)
|
|
4746
|
-
}
|
|
4747
|
+
})
|
|
4747
4748
|
},
|
|
4748
4749
|
async ({ template, customName }) => {
|
|
4749
4750
|
const body = {};
|