@app-connect/core 1.7.10 → 1.7.11
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/connector/developerPortal.js +43 -0
- package/connector/proxy/index.js +10 -3
- package/connector/registry.js +8 -6
- package/handlers/admin.js +44 -21
- package/handlers/auth.js +89 -67
- package/handlers/calldown.js +10 -4
- package/handlers/contact.js +4 -104
- package/handlers/disposition.js +4 -142
- package/handlers/log.js +172 -257
- package/handlers/user.js +19 -6
- package/index.js +213 -47
- package/lib/analytics.js +3 -1
- package/lib/authSession.js +68 -0
- package/lib/callLogComposer.js +498 -420
- package/lib/errorHandler.js +206 -0
- package/lib/jwt.js +2 -0
- package/lib/logger.js +190 -0
- package/lib/oauth.js +21 -10
- package/lib/ringcentral.js +2 -10
- package/lib/sharedSMSComposer.js +471 -0
- package/mcp/SupportedPlatforms.md +12 -0
- package/mcp/lib/validator.js +91 -0
- package/mcp/mcpHandler.js +166 -0
- package/mcp/tools/checkAuthStatus.js +90 -0
- package/mcp/tools/collectAuthInfo.js +86 -0
- package/mcp/tools/createCallLog.js +299 -0
- package/mcp/tools/createMessageLog.js +283 -0
- package/mcp/tools/doAuth.js +185 -0
- package/mcp/tools/findContactByName.js +87 -0
- package/mcp/tools/findContactByPhone.js +96 -0
- package/mcp/tools/getCallLog.js +98 -0
- package/mcp/tools/getHelp.js +39 -0
- package/mcp/tools/getPublicConnectors.js +46 -0
- package/mcp/tools/index.js +58 -0
- package/mcp/tools/logout.js +63 -0
- package/mcp/tools/rcGetCallLogs.js +73 -0
- package/mcp/tools/setConnector.js +64 -0
- package/mcp/tools/updateCallLog.js +122 -0
- package/models/cacheModel.js +3 -0
- package/package.json +71 -70
- package/releaseNotes.json +12 -0
- package/test/handlers/log.test.js +6 -2
- package/test/lib/logger.test.js +206 -0
- package/test/lib/sharedSMSComposer.test.js +1084 -0
- package/test/mcp/tools/collectAuthInfo.test.js +192 -0
- package/test/mcp/tools/createCallLog.test.js +412 -0
- package/test/mcp/tools/createMessageLog.test.js +580 -0
- package/test/mcp/tools/doAuth.test.js +363 -0
- package/test/mcp/tools/findContactByName.test.js +263 -0
- package/test/mcp/tools/findContactByPhone.test.js +284 -0
- package/test/mcp/tools/getCallLog.test.js +286 -0
- package/test/mcp/tools/getPublicConnectors.test.js +128 -0
- package/test/mcp/tools/logout.test.js +169 -0
- package/test/mcp/tools/setConnector.test.js +177 -0
- package/test/mcp/tools/updateCallLog.test.js +346 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
const jwt = require('../../lib/jwt');
|
|
2
|
+
const connectorRegistry = require('../../connector/registry');
|
|
3
|
+
const logCore = require('../../handlers/log');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* MCP Tool: Create Message Log
|
|
7
|
+
*
|
|
8
|
+
* This tool creates message logs in the CRM platform.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const toolDefinition = {
|
|
12
|
+
name: 'createMessageLog',
|
|
13
|
+
description: '⚠️ REQUIRES AUTHENTICATION: User must first authenticate using the "auth" tool to obtain a JWT token before using this tool. | Create message logs in the CRM platform. Returns the created log IDs if successful.',
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
jwtToken: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'JWT token containing userId and platform information. If user does not have this, direct them to use the "auth" tool first.'
|
|
20
|
+
},
|
|
21
|
+
incomingData: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
description: 'Message log data including messages array with conversation info',
|
|
24
|
+
properties: {
|
|
25
|
+
conversation: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
description: 'Log info object. Sometimes it is named logInfo',
|
|
28
|
+
properties: {
|
|
29
|
+
messages: {
|
|
30
|
+
type: 'array',
|
|
31
|
+
description: 'Array of message objects to log',
|
|
32
|
+
minItems: 1,
|
|
33
|
+
items: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: {
|
|
36
|
+
id: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
description: 'Message ID'
|
|
39
|
+
},
|
|
40
|
+
creationTime: {
|
|
41
|
+
type: 'number',
|
|
42
|
+
description: 'Message creation time'
|
|
43
|
+
},
|
|
44
|
+
subject: {
|
|
45
|
+
type: 'string',
|
|
46
|
+
description: 'Message subject'
|
|
47
|
+
},
|
|
48
|
+
conversationId: {
|
|
49
|
+
type: 'string',
|
|
50
|
+
description: 'Conversation/session ID'
|
|
51
|
+
},
|
|
52
|
+
phoneNumber: {
|
|
53
|
+
type: 'string',
|
|
54
|
+
description: 'Phone number associated with the message'
|
|
55
|
+
},
|
|
56
|
+
direction: {
|
|
57
|
+
type: 'string',
|
|
58
|
+
description: 'Message direction (inbound/outbound)'
|
|
59
|
+
},
|
|
60
|
+
from: {
|
|
61
|
+
type: 'object',
|
|
62
|
+
description: 'From object',
|
|
63
|
+
properties: {
|
|
64
|
+
phoneNumber: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
description: 'Phone number associated with the from'
|
|
67
|
+
},
|
|
68
|
+
location: {
|
|
69
|
+
type: 'string',
|
|
70
|
+
description: 'Location associated with the from'
|
|
71
|
+
},
|
|
72
|
+
name: {
|
|
73
|
+
type: 'string',
|
|
74
|
+
description: 'Name associated with the from'
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
to: {
|
|
79
|
+
type: 'array',
|
|
80
|
+
description: 'Array of to objects',
|
|
81
|
+
items: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {
|
|
84
|
+
phoneNumber: {
|
|
85
|
+
type: 'string',
|
|
86
|
+
description: 'Phone number associated with the to'
|
|
87
|
+
},
|
|
88
|
+
location: {
|
|
89
|
+
type: 'string',
|
|
90
|
+
description: 'Location associated with the to'
|
|
91
|
+
},
|
|
92
|
+
name: {
|
|
93
|
+
type: 'string',
|
|
94
|
+
description: 'Name associated with the to'
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
messageStatus: {
|
|
100
|
+
type: 'string',
|
|
101
|
+
description: 'Message status, just for fax document'
|
|
102
|
+
},
|
|
103
|
+
faxPageCount: {
|
|
104
|
+
type: 'number',
|
|
105
|
+
description: 'Fax page count, just for fax document'
|
|
106
|
+
},
|
|
107
|
+
attachments: {
|
|
108
|
+
type: 'array',
|
|
109
|
+
description: 'Array of attachment objects',
|
|
110
|
+
items: {
|
|
111
|
+
type: 'object',
|
|
112
|
+
properties: {
|
|
113
|
+
type: {
|
|
114
|
+
type: 'string',
|
|
115
|
+
description: 'Attachment type'
|
|
116
|
+
},
|
|
117
|
+
link: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
description: 'Attachment link'
|
|
120
|
+
},
|
|
121
|
+
uri: {
|
|
122
|
+
type: 'string',
|
|
123
|
+
description: 'Attachment URI'
|
|
124
|
+
},
|
|
125
|
+
contentType: {
|
|
126
|
+
type: 'string',
|
|
127
|
+
description: 'Attachment content type'
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
required: ['id', 'conversationId', 'phoneNumber', 'direction']
|
|
135
|
+
},
|
|
136
|
+
correspondents: {
|
|
137
|
+
type: 'array',
|
|
138
|
+
description: 'Array of correspondent objects',
|
|
139
|
+
minItems: 1,
|
|
140
|
+
items: {
|
|
141
|
+
type: 'object',
|
|
142
|
+
properties: {
|
|
143
|
+
phoneNumber: {
|
|
144
|
+
type: 'string',
|
|
145
|
+
description: 'Phone number associated with the correspondent'
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
conversationId:{
|
|
151
|
+
type: 'string',
|
|
152
|
+
description: 'Conversation ID'
|
|
153
|
+
},
|
|
154
|
+
conversationLogId: {
|
|
155
|
+
type: 'string',
|
|
156
|
+
description: 'Conversation log ID, conversationId + date. The same conversation happen during the same day will have the same conversationLogId'
|
|
157
|
+
},
|
|
158
|
+
rcAccessToken: {
|
|
159
|
+
type: 'string',
|
|
160
|
+
description: 'RingCentral access token'
|
|
161
|
+
},
|
|
162
|
+
type: {
|
|
163
|
+
type: 'string',
|
|
164
|
+
description: 'Conversation type'
|
|
165
|
+
},
|
|
166
|
+
date: {
|
|
167
|
+
type: 'string',
|
|
168
|
+
description: 'Conversation date'
|
|
169
|
+
},
|
|
170
|
+
creationTime:{
|
|
171
|
+
type: 'number',
|
|
172
|
+
description: 'Conversation creation time'
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
required: ['messages', 'correspondents', 'conversationLogId']
|
|
176
|
+
},
|
|
177
|
+
contactId: {
|
|
178
|
+
type: 'string',
|
|
179
|
+
description: 'Contact ID'
|
|
180
|
+
},
|
|
181
|
+
contactName: {
|
|
182
|
+
type: 'string',
|
|
183
|
+
description: 'Contact name'
|
|
184
|
+
},
|
|
185
|
+
contactType: {
|
|
186
|
+
type: 'string',
|
|
187
|
+
description: 'Contact type'
|
|
188
|
+
},
|
|
189
|
+
additionalSubmission: {
|
|
190
|
+
type: 'object',
|
|
191
|
+
description: 'Additional submission object',
|
|
192
|
+
properties: {
|
|
193
|
+
isAssignedToUser: {
|
|
194
|
+
type: 'boolean',
|
|
195
|
+
description: 'Whether to assign to a specific user'
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
required: ['conversation', 'contactId', 'contactName']
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
required: ['jwtToken', 'incomingData']
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Execute the createMessageLog tool
|
|
209
|
+
* @param {Object} args - The tool arguments
|
|
210
|
+
* @param {string} args.jwtToken - JWT token with user and platform info
|
|
211
|
+
* @param {Object} args.incomingData - Message log data
|
|
212
|
+
* @returns {Object} Result object with created log IDs
|
|
213
|
+
*/
|
|
214
|
+
async function execute(args) {
|
|
215
|
+
try {
|
|
216
|
+
const { jwtToken, incomingData } = args;
|
|
217
|
+
|
|
218
|
+
if (!jwtToken) {
|
|
219
|
+
throw new Error('Please go to Settings and authorize CRM platform');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (!incomingData) {
|
|
223
|
+
throw new Error('Incoming data must be provided');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if(incomingData.conversation && !incomingData.logInfo) {
|
|
227
|
+
incomingData.logInfo = incomingData.conversation;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Decode JWT to get userId and platform
|
|
231
|
+
const { id: userId, platform } = jwt.decodeJwt(jwtToken);
|
|
232
|
+
|
|
233
|
+
if (!userId) {
|
|
234
|
+
throw new Error('Invalid JWT token: userId not found');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Get the platform connector module
|
|
238
|
+
const platformModule = connectorRegistry.getConnector(platform);
|
|
239
|
+
|
|
240
|
+
if (!platformModule) {
|
|
241
|
+
throw new Error(`Platform connector not found for: ${platform}`);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Check if createMessageLog is implemented
|
|
245
|
+
if (!platformModule.createMessageLog) {
|
|
246
|
+
throw new Error(`createMessageLog is not implemented for platform: ${platform}`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Call the createMessageLog method
|
|
250
|
+
const { successful, returnMessage, logIds } = await logCore.createMessageLog({
|
|
251
|
+
platform,
|
|
252
|
+
userId,
|
|
253
|
+
incomingData
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
if (successful) {
|
|
257
|
+
return {
|
|
258
|
+
success: true,
|
|
259
|
+
data: {
|
|
260
|
+
logIds,
|
|
261
|
+
message: returnMessage?.message || 'Message logs created successfully'
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
return {
|
|
267
|
+
success: false,
|
|
268
|
+
error: returnMessage?.message || 'Failed to create message logs',
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
catch (error) {
|
|
273
|
+
return {
|
|
274
|
+
success: false,
|
|
275
|
+
error: error.message || 'Unknown error occurred',
|
|
276
|
+
errorDetails: error.stack
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
exports.definition = toolDefinition;
|
|
282
|
+
exports.execute = execute;
|
|
283
|
+
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
const authCore = require('../../handlers/auth');
|
|
2
|
+
const jwt = require('../../lib/jwt');
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
const { createAuthSession } = require('../../lib/authSession');
|
|
5
|
+
const { isManifestValid } = require('../lib/validator');
|
|
6
|
+
/**
|
|
7
|
+
* MCP Tool: Do Authentication
|
|
8
|
+
*
|
|
9
|
+
* This tool does the authentication.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const toolDefinition = {
|
|
13
|
+
name: 'doAuth',
|
|
14
|
+
description: 'Auth flow step.4. Do the authentication. Next step is calling step.5 "checkAuthStatus" tool.',
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
connectorManifest: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
description: 'connectorManifest variable from above conversation. Must be the full manifest object, not just serverUrl'
|
|
21
|
+
},
|
|
22
|
+
connectorName: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'connectorName variable from above conversation.'
|
|
25
|
+
},
|
|
26
|
+
hostname: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
description: 'Hostname to authenticate to.'
|
|
29
|
+
},
|
|
30
|
+
apiKey: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
description: 'API key to authenticate to.'
|
|
33
|
+
},
|
|
34
|
+
additionalInfo: {
|
|
35
|
+
type: 'object',
|
|
36
|
+
description: 'Additional information to authenticate to.',
|
|
37
|
+
properties: {
|
|
38
|
+
username: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'Username to authenticate to.'
|
|
41
|
+
},
|
|
42
|
+
password: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
description: 'Password to authenticate to.'
|
|
45
|
+
},
|
|
46
|
+
apiUrl: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
description: 'API URL to authenticate to.'
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
callbackUri: {
|
|
53
|
+
type: 'string',
|
|
54
|
+
description: 'Callback URI to authenticate to.'
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
required: ['connectorManifest', 'connectorName', 'hostname']
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Execute the doAuth tool
|
|
63
|
+
* @param {Object} args - The tool arguments
|
|
64
|
+
* @param {string} args.connectorManifest - Connector manifest from conversation or memory.
|
|
65
|
+
* @param {string} args.connectorName - Connector name from conversation or memory.
|
|
66
|
+
* @param {string} args.hostname - Hostname to authenticate to.
|
|
67
|
+
* @param {string} args.apiKey - API key to authenticate to.
|
|
68
|
+
* @param {Object} args.additionalInfo - Additional information to authenticate to.
|
|
69
|
+
* @param {string} args.callbackUri - Callback URI to authenticate to.
|
|
70
|
+
* @returns {Object} Result object with authentication information
|
|
71
|
+
*/
|
|
72
|
+
async function execute(args) {
|
|
73
|
+
try {
|
|
74
|
+
const { connectorManifest, connectorName, hostname, apiKey, additionalInfo, callbackUri } = args;
|
|
75
|
+
const { isValid, errors } = isManifestValid({ connectorManifest, connectorName });
|
|
76
|
+
if (!isValid) {
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
error: "Invalid connector manifest",
|
|
80
|
+
errorDetails: errors.join(', '),
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const platform = connectorManifest.platforms[connectorName];
|
|
84
|
+
switch (platform.auth.type) {
|
|
85
|
+
case 'apiKey':
|
|
86
|
+
const { userInfo } = await authCore.onApiKeyLogin({ platform: platform.name, hostname, apiKey, additionalInfo });
|
|
87
|
+
if (userInfo) {
|
|
88
|
+
const jwtToken = jwt.generateJwt({
|
|
89
|
+
id: userInfo.id.toString(),
|
|
90
|
+
platform: platform.name
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
success: true,
|
|
94
|
+
data: {
|
|
95
|
+
jwtToken,
|
|
96
|
+
message: "IMPORTANT: Authentication successful. Keep jwtToken in memory for future use.",
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
return {
|
|
102
|
+
success: false,
|
|
103
|
+
error: "Authentication failed",
|
|
104
|
+
errorDetails: "User info not found",
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
case 'oauth':
|
|
108
|
+
const hasValidCallbackUri = callbackUri && callbackUri.includes('code=') && callbackUri.includes('state=');
|
|
109
|
+
if (hasValidCallbackUri) {
|
|
110
|
+
const query = Object.fromEntries(new URL(callbackUri).searchParams);
|
|
111
|
+
query.hostname = hostname;
|
|
112
|
+
const { userInfo } = await authCore.onOAuthCallback({ platform: platform.name, hostname, callbackUri, query });
|
|
113
|
+
if (userInfo) {
|
|
114
|
+
const jwtToken = jwt.generateJwt({
|
|
115
|
+
id: userInfo.id.toString(),
|
|
116
|
+
platform: platform.name
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
success: true,
|
|
120
|
+
data: {
|
|
121
|
+
jwtToken,
|
|
122
|
+
message: "IMPORTANT: Authentication successful. Keep jwtToken in memory for future use.",
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
return {
|
|
128
|
+
success: false,
|
|
129
|
+
error: "Authentication failed",
|
|
130
|
+
errorDetails: "User info not found",
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// Generate unique session ID
|
|
136
|
+
const sessionId = crypto.randomUUID();
|
|
137
|
+
|
|
138
|
+
// Store session
|
|
139
|
+
await createAuthSession(sessionId, {
|
|
140
|
+
platform: platform.name,
|
|
141
|
+
hostname,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const authUri = composeAuthUri({ platform, sessionId, hostname });
|
|
145
|
+
return {
|
|
146
|
+
success: true,
|
|
147
|
+
data: {
|
|
148
|
+
authUri,
|
|
149
|
+
sessionId,
|
|
150
|
+
message: "IMPORTANT: Show this uri as a clickable link for user to authorize. After user authorizes, use checkAuthStatus tool with this sessionId to get the jwtToken.",
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return {
|
|
158
|
+
success: false,
|
|
159
|
+
error: error.message || 'Unknown error occurred',
|
|
160
|
+
errorDetails: error.stack
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function composeAuthUri({ platform, sessionId, hostname }) {
|
|
166
|
+
let customState = '';
|
|
167
|
+
if (platform.auth.oauth.customState) {
|
|
168
|
+
customState = platform.auth.oauth.customState;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Include sessionId in state if provided
|
|
172
|
+
const stateParam = sessionId ?
|
|
173
|
+
`sessionId=${sessionId}&platform=${platform.name}&hostname=${hostname}` :
|
|
174
|
+
`platform=${platform.name}&hostname=${hostname}`;
|
|
175
|
+
|
|
176
|
+
return `${platform.auth.oauth.authUrl}?` +
|
|
177
|
+
`response_type=code` +
|
|
178
|
+
`&client_id=${platform.auth.oauth.clientId}` +
|
|
179
|
+
`${!!platform.auth.oauth.scope && platform.auth.oauth.scope != '' ? `&${platform.auth.oauth.scope}` : ''}` +
|
|
180
|
+
`&state=${customState === '' ? encodeURIComponent(stateParam) : customState}` +
|
|
181
|
+
`&redirect_uri=${process.env.APP_SERVER}/oauth-callback`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
exports.definition = toolDefinition;
|
|
185
|
+
exports.execute = execute;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const jwt = require('../../lib/jwt');
|
|
2
|
+
const connectorRegistry = require('../../connector/registry');
|
|
3
|
+
const contactCore = require('../../handlers/contact');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* MCP Tool: Find Contact With Name
|
|
7
|
+
*
|
|
8
|
+
* This tool searches for a contact in the CRM platform by name.
|
|
9
|
+
* It uses the platform-specific connector to find matching contacts.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const toolDefinition = {
|
|
13
|
+
name: 'findContactByName',
|
|
14
|
+
description: '⚠️ REQUIRES AUTHENTICATION: User must first authenticate using the "auth" tool to obtain a JWT token before using this tool. | Search for a contact in the CRM platform by name. Returns contact details if found.',
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
jwtToken: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'JWT token containing userId and platform information. If user does not have this, direct them to use the "auth" tool first.'
|
|
21
|
+
},
|
|
22
|
+
name: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'Name to search for'
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
required: ['jwtToken', 'name']
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Execute the findContactByName tool
|
|
33
|
+
* @param {Object} args - The tool arguments
|
|
34
|
+
* @param {string} args.jwtToken - JWT token with user and platform info
|
|
35
|
+
* @param {string} args.name - Name to search for
|
|
36
|
+
* @returns {Object} Result object with contact information
|
|
37
|
+
*/
|
|
38
|
+
async function execute(args) {
|
|
39
|
+
try {
|
|
40
|
+
const { jwtToken, name } = args;
|
|
41
|
+
|
|
42
|
+
// Decode JWT to get userId and platform
|
|
43
|
+
const { id: userId, platform } = jwt.decodeJwt(jwtToken);
|
|
44
|
+
|
|
45
|
+
if (!userId) {
|
|
46
|
+
throw new Error('Invalid JWT token: userId not found');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Get the platform connector module
|
|
50
|
+
const platformModule = connectorRegistry.getConnector(platform);
|
|
51
|
+
|
|
52
|
+
if (!platformModule) {
|
|
53
|
+
throw new Error(`Platform connector not found for: ${platform}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check if findContactByName is implemented
|
|
57
|
+
if (!platformModule.findContactWithName) {
|
|
58
|
+
throw new Error(`findContactByName is not implemented for platform: ${platform}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Call the findContactByName method
|
|
62
|
+
const { successful, returnMessage, contact } = await contactCore.findContactWithName({ platform, userId, name });
|
|
63
|
+
if (successful) {
|
|
64
|
+
return {
|
|
65
|
+
success: true,
|
|
66
|
+
data: contact,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
return {
|
|
71
|
+
success: false,
|
|
72
|
+
error: returnMessage.message,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
error: error.message || 'Unknown error occurred',
|
|
80
|
+
errorDetails: error.stack
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
exports.definition = toolDefinition;
|
|
86
|
+
exports.execute = execute;
|
|
87
|
+
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const jwt = require('../../lib/jwt');
|
|
2
|
+
const connectorRegistry = require('../../connector/registry');
|
|
3
|
+
const contactCore = require('../../handlers/contact');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* MCP Tool: Find Contact
|
|
7
|
+
*
|
|
8
|
+
* This tool searches for a contact in the CRM platform by phone number.
|
|
9
|
+
* It uses the platform-specific connector to find matching contacts.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const toolDefinition = {
|
|
13
|
+
name: 'findContactByPhone',
|
|
14
|
+
description: '⚠️ REQUIRES AUTHENTICATION: User must first authenticate using the "auth" tool to obtain a JWT token before using this tool. | Search for a contact in the CRM platform by phone number. Returns contact details if found.',
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
jwtToken: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'JWT token containing userId and platform information. If user does not have this, direct them to use the "auth" tool first.'
|
|
21
|
+
},
|
|
22
|
+
phoneNumber: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'Phone number to search for, if not in E.164 format, convert it to E.164 format'
|
|
25
|
+
},
|
|
26
|
+
overridingFormat: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
description: 'Overriding format to search for'
|
|
29
|
+
},
|
|
30
|
+
isExtension: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
description: 'Whether the request is from an extension'
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
required: ['jwtToken', 'phoneNumber']
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Execute the findContactByPhone tool
|
|
41
|
+
* @param {Object} args - The tool arguments
|
|
42
|
+
* @param {string} args.jwtToken - JWT token with user and platform info
|
|
43
|
+
* @param {string} [args.phoneNumber] - Phone number to search for
|
|
44
|
+
* @param {string} [args.overridingFormat] - Overriding format to search for
|
|
45
|
+
* @param {string} [args.isExtension] - Whether the request is from an extension
|
|
46
|
+
* @returns {Object} Result object with contact information
|
|
47
|
+
*/
|
|
48
|
+
async function execute(args) {
|
|
49
|
+
try {
|
|
50
|
+
const { jwtToken, phoneNumber, overridingFormat, isExtension } = args;
|
|
51
|
+
|
|
52
|
+
// Decode JWT to get userId and platform
|
|
53
|
+
const { id: userId, platform } = jwt.decodeJwt(jwtToken);
|
|
54
|
+
|
|
55
|
+
if (!userId) {
|
|
56
|
+
throw new Error('Invalid JWT token: userId not found');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Get the platform connector module
|
|
60
|
+
const platformModule = connectorRegistry.getConnector(platform);
|
|
61
|
+
|
|
62
|
+
if (!platformModule) {
|
|
63
|
+
throw new Error(`Platform connector not found for: ${platform}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Check if findContactByPhone is implemented
|
|
67
|
+
if (!platformModule.findContact) {
|
|
68
|
+
throw new Error(`findContactByPhone is not implemented for platform: ${platform}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Call the findContactByPhone method
|
|
72
|
+
const { successful, returnMessage, contact } = await contactCore.findContact({ platform, userId, phoneNumber, overridingFormat: overridingFormat ?? '', isExtension: isExtension ?? false });
|
|
73
|
+
if (successful) {
|
|
74
|
+
return {
|
|
75
|
+
success: true,
|
|
76
|
+
data: contact,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
return {
|
|
81
|
+
success: false,
|
|
82
|
+
error: returnMessage.message,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
return {
|
|
88
|
+
success: false,
|
|
89
|
+
error: error.message || 'Unknown error occurred',
|
|
90
|
+
errorDetails: error.stack
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
exports.definition = toolDefinition;
|
|
96
|
+
exports.execute = execute;
|