@app-connect/core 1.7.10 → 1.7.12

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 (59) 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 +135 -22
  5. package/handlers/auth.js +89 -67
  6. package/handlers/calldown.js +10 -4
  7. package/handlers/contact.js +4 -104
  8. package/handlers/disposition.js +7 -145
  9. package/handlers/log.js +174 -258
  10. package/handlers/user.js +19 -6
  11. package/index.js +280 -47
  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 -10
  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 +110 -0
  25. package/mcp/tools/collectAuthInfo.js +91 -0
  26. package/mcp/tools/createCallLog.js +308 -0
  27. package/mcp/tools/createContact.js +117 -0
  28. package/mcp/tools/createMessageLog.js +283 -0
  29. package/mcp/tools/doAuth.js +190 -0
  30. package/mcp/tools/findContactByName.js +92 -0
  31. package/mcp/tools/findContactByPhone.js +101 -0
  32. package/mcp/tools/getCallLog.js +98 -0
  33. package/mcp/tools/getGoogleFilePicker.js +103 -0
  34. package/mcp/tools/getHelp.js +44 -0
  35. package/mcp/tools/getPublicConnectors.js +53 -0
  36. package/mcp/tools/index.js +64 -0
  37. package/mcp/tools/logout.js +68 -0
  38. package/mcp/tools/rcGetCallLogs.js +78 -0
  39. package/mcp/tools/setConnector.js +69 -0
  40. package/mcp/tools/updateCallLog.js +122 -0
  41. package/models/cacheModel.js +3 -0
  42. package/package.json +71 -70
  43. package/releaseNotes.json +24 -0
  44. package/test/handlers/log.test.js +11 -4
  45. package/test/lib/logger.test.js +206 -0
  46. package/test/lib/ringcentral.test.js +0 -6
  47. package/test/lib/sharedSMSComposer.test.js +1084 -0
  48. package/test/mcp/tools/collectAuthInfo.test.js +234 -0
  49. package/test/mcp/tools/createCallLog.test.js +425 -0
  50. package/test/mcp/tools/createMessageLog.test.js +580 -0
  51. package/test/mcp/tools/doAuth.test.js +376 -0
  52. package/test/mcp/tools/findContactByName.test.js +263 -0
  53. package/test/mcp/tools/findContactByPhone.test.js +284 -0
  54. package/test/mcp/tools/getCallLog.test.js +286 -0
  55. package/test/mcp/tools/getGoogleFilePicker.test.js +281 -0
  56. package/test/mcp/tools/getPublicConnectors.test.js +128 -0
  57. package/test/mcp/tools/logout.test.js +169 -0
  58. package/test/mcp/tools/setConnector.test.js +177 -0
  59. package/test/mcp/tools/updateCallLog.test.js +346 -0
