@opencx/mcp 1.15.15 → 1.15.21
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/campaign-tools.spec.d.ts +2 -0
- package/dist/campaign-tools.spec.d.ts.map +1 -0
- package/dist/campaign-tools.spec.js +508 -0
- package/dist/campaign-tools.spec.js.map +1 -0
- package/dist/companies.spec.d.ts +2 -0
- package/dist/companies.spec.d.ts.map +1 -0
- package/dist/companies.spec.js +191 -0
- package/dist/companies.spec.js.map +1 -0
- package/dist/phone-caller-number-tool.spec.d.ts +2 -0
- package/dist/phone-caller-number-tool.spec.d.ts.map +1 -0
- package/dist/phone-caller-number-tool.spec.js +97 -0
- package/dist/phone-caller-number-tool.spec.js.map +1 -0
- package/dist/schema.d.ts +10756 -7565
- package/dist/schema.d.ts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +12 -2
- package/dist/server.js.map +1 -1
- package/dist/slack-tools.spec.d.ts +2 -0
- package/dist/slack-tools.spec.d.ts.map +1 -0
- package/dist/slack-tools.spec.js +148 -0
- package/dist/slack-tools.spec.js.map +1 -0
- package/dist/tools/campaign-channel.d.ts +4 -0
- package/dist/tools/campaign-channel.d.ts.map +1 -0
- package/dist/tools/campaign-channel.js +250 -0
- package/dist/tools/campaign-channel.js.map +1 -0
- package/dist/tools/campaign-discovery.d.ts +4 -0
- package/dist/tools/campaign-discovery.d.ts.map +1 -0
- package/dist/tools/campaign-discovery.js +70 -0
- package/dist/tools/campaign-discovery.js.map +1 -0
- package/dist/tools/campaign-qualification.d.ts +4 -0
- package/dist/tools/campaign-qualification.d.ts.map +1 -0
- package/dist/tools/campaign-qualification.js +289 -0
- package/dist/tools/campaign-qualification.js.map +1 -0
- package/dist/tools/campaign-spine.d.ts +4 -0
- package/dist/tools/campaign-spine.d.ts.map +1 -0
- package/dist/tools/campaign-spine.js +630 -0
- package/dist/tools/campaign-spine.js.map +1 -0
- package/dist/tools/companies.d.ts +4 -0
- package/dist/tools/companies.d.ts.map +1 -0
- package/dist/tools/companies.js +127 -0
- package/dist/tools/companies.js.map +1 -0
- package/dist/tools/macros.js +1 -1
- package/dist/tools/macros.js.map +1 -1
- package/dist/tools/phone.d.ts.map +1 -1
- package/dist/tools/phone.js +54 -2
- package/dist/tools/phone.js.map +1 -1
- package/dist/tools/reports.d.ts.map +1 -1
- package/dist/tools/reports.js +1 -0
- package/dist/tools/reports.js.map +1 -1
- package/dist/tools/sla.d.ts.map +1 -1
- package/dist/tools/sla.js +3 -3
- package/dist/tools/sla.js.map +1 -1
- package/dist/tools/slack.d.ts +4 -0
- package/dist/tools/slack.d.ts.map +1 -0
- package/dist/tools/slack.js +76 -0
- package/dist/tools/slack.js.map +1 -0
- package/dist/utils/session-channel.d.ts +2 -2
- package/dist/utils/session-channel.d.ts.map +1 -1
- package/dist/utils/session-channel.js +1 -0
- package/dist/utils/session-channel.js.map +1 -1
- package/package.json +1 -1
- package/dist/tools/sequences.d.ts +0 -4
- package/dist/tools/sequences.d.ts.map +0 -1
- package/dist/tools/sequences.js +0 -182
- package/dist/tools/sequences.js.map +0 -1
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmDpE,MAAM,WAAW,mBAAmB;IAClC,6FAA6F;IAC7F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,mBAAwB,GAChC,SAAS,CA4DX"}
|
package/dist/server.js
CHANGED
|
@@ -4,6 +4,7 @@ import { registerActionTools } from './tools/actions.js';
|
|
|
4
4
|
import { registerAvailabilityStatusTools } from './tools/availability-statuses.js';
|
|
5
5
|
import { registerAutopilotTools } from './tools/autopilot.js';
|
|
6
6
|
import { registerBlocklistTools } from './tools/blocklist.js';
|
|
7
|
+
import { registerCompanyTools } from './tools/companies.js';
|
|
7
8
|
import { registerContactTools } from './tools/contacts.js';
|
|
8
9
|
import { registerContactSegmentTools } from './tools/contact-segments.js';
|
|
9
10
|
import { registerSessionTools } from './tools/sessions.js';
|
|
@@ -21,7 +22,7 @@ import { registerSalesforceAiReplyTemplateTools } from './tools/salesforce-ai-re
|
|
|
21
22
|
import { registerPhoneTools } from './tools/phone.js';
|
|
22
23
|
import { registerOrgTools } from './tools/org.js';
|
|
23
24
|
import { registerSearchTools } from './tools/search.js';
|
|
24
|
-
import {
|
|
25
|
+
import { registerSlackTools } from './tools/slack.js';
|
|
25
26
|
import { registerSlaTools } from './tools/sla.js';
|
|
26
27
|
import { registerOfficeHoursTools } from './tools/office-hours.js';
|
|
27
28
|
import { registerTagTools } from './tools/tags.js';
|
|
@@ -32,6 +33,10 @@ import { registerHandoffAnalyticsTools } from './tools/handoff-analytics.js';
|
|
|
32
33
|
import { registerImpactReportTools } from './tools/impact-report.js';
|
|
33
34
|
import { registerConversationSankeyTools } from './tools/conversation-sankey.js';
|
|
34
35
|
import { registerReportTools } from './tools/reports.js';
|
|
36
|
+
import { registerCampaignDiscoveryTools } from './tools/campaign-discovery.js';
|
|
37
|
+
import { registerCampaignQualificationTools } from './tools/campaign-qualification.js';
|
|
38
|
+
import { registerCampaignChannelTools } from './tools/campaign-channel.js';
|
|
39
|
+
import { registerCampaignSpineTools } from './tools/campaign-spine.js';
|
|
35
40
|
import { registerSlaAnalyticsTools } from './tools/sla-analytics.js';
|
|
36
41
|
import { registerCoworkerTools } from './tools/coworker.js';
|
|
37
42
|
import { registerWorkflowTools } from './tools/workflows.js';
|
|
@@ -56,6 +61,7 @@ export function createServer(apiKey, baseUrl, options = {}) {
|
|
|
56
61
|
registerAvailabilityStatusTools(server, client);
|
|
57
62
|
registerBlocklistTools(server, client);
|
|
58
63
|
registerContactTools(server, client);
|
|
64
|
+
registerCompanyTools(server, client);
|
|
59
65
|
registerContactSegmentTools(server, client);
|
|
60
66
|
registerSessionTools(server, client);
|
|
61
67
|
registerTrainingTools(server, client);
|
|
@@ -72,7 +78,7 @@ export function createServer(apiKey, baseUrl, options = {}) {
|
|
|
72
78
|
registerPhoneTools(server, client);
|
|
73
79
|
registerOrgTools(server, client);
|
|
74
80
|
registerSearchTools(server, client);
|
|
75
|
-
|
|
81
|
+
registerSlackTools(server, client);
|
|
76
82
|
registerSlaTools(server, client);
|
|
77
83
|
registerOfficeHoursTools(server, client);
|
|
78
84
|
registerTagTools(server, client);
|
|
@@ -83,6 +89,10 @@ export function createServer(apiKey, baseUrl, options = {}) {
|
|
|
83
89
|
registerImpactReportTools(server, client);
|
|
84
90
|
registerConversationSankeyTools(server, client);
|
|
85
91
|
registerReportTools(server, client);
|
|
92
|
+
registerCampaignDiscoveryTools(server, client);
|
|
93
|
+
registerCampaignQualificationTools(server, client);
|
|
94
|
+
registerCampaignChannelTools(server, client);
|
|
95
|
+
registerCampaignSpineTools(server, client);
|
|
86
96
|
registerSlaAnalyticsTools(server, client);
|
|
87
97
|
registerWorkflowTools(server, client);
|
|
88
98
|
registerCoworkerTools(server, client);
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,sCAAsC,EAAE,MAAM,0CAA0C,CAAC;AAClG,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-tools.spec.d.ts","sourceRoot":"","sources":["../src/slack-tools.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
+
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
|
|
4
|
+
import { createServer } from './server.js';
|
|
5
|
+
function mockResponse(body, status = 200) {
|
|
6
|
+
return new Response(JSON.stringify(body), { status, statusText: 'OK' });
|
|
7
|
+
}
|
|
8
|
+
function getRequestUrl(call) {
|
|
9
|
+
const arg = call[0];
|
|
10
|
+
return arg instanceof Request ? arg.url : String(arg);
|
|
11
|
+
}
|
|
12
|
+
function getRequestMethod(call) {
|
|
13
|
+
const arg = call[0];
|
|
14
|
+
if (arg instanceof Request)
|
|
15
|
+
return arg.method;
|
|
16
|
+
return call[1].method ?? 'GET';
|
|
17
|
+
}
|
|
18
|
+
async function getRequestBody(call) {
|
|
19
|
+
const arg = call[0];
|
|
20
|
+
if (arg instanceof Request) {
|
|
21
|
+
const text = await arg.clone().text();
|
|
22
|
+
return text ? JSON.parse(text) : undefined;
|
|
23
|
+
}
|
|
24
|
+
const body = call[1].body;
|
|
25
|
+
return body ? JSON.parse(body) : undefined;
|
|
26
|
+
}
|
|
27
|
+
describe('slack tools', () => {
|
|
28
|
+
let client;
|
|
29
|
+
let cleanup;
|
|
30
|
+
let fetchSpy;
|
|
31
|
+
beforeEach(async () => {
|
|
32
|
+
fetchSpy = vi.fn();
|
|
33
|
+
vi.stubGlobal('fetch', fetchSpy);
|
|
34
|
+
const server = createServer('test-api-key', 'https://api.test.com');
|
|
35
|
+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
36
|
+
await server.connect(serverTransport);
|
|
37
|
+
client = new Client({ name: 'test-client', version: '1.0.0' });
|
|
38
|
+
await client.connect(clientTransport);
|
|
39
|
+
cleanup = async () => {
|
|
40
|
+
await client.close();
|
|
41
|
+
await server.close();
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
afterEach(async () => {
|
|
45
|
+
await cleanup();
|
|
46
|
+
vi.restoreAllMocks();
|
|
47
|
+
});
|
|
48
|
+
it('get_slack_connection_status reads GET /slack/connection-status', async () => {
|
|
49
|
+
fetchSpy.mockResolvedValueOnce(mockResponse({ connected: true, workspace_id: 'W1', workspace_name: 'Acme' }));
|
|
50
|
+
const result = await client.callTool({ name: 'get_slack_connection_status', arguments: {} });
|
|
51
|
+
expect(result.isError).toBeFalsy();
|
|
52
|
+
const call = fetchSpy.mock.calls[0];
|
|
53
|
+
expect(getRequestUrl(call)).toBe('https://api.test.com/slack/connection-status');
|
|
54
|
+
expect(getRequestMethod(call)).toBe('GET');
|
|
55
|
+
expect(JSON.stringify(result.content)).toContain('Acme');
|
|
56
|
+
});
|
|
57
|
+
it('list_slack_channels reads GET /slack/bot-channels', async () => {
|
|
58
|
+
fetchSpy.mockResolvedValueOnce(mockResponse({
|
|
59
|
+
connected: true,
|
|
60
|
+
channels: [{ id: 'C1', name: 'support', is_private: false }],
|
|
61
|
+
}));
|
|
62
|
+
const result = await client.callTool({ name: 'list_slack_channels', arguments: {} });
|
|
63
|
+
expect(result.isError).toBeFalsy();
|
|
64
|
+
expect(getRequestUrl(fetchSpy.mock.calls[0])).toBe('https://api.test.com/slack/bot-channels');
|
|
65
|
+
expect(JSON.stringify(result.content)).toContain('support');
|
|
66
|
+
});
|
|
67
|
+
it('update_slack_notification_settings sends only the fields it was given', async () => {
|
|
68
|
+
fetchSpy.mockResolvedValueOnce(mockResponse({
|
|
69
|
+
connected: true,
|
|
70
|
+
notification_channel_id: 'C1',
|
|
71
|
+
notification_channel_name: 'handoffs',
|
|
72
|
+
notify_assignee_enabled: false,
|
|
73
|
+
}));
|
|
74
|
+
// The Voltico shape: turn the assignee DM off, leave the channel alone.
|
|
75
|
+
const result = await client.callTool({
|
|
76
|
+
name: 'update_slack_notification_settings',
|
|
77
|
+
arguments: { notify_assignee_enabled: false },
|
|
78
|
+
});
|
|
79
|
+
expect(result.isError).toBeFalsy();
|
|
80
|
+
const call = fetchSpy.mock.calls[0];
|
|
81
|
+
expect(getRequestUrl(call)).toBe('https://api.test.com/slack/notification-settings');
|
|
82
|
+
expect(getRequestMethod(call)).toBe('PUT');
|
|
83
|
+
expect(await getRequestBody(call)).toEqual({ notify_assignee_enabled: false });
|
|
84
|
+
});
|
|
85
|
+
it('update_slack_notification_settings can turn the channel off with an explicit null', async () => {
|
|
86
|
+
fetchSpy.mockResolvedValueOnce(mockResponse({
|
|
87
|
+
connected: true,
|
|
88
|
+
notification_channel_id: null,
|
|
89
|
+
notification_channel_name: null,
|
|
90
|
+
notify_assignee_enabled: true,
|
|
91
|
+
}));
|
|
92
|
+
await client.callTool({
|
|
93
|
+
name: 'update_slack_notification_settings',
|
|
94
|
+
arguments: { notification_channel_id: null },
|
|
95
|
+
});
|
|
96
|
+
expect(await getRequestBody(fetchSpy.mock.calls[0])).toEqual({
|
|
97
|
+
notification_channel_id: null,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
it('update_slack_tag_directory forwards the whole directory', async () => {
|
|
101
|
+
const tagDirectory = {
|
|
102
|
+
billing_oncall: { type: 'usergroup', id: 'S1' },
|
|
103
|
+
everyone: { type: 'special', id: 'here' },
|
|
104
|
+
};
|
|
105
|
+
fetchSpy.mockResolvedValueOnce(mockResponse({ connected: true, tag_directory: tagDirectory }));
|
|
106
|
+
await client.callTool({
|
|
107
|
+
name: 'update_slack_tag_directory',
|
|
108
|
+
arguments: { tag_directory: tagDirectory },
|
|
109
|
+
});
|
|
110
|
+
const call = fetchSpy.mock.calls[0];
|
|
111
|
+
expect(getRequestUrl(call)).toBe('https://api.test.com/slack/tag-directory');
|
|
112
|
+
expect(getRequestMethod(call)).toBe('PUT');
|
|
113
|
+
expect(await getRequestBody(call)).toEqual({ tag_directory: tagDirectory });
|
|
114
|
+
});
|
|
115
|
+
it('rejects a mention target Slack cannot render, before it reaches the API', async () => {
|
|
116
|
+
const result = await client.callTool({
|
|
117
|
+
name: 'update_slack_tag_directory',
|
|
118
|
+
arguments: { tag_directory: { everyone: { type: 'special', id: 'everybody' } } },
|
|
119
|
+
});
|
|
120
|
+
expect(result.isError).toBeTruthy();
|
|
121
|
+
expect(fetchSpy).not.toHaveBeenCalled();
|
|
122
|
+
});
|
|
123
|
+
it('does not let the caller invent a channel name — the API resolves it from Slack', async () => {
|
|
124
|
+
const { tools } = await client.listTools();
|
|
125
|
+
const tool = tools.find((t) => t.name === 'update_slack_notification_settings');
|
|
126
|
+
expect(tool).toBeDefined();
|
|
127
|
+
expect(Object.keys(tool?.inputSchema.properties ?? {})).toEqual([
|
|
128
|
+
'notification_channel_id',
|
|
129
|
+
'notify_assignee_enabled',
|
|
130
|
+
]);
|
|
131
|
+
});
|
|
132
|
+
it('exposes reads and config writes, but never disconnect or message sending', async () => {
|
|
133
|
+
const { tools } = await client.listTools();
|
|
134
|
+
const names = tools.map((t) => t.name);
|
|
135
|
+
expect(names).toEqual(expect.arrayContaining([
|
|
136
|
+
'get_slack_connection_status',
|
|
137
|
+
'list_slack_channels',
|
|
138
|
+
'get_slack_notification_settings',
|
|
139
|
+
'update_slack_notification_settings',
|
|
140
|
+
'get_slack_tag_directory',
|
|
141
|
+
'update_slack_tag_directory',
|
|
142
|
+
]));
|
|
143
|
+
for (const forbidden of ['disconnect_slack', 'send_slack_message', 'leave_slack_channel']) {
|
|
144
|
+
expect(names).not.toContain(forbidden);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
//# sourceMappingURL=slack-tools.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-tools.spec.js","sourceRoot":"","sources":["../src/slack-tools.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { OpenCXClient } from '../api-client.js';
|
|
3
|
+
export declare function registerCampaignChannelTools(server: McpServer, client: OpenCXClient): void;
|
|
4
|
+
//# sourceMappingURL=campaign-channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"campaign-channel.d.ts","sourceRoot":"","sources":["../../src/tools/campaign-channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAUrD,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,QA+RnF"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ApiError, jsonContent } from '../api-client.js';
|
|
3
|
+
// "What can this sequence send, from which number, and what can the table
|
|
4
|
+
// show?" — the questions an author must answer before the messages step, and
|
|
5
|
+
// the ones that previously had no tool at all. Without these the agent could
|
|
6
|
+
// only ask the user to read the dashboard and type an answer back, for facts
|
|
7
|
+
// the server already knows.
|
|
8
|
+
//
|
|
9
|
+
// The template/sender tools are org-scoped (they hit the whatsapp surface, the
|
|
10
|
+
// same one the dashboard picker uses); the column tools are per-sequence.
|
|
11
|
+
export function registerCampaignChannelTools(server, client) {
|
|
12
|
+
server.registerTool('list_whatsapp_templates', {
|
|
13
|
+
description: 'Every WhatsApp template the org has, flattened to what you pick on: body text, its ' +
|
|
14
|
+
'placeholder keys (`variables`), category, approval status, and `sendable` (true only ' +
|
|
15
|
+
'when APPROVED). Sendable ones are listed first. ALWAYS call this before asking the user ' +
|
|
16
|
+
'which template to use — then ask only to choose between real candidates, or to confirm ' +
|
|
17
|
+
'a new one is needed. `unreadable_wabas` being non-empty means some templates are ' +
|
|
18
|
+
'MISSING from the list, not that they do not exist: say so rather than authoring a ' +
|
|
19
|
+
'duplicate.',
|
|
20
|
+
inputSchema: {},
|
|
21
|
+
}, async () => {
|
|
22
|
+
try {
|
|
23
|
+
const { data } = await client.GET('/whatsapp/templates/catalog', {});
|
|
24
|
+
return jsonContent(data);
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
if (e instanceof ApiError)
|
|
28
|
+
return jsonContent({ ok: false, status: e.status, error: e.body });
|
|
29
|
+
throw e;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
server.registerTool('list_whatsapp_senders', {
|
|
33
|
+
description: 'The WhatsApp numbers this organization can send from, with their display numbers. ' +
|
|
34
|
+
'Anything listed is accepted by set_sequence_senders. Call this before asking which ' +
|
|
35
|
+
'number to send from: with exactly one option there is nothing to ask, so bind it and ' +
|
|
36
|
+
'say which you used. (To see what a sequence is ALREADY bound to, read the sequence.)',
|
|
37
|
+
inputSchema: {},
|
|
38
|
+
}, async () => {
|
|
39
|
+
try {
|
|
40
|
+
const { data } = await client.GET('/whatsapp/senders', {});
|
|
41
|
+
return jsonContent(data);
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
if (e instanceof ApiError)
|
|
45
|
+
return jsonContent({ ok: false, status: e.status, error: e.body });
|
|
46
|
+
throw e;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
server.registerTool('set_sequence_senders', {
|
|
50
|
+
description: 'Bind what this sequence sends from (replace-set PER CHANNEL — one call per channel a ' +
|
|
51
|
+
'sequence uses). A sequence cannot launch a channel without a sender bound on it. ' +
|
|
52
|
+
'whatsapp: ids from list_whatsapp_senders. voice: eligible agent_ids from ' +
|
|
53
|
+
'list_voice_senders (the AI phone agent that places the calls — its persona, voice ' +
|
|
54
|
+
'and caller number). email: eligible mailbox_ids from list_email_senders — and email ' +
|
|
55
|
+
'is the one channel where binding SEVERAL senders is normal: sends spread across all ' +
|
|
56
|
+
'bound mailboxes, each paced on its own daily budget, so more mailboxes = more sends ' +
|
|
57
|
+
'per day. Default to binding all eligible mailboxes unless the user narrows the set.',
|
|
58
|
+
inputSchema: {
|
|
59
|
+
sequence_id: z.string().describe('The sequence id'),
|
|
60
|
+
channel: z.enum(['whatsapp', 'voice', 'email']),
|
|
61
|
+
sender_ids: z
|
|
62
|
+
.array(z.string())
|
|
63
|
+
.describe('whatsapp: `sender_id` values from list_whatsapp_senders. voice: `agent_id` ' +
|
|
64
|
+
'values from list_voice_senders (eligible only). email: `mailbox_id` values ' +
|
|
65
|
+
'from list_email_senders (eligible only). Replaces the current set for ' +
|
|
66
|
+
'the channel.'),
|
|
67
|
+
},
|
|
68
|
+
}, async (params) => {
|
|
69
|
+
try {
|
|
70
|
+
const { data } = await client.PUT('/sequences/{sequenceId}/senders', {
|
|
71
|
+
params: { path: { sequenceId: params.sequence_id } },
|
|
72
|
+
body: { channel: params.channel, sender_ids: params.sender_ids },
|
|
73
|
+
});
|
|
74
|
+
return jsonContent(data);
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
if (e instanceof ApiError)
|
|
78
|
+
return jsonContent({ ok: false, status: e.status, error: e.body });
|
|
79
|
+
throw e;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
server.registerTool('list_voice_senders', {
|
|
83
|
+
description: 'The AI phone agents this organization can bind as sequence VOICE senders, each with ' +
|
|
84
|
+
'a bindability verdict AND the mission it already carries. `eligible: true` agents are ' +
|
|
85
|
+
'accepted by set_sequence_senders on the voice channel. Ineligible ones carry the ' +
|
|
86
|
+
'reason so you can name the fix: `no_caller_number` → attach a verified number ' +
|
|
87
|
+
'(set_phone_agent_caller_number, using list_verified_phone_numbers); ' +
|
|
88
|
+
"`no_hosted_trunk` / `foreign_trunk` → the org's telephony needs dashboard attention; " +
|
|
89
|
+
"`not_livekit` → that agent's stack cannot place sequence calls, create an Agent 3 " +
|
|
90
|
+
'instead. ' +
|
|
91
|
+
'READ `first_message` AND `persona` BEFORE BINDING — eligibility only means the agent ' +
|
|
92
|
+
"CAN dial. `first_message` is spoken VERBATIM at pickup, before the step's call brief " +
|
|
93
|
+
'can influence anything, so an agent whose opening line or persona is about a ' +
|
|
94
|
+
'different mission runs ITS script and ignores yours; no brief overrides that. When ' +
|
|
95
|
+
'none of them fits this sequence, create a purpose-built agent instead of reusing one.',
|
|
96
|
+
inputSchema: {},
|
|
97
|
+
}, async () => {
|
|
98
|
+
try {
|
|
99
|
+
const { data } = await client.GET('/sequences/voice-senders', {});
|
|
100
|
+
return jsonContent(data);
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
if (e instanceof ApiError)
|
|
104
|
+
return jsonContent({ ok: false, status: e.status, error: e.body });
|
|
105
|
+
throw e;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
server.registerTool('list_email_senders', {
|
|
109
|
+
description: 'The email mailboxes this organization can bind as sequence EMAIL senders, each with a ' +
|
|
110
|
+
'bindability verdict and a set of HEALTH NUMBERS. `eligible: true` mailboxes are ' +
|
|
111
|
+
'accepted by set_sequence_senders on the email channel; ineligible ones carry the ' +
|
|
112
|
+
'reason (`not_active` → still provisioning or paused, it becomes usable on its own; ' +
|
|
113
|
+
'`domain_not_live` → its domain lapsed, so sending would fail authentication). ' +
|
|
114
|
+
'The `health` object is warm-up status, inbox rate, spam rate, an overall score, ' +
|
|
115
|
+
'warming-since, and the share of recent real sends that hard-bounced (with the sample ' +
|
|
116
|
+
'size). A null means that number is not known yet — common for a new mailbox — and ' +
|
|
117
|
+
'never means bad. ' +
|
|
118
|
+
"These mailboxes are OURS from the user's point of view: never mention a provider, a " +
|
|
119
|
+
'vendor, or a warm-up network when talking about them. ' +
|
|
120
|
+
'DO NOT use health to choose a mailbox and do not editorialize about it: there is no ' +
|
|
121
|
+
'threshold and nothing is blocked. Bind what the user asks for. DO read the figures ' +
|
|
122
|
+
'back when they ask how a mailbox is doing, quoting the numbers rather than an ' +
|
|
123
|
+
'interpretation.',
|
|
124
|
+
inputSchema: {},
|
|
125
|
+
}, async () => {
|
|
126
|
+
try {
|
|
127
|
+
const { data } = await client.GET('/sequences/email-senders', {});
|
|
128
|
+
return jsonContent(data);
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
if (e instanceof ApiError)
|
|
132
|
+
return jsonContent({ ok: false, status: e.status, error: e.body });
|
|
133
|
+
throw e;
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
server.registerTool('create_whatsapp_template', {
|
|
137
|
+
description: 'Submit a NEW WhatsApp template to Meta for approval — for when list_whatsapp_templates ' +
|
|
138
|
+
'has nothing that fits. Write the header/body/footer text; the components payload is ' +
|
|
139
|
+
'assembled server-side. It comes back PENDING: Meta review takes minutes to hours, so ' +
|
|
140
|
+
'bind the step to it and keep building — a pending template does NOT block launch; ' +
|
|
141
|
+
'people arm and sends start the moment it clears. Tell the user it is pending and that ' +
|
|
142
|
+
"you'll confirm once it clears; do NOT wait on it and do NOT ask them to go submit it " +
|
|
143
|
+
'themselves. If this tool returns a 403, template creation needs channel access this ' +
|
|
144
|
+
"user's account doesn't have — show them the drafted body, say an admin (or someone " +
|
|
145
|
+
'with WhatsApp channel access) has to submit it, and keep building the rest. ' +
|
|
146
|
+
'UTILITY for following up on something the person already contacted you about (better ' +
|
|
147
|
+
'delivery, no marketing opt-out gate); MARKETING for promotion. Meta may re-file it ' +
|
|
148
|
+
'under a different category — the response says which.',
|
|
149
|
+
inputSchema: {
|
|
150
|
+
name: z
|
|
151
|
+
.string()
|
|
152
|
+
.describe('Lowercase letters, digits and underscores only, e.g. invoicing_followup.'),
|
|
153
|
+
language: z.string().describe('BCP-47, e.g. en_US, ar.'),
|
|
154
|
+
category: z.enum(['UTILITY', 'MARKETING', 'AUTHENTICATION']),
|
|
155
|
+
body_text: z
|
|
156
|
+
.string()
|
|
157
|
+
.describe('The message. Placeholders are NUMBERED — {{1}}, {{2}} in order. Never {{named}} ' +
|
|
158
|
+
'here: Meta files a named-placeholder template under its named parameter format, ' +
|
|
159
|
+
'which sequence steps cannot send yet, and the failure is silent (the template is ' +
|
|
160
|
+
'approved, the step binds, and the sends never go out). Email and voice steps DO ' +
|
|
161
|
+
'take named variables — this rule is WhatsApp-only.'),
|
|
162
|
+
body_variable_examples: z
|
|
163
|
+
.array(z.string())
|
|
164
|
+
.optional()
|
|
165
|
+
.describe('One realistic sample per placeholder, in body order. REQUIRED whenever the body has placeholders — Meta rejects templates without examples, and this call refuses first.'),
|
|
166
|
+
header_text: z.string().optional().describe('Plain text, 60 chars, no placeholders.'),
|
|
167
|
+
footer_text: z.string().optional().describe('60 chars.'),
|
|
168
|
+
waba_id: z.string().optional().describe('Only when the org has more than one WABA.'),
|
|
169
|
+
},
|
|
170
|
+
}, async (params) => {
|
|
171
|
+
try {
|
|
172
|
+
const { data } = await client.POST('/whatsapp/templates', {
|
|
173
|
+
body: {
|
|
174
|
+
name: params.name,
|
|
175
|
+
language: params.language,
|
|
176
|
+
category: params.category,
|
|
177
|
+
body_text: params.body_text,
|
|
178
|
+
body_variable_examples: params.body_variable_examples ?? [],
|
|
179
|
+
...(params.header_text !== undefined ? { header_text: params.header_text } : {}),
|
|
180
|
+
...(params.footer_text !== undefined ? { footer_text: params.footer_text } : {}),
|
|
181
|
+
...(params.waba_id !== undefined ? { waba_id: params.waba_id } : {}),
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
return jsonContent(data);
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
if (e instanceof ApiError)
|
|
188
|
+
return jsonContent({ ok: false, status: e.status, error: e.body });
|
|
189
|
+
throw e;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
server.registerTool('list_enrichment_paths', {
|
|
193
|
+
description: "Every CATALOG jsonpath a People-table column can project (the org's own data), with " +
|
|
194
|
+
'its type. Read this before set_sequence_columns for catalog columns — a path that is ' +
|
|
195
|
+
'neither in the catalog nor a $.extra_data.* path is rejected by name, so guessing one ' +
|
|
196
|
+
'only costs a round trip. extra_data paths are never listed here: you know that data ' +
|
|
197
|
+
'better than the server does (you attached it), and you supply their type yourself.',
|
|
198
|
+
inputSchema: {},
|
|
199
|
+
}, async () => {
|
|
200
|
+
try {
|
|
201
|
+
const { data } = await client.GET('/sequences/enrichment-catalog', {});
|
|
202
|
+
return jsonContent(data);
|
|
203
|
+
}
|
|
204
|
+
catch (e) {
|
|
205
|
+
if (e instanceof ApiError)
|
|
206
|
+
return jsonContent({ ok: false, status: e.status, error: e.body });
|
|
207
|
+
throw e;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
server.registerTool('set_sequence_columns', {
|
|
211
|
+
description: "Set the columns the sequence's People table shows (replace-set, max 12). This is how " +
|
|
212
|
+
'the user CHECKS your judgement instead of taking a fit score on trust — pick the four ' +
|
|
213
|
+
'or five fields your criteria actually turned on. Paths come from ' +
|
|
214
|
+
'list_enrichment_paths — for those you never write the type, the server resolves it. ' +
|
|
215
|
+
'A column can also project the extra_data you attached at enroll ($.extra_data.plan); ' +
|
|
216
|
+
'for THOSE you must supply the type, from what you saw in the data — the server has ' +
|
|
217
|
+
'no schema for it, and a wrong type just renders badly (re-author to fix). ' +
|
|
218
|
+
'Re-author whenever the criteria or enrichers change.',
|
|
219
|
+
inputSchema: {
|
|
220
|
+
sequence_id: z.string().describe('The sequence id'),
|
|
221
|
+
columns: z
|
|
222
|
+
.array(z.object({
|
|
223
|
+
key: z.string().describe('lowercase letters, digits, underscores'),
|
|
224
|
+
label: z.string().describe('Column header the user reads, e.g. "Topics"'),
|
|
225
|
+
path: z
|
|
226
|
+
.string()
|
|
227
|
+
.describe('A path from list_enrichment_paths, or a $.extra_data.* path'),
|
|
228
|
+
type: z
|
|
229
|
+
.enum(['string', 'number', 'boolean', 'date', 'string[]', 'number[]'])
|
|
230
|
+
.optional()
|
|
231
|
+
.describe('REQUIRED for $.extra_data.* paths; ignored for catalog paths (server resolves those).'),
|
|
232
|
+
}))
|
|
233
|
+
.max(12),
|
|
234
|
+
},
|
|
235
|
+
}, async (params) => {
|
|
236
|
+
try {
|
|
237
|
+
const { data } = await client.PUT('/sequences/{sequenceId}/columns', {
|
|
238
|
+
params: { path: { sequenceId: params.sequence_id } },
|
|
239
|
+
body: { columns: params.columns },
|
|
240
|
+
});
|
|
241
|
+
return jsonContent(data);
|
|
242
|
+
}
|
|
243
|
+
catch (e) {
|
|
244
|
+
if (e instanceof ApiError)
|
|
245
|
+
return jsonContent({ ok: false, status: e.status, error: e.body });
|
|
246
|
+
throw e;
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=campaign-channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"campaign-channel.js","sourceRoot":"","sources":["../../src/tools/campaign-channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { OpenCXClient } from '../api-client.js';
|
|
3
|
+
export declare function registerCampaignDiscoveryTools(server: McpServer, client: OpenCXClient): void;
|
|
4
|
+
//# sourceMappingURL=campaign-discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"campaign-discovery.d.ts","sourceRoot":"","sources":["../../src/tools/campaign-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,QA4ErF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ApiError, jsonContent } from '../api-client.js';
|
|
3
|
+
export function registerCampaignDiscoveryTools(server, client) {
|
|
4
|
+
server.registerTool('discover_sequence_contacts', {
|
|
5
|
+
description: 'Semantic audience discovery for sequences (sequences): match a natural-language ask ' +
|
|
6
|
+
'("customers frustrated by activation delays") against what customers ACTUALLY said — the ' +
|
|
7
|
+
"org's Voice-of-Customer insight catalog — and walk the matches back to real, reachable " +
|
|
8
|
+
'people. Returns two linked lists: `insights` (the matched themes, ranked by similarity, ' +
|
|
9
|
+
'with in-window session/people counts for sizing) and `people` (deduplicated candidates ' +
|
|
10
|
+
'with normalized handles, unsubscribed flag, and per-insight evidence session ids). ' +
|
|
11
|
+
'Retrieval only — it never judges fit; qualification is a separate step. Matches paraphrase ' +
|
|
12
|
+
'and cross-language phrasing (insights are English-normalized). For behavioral/exact-term ' +
|
|
13
|
+
'audiences use run_analytics_query instead; combine both result sets by contact_id — load ' +
|
|
14
|
+
'the "audience-discovery" skill for the full playbook. ' +
|
|
15
|
+
'If `truncated`, raise max_people (tool cap 500) — for larger audiences pull the full ' +
|
|
16
|
+
'result to a file via the API endpoint instead of re-calling this tool in a loop.',
|
|
17
|
+
inputSchema: {
|
|
18
|
+
query: z
|
|
19
|
+
.string()
|
|
20
|
+
.min(3)
|
|
21
|
+
.max(500)
|
|
22
|
+
.describe('The audience meaning to search for, in natural language. Describe the customer ' +
|
|
23
|
+
'sentiment/topic ("complaints about inventory sync failing"), not SQL-ish filters.'),
|
|
24
|
+
since: z
|
|
25
|
+
.string()
|
|
26
|
+
.datetime()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('Only sessions at/after this ISO instant link insights to people (default: 90 days ' +
|
|
29
|
+
'ago). Widen deliberately for "we fixed it" sequences; stale matches are usually ' +
|
|
30
|
+
'resolved complaints.'),
|
|
31
|
+
max_insights: z.number().int().min(1).max(50).optional().describe('Default 10.'),
|
|
32
|
+
max_people: z
|
|
33
|
+
.number()
|
|
34
|
+
.int()
|
|
35
|
+
.min(1)
|
|
36
|
+
.max(500)
|
|
37
|
+
.optional()
|
|
38
|
+
.describe('Default 100. Tool cap 500 — larger pulls belong in a file via the API.'),
|
|
39
|
+
min_similarity: z
|
|
40
|
+
.number()
|
|
41
|
+
.min(0)
|
|
42
|
+
.max(1)
|
|
43
|
+
.optional()
|
|
44
|
+
.describe('Default 0.55. Read the returned similarity distribution and tighten if the tail ' +
|
|
45
|
+
'looks off-topic.'),
|
|
46
|
+
},
|
|
47
|
+
}, async (params) => {
|
|
48
|
+
try {
|
|
49
|
+
const { data } = await client.POST('/sequences/discovery/search', {
|
|
50
|
+
body: {
|
|
51
|
+
query: params.query,
|
|
52
|
+
...(params.since !== undefined ? { since: params.since } : {}),
|
|
53
|
+
...(params.max_insights !== undefined ? { max_insights: params.max_insights } : {}),
|
|
54
|
+
...(params.max_people !== undefined ? { max_people: params.max_people } : {}),
|
|
55
|
+
...(params.min_similarity !== undefined
|
|
56
|
+
? { min_similarity: params.min_similarity }
|
|
57
|
+
: {}),
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
return jsonContent(data);
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
if (e instanceof ApiError) {
|
|
64
|
+
return jsonContent({ ok: false, status: e.status, error: e.body });
|
|
65
|
+
}
|
|
66
|
+
throw e;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=campaign-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"campaign-discovery.js","sourceRoot":"","sources":["../../src/tools/campaign-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { OpenCXClient } from '../api-client.js';
|
|
3
|
+
export declare function registerCampaignQualificationTools(server: McpServer, client: OpenCXClient): void;
|
|
4
|
+
//# sourceMappingURL=campaign-qualification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"campaign-qualification.d.ts","sourceRoot":"","sources":["../../src/tools/campaign-qualification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AA4ErD,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,QAqQzF"}
|