conduyt-mcp 4.48.0 → 4.50.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 +3 -1
- package/dist/index.js +2 -0
- package/dist/tools/messaging.js +12 -2
- package/dist/tools/whatsapp.d.ts +8 -0
- package/dist/tools/whatsapp.js +30 -0
- package/package.json +1 -1
- package/scripts/coverage-matrix.json +45 -5
package/README.md
CHANGED
|
@@ -86,7 +86,9 @@ MCP server for [Conduyt CRM](https://conduyt.app) — expose your CRM as AI-acce
|
|
|
86
86
|
### Messaging
|
|
87
87
|
| Tool | Description |
|
|
88
88
|
|------|-------------|
|
|
89
|
-
| `
|
|
89
|
+
| `conduyt_sms_transports` | What a workflow Send SMS step can speak through today: Twilio numbers, Project Blue lines held by active reps, the WhatsApp sender, webhook provider count, FromK.ai coming soon |
|
|
90
|
+
| `conduyt_whatsapp_templates` | The account's WhatsApp templates (Twilio Content) with Meta's approval verdict: sid, text with {{n}} placeholders, variables, approval |
|
|
91
|
+
| `conduyt_send_sms` | Send SMS to a contact (max 1600 chars); transport twilio, project_blue, or whatsapp (an approved template by Content SID, or free-form within the 24-hour window) |
|
|
90
92
|
| `conduyt_send_email` | Send a single email to a contact |
|
|
91
93
|
|
|
92
94
|
### Companies
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,7 @@ import { registerLifecycleTools } from "./tools/lifecycle.js";
|
|
|
41
41
|
import { registerReplyCaptureTools } from "./tools/reply-capture.js";
|
|
42
42
|
import { registerCallFlowTools } from "./tools/call-flows.js";
|
|
43
43
|
import { registerProjectBlueTools } from "./tools/project-blue.js";
|
|
44
|
+
import { registerWhatsappTools } from "./tools/whatsapp.js";
|
|
44
45
|
import { registerReportTools } from "./tools/reports.js";
|
|
45
46
|
import { registerReportDashboardTools } from "./tools/dashboards.js";
|
|
46
47
|
const apiUrl = process.env.CONDUYT_API_URL;
|
|
@@ -106,6 +107,7 @@ registerLifecycleTools(server, client);
|
|
|
106
107
|
registerReplyCaptureTools(server, client);
|
|
107
108
|
registerCallFlowTools(server, client);
|
|
108
109
|
registerProjectBlueTools(server, client);
|
|
110
|
+
registerWhatsappTools(server, client);
|
|
109
111
|
registerReportTools(server, client);
|
|
110
112
|
registerReportDashboardTools(server, client);
|
|
111
113
|
const transport = new StdioServerTransport();
|
package/dist/tools/messaging.js
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { formatResult } from "../client.js";
|
|
3
3
|
export function registerMessagingTools(server, client) {
|
|
4
|
+
server.tool("conduyt_sms_transports", "What a workflow Send SMS step can speak through TODAY (GET /api/v1/sms/transports): twilio {connected, numbers[] = the account number + every active rep's assigned line, each a valid send_sms config.fromNumber}, projectBlue {connected, lines[] = Project Blue iPhone lines held by active reps, each lineId a valid config.projectBlueLineId for smsMode project_blue}, whatsapp {connected, sender = the account's WhatsApp sender for smsMode whatsapp; templates come from conduyt_whatsapp_templates}, webhook {providers = active webhook providers for smsMode webhook}, fromk {status: coming_soon}. Use it before building or editing a send_sms step so you never configure a transport that is not connected. Requires automations:view.", {}, async () => {
|
|
5
|
+
const result = await client.get("/api/v1/sms/transports");
|
|
6
|
+
return formatResult(result);
|
|
7
|
+
});
|
|
8
|
+
server.tool("conduyt_whatsapp_templates", "The account's WhatsApp templates (Twilio Content) with Meta's approval verdict (GET /api/v1/sms/whatsapp/templates): sid (a send_sms step's whatsappTemplateSid / conduyt_send_sms whatsappContentSid), friendlyName, language, body (the approved text with {{1}}, {{2}} placeholders), variables (the placeholder numbers to fill), approval (approved | pending | rejected | paused | disabled | unsubmitted | unknown), rejectionReason, category; plus `connected` (Twilio credentials AND a WhatsApp sender stored). Only an APPROVED template can be sent; outreach outside a contact's 24-hour window must use one. Reads Twilio live. Requires automations:view.", {}, async () => {
|
|
9
|
+
const result = await client.get("/api/v1/sms/whatsapp/templates");
|
|
10
|
+
return formatResult(result);
|
|
11
|
+
});
|
|
4
12
|
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
13
|
contactId: z.string().describe("Contact UUID — must have a phone number on file"),
|
|
6
|
-
body: z.string().describe("
|
|
14
|
+
body: z.string().max(1600).optional().describe("Message text (max 1600 characters). Required unless a WhatsApp template is sent (transport whatsapp + whatsappContentSid): then the template Twilio renders is the text, and a media-only template has none."),
|
|
7
15
|
fromNumber: z.string().optional().describe("Sender phone number (defaults to account's primary number)"),
|
|
8
|
-
transport: z.enum(["twilio", "project_blue"]).optional().describe("'project_blue' sends from the acting user's own Project Blue iPhone line (iMessage when the lead is on Apple, SMS otherwise; the user must have a line assigned in Settings → Project Blue). Default: Twilio."),
|
|
16
|
+
transport: z.enum(["twilio", "project_blue", "whatsapp"]).optional().describe("'project_blue' sends from the acting user's own Project Blue iPhone line (iMessage when the lead is on Apple, SMS otherwise; the user must have a line assigned in Settings → Project Blue). 'whatsapp' sends from the account's WhatsApp sender (Settings → WhatsApp): free-form text only within 24 hours of the contact's last WhatsApp message (422 whatsapp_window_closed otherwise), or an approved template via whatsappContentSid. Default: Twilio."),
|
|
17
|
+
whatsappContentSid: z.string().regex(/^HX[0-9a-fA-F]{32}$/).optional().describe("transport whatsapp: an APPROVED WhatsApp template (Twilio Content SID from conduyt_whatsapp_templates); Conduyt reads the template from Twilio at send time, records its text with the variables in place, and refuses an unlisted (whatsapp_template_invalid) or unapproved (whatsapp_template_not_approved) one. body is still required but the template's text is what is sent and recorded."),
|
|
18
|
+
whatsappContentVariables: z.record(z.string().regex(/^\d+$/), z.string().max(1024)).optional().describe("transport whatsapp with a template: placeholder number → value, e.g. { \"1\": \"Alex\" }"),
|
|
9
19
|
idempotencyKey: z.string().min(8).max(200).optional().describe("Operation key for at-most-once sends: reuse the SAME key when retrying a send whose outcome you did not see; a settled key answers with the original message and never sends twice."),
|
|
10
20
|
}, async (params) => {
|
|
11
21
|
const result = await client.post("/api/v1/messages/sms/send", params);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { ConduytClient } from "../client.js";
|
|
3
|
+
/**
|
|
4
|
+
* WhatsApp via Twilio (2026-09-11): the tenant's own Twilio account carries a Meta-approved WhatsApp sender. These
|
|
5
|
+
* tools cover what an AI operator needs: is WhatsApp connected and from which number, which senders Twilio lists
|
|
6
|
+
* for the account (only an ONLINE one can be connected), connect / disconnect. Templates: conduyt_whatsapp_templates.
|
|
7
|
+
*/
|
|
8
|
+
export declare function registerWhatsappTools(server: McpServer, client: ConduytClient): void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatResult } from "../client.js";
|
|
3
|
+
/**
|
|
4
|
+
* WhatsApp via Twilio (2026-09-11): the tenant's own Twilio account carries a Meta-approved WhatsApp sender. These
|
|
5
|
+
* tools cover what an AI operator needs: is WhatsApp connected and from which number, which senders Twilio lists
|
|
6
|
+
* for the account (only an ONLINE one can be connected), connect / disconnect. Templates: conduyt_whatsapp_templates.
|
|
7
|
+
*/
|
|
8
|
+
export function registerWhatsappTools(server, client) {
|
|
9
|
+
server.tool("conduyt_whatsapp_status", "WhatsApp connection for this account (GET /api/v1/settings/whatsapp): status connected | not_configured | twilio_required (a sender is stored but Twilio is disconnected), twilioConnected, and the sender {phoneNumber (plain E.164), sid}. WhatsApp rides the account's Twilio credentials; the workflow Send SMS step, conduyt_send_sms (transport whatsapp) and the contact composer can use it once connected. Requires settings:view.", {}, async () => {
|
|
10
|
+
const result = await client.get("/api/v1/settings/whatsapp");
|
|
11
|
+
return formatResult(result);
|
|
12
|
+
});
|
|
13
|
+
server.tool("conduyt_whatsapp_senders", "The WhatsApp senders Twilio lists under this account's credentials (GET /api/v1/settings/whatsapp/senders): sid (XE…), phoneNumber, status (only ONLINE can be connected), displayName, connected (the stored one). 422 twilio_required without Twilio credentials. Requires settings:view.", {}, async () => {
|
|
14
|
+
const result = await client.get("/api/v1/settings/whatsapp/senders");
|
|
15
|
+
return formatResult(result);
|
|
16
|
+
});
|
|
17
|
+
server.tool("conduyt_whatsapp_connect", "Connect the account's WhatsApp sender (PUT /api/v1/settings/whatsapp): pass the sender sid from conduyt_whatsapp_senders. Verified with Twilio before it is stored: it must be on this account and ONLINE (422 sender_not_found / sender_not_online), one sender belongs to one Conduyt account (409 sender_in_use), Twilio is required (422 twilio_required). Pass disconnect: true to forget the sender instead (DELETE): workflow steps on the WhatsApp channel stop sending. Requires settings:edit.", {
|
|
18
|
+
senderSid: z.string().regex(/^XE[0-9a-fA-F]{32}$/).optional().describe("Twilio WhatsApp sender SID (XE…) from conduyt_whatsapp_senders; required unless disconnect is true"),
|
|
19
|
+
disconnect: z.boolean().optional().describe("true = forget the stored sender (DELETE)"),
|
|
20
|
+
}, async ({ senderSid, disconnect }) => {
|
|
21
|
+
if (disconnect) {
|
|
22
|
+
const result = await client.del("/api/v1/settings/whatsapp");
|
|
23
|
+
return formatResult(result);
|
|
24
|
+
}
|
|
25
|
+
if (!senderSid)
|
|
26
|
+
throw new Error("senderSid is required unless disconnect is true");
|
|
27
|
+
const result = await client.put("/api/v1/settings/whatsapp", { senderSid });
|
|
28
|
+
return formatResult(result);
|
|
29
|
+
});
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-09-
|
|
3
|
-
"toolCount":
|
|
4
|
-
"totalEndpoints":
|
|
2
|
+
"generatedAt": "2026-09-11T21:39:51.508Z",
|
|
3
|
+
"toolCount": 255,
|
|
4
|
+
"totalEndpoints": 963,
|
|
5
5
|
"counts": {
|
|
6
|
-
"covered":
|
|
6
|
+
"covered": 238,
|
|
7
7
|
"excluded": 284,
|
|
8
|
-
"planned":
|
|
8
|
+
"planned": 441,
|
|
9
9
|
"uncategorized": 0
|
|
10
10
|
},
|
|
11
11
|
"matrix": {
|
|
@@ -2937,6 +2937,10 @@
|
|
|
2937
2937
|
"status": "planned",
|
|
2938
2938
|
"reason": "notification surfaces"
|
|
2939
2939
|
},
|
|
2940
|
+
"GET /api/v1/ops/capacity": {
|
|
2941
|
+
"status": "planned",
|
|
2942
|
+
"reason": "operator capacity dashboard (#51, shipped 2026-09) — read-only queue/park telemetry; a typed conduyt_capacity_snapshot tool is agent-relevant for throughput questions"
|
|
2943
|
+
},
|
|
2940
2944
|
"GET /api/v1/phone-numbers": {
|
|
2941
2945
|
"status": "planned",
|
|
2942
2946
|
"reason": "phone number inventory"
|
|
@@ -3733,6 +3737,30 @@
|
|
|
3733
3737
|
"status": "planned",
|
|
3734
3738
|
"reason": "account settings read/update surfaces"
|
|
3735
3739
|
},
|
|
3740
|
+
"GET /api/v1/settings/whatsapp": {
|
|
3741
|
+
"status": "covered",
|
|
3742
|
+
"tools": [
|
|
3743
|
+
"conduyt_whatsapp_status"
|
|
3744
|
+
]
|
|
3745
|
+
},
|
|
3746
|
+
"PUT /api/v1/settings/whatsapp": {
|
|
3747
|
+
"status": "covered",
|
|
3748
|
+
"tools": [
|
|
3749
|
+
"conduyt_whatsapp_connect"
|
|
3750
|
+
]
|
|
3751
|
+
},
|
|
3752
|
+
"DELETE /api/v1/settings/whatsapp": {
|
|
3753
|
+
"status": "covered",
|
|
3754
|
+
"tools": [
|
|
3755
|
+
"conduyt_whatsapp_connect"
|
|
3756
|
+
]
|
|
3757
|
+
},
|
|
3758
|
+
"GET /api/v1/settings/whatsapp/senders": {
|
|
3759
|
+
"status": "covered",
|
|
3760
|
+
"tools": [
|
|
3761
|
+
"conduyt_whatsapp_senders"
|
|
3762
|
+
]
|
|
3763
|
+
},
|
|
3736
3764
|
"GET /api/v1/smart-lists": {
|
|
3737
3765
|
"status": "covered",
|
|
3738
3766
|
"tools": [
|
|
@@ -3845,6 +3873,18 @@
|
|
|
3845
3873
|
"status": "planned",
|
|
3846
3874
|
"reason": "SMS surfaces beyond send tools"
|
|
3847
3875
|
},
|
|
3876
|
+
"GET /api/v1/sms/transports": {
|
|
3877
|
+
"status": "covered",
|
|
3878
|
+
"tools": [
|
|
3879
|
+
"conduyt_sms_transports"
|
|
3880
|
+
]
|
|
3881
|
+
},
|
|
3882
|
+
"GET /api/v1/sms/whatsapp/templates": {
|
|
3883
|
+
"status": "covered",
|
|
3884
|
+
"tools": [
|
|
3885
|
+
"conduyt_whatsapp_templates"
|
|
3886
|
+
]
|
|
3887
|
+
},
|
|
3848
3888
|
"GET /api/v1/sso/connection": {
|
|
3849
3889
|
"status": "excluded",
|
|
3850
3890
|
"reason": "SAML/SSO configuration + protocol endpoints; interactive/IdP-facing"
|