@@ -0,0 +1,117 @@
1
+ const jwt = require('../../lib/jwt');
2
+ const connectorRegistry = require('../../connector/registry');
3
+ const contactCore = require('../../handlers/contact');
4
+
5
+ /**
6
+ * MCP Tool: Create Contact
7
+ *
8
+ * This tool creates a new contact in the CRM platform.
9
+ */
10
+
11
+ const toolDefinition = {
12
+ name: 'createContact',
13
+ description: '⚠️ REQUIRES AUTHENTICATION: User must first authenticate using the "auth" tool to obtain a JWT token before using this tool. | Create a new contact in the CRM platform. Returns the created contact information 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
+ phoneNumber: {
22
+ type: 'string',
23
+ description: 'Phone number of the new contact (MUST BE in E.164 format, e.g., +14155551234)'
24
+ },
25
+ newContactName: {
26
+ type: 'string',
27
+ description: 'Full name of the new contact. If not provided, use phone number as the name'
28
+ }
29
+ },
30
+ required: ['jwtToken', 'phoneNumber']
31
+ },
32
+ annotations: {
33
+ readOnlyHint: false,
34
+ openWorldHint: true,
35
+ destructiveHint: false
36
+ }
37
+ };
38
+
39
+ /**
40
+ * Execute the createContact 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 of the new contact
44
+ * @param {string} args.newContactName - Name of the new contact
45
+ * @returns {Object} Result object with created contact information
46
+ */
47
+ async function execute(args) {
48
+ try {
49
+ const { jwtToken, phoneNumber, newContactName } = args;
50
+
51
+ if (!jwtToken) {
52
+ throw new Error('Please go to Settings and authorize CRM platform');
53
+ }
54
+
55
+ if (!phoneNumber) {
56
+ throw new Error('Phone number is required');
57
+ }
58
+
59
+ if (!newContactName) {
60
+ throw new Error('Contact name is required');
61
+ }
62
+
63
+ // Decode JWT to get userId and platform
64
+ const { id: userId, platform } = jwt.decodeJwt(jwtToken);
65
+
66
+ if (!userId) {
67
+ throw new Error('Invalid JWT token: userId not found');
68
+ }
69
+
70
+ // Get the platform connector module
71
+ const platformModule = connectorRegistry.getConnector(platform);
72
+
73
+ if (!platformModule) {
74
+ throw new Error(`Platform connector not found for: ${platform}`);
75
+ }
76
+
77
+ // Check if createContact is implemented
78
+ if (!platformModule.createContact) {
79
+ throw new Error(`createContact is not implemented for platform: ${platform}`);
80
+ }
81
+
82
+ // Call the createContact method
83
+ const { successful, returnMessage, contact } = await contactCore.createContact({
84
+ platform,
85
+ userId,
86
+ phoneNumber,
87
+ newContactName
88
+ });
89
+
90
+ if (successful) {
91
+ return {
92
+ success: true,
93
+ data: {
94
+ contact,
95
+ message: returnMessage?.message || 'Contact created successfully'
96
+ }
97
+ };
98
+ }
99
+ else {
100
+ return {
101
+ success: false,
102
+ error: returnMessage?.message || 'Failed to create contact'
103
+ };
104
+ }
105
+ }
106
+ catch (error) {
107
+ return {
108
+ success: false,
109
+ error: error.message || 'Unknown error occurred',
110
+ errorDetails: error.stack
111
+ };
112
+ }
113
+ }
114
+
115
+ exports.definition = toolDefinition;
116
+ exports.execute = execute;
117
+
@@ -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,190 @@
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
+ annotations: {
60
+ readOnlyHint: false,
61
+ openWorldHint: true,
62
+ destructiveHint: true
63
+ }
64
+ };
65
+
66
+ /**
67
+ * Execute the doAuth tool
68
+ * @param {Object} args - The tool arguments
69
+ * @param {string} args.connectorManifest - Connector manifest from conversation or memory.
70
+ * @param {string} args.connectorName - Connector name from conversation or memory.
71
+ * @param {string} args.hostname - Hostname to authenticate to.
72
+ * @param {string} args.apiKey - API key to authenticate to.
73
+ * @param {Object} args.additionalInfo - Additional information to authenticate to.
74
+ * @param {string} args.callbackUri - Callback URI to authenticate to.
75
+ * @returns {Object} Result object with authentication information
76
+ */
77
+ async function execute(args) {
78
+ try {
79
+ const { connectorManifest, connectorName, hostname, apiKey, additionalInfo, callbackUri } = args;
80
+ const { isValid, errors } = isManifestValid({ connectorManifest, connectorName });
81
+ if (!isValid) {
82
+ return {
83
+ success: false,
84
+ error: "Invalid connector manifest",
85
+ errorDetails: errors.join(', '),
86
+ }
87
+ }
88
+ const platform = connectorManifest.platforms[connectorName];
89
+ switch (platform.auth.type) {
90
+ case 'apiKey':
91
+ const { userInfo } = await authCore.onApiKeyLogin({ platform: platform.name, hostname, apiKey, additionalInfo });
92
+ if (userInfo) {
93
+ const jwtToken = jwt.generateJwt({
94
+ id: userInfo.id.toString(),
95
+ platform: platform.name
96
+ });
97
+ return {
98
+ success: true,
99
+ data: {
100
+ jwtToken,
101
+ message: "IMPORTANT: Authentication successful. Keep jwtToken in memory for future use. DO NOT directly show it to user.",
102
+ }
103
+ }
104
+ }
105
+ else {
106
+ return {
107
+ success: false,
108
+ error: "Authentication failed",
109
+ errorDetails: "User info not found",
110
+ }
111
+ }
112
+ case 'oauth':
113
+ const hasValidCallbackUri = callbackUri && callbackUri.includes('code=') && callbackUri.includes('state=');
114
+ if (hasValidCallbackUri) {
115
+ const query = Object.fromEntries(new URL(callbackUri).searchParams);
116
+ query.hostname = hostname;
117
+ const { userInfo } = await authCore.onOAuthCallback({ platform: platform.name, hostname, callbackUri, query });
118
+ if (userInfo) {
119
+ const jwtToken = jwt.generateJwt({
120
+ id: userInfo.id.toString(),
121
+ platform: platform.name
122
+ });
123
+ return {
124
+ success: true,
125
+ data: {
126
+ jwtToken,
127
+ message: "IMPORTANT: Authentication successful. Keep jwtToken in memory for future use. DO NOT directly show it to user.",
128
+ }
129
+ }
130
+ }
131
+ else {
132
+ return {
133
+ success: false,
134
+ error: "Authentication failed",
135
+ errorDetails: "User info not found",
136
+ }
137
+ }
138
+ }
139
+ else {
140
+ // Generate unique session ID
141
+ const sessionId = crypto.randomUUID();
142
+
143
+ // Store session
144
+ await createAuthSession(sessionId, {
145
+ platform: platform.name,
146
+ hostname,
147
+ });
148
+
149
+ const authUri = composeAuthUri({ platform, sessionId, hostname });
150
+ return {
151
+ success: true,
152
+ data: {
153
+ authUri,
154
+ sessionId,
155
+ 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.",
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+ catch (error) {
162
+ return {
163
+ success: false,
164
+ error: error.message || 'Unknown error occurred',
165
+ errorDetails: error.stack
166
+ };
167
+ }
168
+ }
169
+
170
+ function composeAuthUri({ platform, sessionId, hostname }) {
171
+ // Build base state param
172
+ let stateParam = sessionId ?
173
+ `sessionId=${sessionId}&platform=${platform.name}&hostname=${hostname}` :
174
+ `platform=${platform.name}&hostname=${hostname}`;
175
+
176
+ // Merge customState if provided
177
+ if (platform.auth.oauth.customState) {
178
+ stateParam += `&${platform.auth.oauth.customState}`;
179
+ }
180
+
181
+ return `${platform.auth.oauth.authUrl}?` +
182
+ `response_type=code` +
183
+ `&client_id=${platform.auth.oauth.clientId}` +
184
+ `${!!platform.auth.oauth.scope && platform.auth.oauth.scope != '' ? `&${platform.auth.oauth.scope}` : ''}` +
185
+ `&state=${encodeURIComponent(stateParam)}` +
186
+ `&redirect_uri=${process.env.APP_SERVER}/oauth-callback`;
187
+ }
188
+
189
+ exports.definition = toolDefinition;
190
+ exports.execute = execute;
@@ -0,0 +1,92 @@
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
+ annotations: {
30
+ readOnlyHint: true,
31
+ openWorldHint: true,
32
+ destructiveHint: false
33
+ }
34
+ };
35
+
36
+ /**
37
+ * Execute the findContactByName tool
38
+ * @param {Object} args - The tool arguments
39
+ * @param {string} args.jwtToken - JWT token with user and platform info
40
+ * @param {string} args.name - Name to search for
41
+ * @returns {Object} Result object with contact information
42
+ */
43
+ async function execute(args) {
44
+ try {
45
+ const { jwtToken, name } = args;
46
+
47
+ // Decode JWT to get userId and platform
48
+ const { id: userId, platform } = jwt.decodeJwt(jwtToken);
49
+
50
+ if (!userId) {
51
+ throw new Error('Invalid JWT token: userId not found');
52
+ }
53
+
54
+ // Get the platform connector module
55
+ const platformModule = connectorRegistry.getConnector(platform);
56
+
57
+ if (!platformModule) {
58
+ throw new Error(`Platform connector not found for: ${platform}`);
59
+ }
60
+
61
+ // Check if findContactByName is implemented
62
+ if (!platformModule.findContactWithName) {
63
+ throw new Error(`findContactByName is not implemented for platform: ${platform}`);
64
+ }
65
+
66
+ // Call the findContactByName method
67
+ const { successful, returnMessage, contact } = await contactCore.findContactWithName({ platform, userId, name });
68
+ if (successful) {
69
+ return {
70
+ success: true,
71
+ data: contact,
72
+ };
73
+ }
74
+ else {
75
+ return {
76
+ success: false,
77
+ error: returnMessage.message,
78
+ };
79
+ }
80
+ }
81
+ catch (error) {
82
+ return {
83
+ success: false,
84
+ error: error.message || 'Unknown error occurred',
85
+ errorDetails: error.stack
86
+ };
87
+ }
88
+ }
89
+
90
+ exports.definition = toolDefinition;
91
+ exports.execute = execute;
92
+