@loopops/mcp-server 3.33.0 → 3.35.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/account-master.js +2 -2
- package/dist/tools/config.js +27 -2
- package/dist/tools/deploy.js +22 -9
- package/package.json +1 -1
|
@@ -158,7 +158,7 @@ export function registerAccountMasterTools(server, allowed) {
|
|
|
158
158
|
.min(1)
|
|
159
159
|
.max(64)
|
|
160
160
|
.regex(/^[a-z0-9_]+$/)
|
|
161
|
-
.describe("Attribute name in snake_case (e.g. '
|
|
161
|
+
.describe("Attribute name in snake_case (e.g. 'billing_state', 'industry_naics', 'employee_count'). Must match the `attribute_name` used in resolution rules."),
|
|
162
162
|
value: z
|
|
163
163
|
.string()
|
|
164
164
|
.min(1)
|
|
@@ -218,7 +218,7 @@ export function registerAccountMasterTools(server, allowed) {
|
|
|
218
218
|
.min(1)
|
|
219
219
|
.max(64)
|
|
220
220
|
.regex(/^[a-z0-9_]+$/)
|
|
221
|
-
.describe("Attribute name (e.g. '
|
|
221
|
+
.describe("Attribute name (e.g. 'billing_state'). Must match a prior manual override row."),
|
|
222
222
|
reason: z
|
|
223
223
|
.string()
|
|
224
224
|
.min(3)
|
package/dist/tools/config.js
CHANGED
|
@@ -137,7 +137,23 @@ export function registerConfigTools(server, allowed) {
|
|
|
137
137
|
})));
|
|
138
138
|
}
|
|
139
139
|
if (allowed.has("promote_scenario")) {
|
|
140
|
-
server.tool("promote_scenario",
|
|
140
|
+
server.tool("promote_scenario", [
|
|
141
|
+
"Promote a scenario to active by editing `active_scenario` in",
|
|
142
|
+
"config/design/capacity_config.yaml. Fails hard if the scenario",
|
|
143
|
+
"doesn't resolve (missing or dangling components) — won't promote",
|
|
144
|
+
"a broken plan. Dry-run by default — returns the diff; pass",
|
|
145
|
+
"dryRun:false to commit.",
|
|
146
|
+
"Open-cycle conflict: when the org has an open planning cycle",
|
|
147
|
+
"bound to a different scenario, promote refuses by default — the",
|
|
148
|
+
"cycle's scenarioId needs to move with the active scenario or",
|
|
149
|
+
"commit_cycle promotes the wrong scenario at cutover. Re-run with",
|
|
150
|
+
"rebindOpenCycle:true to apply the rebind atomically — the open",
|
|
151
|
+
"cycle's scenarioId moves, every non-superseded proposal across",
|
|
152
|
+
"all three phases is superseded (re-run propose after rebind),",
|
|
153
|
+
"and the planning scope snapshot is cleared (re-run",
|
|
154
|
+
"snapshot_planning_scope). A cycle-level audit row of",
|
|
155
|
+
"action='rebind_scenario' captures the impact counts.",
|
|
156
|
+
].join(" "), {
|
|
141
157
|
scenarioId: z
|
|
142
158
|
.string()
|
|
143
159
|
.describe("Scenario id to promote (e.g. 'stretch'). Must exist in config/design/scenarios/ and be complete."),
|
|
@@ -145,11 +161,20 @@ export function registerConfigTools(server, allowed) {
|
|
|
145
161
|
.boolean()
|
|
146
162
|
.default(true)
|
|
147
163
|
.describe("When true (default), return the diff without writing. Pass dryRun:false to commit."),
|
|
164
|
+
rebindOpenCycle: z
|
|
165
|
+
.boolean()
|
|
166
|
+
.default(false)
|
|
167
|
+
.describe("Required acknowledgement when an open cycle is bound to a different scenario. Default false → refuse with structured impact counts. Pass true to apply the rebind: update planning_cycle.scenarioId, supersede every non-superseded user / quota / account proposal in the cycle, delete planning_cycle_account_scope rows, then flip active_scenario in capacity_config.yaml. Atomic; audited as action='rebind_scenario'."),
|
|
148
168
|
branch: z
|
|
149
169
|
.string()
|
|
150
170
|
.optional()
|
|
151
171
|
.describe("Git branch to read from and write back to. Default: main. Writing to main = live promotion."),
|
|
152
|
-
}, safeTool(async ({ scenarioId, dryRun, branch }) => trpcMutation("mcp.promoteScenario", {
|
|
172
|
+
}, safeTool(async ({ scenarioId, dryRun, rebindOpenCycle, branch }) => trpcMutation("mcp.promoteScenario", {
|
|
173
|
+
scenarioId,
|
|
174
|
+
dryRun,
|
|
175
|
+
rebindOpenCycle,
|
|
176
|
+
branch,
|
|
177
|
+
})));
|
|
153
178
|
}
|
|
154
179
|
if (allowed.has("gap_analysis")) {
|
|
155
180
|
server.tool("gap_analysis", "Use a Claude agent to find the smallest change set that closes a scenario's capacity gap on the target measure. The agent iterates simulate_capacity calls (mutating roster + target_productivity in memory, calling the existing /capacity endpoint) up to a budget cap, then submits a structured proposal. Output is exploratory by default — pass `writeFile: true` to materialize the proposal as a draft scenario at `config/design/scenarios/proposed-gap-{measure}-{ts}.yaml`, then use `compare_scenarios` to verify and `promote_scenario` to make it active.", {
|
package/dist/tools/deploy.js
CHANGED
|
@@ -472,9 +472,23 @@ export function registerDeployTools(server, allowed) {
|
|
|
472
472
|
preserveCurrentOwnershipOverride: z.boolean().optional().describe("Override config/deploy/account_placement.yaml's preserve_current_ownership policy."),
|
|
473
473
|
accountIds: z.array(z.string().uuid()).optional().describe("Optional restriction; only model these accounts."),
|
|
474
474
|
scenarioId: z.string().optional().describe("Override active scenario."),
|
|
475
|
+
async: z.boolean().optional().describe("Run the placement model as a Modal background job (bypasses Vercel's 5-min function ceiling). Returns immediately with a job_id; poll status via propose_account_assignments_status. Recommended for cycles with >500 accounts. Default: false."),
|
|
475
476
|
branch: z.string().optional(),
|
|
476
477
|
}, safeTool(async (input) => trpcMutation("mcp.proposeAccountAssignments", input)));
|
|
477
478
|
}
|
|
479
|
+
if (allowed.has("propose_account_assignments_status")) {
|
|
480
|
+
server.tool("propose_account_assignments_status", [
|
|
481
|
+
"Read the status of an async account-placement job kicked off by",
|
|
482
|
+
"`propose_account_assignments async:true`. Returns the job's current",
|
|
483
|
+
"status (queued / running / complete / failed), how many proposals",
|
|
484
|
+
"have been written so far, when it started/completed, and the",
|
|
485
|
+
"Modal call id for cross-referencing in the Modal UI. Once the",
|
|
486
|
+
"status is `complete`, run `review_account_assignments` to see the",
|
|
487
|
+
"proposals.",
|
|
488
|
+
].join(" "), {
|
|
489
|
+
jobId: z.string().uuid().describe("placement_job.id returned by `propose_account_assignments async:true`."),
|
|
490
|
+
}, safeTool(async (input) => trpcQuery("mcp.proposeAccountAssignmentsStatus", input)));
|
|
491
|
+
}
|
|
478
492
|
if (allowed.has("review_account_assignments")) {
|
|
479
493
|
server.tool("review_account_assignments", [
|
|
480
494
|
"List Phase 3 account placement proposals for a cycle. Subtree-",
|
|
@@ -582,17 +596,16 @@ export function registerDeployTools(server, allowed) {
|
|
|
582
596
|
}
|
|
583
597
|
if (allowed.has("commit_cycle")) {
|
|
584
598
|
server.tool("commit_cycle", [
|
|
585
|
-
"Ops only.
|
|
586
|
-
"
|
|
587
|
-
"
|
|
588
|
-
"
|
|
589
|
-
"
|
|
590
|
-
"
|
|
599
|
+
"Ops only. Atomic cutover for a planning cycle. Reads all",
|
|
600
|
+
"approved rows across user / quota / account placement tables,",
|
|
601
|
+
"promotes scenario inputs (territories, hierarchy, composition,",
|
|
602
|
+
"account_placement) to canonical config/deploy/, writes",
|
|
603
|
+
"assignments.yaml + quotas.yaml outputs, propagates",
|
|
604
|
+
"rep_input_override rows to the scenario roster, updates",
|
|
605
|
+
"account.territory_slug for committed account placements,",
|
|
591
606
|
"transitions all rows to 'committed', closes the cycle. ONE",
|
|
592
607
|
"GitHub commit + ONE DB transaction — either everything lands",
|
|
593
|
-
"or nothing does. Force two-step (default dryRun:true).
|
|
594
|
-
"on legacy single-file scenarios; per-phase commits still work",
|
|
595
|
-
"for those.",
|
|
608
|
+
"or nothing does. Force two-step (default dryRun:true).",
|
|
596
609
|
].join(" "), {
|
|
597
610
|
planningCycleId: z.string().uuid().optional().describe("Planning cycle. Defaults to the org's currently-open cycle."),
|
|
598
611
|
dryRun: z.boolean().optional().describe("Default true. Pass false to perform the atomic commit."),
|