@loopops/mcp-server 3.26.0 → 3.31.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/dist/index.js +0 -0
- package/dist/tools/deploy.js +92 -6
- package/package.json +8 -7
package/dist/index.js
CHANGED
|
File without changes
|
package/dist/tools/deploy.js
CHANGED
|
@@ -396,18 +396,57 @@ export function registerDeployTools(server, allowed) {
|
|
|
396
396
|
}, safeTool(async (input) => trpcMutation("mcp.reviseUserAssignment", input)));
|
|
397
397
|
}
|
|
398
398
|
// ── Phase 3 — Account → Territory placement ────────────────────────
|
|
399
|
+
if (allowed.has("snapshot_planning_scope")) {
|
|
400
|
+
server.tool("snapshot_planning_scope", [
|
|
401
|
+
"Ops only. Three modes:",
|
|
402
|
+
"(1) DEFAULT — materialize live TAL membership into the cycle's",
|
|
403
|
+
"frozen scope. TAL slug comes from",
|
|
404
|
+
"config/deploy/account_placement.yaml's planning_scope.tal_slug",
|
|
405
|
+
"(override via talSlugOverride). Must run BEFORE",
|
|
406
|
+
"propose_account_assignments. Idempotent on the same cycle.",
|
|
407
|
+
"(2) FORCE REFRESH — pass force:true (with reason ≥10 chars) to",
|
|
408
|
+
"delete the existing snapshot and re-read live TAL membership.",
|
|
409
|
+
"Replaces everything; invalidates ongoing manager review work.",
|
|
410
|
+
"(3) APPEND — pass appendTalSlug (with reason) to UNION members",
|
|
411
|
+
"from a second TAL into the existing scope. Surgical mid-cycle",
|
|
412
|
+
"additions. Existing rows untouched (first-snapshotted-wins on",
|
|
413
|
+
"source_tal_slug). Doesn't disturb prior manager review; the",
|
|
414
|
+
"newly-appended accounts get fresh proposal rows on next propose.",
|
|
415
|
+
"force and appendTalSlug are mutually exclusive.",
|
|
416
|
+
].join(" "), {
|
|
417
|
+
planningCycleId: z.string().uuid().optional().describe("Planning cycle. Defaults to the org's currently-open cycle."),
|
|
418
|
+
talSlugOverride: z.string().optional().describe("Override TAL slug from account_placement.yaml."),
|
|
419
|
+
force: z.boolean().optional().describe("Default false. Pass true to delete + re-snapshot. Mutually exclusive with appendTalSlug."),
|
|
420
|
+
appendTalSlug: z.string().optional().describe("Append membership from this additional TAL into the existing scope. Surgical mid-cycle additions; existing rows untouched. Requires an existing snapshot. Mutually exclusive with force."),
|
|
421
|
+
reason: z.string().min(10).optional().describe("Required when force=true OR appendTalSlug is set. Why you're modifying scope mid-cycle."),
|
|
422
|
+
branch: z.string().optional(),
|
|
423
|
+
}, safeTool(async (input) => trpcMutation("mcp.snapshotPlanningScope", input)));
|
|
424
|
+
}
|
|
425
|
+
if (allowed.has("show_planning_scope")) {
|
|
426
|
+
server.tool("show_planning_scope", [
|
|
427
|
+
"Read-only. Show the snapshotted scope for a planning cycle:",
|
|
428
|
+
"source TAL, snapshot date, total + inactive counts, and a",
|
|
429
|
+
"sample of accounts. Empty when no snapshot has been taken yet",
|
|
430
|
+
"(run snapshot_planning_scope first).",
|
|
431
|
+
].join(" "), {
|
|
432
|
+
planningCycleId: z.string().uuid().optional().describe("Planning cycle. Defaults to the org's currently-open cycle."),
|
|
433
|
+
sampleSize: z.number().int().min(0).max(100).optional().describe("Sample rows. Default 20."),
|
|
434
|
+
}, safeTool(async (input) => trpcQuery("mcp.showPlanningScope", input)));
|
|
435
|
+
}
|
|
399
436
|
if (allowed.has("propose_account_assignments")) {
|
|
400
437
|
server.tool("propose_account_assignments", [
|
|
401
438
|
"Ops/eng. Run the Phase 3 account-placement model for an open",
|
|
402
439
|
"planning cycle. Continuity-preservation policy from",
|
|
403
440
|
"config/deploy/account_placement.yaml is honored unless overridden.",
|
|
404
|
-
"
|
|
441
|
+
"Three refusal gates: (1) Phase 1 (user → territory) must be fully",
|
|
405
442
|
"committed/superseded; (2) capacity_config.active_scenario must",
|
|
406
|
-
"be set
|
|
407
|
-
"
|
|
408
|
-
"
|
|
409
|
-
"
|
|
410
|
-
"
|
|
443
|
+
"be set; (3) a planning scope snapshot must exist for the cycle",
|
|
444
|
+
"(run snapshot_planning_scope first). Default behavior: accounts",
|
|
445
|
+
"with active current owners auto-ratify their current territory",
|
|
446
|
+
"(continuity); only new or owner-departed accounts go through",
|
|
447
|
+
"full match-rule + composition + balance modeling. Pass",
|
|
448
|
+
"preserveCurrentOwnershipOverride:false for full re-plans (M&A,",
|
|
449
|
+
"geographic restructure).",
|
|
411
450
|
].join(" "), {
|
|
412
451
|
planningCycleId: z.string().uuid().optional().describe("Planning cycle. Defaults to the org's currently-open cycle."),
|
|
413
452
|
preserveCurrentOwnershipOverride: z.boolean().optional().describe("Override config/deploy/account_placement.yaml's preserve_current_ownership policy."),
|
|
@@ -494,6 +533,53 @@ export function registerDeployTools(server, allowed) {
|
|
|
494
533
|
branch: z.string().optional(),
|
|
495
534
|
}, safeTool(async (input) => trpcMutation("mcp.commitAccountAssignments", input)));
|
|
496
535
|
}
|
|
536
|
+
if (allowed.has("rollback_account_commit")) {
|
|
537
|
+
server.tool("rollback_account_commit", [
|
|
538
|
+
"Ops only. Reverse a prior commit_account_assignments by reading",
|
|
539
|
+
"the per-proposal audit rows under the given rollback_id and",
|
|
540
|
+
"restoring each account's territory_slug to its pre_snapshot",
|
|
541
|
+
"value. Force two-step (default dryRun:true). Writes a per-row",
|
|
542
|
+
"audit entry with action='rollback' and metadata linking to the",
|
|
543
|
+
"original commit's audit_id. Proposal rows stay at",
|
|
544
|
+
"state='committed' — this is a data-plane reversal, not a",
|
|
545
|
+
"state-machine reversal. The response surfaces a fresh rollback",
|
|
546
|
+
"id you can pass back through this tool to revert the rollback.",
|
|
547
|
+
"AM's SFDC sync orchestrator (every 15m) propagates to SF.",
|
|
548
|
+
].join(" "), {
|
|
549
|
+
rollbackId: z
|
|
550
|
+
.string()
|
|
551
|
+
.uuid()
|
|
552
|
+
.describe("rollback_id surfaced by the original commit_account_assignments call."),
|
|
553
|
+
dryRun: z
|
|
554
|
+
.boolean()
|
|
555
|
+
.optional()
|
|
556
|
+
.describe("Default true. Pass false to apply the reversal."),
|
|
557
|
+
reason: z
|
|
558
|
+
.string()
|
|
559
|
+
.min(20)
|
|
560
|
+
.describe("Why you're rolling back — required, min 20 chars. Captured in every per-proposal audit row."),
|
|
561
|
+
}, safeTool(async (input) => trpcMutation("mcp.rollbackAccountCommit", input)));
|
|
562
|
+
}
|
|
563
|
+
if (allowed.has("commit_cycle")) {
|
|
564
|
+
server.tool("commit_cycle", [
|
|
565
|
+
"Ops only. Phase 4.3 atomic cutover for directory-shape",
|
|
566
|
+
"scenarios. Reads all approved rows across user / quota /",
|
|
567
|
+
"account placement tables, promotes scenario inputs (territories,",
|
|
568
|
+
"hierarchy, composition, account_placement) to canonical",
|
|
569
|
+
"config/deploy/, writes assignments.yaml + quotas.yaml outputs,",
|
|
570
|
+
"updates account.territory_slug for committed account placements,",
|
|
571
|
+
"transitions all rows to 'committed', closes the cycle. ONE",
|
|
572
|
+
"GitHub commit + ONE DB transaction — either everything lands",
|
|
573
|
+
"or nothing does. Force two-step (default dryRun:true). Refuses",
|
|
574
|
+
"on legacy single-file scenarios; per-phase commits still work",
|
|
575
|
+
"for those.",
|
|
576
|
+
].join(" "), {
|
|
577
|
+
planningCycleId: z.string().uuid().optional().describe("Planning cycle. Defaults to the org's currently-open cycle."),
|
|
578
|
+
dryRun: z.boolean().optional().describe("Default true. Pass false to perform the atomic commit."),
|
|
579
|
+
message: z.string().optional().describe("Override the auto-generated commit message."),
|
|
580
|
+
branch: z.string().optional().describe("Branch to write to. Default: main."),
|
|
581
|
+
}, safeTool(async (input) => trpcMutation("mcp.commitCycle", input)));
|
|
582
|
+
}
|
|
497
583
|
if (allowed.has("close_cycle")) {
|
|
498
584
|
server.tool("close_cycle", [
|
|
499
585
|
"Ops only. Mark a planning cycle done. State `open → closed`.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loopops/mcp-server",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.31.0",
|
|
4
4
|
"description": "Loop Operations MCP Server — AI skills for RevOps",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -20,6 +20,12 @@
|
|
|
20
20
|
"publishConfig": {
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"dev": "tsx src/index.ts",
|
|
26
|
+
"start": "node dist/index.js",
|
|
27
|
+
"prepublishOnly": "pnpm build"
|
|
28
|
+
},
|
|
23
29
|
"dependencies": {
|
|
24
30
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
25
31
|
"zod": "^3.24.4"
|
|
@@ -28,10 +34,5 @@
|
|
|
28
34
|
"@types/node": "^22.15.21",
|
|
29
35
|
"tsx": "^4.19.4",
|
|
30
36
|
"typescript": "^5.8.3"
|
|
31
|
-
},
|
|
32
|
-
"scripts": {
|
|
33
|
-
"build": "tsc",
|
|
34
|
-
"dev": "tsx src/index.ts",
|
|
35
|
-
"start": "node dist/index.js"
|
|
36
37
|
}
|
|
37
|
-
}
|
|
38
|
+
}
|