@loopops/mcp-server 3.31.0 → 3.33.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 CHANGED
File without changes
@@ -318,31 +318,9 @@ export function registerConfigTools(server, allowed) {
318
318
  source: z.string().optional().describe("Lead source (Web, Partner Referral, etc.)."),
319
319
  }, safeTool(async (input) => trpcMutation("mcp.previewRouting", input)));
320
320
  }
321
- if (allowed.has("list_pending_territories")) {
322
- server.tool("list_pending_territories", "List Accounts currently in a pending territory assignment state (Territory_Slug__c starts with 'pending:'). Returns the status breakdown + per-account table with agent reasoning when available. Pending accounts are re-evaluated on each assign_territories run.", {
323
- includeReasoning: z
324
- .boolean()
325
- .default(true)
326
- .describe("Include the agent's reasoning column (joins agent_decisions)."),
327
- }, safeTool(async ({ includeReasoning }) => trpcQuery("mcp.listPendingTerritories", { includeReasoning })));
328
- }
329
- if (allowed.has("assign_territories")) {
330
- server.tool("assign_territories", "Match each target Account to a territory Patch using config/design/hierarchy.yaml (tree) + config/deploy/territories.yaml (billing match rules). Writes Account.Territory_Slug__c + ObjectTerritory2Association in SF. Dry-run by default. Uses Claude Haiku + web_search as a fallback when deterministic matching fails. Auto-applies agent matches at confidence ≥ 0.9; flags 0.75-0.9 for review.", {
331
- mode: z
332
- .enum(["new", "all"])
333
- .default("new")
334
- .describe("'new' (default): only accounts without a current territory. 'all': re-evaluate everything (use after territories.yaml changes)."),
335
- dryRun: z
336
- .boolean()
337
- .default(true)
338
- .describe("When true (default), shows the diff without writing to Salesforce."),
339
- useAgent: z
340
- .boolean()
341
- .default(true)
342
- .describe("Run Claude fallback for accounts the deterministic matcher cannot resolve. Set false to skip the agent."),
343
- branch: z.string().optional().describe("Branch to read YAML from. Default: main."),
344
- }, safeTool(async ({ mode, dryRun, useAgent, branch }) => trpcMutation("mcp.assignTerritories", { mode, dryRun, useAgent, branch })));
345
- }
321
+ // list_pending_territories + assign_territories retired 2026-05-10.
322
+ // Account placement now uses the Phase 3 propose_account_assignments
323
+ // chain (with commit_cycle for directory-shape scenarios).
346
324
  if (allowed.has("show_govern_config")) {
347
325
  server.tool("show_govern_config", [
348
326
  "Read a YAML file under `config/govern/`. Most-common use: viewing",
@@ -45,12 +45,32 @@ export function registerDeployTools(server, allowed) {
45
45
  .boolean()
46
46
  .optional()
47
47
  .describe("Run the model and return proposals without persisting. Useful for previewing what the model would emit before committing to a cycle. Default: false."),
48
+ async: z
49
+ .boolean()
50
+ .optional()
51
+ .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_user_assignments_status. Required for rosters >50 hires. Cannot be combined with dryRun:true. Default: false."),
48
52
  branch: z
49
53
  .string()
50
54
  .optional()
51
55
  .describe("Git branch to read configs from. Default: main."),
52
56
  }, safeTool(async (input) => trpcMutation("mcp.proposeUserAssignments", input)));
53
57
  }
58
+ if (allowed.has("propose_user_assignments_status")) {
59
+ server.tool("propose_user_assignments_status", [
60
+ "Read the status of an async user-placement job kicked off by",
61
+ "`propose_user_assignments async:true`. Returns the job's current",
62
+ "status (queued / running / complete / failed), how many proposals",
63
+ "have been written so far, when it started/completed, and the",
64
+ "Modal call id for cross-referencing in the Modal UI. Once the",
65
+ "status is `complete`, run `review_user_assignments` to see the",
66
+ "proposals.",
67
+ ].join(" "), {
68
+ jobId: z
69
+ .string()
70
+ .uuid()
71
+ .describe("placement_job.id returned by `propose_user_assignments async:true`."),
72
+ }, safeTool(async (input) => trpcQuery("mcp.proposeUserAssignmentsStatus", input)));
73
+ }
54
74
  if (allowed.has("propose_quotas")) {
55
75
  server.tool("propose_quotas", [
56
76
  "Run the quota model for an open planning cycle. Produces one",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loopops/mcp-server",
3
- "version": "3.31.0",
3
+ "version": "3.33.0",
4
4
  "description": "Loop Operations MCP Server — AI skills for RevOps",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -20,12 +20,6 @@
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
- },
29
23
  "dependencies": {
30
24
  "@modelcontextprotocol/sdk": "^1.12.1",
31
25
  "zod": "^3.24.4"
@@ -34,5 +28,10 @@
34
28
  "@types/node": "^22.15.21",
35
29
  "tsx": "^4.19.4",
36
30
  "typescript": "^5.8.3"
31
+ },
32
+ "scripts": {
33
+ "build": "tsc",
34
+ "dev": "tsx src/index.ts",
35
+ "start": "node dist/index.js"
37
36
  }
38
- }
37
+ }