@app-connect/core 1.7.8 → 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.
Files changed (69) hide show
  1. package/connector/developerPortal.js +43 -0
  2. package/connector/proxy/index.js +10 -3
  3. package/connector/registry.js +8 -6
  4. package/handlers/admin.js +44 -21
  5. package/handlers/auth.js +97 -69
  6. package/handlers/calldown.js +10 -4
  7. package/handlers/contact.js +45 -112
  8. package/handlers/disposition.js +4 -142
  9. package/handlers/log.js +174 -259
  10. package/handlers/user.js +19 -6
  11. package/index.js +310 -122
  12. package/lib/analytics.js +3 -1
  13. package/lib/authSession.js +68 -0
  14. package/lib/callLogComposer.js +498 -420
  15. package/lib/errorHandler.js +206 -0
  16. package/lib/jwt.js +2 -0
  17. package/lib/logger.js +190 -0
  18. package/lib/oauth.js +21 -12
  19. package/lib/ringcentral.js +2 -10
  20. package/lib/sharedSMSComposer.js +471 -0
  21. package/mcp/SupportedPlatforms.md +12 -0
  22. package/mcp/lib/validator.js +91 -0
  23. package/mcp/mcpHandler.js +166 -0
  24. package/mcp/tools/checkAuthStatus.js +90 -0
  25. package/mcp/tools/collectAuthInfo.js +86 -0
  26. package/mcp/tools/createCallLog.js +299 -0
  27. package/mcp/tools/createMessageLog.js +283 -0
  28. package/mcp/tools/doAuth.js +185 -0
  29. package/mcp/tools/findContactByName.js +87 -0
  30. package/mcp/tools/findContactByPhone.js +96 -0
  31. package/mcp/tools/getCallLog.js +98 -0
  32. package/mcp/tools/getHelp.js +39 -0
  33. package/mcp/tools/getPublicConnectors.js +46 -0
  34. package/mcp/tools/index.js +58 -0
  35. package/mcp/tools/logout.js +63 -0
  36. package/mcp/tools/rcGetCallLogs.js +73 -0
  37. package/mcp/tools/setConnector.js +64 -0
  38. package/mcp/tools/updateCallLog.js +122 -0
  39. package/models/accountDataModel.js +34 -0
  40. package/models/cacheModel.js +3 -0
  41. package/package.json +6 -4
  42. package/releaseNotes.json +36 -0
  43. package/test/connector/registry.test.js +145 -0
  44. package/test/handlers/admin.test.js +583 -0
  45. package/test/handlers/auth.test.js +355 -0
  46. package/test/handlers/contact.test.js +852 -0
  47. package/test/handlers/log.test.js +872 -0
  48. package/test/lib/callLogComposer.test.js +1231 -0
  49. package/test/lib/debugTracer.test.js +328 -0
  50. package/test/lib/logger.test.js +206 -0
  51. package/test/lib/oauth.test.js +359 -0
  52. package/test/lib/ringcentral.test.js +473 -0
  53. package/test/lib/sharedSMSComposer.test.js +1084 -0
  54. package/test/lib/util.test.js +282 -0
  55. package/test/mcp/tools/collectAuthInfo.test.js +192 -0
  56. package/test/mcp/tools/createCallLog.test.js +412 -0
  57. package/test/mcp/tools/createMessageLog.test.js +580 -0
  58. package/test/mcp/tools/doAuth.test.js +363 -0
  59. package/test/mcp/tools/findContactByName.test.js +263 -0
  60. package/test/mcp/tools/findContactByPhone.test.js +284 -0
  61. package/test/mcp/tools/getCallLog.test.js +286 -0
  62. package/test/mcp/tools/getPublicConnectors.test.js +128 -0
  63. package/test/mcp/tools/logout.test.js +169 -0
  64. package/test/mcp/tools/setConnector.test.js +177 -0
  65. package/test/mcp/tools/updateCallLog.test.js +346 -0
  66. package/test/models/accountDataModel.test.js +98 -0
  67. package/test/models/dynamo/connectorSchema.test.js +189 -0
  68. package/test/models/models.test.js +539 -0
  69. package/test/setup.js +176 -176
@@ -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;