conduyt-mcp 4.78.0 → 4.79.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/README.md CHANGED
@@ -55,7 +55,7 @@ MCP server for [Conduyt CRM](https://conduyt.app) — expose your CRM as AI-acce
55
55
  | `conduyt_delete_pipeline` | Delete a pipeline (move/remove its deals first) |
56
56
  | `conduyt_create_stage` | Append a stage to a pipeline (e.g. 'On Hold', 'Declined/Dead') |
57
57
  | `conduyt_update_stage` | Rename, recolor, reorder, or change won/lost flags on a stage |
58
- | `conduyt_delete_stage` | Delete a stage from a pipeline; `moveTo` moves its live deals to another stage first, `expectedSettingsRevision` refuses the delete when settings changed (409 `stale_settings_revision`; the answer then carries the new `settingsRevision`) |
58
+ | `conduyt_delete_stage` | Soft-delete a stage: an EMPTY stage can always be deleted (history kept, hidden from every list, GET / PATCH then 404, no restore in v1, name reusable); `moveTo` re-homes its live deals first, `expectedSettingsRevision` refuses the delete when settings changed (409 `stale_settings_revision`; the answer then carries the new `settingsRevision`). Refusals are 409s whose message is surfaced verbatim: deals in the stage, `used by N active automation(s) (names)`, DPP status map, `pipeline_archived`, `intake_target`. A run parked before the delete fails at that step with a clear reason |
59
59
 
60
60
  ### Activities
61
61
  | Tool | Description |
@@ -9,7 +9,7 @@ export const ARCHIVE_ERROR_CODES = "A refusal carries a machine-readable code in
9
9
  /** above the archive route's 60 s transaction (up to 500 deal moves) plus post-commit events; the client default is 30 s */
10
10
  export const ARCHIVE_PIPELINE_TIMEOUT_MS = 75_000;
11
11
  export function registerPipelineTools(server, client) {
12
- server.tool("conduyt_list_pipelines", "List all active sales pipelines with their stages. Use this to discover pipeline and stage UUIDs before creating or moving deals. Each pipeline carries color (one of the 10 palette hex colours, or null until the settings page saves one), automationOnly and sortOrder (the board-menu order); an archived pipeline's pre-archive name is archivedFromName (see conduyt_list_archived_pipelines).", {}, async () => {
12
+ server.tool("conduyt_list_pipelines", "List all active sales pipelines with their stages (soft-deleted stages are never included). Use this to discover pipeline and stage UUIDs before creating or moving deals. Each pipeline carries color (one of the 10 palette hex colours, or null until the settings page saves one), automationOnly and sortOrder (the board-menu order); an archived pipeline's pre-archive name is archivedFromName (see conduyt_list_archived_pipelines).", {}, async () => {
13
13
  const result = await client.get("/api/v1/pipelines");
14
14
  return formatResult(result);
15
15
  });
@@ -90,7 +90,7 @@ export function registerPipelineTools(server, client) {
90
90
  const result = await client.post("/api/v1/pipelines/reorder", { order, expectedRevision });
91
91
  return formatResult(result);
92
92
  }));
93
- server.tool("conduyt_create_stage", "Add a new stage to an existing pipeline. The stage is appended after the current last stage. Use this to extend a funnel (e.g. add 'On Hold' or 'Declined/Dead').", {
93
+ server.tool("conduyt_create_stage", "Add a new stage to an existing pipeline. The stage is appended after the current last stage. Use this to extend a funnel (e.g. add 'On Hold' or 'Declined/Dead'). A name may be reused after the old stage of that name was deleted (deleted stages are soft-deleted and hidden).", {
94
94
  pipelineId: z.string().describe("Pipeline UUID to add the stage to"),
95
95
  name: z.string().describe("Stage name"),
96
96
  color: z.string().optional().describe("Hex color, e.g. '#3B82F6'"),
@@ -107,7 +107,7 @@ export function registerPipelineTools(server, client) {
107
107
  });
108
108
  return formatResult(result);
109
109
  });
110
- server.tool("conduyt_update_stage", "Update a stage within a pipeline — rename, recolor, reorder (sortOrder), or change its won/lost/system flags.", {
110
+ server.tool("conduyt_update_stage", "Update a stage within a pipeline — rename, recolor, reorder (sortOrder), or change its won/lost/system flags. A soft-deleted stage (conduyt_delete_stage) answers 404.", {
111
111
  pipelineId: z.string().describe("Pipeline UUID"),
112
112
  stageId: z.string().describe("Stage UUID to update"),
113
113
  name: z.string().optional().describe("Updated stage name"),
@@ -128,7 +128,7 @@ export function registerPipelineTools(server, client) {
128
128
  const result = await client.post(`/api/v1/pipelines/${pipelineId}/stages/reorder`, { order, expectedRevision });
129
129
  return formatResult(result);
130
130
  }));
131
- strictInput(server.tool("conduyt_delete_stage", "Delete a stage from a pipeline. Strict input: the guards are spelled moveTo and expectedSettingsRevision, any other spelling (move_to, expected_settings_revision, a typo) is InvalidParams and nothing is deleted. The stage must be empty (no deals) unless moveTo names another stage of the same pipeline (same won / lost setting, not a system stage): its live deals then move there and the stage is deleted in one transaction. A stage a soft-deleted deal still points at is refused. Pass expectedSettingsRevision (the settingsRevision from conduyt_get_settings_revision, read right before) to refuse the delete when settings changed since you read them; the answer is then { id, deleted: true, settingsRevision } with the revision after the delete. A refusal carries a machine-readable code in the error text and the server's message, never swallowed: stale_settings_revision (409), pipeline_archived (409), intake_target (409, enabled intake routes deals into this stage); other 409s (DPP status map, unattended-lead automations, deals that used the stage) have no code but name the cause.", {
131
+ strictInput(server.tool("conduyt_delete_stage", "Delete a stage from a pipeline (soft delete). Strict input: the guards are spelled moveTo and expectedSettingsRevision, any other spelling (move_to, expected_settings_revision, a typo) is InvalidParams and nothing is deleted. An EMPTY stage can always be deleted, even if deals once used it: the row is kept so deal history, activities, audit rows and reports keep its name, but the stage is hidden from every pipeline and stage list, GET / PATCH on it answer 404, there is NO restore in v1, and its name may be reused by a new stage. Its stage rule, appointment-outcome mappings and status metadata are removed with it. With moveTo (another stage of the same pipeline, same won / lost setting, not a system stage) its live deals move there and the stage is deleted in one transaction. Pass expectedSettingsRevision (the settingsRevision from conduyt_get_settings_revision, read right before) to refuse the delete when settings changed since you read them; the answer is then { id, deleted: true, settingsRevision } with the revision after the delete. A refusal is a 409 whose server message is surfaced verbatim (never swallowed, never retried): deals currently in the stage and no moveTo (\"Cannot delete stage: N deal(s) are in this stage...\"), \"Cannot delete stage: it is used by N active automation(s) (names). Change their stage or pause them first.\" (a published automation references the stage in an action, trigger, condition or wait-until), the DPP status map selects it, plus the coded refusals stale_settings_revision, pipeline_archived and intake_target (enabled intake routes deals into this stage); a moveTo that is not a valid target is a 400. Accepted window: a run parked or in flight before the delete is not tracked; at the step that targets the deleted stage it fails or is skipped with a clear reason in the execution log.", {
132
132
  pipelineId: z.string().describe("Pipeline UUID"),
133
133
  stageId: z.string().describe("Stage UUID to delete"),
134
134
  moveTo: z.string().uuid().optional().describe("Another stage of the same pipeline the live deals move to (sent as move_to)"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conduyt-mcp",
3
- "version": "4.78.0",
3
+ "version": "4.79.0",
4
4
  "mcpName": "com.conduyt/mcp",
5
5
  "description": "MCP server for Conduyt CRM — expose CRM operations as AI-accessible tools",
6
6
  "type": "module",