@loopops/mcp-server 3.24.0 → 3.26.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/tools/deploy.js +99 -0
- package/package.json +1 -1
package/dist/tools/deploy.js
CHANGED
|
@@ -395,6 +395,105 @@ export function registerDeployTools(server, allowed) {
|
|
|
395
395
|
.describe("Why you're sending this back — required, captured in the audit log so the manager sees the intent."),
|
|
396
396
|
}, safeTool(async (input) => trpcMutation("mcp.reviseUserAssignment", input)));
|
|
397
397
|
}
|
|
398
|
+
// ── Phase 3 — Account → Territory placement ────────────────────────
|
|
399
|
+
if (allowed.has("propose_account_assignments")) {
|
|
400
|
+
server.tool("propose_account_assignments", [
|
|
401
|
+
"Ops/eng. Run the Phase 3 account-placement model for an open",
|
|
402
|
+
"planning cycle. Continuity-preservation policy from",
|
|
403
|
+
"config/deploy/account_placement.yaml is honored unless overridden.",
|
|
404
|
+
"Two refusal gates: (1) Phase 1 (user → territory) must be fully",
|
|
405
|
+
"committed/superseded; (2) capacity_config.active_scenario must",
|
|
406
|
+
"be set. Default behavior: accounts with active current owners",
|
|
407
|
+
"auto-ratify their current territory (continuity); only new or",
|
|
408
|
+
"owner-departed accounts go through full match-rule + composition",
|
|
409
|
+
"+ balance modeling. Pass preserveCurrentOwnershipOverride:false",
|
|
410
|
+
"for full re-plans (M&A, geographic restructure).",
|
|
411
|
+
].join(" "), {
|
|
412
|
+
planningCycleId: z.string().uuid().optional().describe("Planning cycle. Defaults to the org's currently-open cycle."),
|
|
413
|
+
preserveCurrentOwnershipOverride: z.boolean().optional().describe("Override config/deploy/account_placement.yaml's preserve_current_ownership policy."),
|
|
414
|
+
accountIds: z.array(z.string().uuid()).optional().describe("Optional restriction; only model these accounts."),
|
|
415
|
+
scenarioId: z.string().optional().describe("Override active scenario."),
|
|
416
|
+
branch: z.string().optional(),
|
|
417
|
+
}, safeTool(async (input) => trpcMutation("mcp.proposeAccountAssignments", input)));
|
|
418
|
+
}
|
|
419
|
+
if (allowed.has("review_account_assignments")) {
|
|
420
|
+
server.tool("review_account_assignments", [
|
|
421
|
+
"List Phase 3 account placement proposals for a cycle. Subtree-",
|
|
422
|
+
"scoped for managers; full org for ops/eng/leadership. Default",
|
|
423
|
+
"sort = confidence ascending (lowest first — these need attention).",
|
|
424
|
+
"Confidence band filter for triage: 'low' (<0.75) for the rows",
|
|
425
|
+
"that need real review; 'high' (≥0.9) for bulk-approve candidates.",
|
|
426
|
+
"Continuity-preserved rows show 'preserved' in their continuity",
|
|
427
|
+
"column. Composition violations get a ⚠️ marker.",
|
|
428
|
+
].join(" "), {
|
|
429
|
+
planningCycleId: z.string().uuid().optional(),
|
|
430
|
+
state: z.array(z.enum(["proposed", "in_review", "edited", "approved", "committed", "superseded"])).optional(),
|
|
431
|
+
territorySlug: z.string().optional(),
|
|
432
|
+
confidenceBand: z.enum(["low", "mid", "high", "all"]).optional().describe("low: <0.75; mid: 0.75-0.9; high: >=0.9. Default: all."),
|
|
433
|
+
cursor: z.string().optional(),
|
|
434
|
+
limit: z.number().int().positive().max(500).optional(),
|
|
435
|
+
branch: z.string().optional(),
|
|
436
|
+
}, safeTool(async (input) => trpcQuery("mcp.reviewAccountAssignments", input)));
|
|
437
|
+
}
|
|
438
|
+
if (allowed.has("approve_account_assignments")) {
|
|
439
|
+
server.tool("approve_account_assignments", [
|
|
440
|
+
"Manager+. Bulk-approve Phase 3 account placement proposals.",
|
|
441
|
+
"State proposed/in_review/edited → approved. Default = all in your",
|
|
442
|
+
"subtree; pass proposalIds for a subset (e.g., bulk-approve all",
|
|
443
|
+
"high-confidence rows after reviewing). Speed equivalent of",
|
|
444
|
+
"today's auto-commit, but gated by an explicit operator action.",
|
|
445
|
+
].join(" "), {
|
|
446
|
+
planningCycleId: z.string().uuid().optional(),
|
|
447
|
+
proposalIds: z.array(z.string().uuid()).optional(),
|
|
448
|
+
notes: z.string().optional(),
|
|
449
|
+
branch: z.string().optional(),
|
|
450
|
+
}, safeTool(async (input) => trpcMutation("mcp.approveAccountAssignments", input)));
|
|
451
|
+
}
|
|
452
|
+
if (allowed.has("edit_account_assignment")) {
|
|
453
|
+
server.tool("edit_account_assignment", [
|
|
454
|
+
"Manager+. Move an account between territories within your",
|
|
455
|
+
"hierarchy subtree. State proposed/in_review/edited → edited.",
|
|
456
|
+
"Both source AND destination territories must be in your subtree.",
|
|
457
|
+
"Returns synchronous recompute of composition + balance for the",
|
|
458
|
+
"affected territories so you see the impact of the move before",
|
|
459
|
+
"approving. Composition violations surface as warnings (not",
|
|
460
|
+
"blocking — manager judgment overrides). Match-rule violations",
|
|
461
|
+
"(e.g., NY account moved to SF Bay) are also warned-but-allowed",
|
|
462
|
+
"with audit captured.",
|
|
463
|
+
].join(" "), {
|
|
464
|
+
proposalId: z.string().uuid(),
|
|
465
|
+
newTerritorySlug: z.string().describe("Target patch slug. Must be in your hierarchy subtree."),
|
|
466
|
+
notes: z.string().min(5).describe("Required, min 5 chars. Captured in audit log."),
|
|
467
|
+
branch: z.string().optional(),
|
|
468
|
+
}, safeTool(async (input) => trpcMutation("mcp.editAccountAssignment", input)));
|
|
469
|
+
}
|
|
470
|
+
if (allowed.has("revise_account_proposal")) {
|
|
471
|
+
server.tool("revise_account_proposal", [
|
|
472
|
+
"Ops only. Demote an approved account proposal back to edited",
|
|
473
|
+
"so the manager can revise. State `approved → edited`.",
|
|
474
|
+
"final_territory_slug preserved. Audit row records who sent it",
|
|
475
|
+
"back and why. Mirrors revise_user_assignment + revise_quota_proposal.",
|
|
476
|
+
].join(" "), {
|
|
477
|
+
proposalId: z.string().uuid(),
|
|
478
|
+
notes: z.string().min(5),
|
|
479
|
+
}, safeTool(async (input) => trpcMutation("mcp.reviseAccountProposal", input)));
|
|
480
|
+
}
|
|
481
|
+
if (allowed.has("commit_account_assignments")) {
|
|
482
|
+
server.tool("commit_account_assignments", [
|
|
483
|
+
"Ops only. Force two-step (default dryRun:true). Writes",
|
|
484
|
+
"account.territory_slug (Account Master); the existing AM SFDC",
|
|
485
|
+
"sync orchestrator (cron every 15m) pushes to Salesforce on its",
|
|
486
|
+
"next run. Pre-snapshot of every affected account's prior",
|
|
487
|
+
"territory_slug lands in audit_log under a stable rollback_id",
|
|
488
|
+
"the response surfaces — keep it for any reversal need. Re-run",
|
|
489
|
+
"with dryRun:false to commit; the response includes rollback",
|
|
490
|
+
"instructions.",
|
|
491
|
+
].join(" "), {
|
|
492
|
+
planningCycleId: z.string().uuid().optional(),
|
|
493
|
+
dryRun: z.boolean().optional().describe("Default true. Pass false to commit + advance state."),
|
|
494
|
+
branch: z.string().optional(),
|
|
495
|
+
}, safeTool(async (input) => trpcMutation("mcp.commitAccountAssignments", input)));
|
|
496
|
+
}
|
|
398
497
|
if (allowed.has("close_cycle")) {
|
|
399
498
|
server.tool("close_cycle", [
|
|
400
499
|
"Ops only. Mark a planning cycle done. State `open → closed`.",
|