conduyt-mcp 4.32.0 → 4.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.
@@ -36,7 +36,7 @@ const masterStatusName = z
36
36
  .max(40)
37
37
  .regex(/^[a-z0-9][a-z0-9 _-]*$/i, "letters, numbers, spaces, - and _ only");
38
38
  export function registerLifecycleTools(server, client) {
39
- server.tool("conduyt_get_lifecycle_settings", "Read the account's Lifecycle v2 configuration, shaped for read-before-write: masterStatuses.effective is the full list a contact's masterStatus may take (the five built-in defaults plus the account's customs — the raw settings key stores only the customs); intakeDeals is the automatic deal-on-intake config, or null with an intakeDealsNote explaining that null can mean either not-configured or not-visible-to-your-key (the setting is admin-visible; member-tier responses omit it).", {}, async () => {
39
+ server.tool("conduyt_get_lifecycle_settings", "Read the account's Lifecycle configuration (v2 + v3), shaped for read-before-write: dealWorkingMode and lostPropagation say how the tenant works leads and whether lost propagation is live; masterStatuses.effective is the full list a contact's masterStatus may take (the five built-in defaults plus the account's customs — the raw settings key stores only the customs); intakeDeals is the automatic deal-on-intake config, or null with an intakeDealsNote explaining that null can mean either not-configured or not-visible-to-your-key (the setting is admin-visible; member-tier responses omit it).", {}, async () => {
40
40
  const result = await client.get("/api/v1/settings");
41
41
  const raw = result?.data ?? {};
42
42
  const customs = Array.isArray(raw.masterStatuses)
@@ -46,7 +46,22 @@ export function registerLifecycleTools(server, client) {
46
46
  // and an unconfigured account also lacks it. The two are not
47
47
  // distinguishable from here, so null is reported with a note saying so.
48
48
  const intakeDeals = raw.intakeDeals && typeof raw.intakeDeals === "object" ? raw.intakeDeals : null;
49
+ // Lifecycle v3 (2026-09-08): how the tenant works leads, and whether LOST
50
+ // propagation is live for it (P2: contact flips to lost when its LAST
51
+ // open card closes lost; a new open card reopens it; forward-only from
52
+ // enabledAt; off = the nightly shadow report only).
53
+ const dealWorkingMode = raw.dealWorkingMode === "pipeline" || raw.dealWorkingMode === "status" ? raw.dealWorkingMode : null;
54
+ const lostRaw = raw.lostPropagation && typeof raw.lostPropagation === "object" ? raw.lostPropagation : null;
55
+ const lostPropagation = {
56
+ enabled: lostRaw?.enabled === true,
57
+ enabledAt: typeof lostRaw?.enabledAt === "string" ? lostRaw.enabledAt : null,
58
+ };
49
59
  const shaped = {
60
+ dealWorkingMode,
61
+ dealWorkingModeNote: dealWorkingMode === null
62
+ ? "null = not chosen yet (legacy account) — 'pipeline': every inbound contact gets a deal card (intakeDeals required); 'status': the contact is the opportunity"
63
+ : undefined,
64
+ lostPropagation,
50
65
  masterStatuses: {
51
66
  defaults: DEFAULT_MASTER_STATUSES,
52
67
  customs,
@@ -68,6 +83,12 @@ export function registerLifecycleTools(server, client) {
68
83
  .optional()
69
84
  .describe("Policy for contacts that already exist (default 'if_no_open')"),
70
85
  }, async (params) => patchGeneralSettings(client, { intakeDeals: params }));
86
+ server.tool("conduyt_update_deal_working_mode", "Set how this tenant works leads (Lifecycle v3). 'pipeline': every inbound contact gets a deal card in the intake pipeline — requires intakeDeals enabled with a pipelineId and stageId (conduyt_update_intake_deals first), and a new form/webhook/line cannot go live without a pipeline. 'status': the contact is the opportunity, no automatic cards (small shops). Switchable later; new tenants default to 'pipeline'.", {
87
+ mode: z.enum(["pipeline", "status"]).describe("'pipeline' (cards on every inbound) or 'status' (the contact is the opportunity)"),
88
+ }, async ({ mode }) => patchGeneralSettings(client, { dealWorkingMode: mode }));
89
+ server.tool("conduyt_update_lost_propagation", "Turn LOST propagation on or off for this tenant (Lifecycle v3 P2). When on: a contact's masterStatus flips to 'lost' within a minute of its LAST open deal card closing lost (a per-minute resolver applies the rule on the committed state) (carrying that card's lostReason into masterStatusReason), a new open card on a lost/abandoned/disqualified contact reopens it, and a won contact never flips. Forward-only from the first enable (enabledAt is stamped server-side): existing history never flips by itself. A terminal masterStatus silences every drip, sequence and playbook for that contact, so read the nightly shadow report first (job run 'lost-propagation-shadow': contacts that would flip, their reasons, and the automations that would go quiet) before enabling.", {
90
+ enabled: z.boolean().describe("true = flips happen live from now on; false = shadow report only"),
91
+ }, async ({ enabled }) => patchGeneralSettings(client, { lostPropagation: { enabled } }));
71
92
  server.tool("conduyt_update_master_statuses", "Set the account's custom lead lifecycle statuses. The five defaults (open, won, lost, abandoned, disqualified) always exist and cannot be removed; this REPLACES the custom list on top of them (max 20 names, 1-40 chars each, letters/numbers/spaces/-/_ only). Terminal statuses stop all outbound automation for a contact. Requires settings:edit.", {
72
93
  statuses: z
73
94
  .array(masterStatusName)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conduyt-mcp",
3
- "version": "4.32.0",
3
+ "version": "4.33.0",
4
4
  "description": "MCP server for Conduyt CRM — expose CRM operations as AI-accessible tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,10 +1,10 @@
1
1
  {
2
- "generatedAt": "2026-09-07T18:36:27.469Z",
3
- "toolCount": 217,
4
- "totalEndpoints": 925,
2
+ "generatedAt": "2026-09-09T04:17:05.786Z",
3
+ "toolCount": 219,
4
+ "totalEndpoints": 929,
5
5
  "counts": {
6
6
  "covered": 202,
7
- "excluded": 278,
7
+ "excluded": 282,
8
8
  "planned": 445,
9
9
  "uncategorized": 0
10
10
  },
@@ -1553,6 +1553,10 @@
1553
1553
  "status": "excluded",
1554
1554
  "reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
1555
1555
  },
1556
+ "GET /api/v1/cron/lost-propagation-shadow": {
1557
+ "status": "excluded",
1558
+ "reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
1559
+ },
1556
1560
  "GET /api/v1/cron/mailbox-delta-recovery": {
1557
1561
  "status": "excluded",
1558
1562
  "reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
@@ -1757,6 +1761,10 @@
1757
1761
  "status": "excluded",
1758
1762
  "reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
1759
1763
  },
1764
+ "GET /api/v1/cron/resolve-master-status": {
1765
+ "status": "excluded",
1766
+ "reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
1767
+ },
1760
1768
  "GET /api/v1/cron/resume-imports": {
1761
1769
  "status": "excluded",
1762
1770
  "reason": "CRON_SECRET-gated infrastructure jobs; never key-callable"
@@ -4076,6 +4084,14 @@
4076
4084
  "status": "excluded",
4077
4085
  "reason": "inbound provider callback receivers (Twilio/Resend/etc.), not client-callable"
4078
4086
  },
4087
+ "POST /api/v1/webhooks/voice/vendor-recording": {
4088
+ "status": "excluded",
4089
+ "reason": "inbound provider callback receivers (Twilio/Resend/etc.), not client-callable"
4090
+ },
4091
+ "POST /api/v1/webhooks/voice/vendor-status": {
4092
+ "status": "excluded",
4093
+ "reason": "inbound provider callback receivers (Twilio/Resend/etc.), not client-callable"
4094
+ },
4079
4095
  "POST /api/v1/webhooks/voice/voicemail": {
4080
4096
  "status": "excluded",
4081
4097
  "reason": "inbound provider callback receivers (Twilio/Resend/etc.), not client-callable"