conduyt-mcp 4.1.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/.env.example +2 -0
- package/README.md +286 -0
- package/dist/client.d.ts +17 -0
- package/dist/client.js +43 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +79 -0
- package/dist/tools/activities.d.ts +3 -0
- package/dist/tools/activities.js +35 -0
- package/dist/tools/ai-extended.d.ts +3 -0
- package/dist/tools/ai-extended.js +38 -0
- package/dist/tools/ai.d.ts +3 -0
- package/dist/tools/ai.js +22 -0
- package/dist/tools/automations.d.ts +3 -0
- package/dist/tools/automations.js +66 -0
- package/dist/tools/bulk.d.ts +3 -0
- package/dist/tools/bulk.js +71 -0
- package/dist/tools/calendar.d.ts +3 -0
- package/dist/tools/calendar.js +81 -0
- package/dist/tools/companies.d.ts +3 -0
- package/dist/tools/companies.js +67 -0
- package/dist/tools/contacts.d.ts +3 -0
- package/dist/tools/contacts.js +64 -0
- package/dist/tools/custom-fields.d.ts +3 -0
- package/dist/tools/custom-fields.js +48 -0
- package/dist/tools/dashboard.d.ts +3 -0
- package/dist/tools/dashboard.js +7 -0
- package/dist/tools/deals.d.ts +3 -0
- package/dist/tools/deals.js +59 -0
- package/dist/tools/discovery.d.ts +3 -0
- package/dist/tools/discovery.js +28 -0
- package/dist/tools/drip-campaigns.d.ts +3 -0
- package/dist/tools/drip-campaigns.js +98 -0
- package/dist/tools/forms.d.ts +3 -0
- package/dist/tools/forms.js +54 -0
- package/dist/tools/invoices.d.ts +3 -0
- package/dist/tools/invoices.js +76 -0
- package/dist/tools/messaging.d.ts +3 -0
- package/dist/tools/messaging.js +25 -0
- package/dist/tools/notifications.d.ts +3 -0
- package/dist/tools/notifications.js +28 -0
- package/dist/tools/pipelines.d.ts +3 -0
- package/dist/tools/pipelines.js +7 -0
- package/dist/tools/products.d.ts +3 -0
- package/dist/tools/products.js +55 -0
- package/dist/tools/scoring.d.ts +3 -0
- package/dist/tools/scoring.js +48 -0
- package/dist/tools/sequences.d.ts +3 -0
- package/dist/tools/sequences.js +53 -0
- package/dist/tools/smart-lists.d.ts +3 -0
- package/dist/tools/smart-lists.js +54 -0
- package/dist/tools/tags.d.ts +3 -0
- package/dist/tools/tags.js +44 -0
- package/dist/tools/tasks.d.ts +3 -0
- package/dist/tools/tasks.js +40 -0
- package/dist/tools/templates.d.ts +3 -0
- package/dist/tools/templates.js +55 -0
- package/dist/tools/users.d.ts +3 -0
- package/dist/tools/users.js +65 -0
- package/dist/tools/webhooks.d.ts +3 -0
- package/dist/tools/webhooks.js +41 -0
- package/dist/tools/workflow-sandbox.d.ts +3 -0
- package/dist/tools/workflow-sandbox.js +90 -0
- package/dist/types.d.ts +20 -0
- package/dist/types.js +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
export function registerInvoiceTools(server, client) {
|
|
4
|
+
server.tool("conduyt_list_invoices", "List invoices with filtering by status, contact, or date range.", {
|
|
5
|
+
status: z.string().optional().describe("Filter by status (e.g. 'draft', 'sent', 'paid', 'overdue', 'voided')"),
|
|
6
|
+
contact_id: z.string().optional().describe("Filter by contact UUID"),
|
|
7
|
+
date_from: z.string().optional().describe("Start of date range (ISO 8601)"),
|
|
8
|
+
date_to: z.string().optional().describe("End of date range (ISO 8601)"),
|
|
9
|
+
page: z.number().optional().describe("Page number (default 1)"),
|
|
10
|
+
per_page: z.number().optional().describe("Results per page"),
|
|
11
|
+
}, async ({ status, contact_id, date_from, date_to, page, per_page }) => {
|
|
12
|
+
const params = new URLSearchParams();
|
|
13
|
+
if (status)
|
|
14
|
+
params.set("status", status);
|
|
15
|
+
if (contact_id)
|
|
16
|
+
params.set("contact_id", contact_id);
|
|
17
|
+
if (date_from)
|
|
18
|
+
params.set("date_from", date_from);
|
|
19
|
+
if (date_to)
|
|
20
|
+
params.set("date_to", date_to);
|
|
21
|
+
if (page)
|
|
22
|
+
params.set("page", String(page));
|
|
23
|
+
if (per_page)
|
|
24
|
+
params.set("per_page", String(per_page));
|
|
25
|
+
const result = await client.get(`/api/v1/invoices?${params}`);
|
|
26
|
+
return formatResult(result);
|
|
27
|
+
});
|
|
28
|
+
server.tool("conduyt_get_invoice", "Get a single invoice with line items, payments, contact, and company details.", {
|
|
29
|
+
id: z.string().describe("Invoice UUID"),
|
|
30
|
+
}, async ({ id }) => {
|
|
31
|
+
const result = await client.get(`/api/v1/invoices/${id}`);
|
|
32
|
+
return formatResult(result);
|
|
33
|
+
});
|
|
34
|
+
server.tool("conduyt_create_invoice", "Create a new invoice with line items. Automatically calculates subtotal, tax, and total.", {
|
|
35
|
+
items: z.array(z.object({
|
|
36
|
+
description: z.string().describe("Line item description"),
|
|
37
|
+
unitPrice: z.number().describe("Price per unit"),
|
|
38
|
+
quantity: z.number().optional().describe("Quantity (default 1)"),
|
|
39
|
+
productId: z.string().optional().describe("Product UUID to link"),
|
|
40
|
+
})).describe("Line items (at least 1 required)"),
|
|
41
|
+
contactId: z.string().optional().describe("Bill-to contact UUID"),
|
|
42
|
+
companyId: z.string().optional().describe("Bill-to company UUID"),
|
|
43
|
+
dealId: z.string().optional().describe("Associated deal UUID"),
|
|
44
|
+
dueDate: z.string().optional().describe("Payment due date (ISO 8601)"),
|
|
45
|
+
taxRate: z.number().optional().describe("Tax rate as decimal (e.g. 0.10 for 10%)"),
|
|
46
|
+
currency: z.string().optional().describe("3-letter currency code (default: USD)"),
|
|
47
|
+
notes: z.string().optional().describe("Notes visible to client"),
|
|
48
|
+
terms: z.string().optional().describe("Payment terms"),
|
|
49
|
+
}, async (params) => {
|
|
50
|
+
const result = await client.post("/api/v1/invoices", params);
|
|
51
|
+
return formatResult(result);
|
|
52
|
+
});
|
|
53
|
+
server.tool("conduyt_update_invoice", "Update a draft invoice — change items, contact, due date, or terms. Cannot update paid or voided invoices.", {
|
|
54
|
+
id: z.string().describe("Invoice UUID"),
|
|
55
|
+
contactId: z.string().optional().describe("Updated bill-to contact"),
|
|
56
|
+
companyId: z.string().optional().describe("Updated bill-to company"),
|
|
57
|
+
dueDate: z.string().optional().describe("Updated due date"),
|
|
58
|
+
notes: z.string().optional().describe("Updated notes"),
|
|
59
|
+
terms: z.string().optional().describe("Updated terms"),
|
|
60
|
+
taxRate: z.number().optional().describe("Updated tax rate"),
|
|
61
|
+
items: z.array(z.object({
|
|
62
|
+
description: z.string().describe("Line item description"),
|
|
63
|
+
unitPrice: z.number().describe("Price per unit"),
|
|
64
|
+
quantity: z.number().optional().describe("Quantity"),
|
|
65
|
+
})).optional().describe("Replacement line items (replaces all existing items)"),
|
|
66
|
+
}, async ({ id, ...updates }) => {
|
|
67
|
+
const result = await client.patch(`/api/v1/invoices/${id}`, updates);
|
|
68
|
+
return formatResult(result);
|
|
69
|
+
});
|
|
70
|
+
server.tool("conduyt_send_invoice", "Send an invoice to the contact via email. Generates PDF, creates Stripe payment link, and sends via email.", {
|
|
71
|
+
id: z.string().describe("Invoice UUID — must be draft, pending, sent, or overdue"),
|
|
72
|
+
}, async ({ id }) => {
|
|
73
|
+
const result = await client.post(`/api/v1/invoices/${id}/send`, {});
|
|
74
|
+
return formatResult(result);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
export function registerMessagingTools(server, client) {
|
|
4
|
+
server.tool("conduyt_send_sms", "Send an SMS message to a contact. Contact must have a phone number and not have opted out. Max 1600 characters.", {
|
|
5
|
+
contactId: z.string().describe("Contact UUID — must have a phone number on file"),
|
|
6
|
+
body: z.string().describe("SMS message body (max 1600 characters)"),
|
|
7
|
+
fromNumber: z.string().optional().describe("Sender phone number (defaults to account's primary number)"),
|
|
8
|
+
}, async (params) => {
|
|
9
|
+
const result = await client.post("/api/v1/messages/sms/send", params);
|
|
10
|
+
return formatResult(result);
|
|
11
|
+
});
|
|
12
|
+
server.tool("conduyt_send_email", "Send a single email to a contact. Requires either HTML or plain text body. Subject line max 998 characters.", {
|
|
13
|
+
to: z.string().describe("Recipient email address"),
|
|
14
|
+
subject: z.string().describe("Email subject line (max 998 chars)"),
|
|
15
|
+
html: z.string().optional().describe("HTML email body (sanitized server-side)"),
|
|
16
|
+
text: z.string().optional().describe("Plain text email body"),
|
|
17
|
+
contactId: z.string().describe("Contact UUID — must exist in the account"),
|
|
18
|
+
replyTo: z.string().optional().describe("Reply-to email address"),
|
|
19
|
+
cc: z.array(z.string()).optional().describe("CC email addresses"),
|
|
20
|
+
bcc: z.array(z.string()).optional().describe("BCC email addresses"),
|
|
21
|
+
}, async (params) => {
|
|
22
|
+
const result = await client.post("/api/v1/email/send", params);
|
|
23
|
+
return formatResult(result);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
export function registerNotificationTools(server, client) {
|
|
4
|
+
server.tool("conduyt_list_notifications", "List notifications for the current user (determined by API key's associated user).", {
|
|
5
|
+
page: z.number().optional().describe("Page number (default 1)"),
|
|
6
|
+
per_page: z.number().optional().describe("Results per page"),
|
|
7
|
+
}, async ({ page, per_page }) => {
|
|
8
|
+
const params = new URLSearchParams();
|
|
9
|
+
if (page)
|
|
10
|
+
params.set("page", String(page));
|
|
11
|
+
if (per_page)
|
|
12
|
+
params.set("per_page", String(per_page));
|
|
13
|
+
const result = await client.get(`/api/v1/notifications?${params}`);
|
|
14
|
+
return formatResult(result);
|
|
15
|
+
});
|
|
16
|
+
server.tool("conduyt_create_notification", "Send an in-app notification to a team member. Optionally triggers a web push notification.", {
|
|
17
|
+
type: z.string().describe("Notification type (e.g. 'task_assigned', 'deal_won', 'mention')"),
|
|
18
|
+
title: z.string().describe("Notification title (max 200 chars)"),
|
|
19
|
+
message: z.string().describe("Notification body (max 1000 chars)"),
|
|
20
|
+
userId: z.string().optional().describe("Target user UUID (defaults to API key owner)"),
|
|
21
|
+
url: z.string().optional().describe("Deep link URL when notification is clicked"),
|
|
22
|
+
metadata: z.any().optional().describe("Additional data attached to the notification"),
|
|
23
|
+
push: z.boolean().optional().describe("Send web push notification (default true)"),
|
|
24
|
+
}, async (params) => {
|
|
25
|
+
const result = await client.post("/api/v1/notifications", params);
|
|
26
|
+
return formatResult(result);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { formatResult } from "../client.js";
|
|
2
|
+
export function registerPipelineTools(server, client) {
|
|
3
|
+
server.tool("conduyt_list_pipelines", "List all sales pipelines with their stages. Use this to discover pipeline and stage UUIDs before creating or moving deals.", {}, async () => {
|
|
4
|
+
const result = await client.get("/api/v1/pipelines");
|
|
5
|
+
return formatResult(result);
|
|
6
|
+
});
|
|
7
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
export function registerProductTools(server, client) {
|
|
4
|
+
server.tool("conduyt_list_products", "List products in the catalog. Filter by active status or search by name.", {
|
|
5
|
+
search: z.string().optional().describe("Search by product name"),
|
|
6
|
+
is_active: z.boolean().optional().describe("Filter by active/inactive"),
|
|
7
|
+
page: z.number().optional().describe("Page number (default 1)"),
|
|
8
|
+
per_page: z.number().optional().describe("Results per page (default 50, max 200)"),
|
|
9
|
+
}, async ({ search, is_active, page, per_page }) => {
|
|
10
|
+
const params = new URLSearchParams();
|
|
11
|
+
if (search)
|
|
12
|
+
params.set("search", search);
|
|
13
|
+
if (is_active !== undefined)
|
|
14
|
+
params.set("is_active", String(is_active));
|
|
15
|
+
if (page)
|
|
16
|
+
params.set("page", String(page));
|
|
17
|
+
if (per_page)
|
|
18
|
+
params.set("per_page", String(per_page));
|
|
19
|
+
const result = await client.get(`/api/v1/products?${params}`);
|
|
20
|
+
return formatResult(result);
|
|
21
|
+
});
|
|
22
|
+
server.tool("conduyt_get_product", "Get a single product with full details — pricing, SKU, and metadata.", {
|
|
23
|
+
id: z.string().describe("Product UUID"),
|
|
24
|
+
}, async ({ id }) => {
|
|
25
|
+
const result = await client.get(`/api/v1/products/${id}`);
|
|
26
|
+
return formatResult(result);
|
|
27
|
+
});
|
|
28
|
+
server.tool("conduyt_create_product", "Create a new product in the catalog.", {
|
|
29
|
+
name: z.string().describe("Product name"),
|
|
30
|
+
description: z.string().optional().describe("Product description"),
|
|
31
|
+
sku: z.string().optional().describe("SKU (must be unique)"),
|
|
32
|
+
price: z.number().optional().describe("Price (default 0)"),
|
|
33
|
+
currency: z.string().optional().describe("3-letter currency code (default: USD)"),
|
|
34
|
+
unit: z.string().optional().describe("Unit of measure (default: 'unit')"),
|
|
35
|
+
taxable: z.boolean().optional().describe("Whether product is taxable (default true)"),
|
|
36
|
+
isActive: z.boolean().optional().describe("Whether product is active (default true)"),
|
|
37
|
+
metadata: z.any().optional().describe("Additional metadata object"),
|
|
38
|
+
}, async (params) => {
|
|
39
|
+
const result = await client.post("/api/v1/products", params);
|
|
40
|
+
return formatResult(result);
|
|
41
|
+
});
|
|
42
|
+
server.tool("conduyt_update_product", "Update a product's name, price, description, or other details.", {
|
|
43
|
+
id: z.string().describe("Product UUID"),
|
|
44
|
+
name: z.string().optional().describe("Updated name"),
|
|
45
|
+
description: z.string().optional().describe("Updated description"),
|
|
46
|
+
sku: z.string().optional().describe("Updated SKU"),
|
|
47
|
+
price: z.number().optional().describe("Updated price"),
|
|
48
|
+
currency: z.string().optional().describe("Updated currency"),
|
|
49
|
+
taxable: z.boolean().optional().describe("Updated taxable status"),
|
|
50
|
+
isActive: z.boolean().optional().describe("Updated active status"),
|
|
51
|
+
}, async ({ id, ...updates }) => {
|
|
52
|
+
const result = await client.patch(`/api/v1/products/${id}`, updates);
|
|
53
|
+
return formatResult(result);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
export function registerScoringTools(server, client) {
|
|
4
|
+
server.tool("conduyt_list_scoring_rules", "List lead scoring rules. Each rule awards points when a condition matches a contact.", {
|
|
5
|
+
is_active: z.boolean().optional().describe("Filter by active/inactive"),
|
|
6
|
+
page: z.number().optional().describe("Page number (default 1)"),
|
|
7
|
+
per_page: z.number().optional().describe("Results per page (default 100, max 200)"),
|
|
8
|
+
}, async ({ is_active, page, per_page }) => {
|
|
9
|
+
const params = new URLSearchParams();
|
|
10
|
+
if (is_active !== undefined)
|
|
11
|
+
params.set("is_active", String(is_active));
|
|
12
|
+
if (page)
|
|
13
|
+
params.set("page", String(page));
|
|
14
|
+
if (per_page)
|
|
15
|
+
params.set("per_page", String(per_page));
|
|
16
|
+
const result = await client.get(`/api/v1/scoring-rules?${params}`);
|
|
17
|
+
return formatResult(result);
|
|
18
|
+
});
|
|
19
|
+
server.tool("conduyt_create_scoring_rule", "Create a lead scoring rule. Awards points to contacts matching a condition.", {
|
|
20
|
+
name: z.string().describe("Rule name (e.g. 'Opened email')"),
|
|
21
|
+
points: z.number().describe("Points to award (positive or negative)"),
|
|
22
|
+
condition: z.any().describe("Condition object that determines which contacts match"),
|
|
23
|
+
isActive: z.boolean().optional().describe("Whether the rule is active (default true)"),
|
|
24
|
+
}, async (params) => {
|
|
25
|
+
const result = await client.post("/api/v1/scoring-rules", params);
|
|
26
|
+
return formatResult(result);
|
|
27
|
+
});
|
|
28
|
+
server.tool("conduyt_update_scoring_rule", "Update a scoring rule's name, points, condition, or active status.", {
|
|
29
|
+
id: z.string().describe("Scoring rule UUID"),
|
|
30
|
+
name: z.string().optional().describe("Updated name"),
|
|
31
|
+
points: z.number().optional().describe("Updated points"),
|
|
32
|
+
condition: z.any().optional().describe("Updated condition"),
|
|
33
|
+
isActive: z.boolean().optional().describe("Enable or disable"),
|
|
34
|
+
}, async ({ id, ...updates }) => {
|
|
35
|
+
const result = await client.patch(`/api/v1/scoring-rules/${id}`, updates);
|
|
36
|
+
return formatResult(result);
|
|
37
|
+
});
|
|
38
|
+
server.tool("conduyt_delete_scoring_rule", "Delete a lead scoring rule.", {
|
|
39
|
+
id: z.string().describe("Scoring rule UUID"),
|
|
40
|
+
}, async ({ id }) => {
|
|
41
|
+
const result = await client.del(`/api/v1/scoring-rules/${id}`);
|
|
42
|
+
return formatResult(result);
|
|
43
|
+
});
|
|
44
|
+
server.tool("conduyt_recalculate_scores", "Recalculate lead scores for all contacts based on current scoring rules. Returns count of contacts processed and changed.", {}, async () => {
|
|
45
|
+
const result = await client.post("/api/v1/scoring-rules/recalculate", {});
|
|
46
|
+
return formatResult(result);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
export function registerSequenceTools(server, client) {
|
|
4
|
+
server.tool("conduyt_list_sequences", "List email sequences (drip campaigns). Returns name, step count, enrollment stats, and active status.", {
|
|
5
|
+
is_active: z.boolean().optional().describe("Filter by active/inactive status"),
|
|
6
|
+
page: z.number().optional().describe("Page number (default 1)"),
|
|
7
|
+
per_page: z.number().optional().describe("Results per page (default 50, max 200)"),
|
|
8
|
+
}, async ({ is_active, page, per_page }) => {
|
|
9
|
+
const params = new URLSearchParams();
|
|
10
|
+
if (is_active !== undefined)
|
|
11
|
+
params.set("is_active", String(is_active));
|
|
12
|
+
if (page)
|
|
13
|
+
params.set("page", String(page));
|
|
14
|
+
if (per_page)
|
|
15
|
+
params.set("per_page", String(per_page));
|
|
16
|
+
const result = await client.get(`/api/v1/emails/sequences?${params}`);
|
|
17
|
+
return formatResult(result);
|
|
18
|
+
});
|
|
19
|
+
server.tool("conduyt_get_sequence", "Get a single email sequence with full details — steps, enrollment stats, and configuration.", {
|
|
20
|
+
id: z.string().describe("Sequence UUID"),
|
|
21
|
+
}, async ({ id }) => {
|
|
22
|
+
const result = await client.get(`/api/v1/emails/sequences/${id}`);
|
|
23
|
+
return formatResult(result);
|
|
24
|
+
});
|
|
25
|
+
server.tool("conduyt_create_sequence", "Create a new email sequence with steps. Each step has a delay and email content.", {
|
|
26
|
+
name: z.string().describe("Sequence name"),
|
|
27
|
+
description: z.string().optional().describe("Sequence description"),
|
|
28
|
+
isActive: z.boolean().optional().describe("Whether the sequence is active (default true)"),
|
|
29
|
+
steps: z.array(z.object({
|
|
30
|
+
delay: z.number().optional().describe("Delay in seconds before sending this step"),
|
|
31
|
+
body: z.string().optional().describe("Plain text email body"),
|
|
32
|
+
bodyHtml: z.string().optional().describe("HTML email body"),
|
|
33
|
+
templateId: z.string().optional().describe("Email template UUID to use instead of inline body"),
|
|
34
|
+
})).optional().describe("Sequence steps in order"),
|
|
35
|
+
}, async (params) => {
|
|
36
|
+
const result = await client.post("/api/v1/emails/sequences", params);
|
|
37
|
+
return formatResult(result);
|
|
38
|
+
});
|
|
39
|
+
server.tool("conduyt_enroll_in_sequence", "Enroll one or more contacts into an email sequence. Skips contacts already enrolled.", {
|
|
40
|
+
sequenceId: z.string().describe("Sequence UUID"),
|
|
41
|
+
contactIds: z.array(z.string()).describe("Array of contact UUIDs to enroll"),
|
|
42
|
+
}, async ({ sequenceId, contactIds }) => {
|
|
43
|
+
const result = await client.post(`/api/v1/emails/sequences/${sequenceId}/enroll`, { contactIds });
|
|
44
|
+
return formatResult(result);
|
|
45
|
+
});
|
|
46
|
+
server.tool("conduyt_unenroll_from_sequence", "Remove a contact from an email sequence. Pauses their enrollment.", {
|
|
47
|
+
sequenceId: z.string().describe("Sequence UUID"),
|
|
48
|
+
contactId: z.string().describe("Contact UUID to unenroll"),
|
|
49
|
+
}, async ({ sequenceId, contactId }) => {
|
|
50
|
+
const result = await client.post(`/api/v1/emails/sequences/${sequenceId}/unenroll`, { contactId });
|
|
51
|
+
return formatResult(result);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
export function registerSmartListTools(server, client) {
|
|
4
|
+
server.tool("conduyt_list_smart_lists", "List all smart lists (segments) with contact counts.", {}, async () => {
|
|
5
|
+
const result = await client.get("/api/v1/smart-lists");
|
|
6
|
+
return formatResult(result);
|
|
7
|
+
});
|
|
8
|
+
server.tool("conduyt_get_smart_list", "Get a single smart list with contact count and filter definitions.", {
|
|
9
|
+
id: z.string().describe("Smart list UUID"),
|
|
10
|
+
}, async ({ id }) => {
|
|
11
|
+
const result = await client.get(`/api/v1/smart-lists/${id}`);
|
|
12
|
+
return formatResult(result);
|
|
13
|
+
});
|
|
14
|
+
server.tool("conduyt_create_smart_list", "Create a new smart list (segment). Static lists have manually added contacts; dynamic lists use filter rules.", {
|
|
15
|
+
name: z.string().describe("Smart list name"),
|
|
16
|
+
description: z.string().optional().describe("Description"),
|
|
17
|
+
type: z.enum(["static", "dynamic"]).optional().describe("List type — 'static' (manual) or 'dynamic' (filter-based). Default: static"),
|
|
18
|
+
filters: z.any().optional().describe("Filter rules for dynamic lists (array of filter objects)"),
|
|
19
|
+
}, async (params) => {
|
|
20
|
+
const result = await client.post("/api/v1/smart-lists", params);
|
|
21
|
+
return formatResult(result);
|
|
22
|
+
});
|
|
23
|
+
server.tool("conduyt_update_smart_list", "Update a smart list's name, description, type, or filters.", {
|
|
24
|
+
id: z.string().describe("Smart list UUID"),
|
|
25
|
+
name: z.string().optional().describe("Updated name"),
|
|
26
|
+
description: z.string().optional().describe("Updated description"),
|
|
27
|
+
type: z.enum(["static", "dynamic"]).optional().describe("Updated type"),
|
|
28
|
+
filters: z.any().optional().describe("Updated filter rules"),
|
|
29
|
+
isActive: z.boolean().optional().describe("Enable or disable"),
|
|
30
|
+
}, async ({ id, ...updates }) => {
|
|
31
|
+
const result = await client.patch(`/api/v1/smart-lists/${id}`, updates);
|
|
32
|
+
return formatResult(result);
|
|
33
|
+
});
|
|
34
|
+
server.tool("conduyt_add_contacts_to_smart_list", "Add contacts to a static smart list. Max 500 contacts per request.", {
|
|
35
|
+
smartListId: z.string().describe("Smart list UUID"),
|
|
36
|
+
contactIds: z.array(z.string()).describe("Contact UUIDs to add (max 500)"),
|
|
37
|
+
}, async ({ smartListId, contactIds }) => {
|
|
38
|
+
const result = await client.post(`/api/v1/smart-lists/${smartListId}/contacts`, { contactIds });
|
|
39
|
+
return formatResult(result);
|
|
40
|
+
});
|
|
41
|
+
server.tool("conduyt_get_smart_list_contacts", "Get contacts in a smart list. For static lists, returns the members; for dynamic lists, runs the filter query.", {
|
|
42
|
+
smartListId: z.string().describe("Smart list UUID"),
|
|
43
|
+
page: z.number().optional().describe("Page number"),
|
|
44
|
+
per_page: z.number().optional().describe("Results per page"),
|
|
45
|
+
}, async ({ smartListId, page, per_page }) => {
|
|
46
|
+
const params = new URLSearchParams();
|
|
47
|
+
if (page)
|
|
48
|
+
params.set("page", String(page));
|
|
49
|
+
if (per_page)
|
|
50
|
+
params.set("per_page", String(per_page));
|
|
51
|
+
const result = await client.get(`/api/v1/smart-lists/${smartListId}/contacts?${params}`);
|
|
52
|
+
return formatResult(result);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
export function registerTagTools(server, client) {
|
|
4
|
+
server.tool("conduyt_list_tags", "List all tags in the account with contact counts. Use this to discover tag names and IDs.", {
|
|
5
|
+
page: z.number().optional().describe("Page number (default 1)"),
|
|
6
|
+
per_page: z.number().optional().describe("Results per page (default 25, max 200)"),
|
|
7
|
+
}, async ({ page, per_page }) => {
|
|
8
|
+
const params = new URLSearchParams();
|
|
9
|
+
if (page)
|
|
10
|
+
params.set("page", String(page));
|
|
11
|
+
if (per_page)
|
|
12
|
+
params.set("per_page", String(per_page));
|
|
13
|
+
const result = await client.get(`/api/v1/tags?${params}`);
|
|
14
|
+
return formatResult(result);
|
|
15
|
+
});
|
|
16
|
+
server.tool("conduyt_create_tag", "Create a new tag. Rejects duplicates.", {
|
|
17
|
+
name: z.string().describe("Tag name (must be unique)"),
|
|
18
|
+
color: z.string().optional().describe("Hex color code (default: #6B7280)"),
|
|
19
|
+
}, async (params) => {
|
|
20
|
+
const result = await client.post("/api/v1/tags", params);
|
|
21
|
+
return formatResult(result);
|
|
22
|
+
});
|
|
23
|
+
server.tool("conduyt_update_tag", "Rename a tag or change its color.", {
|
|
24
|
+
id: z.string().describe("Tag UUID"),
|
|
25
|
+
name: z.string().optional().describe("New tag name"),
|
|
26
|
+
color: z.string().optional().describe("New hex color code"),
|
|
27
|
+
}, async ({ id, ...updates }) => {
|
|
28
|
+
const result = await client.patch(`/api/v1/tags/${id}`, updates);
|
|
29
|
+
return formatResult(result);
|
|
30
|
+
});
|
|
31
|
+
server.tool("conduyt_delete_tag", "Delete a tag. Removes the tag from all contacts.", {
|
|
32
|
+
id: z.string().describe("Tag UUID"),
|
|
33
|
+
}, async ({ id }) => {
|
|
34
|
+
const result = await client.del(`/api/v1/tags/${id}`);
|
|
35
|
+
return formatResult(result);
|
|
36
|
+
});
|
|
37
|
+
server.tool("conduyt_merge_tags", "Merge two tags — moves all contacts from source tag to target tag, then deletes the source. Useful for deduplicating tags.", {
|
|
38
|
+
sourceTagId: z.string().describe("Tag UUID to merge FROM (will be deleted)"),
|
|
39
|
+
targetTagId: z.string().describe("Tag UUID to merge INTO (will be kept)"),
|
|
40
|
+
}, async (params) => {
|
|
41
|
+
const result = await client.post("/api/v1/tags/merge", params);
|
|
42
|
+
return formatResult(result);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
export function registerTaskTools(server, client) {
|
|
4
|
+
server.tool("conduyt_list_tasks", "List tasks with filtering by assignee, status, or due date. Returns task title, description, due date, priority, and assignee.", {
|
|
5
|
+
assignedTo: z.string().optional().describe("Filter by assigned user UUID"),
|
|
6
|
+
status: z.enum(["pending", "in_progress", "completed", "cancelled"]).optional().describe("Filter by task status"),
|
|
7
|
+
dueDate: z.string().optional().describe("Filter by due date (ISO 8601 format, e.g. '2026-04-30')"),
|
|
8
|
+
contactId: z.string().optional().describe("Filter tasks linked to a specific contact"),
|
|
9
|
+
page: z.number().optional().describe("Page number (default 1)"),
|
|
10
|
+
per_page: z.number().optional().describe("Results per page (default 25, max 100)"),
|
|
11
|
+
}, async ({ assignedTo, status, dueDate, contactId, page, per_page }) => {
|
|
12
|
+
const params = new URLSearchParams();
|
|
13
|
+
if (assignedTo)
|
|
14
|
+
params.set("assignedTo", assignedTo);
|
|
15
|
+
if (status)
|
|
16
|
+
params.set("status", status);
|
|
17
|
+
if (dueDate)
|
|
18
|
+
params.set("dueDate", dueDate);
|
|
19
|
+
if (contactId)
|
|
20
|
+
params.set("contactId", contactId);
|
|
21
|
+
if (page)
|
|
22
|
+
params.set("page", String(page));
|
|
23
|
+
if (per_page)
|
|
24
|
+
params.set("per_page", String(per_page));
|
|
25
|
+
const result = await client.get(`/api/v1/tasks?${params}`);
|
|
26
|
+
return formatResult(result);
|
|
27
|
+
});
|
|
28
|
+
server.tool("conduyt_create_task", "Create a new task. Can be linked to a contact or deal and assigned to a team member.", {
|
|
29
|
+
title: z.string().describe("Task title"),
|
|
30
|
+
description: z.string().optional().describe("Task description"),
|
|
31
|
+
dueDate: z.string().optional().describe("Due date (ISO 8601)"),
|
|
32
|
+
priority: z.enum(["low", "medium", "high", "urgent"]).optional().describe("Task priority"),
|
|
33
|
+
assignedTo: z.string().optional().describe("Assign to user UUID"),
|
|
34
|
+
contactId: z.string().optional().describe("Link to a contact UUID"),
|
|
35
|
+
dealId: z.string().optional().describe("Link to a deal UUID"),
|
|
36
|
+
}, async (params) => {
|
|
37
|
+
const result = await client.post("/api/v1/tasks", params);
|
|
38
|
+
return formatResult(result);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
export function registerTemplateTools(server, client) {
|
|
4
|
+
server.tool("conduyt_list_templates", "List email and SMS templates. Filter by channel (sms/email), category, or active status.", {
|
|
5
|
+
channel: z.enum(["sms", "email"]).optional().describe("Filter by channel — 'sms' or 'email'"),
|
|
6
|
+
category: z.string().optional().describe("Filter by category"),
|
|
7
|
+
is_active: z.boolean().optional().describe("Filter by active/inactive"),
|
|
8
|
+
page: z.number().optional().describe("Page number (default 1)"),
|
|
9
|
+
per_page: z.number().optional().describe("Results per page (default 50, max 200)"),
|
|
10
|
+
}, async ({ channel, category, is_active, page, per_page }) => {
|
|
11
|
+
const params = new URLSearchParams();
|
|
12
|
+
if (channel)
|
|
13
|
+
params.set("channel", channel);
|
|
14
|
+
if (category)
|
|
15
|
+
params.set("category", category);
|
|
16
|
+
if (is_active !== undefined)
|
|
17
|
+
params.set("is_active", String(is_active));
|
|
18
|
+
if (page)
|
|
19
|
+
params.set("page", String(page));
|
|
20
|
+
if (per_page)
|
|
21
|
+
params.set("per_page", String(per_page));
|
|
22
|
+
const result = await client.get(`/api/v1/emails/templates?${params}`);
|
|
23
|
+
return formatResult(result);
|
|
24
|
+
});
|
|
25
|
+
server.tool("conduyt_get_template", "Get a single email or SMS template with full content.", {
|
|
26
|
+
id: z.string().describe("Template UUID"),
|
|
27
|
+
}, async ({ id }) => {
|
|
28
|
+
const result = await client.get(`/api/v1/emails/templates/${id}`);
|
|
29
|
+
return formatResult(result);
|
|
30
|
+
});
|
|
31
|
+
server.tool("conduyt_create_template", "Create a new email or SMS template.", {
|
|
32
|
+
name: z.string().describe("Template name"),
|
|
33
|
+
channel: z.enum(["sms", "email"]).describe("Channel — 'sms' or 'email'"),
|
|
34
|
+
subject: z.string().optional().describe("Email subject line (for email channel)"),
|
|
35
|
+
body: z.string().describe("Template body (plain text for SMS, text/HTML for email)"),
|
|
36
|
+
bodyHtml: z.string().optional().describe("HTML body (for email channel, sanitized server-side)"),
|
|
37
|
+
category: z.string().optional().describe("Category for organization"),
|
|
38
|
+
isActive: z.boolean().optional().describe("Whether template is active (default true)"),
|
|
39
|
+
}, async (params) => {
|
|
40
|
+
const result = await client.post("/api/v1/emails/templates", params);
|
|
41
|
+
return formatResult(result);
|
|
42
|
+
});
|
|
43
|
+
server.tool("conduyt_update_template", "Update a template's content, subject, or category.", {
|
|
44
|
+
id: z.string().describe("Template UUID"),
|
|
45
|
+
name: z.string().optional().describe("Updated name"),
|
|
46
|
+
subject: z.string().optional().describe("Updated subject"),
|
|
47
|
+
body: z.string().optional().describe("Updated body"),
|
|
48
|
+
bodyHtml: z.string().optional().describe("Updated HTML body"),
|
|
49
|
+
category: z.string().optional().describe("Updated category"),
|
|
50
|
+
isActive: z.boolean().optional().describe("Updated active status"),
|
|
51
|
+
}, async ({ id, ...updates }) => {
|
|
52
|
+
const result = await client.patch(`/api/v1/emails/templates/${id}`, updates);
|
|
53
|
+
return formatResult(result);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
export function registerUserTools(server, client) {
|
|
4
|
+
server.tool("conduyt_list_users", "List team members with optional performance stats. Returns name, email, role, status, and last login.", {
|
|
5
|
+
include_stats: z.boolean().optional().describe("Include contactsAssigned and tasksAssigned counts"),
|
|
6
|
+
page: z.number().optional().describe("Page number (default 1)"),
|
|
7
|
+
per_page: z.number().optional().describe("Results per page"),
|
|
8
|
+
}, async ({ include_stats, page, per_page }) => {
|
|
9
|
+
const params = new URLSearchParams();
|
|
10
|
+
if (include_stats)
|
|
11
|
+
params.set("include_stats", "true");
|
|
12
|
+
if (page)
|
|
13
|
+
params.set("page", String(page));
|
|
14
|
+
if (per_page)
|
|
15
|
+
params.set("per_page", String(per_page));
|
|
16
|
+
const result = await client.get(`/api/v1/users?${params}`);
|
|
17
|
+
return formatResult(result);
|
|
18
|
+
});
|
|
19
|
+
server.tool("conduyt_get_user", "Get a single team member with full profile — name, email, phone, role, permissions, and activity.", {
|
|
20
|
+
id: z.string().describe("User UUID"),
|
|
21
|
+
}, async ({ id }) => {
|
|
22
|
+
const result = await client.get(`/api/v1/users/${id}`);
|
|
23
|
+
return formatResult(result);
|
|
24
|
+
});
|
|
25
|
+
server.tool("conduyt_create_user", "Create a new team member directly (no invite email). Generates a random password. Use conduyt_invite_user for email-based onboarding.", {
|
|
26
|
+
email: z.string().describe("User email address"),
|
|
27
|
+
firstName: z.string().optional().describe("First name"),
|
|
28
|
+
lastName: z.string().optional().describe("Last name"),
|
|
29
|
+
phone: z.string().optional().describe("Phone number"),
|
|
30
|
+
role: z.enum(["member", "admin"]).optional().describe("Role (default: member). Only owners can create owner-role users."),
|
|
31
|
+
permissions: z.array(z.string()).optional().describe("Permission scopes (e.g. ['contacts', 'deals', 'tasks'])"),
|
|
32
|
+
}, async (params) => {
|
|
33
|
+
const result = await client.post("/api/v1/users", params);
|
|
34
|
+
return formatResult(result);
|
|
35
|
+
});
|
|
36
|
+
server.tool("conduyt_update_user", "Update a team member's profile, role, or permissions. Cannot modify your own role.", {
|
|
37
|
+
id: z.string().describe("User UUID"),
|
|
38
|
+
firstName: z.string().optional().describe("Updated first name"),
|
|
39
|
+
lastName: z.string().optional().describe("Updated last name"),
|
|
40
|
+
email: z.string().optional().describe("Updated email (must be unique)"),
|
|
41
|
+
phone: z.string().optional().describe("Updated phone"),
|
|
42
|
+
role: z.enum(["member", "admin", "owner"]).optional().describe("Updated role"),
|
|
43
|
+
permissions: z.array(z.string()).optional().describe("Updated permission scopes"),
|
|
44
|
+
isActive: z.boolean().optional().describe("Activate or deactivate the user"),
|
|
45
|
+
}, async ({ id, ...updates }) => {
|
|
46
|
+
const result = await client.patch(`/api/v1/users/${id}`, updates);
|
|
47
|
+
return formatResult(result);
|
|
48
|
+
});
|
|
49
|
+
server.tool("conduyt_get_user_stats", "Get a team member's performance stats — contacts assigned, deals (total/won/value), tasks (total/completed/pending), and last activity.", {
|
|
50
|
+
id: z.string().describe("User UUID"),
|
|
51
|
+
}, async ({ id }) => {
|
|
52
|
+
const result = await client.get(`/api/v1/users/${id}/stats`);
|
|
53
|
+
return formatResult(result);
|
|
54
|
+
});
|
|
55
|
+
server.tool("conduyt_invite_user", "Invite a new team member via email. Sends an invite email with a link to set their password.", {
|
|
56
|
+
email: z.string().describe("Email address to invite"),
|
|
57
|
+
role: z.enum(["member", "admin"]).optional().describe("Role (default: member)"),
|
|
58
|
+
firstName: z.string().optional().describe("Pre-populate first name"),
|
|
59
|
+
lastName: z.string().optional().describe("Pre-populate last name"),
|
|
60
|
+
phone: z.string().optional().describe("Pre-populate phone number"),
|
|
61
|
+
}, async (params) => {
|
|
62
|
+
const result = await client.post("/api/v1/users/invite", params);
|
|
63
|
+
return formatResult(result);
|
|
64
|
+
});
|
|
65
|
+
}
|