@app-connect/core 1.7.36 → 1.7.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -16
- package/dist/connector/developerPortal.d.ts +6 -0
- package/{connector → dist/connector}/developerPortal.js +29 -12
- package/dist/connector/mock.d.ts +1 -0
- package/{connector → dist/connector}/mock.js +33 -17
- package/dist/connector/proxy/engine.d.ts +10 -0
- package/dist/connector/proxy/engine.js +222 -0
- package/dist/connector/proxy/index.d.ts +5 -0
- package/dist/connector/proxy/index.js +511 -0
- package/dist/connector/registry.d.ts +1 -0
- package/dist/connector/registry.js +243 -0
- package/dist/handlers/admin.d.ts +1 -0
- package/{handlers → dist/handlers}/admin.js +137 -78
- package/dist/handlers/appointment.d.ts +9 -0
- package/{handlers → dist/handlers}/appointment.js +58 -29
- package/dist/handlers/auth.d.ts +9 -0
- package/{handlers → dist/handlers}/auth.js +68 -40
- package/dist/handlers/calldown.d.ts +10 -0
- package/dist/handlers/calldown.js +134 -0
- package/dist/handlers/contact.d.ts +1 -0
- package/{handlers → dist/handlers}/contact.js +61 -39
- package/dist/handlers/disposition.d.ts +1 -0
- package/{handlers → dist/handlers}/disposition.js +20 -10
- package/dist/handlers/log.d.ts +1 -0
- package/{handlers → dist/handlers}/log.js +91 -124
- package/dist/handlers/managedAuth.d.ts +1 -0
- package/{handlers → dist/handlers}/managedAuth.js +134 -61
- package/dist/handlers/managedOAuth.d.ts +13 -0
- package/{handlers → dist/handlers}/managedOAuth.js +102 -30
- package/dist/handlers/plugin.d.ts +1 -0
- package/{handlers → dist/handlers}/plugin.js +59 -27
- package/dist/handlers/user.d.ts +1 -0
- package/{handlers → dist/handlers}/user.js +45 -27
- package/dist/index.d.ts +1 -0
- package/{index.js → dist/index.js} +548 -450
- package/dist/jest.config.d.ts +1 -0
- package/dist/jest.config.js +65 -0
- package/dist/lib/analytics.d.ts +4 -0
- package/{lib → dist/lib}/analytics.js +8 -6
- package/dist/lib/authSession.d.ts +5 -0
- package/{lib → dist/lib}/authSession.js +15 -43
- package/dist/lib/cacheCleanup.d.ts +4 -0
- package/{lib → dist/lib}/cacheCleanup.js +5 -17
- package/dist/lib/callLogComposer.d.ts +109 -0
- package/{lib → dist/lib}/callLogComposer.js +157 -197
- package/dist/lib/callLogLookup.d.ts +6 -0
- package/{lib → dist/lib}/callLogLookup.js +12 -34
- package/dist/lib/constants.d.ts +6 -0
- package/dist/lib/constants.js +9 -0
- package/dist/lib/debugTracer.d.ts +17 -0
- package/{lib → dist/lib}/debugTracer.js +7 -83
- package/dist/lib/encode.d.ts +3 -0
- package/dist/lib/encode.js +50 -0
- package/dist/lib/errorHandler.d.ts +7 -0
- package/dist/lib/errorHandler.js +161 -0
- package/dist/lib/generalErrorMessage.d.ts +7 -0
- package/{lib → dist/lib}/generalErrorMessage.js +6 -6
- package/dist/lib/jwt.d.ts +4 -0
- package/dist/lib/jwt.js +18 -0
- package/dist/lib/logger.d.ts +24 -0
- package/dist/lib/logger.js +126 -0
- package/dist/lib/migrateCallLogsSchema.d.ts +32 -0
- package/dist/lib/migrateCallLogsSchema.js +339 -0
- package/dist/lib/oauth.d.ts +4 -0
- package/{lib → dist/lib}/oauth.js +157 -160
- package/dist/lib/ringcentral.d.ts +24 -0
- package/dist/lib/ringcentral.js +226 -0
- package/dist/lib/s3ErrorLogReport.d.ts +4 -0
- package/{lib → dist/lib}/s3ErrorLogReport.js +11 -23
- package/dist/lib/sharedSMSComposer.d.ts +7 -0
- package/{lib → dist/lib}/sharedSMSComposer.js +21 -107
- package/dist/lib/util.d.ts +7 -0
- package/{lib → dist/lib}/util.js +9 -20
- package/dist/mcp/lib/oauthError.d.ts +1 -0
- package/dist/mcp/lib/oauthError.js +25 -0
- package/dist/mcp/lib/validator.d.ts +1 -0
- package/{mcp → dist/mcp}/lib/validator.js +16 -20
- package/dist/mcp/lib/widgetSessionToken.d.ts +1 -0
- package/dist/mcp/lib/widgetSessionToken.js +46 -0
- package/dist/mcp/mcpHandler.d.ts +8 -0
- package/{mcp → dist/mcp}/mcpHandler.js +98 -88
- package/dist/mcp/tools/cancelAppointment.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/cancelAppointment.js +7 -16
- package/dist/mcp/tools/checkAuthStatus.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/checkAuthStatus.js +21 -14
- package/dist/mcp/tools/confirmAppointment.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/confirmAppointment.js +7 -16
- package/dist/mcp/tools/createAppointment.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/createAppointment.js +7 -19
- package/dist/mcp/tools/createCallLog.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/createCallLog.js +18 -29
- package/dist/mcp/tools/createContact.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/createContact.js +8 -20
- package/dist/mcp/tools/createMessageLog.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/createMessageLog.js +14 -26
- package/dist/mcp/tools/doAuth.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/doAuth.js +17 -13
- package/dist/mcp/tools/findContactByName.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/findContactByName.js +9 -15
- package/dist/mcp/tools/findContactByPhone.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/findContactByPhone.js +8 -15
- package/dist/mcp/tools/getCallLog.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/getCallLog.js +12 -21
- package/dist/mcp/tools/getGoogleFilePicker.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/getGoogleFilePicker.js +9 -18
- package/dist/mcp/tools/getHelp.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/getHelp.js +5 -6
- package/dist/mcp/tools/getPublicConnectors.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/getPublicConnectors.js +19 -18
- package/dist/mcp/tools/getSessionInfo.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/getSessionInfo.js +10 -16
- package/dist/mcp/tools/index.d.ts +8 -0
- package/dist/mcp/tools/index.js +50 -0
- package/dist/mcp/tools/listAppointments.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/listAppointments.js +7 -19
- package/dist/mcp/tools/logout.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/logout.js +16 -14
- package/dist/mcp/tools/rcGetCallLogs.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/rcGetCallLogs.js +10 -8
- package/dist/mcp/tools/updateAppointment.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/updateAppointment.js +17 -22
- package/dist/mcp/tools/updateCallLog.d.ts +1 -0
- package/{mcp → dist/mcp}/tools/updateCallLog.js +16 -26
- package/dist/models/accountDataModel.d.ts +3 -0
- package/dist/models/accountDataModel.js +39 -0
- package/dist/models/adminConfigModel.d.ts +2 -0
- package/dist/models/adminConfigModel.js +39 -0
- package/dist/models/cacheModel.d.ts +2 -0
- package/{models → dist/models}/cacheModel.js +7 -3
- package/dist/models/callDownListModel.d.ts +2 -0
- package/{models → dist/models}/callDownListModel.js +8 -4
- package/dist/models/callLogModel.d.ts +2 -0
- package/dist/models/callLogModel.js +43 -0
- package/dist/models/dynamo/connectorSchema.d.ts +2 -0
- package/dist/models/dynamo/connectorSchema.js +141 -0
- package/dist/models/dynamo/lockSchema.d.ts +2 -0
- package/{models → dist/models}/dynamo/lockSchema.js +5 -7
- package/dist/models/dynamo/noteCacheSchema.d.ts +2 -0
- package/{models → dist/models}/dynamo/noteCacheSchema.js +4 -6
- package/dist/models/llmSessionModel.d.ts +2 -0
- package/dist/models/llmSessionModel.js +21 -0
- package/dist/models/messageLogModel.d.ts +2 -0
- package/{models → dist/models}/messageLogModel.js +8 -4
- package/dist/models/sequelize.d.ts +2 -0
- package/dist/models/sequelize.js +68 -0
- package/dist/models/userModel.d.ts +2 -0
- package/dist/models/userModel.js +49 -0
- package/dist/package.json +100 -0
- package/dist/releaseNotes.json +1222 -0
- package/dist/tsconfig.json +14 -0
- package/dist/types/admin.d.ts +141 -0
- package/dist/types/analytics.d.ts +14 -0
- package/dist/types/appointment.d.ts +50 -0
- package/dist/types/auth.d.ts +137 -0
- package/dist/types/authSession.d.ts +35 -0
- package/dist/types/cacheCleanup.d.ts +12 -0
- package/dist/types/calldown.d.ts +54 -0
- package/dist/types/common.d.ts +46 -0
- package/dist/types/connector.d.ts +165 -0
- package/dist/types/contact.d.ts +125 -0
- package/dist/types/errorHandler.d.ts +60 -0
- package/dist/types/index.d.ts +76 -0
- package/dist/types/json.d.ts +9 -0
- package/dist/types/jwt.d.ts +8 -0
- package/dist/types/logging.d.ts +224 -0
- package/dist/types/managedAuth.d.ts +114 -0
- package/dist/types/managedOAuth.d.ts +59 -0
- package/dist/types/manifest.d.ts +120 -0
- package/dist/types/migration.d.ts +15 -0
- package/dist/types/plugin.d.ts +74 -0
- package/dist/types/ringcentral.d.ts +61 -0
- package/dist/types/s3ErrorLogReport.d.ts +16 -0
- package/dist/types/sharedSMSComposer.d.ts +105 -0
- package/dist/types/user.d.ts +46 -0
- package/dist/types/util.d.ts +7 -0
- package/package.json +34 -6
- package/releaseNotes.json +13 -1
- package/.env.test +0 -5
- package/connector/proxy/engine.js +0 -165
- package/connector/proxy/index.js +0 -500
- package/connector/registry.js +0 -252
- package/docs/README.md +0 -50
- package/docs/architecture.md +0 -94
- package/docs/connectors.md +0 -116
- package/docs/handlers.md +0 -128
- package/docs/libraries.md +0 -98
- package/docs/models.md +0 -146
- package/docs/routes.md +0 -119
- package/docs/tests.md +0 -73
- package/handlers/calldown.js +0 -99
- package/jest.config.js +0 -57
- package/lib/constants.js +0 -9
- package/lib/encode.js +0 -30
- package/lib/errorHandler.js +0 -218
- package/lib/jwt.js +0 -18
- package/lib/logger.js +0 -190
- package/lib/migrateCallLogsSchema.js +0 -237
- package/lib/ringcentral.js +0 -267
- package/mcp/README.md +0 -420
- package/mcp/tools/index.js +0 -51
- package/mcp/ui/App/App.tsx +0 -358
- package/mcp/ui/App/components/AuthInfoForm.tsx +0 -113
- package/mcp/ui/App/components/AuthSuccess.tsx +0 -22
- package/mcp/ui/App/components/ConnectorList.tsx +0 -82
- package/mcp/ui/App/components/DebugPanel.tsx +0 -43
- package/mcp/ui/App/components/OAuthConnect.tsx +0 -270
- package/mcp/ui/App/lib/callTool.ts +0 -130
- package/mcp/ui/App/lib/debugLog.ts +0 -41
- package/mcp/ui/App/lib/developerPortal.ts +0 -111
- package/mcp/ui/App/main.css +0 -6
- package/mcp/ui/App/root.tsx +0 -13
- package/mcp/ui/dist/index.html +0 -53
- package/mcp/ui/vite.config.ts +0 -16
- package/models/accountDataModel.js +0 -34
- package/models/adminConfigModel.js +0 -35
- package/models/callLogModel.js +0 -39
- package/models/dynamo/connectorSchema.js +0 -146
- package/models/llmSessionModel.js +0 -17
- package/models/sequelize.js +0 -17
- package/models/userModel.js +0 -45
- package/test/connector/developerPortal.test.js +0 -166
- package/test/connector/mock.test.js +0 -131
- package/test/connector/proxy/engine.test.js +0 -211
- package/test/connector/proxy/index.test.js +0 -525
- package/test/connector/proxy/sample.json +0 -162
- package/test/connector/registry.test.js +0 -416
- package/test/handlers/admin.test.js +0 -960
- package/test/handlers/appointment.test.js +0 -260
- package/test/handlers/auth.test.js +0 -1096
- package/test/handlers/calldown.test.js +0 -310
- package/test/handlers/contact.test.js +0 -1014
- package/test/handlers/disposition.test.js +0 -396
- package/test/handlers/log.test.js +0 -1847
- package/test/handlers/managedAuth.test.js +0 -458
- package/test/handlers/managedOAuth.test.js +0 -262
- package/test/handlers/plugin.test.js +0 -429
- package/test/handlers/user.test.js +0 -381
- package/test/index.test.js +0 -301
- package/test/lib/analytics.test.js +0 -146
- package/test/lib/authSession.test.js +0 -173
- package/test/lib/cacheCleanup.test.js +0 -127
- package/test/lib/callLogComposer.test.js +0 -1231
- package/test/lib/debugTracer.test.js +0 -328
- package/test/lib/encode.test.js +0 -59
- package/test/lib/errorHandler.test.js +0 -246
- package/test/lib/generalErrorMessage.test.js +0 -82
- package/test/lib/jwt.test.js +0 -176
- package/test/lib/logger.test.js +0 -206
- package/test/lib/oauth.test.js +0 -359
- package/test/lib/ringcentral.test.js +0 -467
- package/test/lib/s3ErrorLogReport.test.js +0 -187
- package/test/lib/sharedSMSComposer.test.js +0 -1084
- package/test/lib/util.test.js +0 -329
- package/test/mcp/mcpHandler.test.js +0 -73
- package/test/mcp/mcpHandlerMore.test.js +0 -384
- package/test/mcp/tools/appointmentTools.test.js +0 -362
- package/test/mcp/tools/checkAuthStatus.test.js +0 -83
- package/test/mcp/tools/createCallLog.test.js +0 -436
- package/test/mcp/tools/createContact.test.js +0 -58
- package/test/mcp/tools/createMessageLog.test.js +0 -595
- package/test/mcp/tools/doAuth.test.js +0 -113
- package/test/mcp/tools/findContactByName.test.js +0 -275
- package/test/mcp/tools/findContactByPhone.test.js +0 -296
- package/test/mcp/tools/getCallLog.test.js +0 -298
- package/test/mcp/tools/getGoogleFilePicker.test.js +0 -281
- package/test/mcp/tools/getPublicConnectors.test.js +0 -107
- package/test/mcp/tools/getSessionInfo.test.js +0 -127
- package/test/mcp/tools/logout.test.js +0 -233
- package/test/mcp/tools/rcGetCallLogs.test.js +0 -56
- package/test/mcp/tools/updateCallLog.test.js +0 -360
- package/test/models/accountDataModel.test.js +0 -98
- package/test/models/callDownListModel.test.js +0 -125
- package/test/models/dynamo/connectorSchema.test.js +0 -189
- package/test/models/dynamo/lockSchema.test.js +0 -37
- package/test/models/dynamo/noteCacheSchema.test.js +0 -45
- package/test/models/llmSessionModel.test.js +0 -91
- package/test/models/models.test.js +0 -660
- package/test/routes/calldownRoutes.test.js +0 -224
- package/test/routes/coreRouterBroadRoutes.test.js +0 -855
- package/test/routes/dispositionRoutes.test.js +0 -192
- package/test/routes/managedAuthRoutes.test.js +0 -386
- package/test/routes/pluginRoutes.test.js +0 -262
- package/test/setup.js +0 -178
- /package/{mcp → dist/mcp}/ui/index.html +0 -0
- /package/{mcp → dist/mcp}/ui/package-lock.json +0 -0
- /package/{mcp → dist/mcp}/ui/package.json +0 -0
- /package/{mcp → dist/mcp}/ui/tsconfig.json +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* MCP Server for RC Unified CRM Extension
|
|
3
4
|
*
|
|
@@ -5,32 +6,41 @@
|
|
|
5
6
|
* Fully compatible with stateless deployments (AWS Lambda, etc.).
|
|
6
7
|
* All auth context is resolved per-request; rcExtensionId is cached in CacheModel.
|
|
7
8
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const {
|
|
14
|
-
const
|
|
15
|
-
const {
|
|
16
|
-
const
|
|
17
|
-
const
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
// @ts-check
|
|
11
|
+
const axios = /** @type {any} */ (require('axios'));
|
|
12
|
+
const { Op } = /** @type {any} */ (require('sequelize'));
|
|
13
|
+
const tools = /** @type {any} */ (require('./tools'));
|
|
14
|
+
const { LlmSessionModel: RawLlmSessionModel } = require('../models/llmSessionModel');
|
|
15
|
+
const LlmSessionModel = /** @type {any} */ (RawLlmSessionModel);
|
|
16
|
+
const { CacheModel: RawCacheModel } = require('../models/cacheModel');
|
|
17
|
+
const CacheModel = /** @type {any} */ (RawCacheModel);
|
|
18
|
+
const { UserModel: RawUserModel } = require('../models/userModel');
|
|
19
|
+
const UserModel = /** @type {any} */ (RawUserModel);
|
|
20
|
+
const { getHashValue: rawGetHashValue } = require('../lib/util');
|
|
21
|
+
const getHashValue = /** @type {any} */ (rawGetHashValue);
|
|
22
|
+
const jwt = /** @type {any} */ (require('../lib/jwt'));
|
|
23
|
+
const logger = /** @type {any} */ (require('../lib/logger'));
|
|
24
|
+
const { verifyWidgetSessionToken: rawVerifyWidgetSessionToken } = require('./lib/widgetSessionToken');
|
|
25
|
+
const verifyWidgetSessionToken = /** @type {any} */ (rawVerifyWidgetSessionToken);
|
|
26
|
+
const { MCP_OAUTH_INVALID_TOKEN_MESSAGE, buildMcpOAuthError: rawBuildMcpOAuthError, } = require('./lib/oauthError');
|
|
27
|
+
const buildMcpOAuthError = /** @type {any} */ (rawBuildMcpOAuthError);
|
|
18
28
|
const fs = require('fs');
|
|
19
29
|
const path = require('path');
|
|
20
|
-
|
|
21
30
|
/**
|
|
22
31
|
* Increment this to bust ChatGPT's widget resource cache after every UI build.
|
|
23
32
|
* This is the single source of truth — injected into getPublicConnectors _meta at response time.
|
|
24
33
|
*/
|
|
25
|
-
const WIDGET_VERSION =
|
|
34
|
+
const WIDGET_VERSION = 11;
|
|
26
35
|
const WIDGET_URI = `ui://widget/ConnectorList-v${WIDGET_VERSION}.html`;
|
|
27
36
|
const RC_EXTENSION_CACHE_KEY = 'rcExtensionId';
|
|
28
37
|
const RC_EXTENSION_CACHE_STATUS = 'resolved';
|
|
29
|
-
|
|
30
38
|
const JSON_RPC_INTERNAL_ERROR = -32603;
|
|
31
39
|
const JSON_RPC_METHOD_NOT_FOUND = -32601;
|
|
32
40
|
const JSON_RPC_INVALID_PARAMS = -32602;
|
|
33
|
-
|
|
41
|
+
function getWidgetSessionToken(req) {
|
|
42
|
+
return req.headers?.['x-app-connect-widget-token'] || req.headers?.['X-App-Connect-Widget-Token'];
|
|
43
|
+
}
|
|
34
44
|
/**
|
|
35
45
|
* JSON Schema definitions for tools that accept parameters.
|
|
36
46
|
* Without inputSchema, ChatGPT silently drops all arguments when calling the tool.
|
|
@@ -84,7 +94,6 @@ const inputSchemas = {
|
|
|
84
94
|
required: [],
|
|
85
95
|
},
|
|
86
96
|
};
|
|
87
|
-
|
|
88
97
|
const standardToolResultOutputSchema = {
|
|
89
98
|
type: 'object',
|
|
90
99
|
properties: {
|
|
@@ -96,7 +105,6 @@ const standardToolResultOutputSchema = {
|
|
|
96
105
|
},
|
|
97
106
|
required: ['success'],
|
|
98
107
|
};
|
|
99
|
-
|
|
100
108
|
/**
|
|
101
109
|
* JSON Schema definitions for each tool's structuredContent response.
|
|
102
110
|
* MCP clients use this from tools/list to understand and validate tool output.
|
|
@@ -173,38 +181,33 @@ const outputSchemas = {
|
|
|
173
181
|
confirmAppointment: standardToolResultOutputSchema,
|
|
174
182
|
cancelAppointment: standardToolResultOutputSchema,
|
|
175
183
|
};
|
|
176
|
-
|
|
177
184
|
/**
|
|
178
185
|
* Verify an RC access token and return the caller's extension ID.
|
|
179
186
|
* Throws if the token is invalid.
|
|
180
187
|
*/
|
|
181
188
|
async function resolveRcExtensionId(rcAccessToken) {
|
|
182
|
-
const resp = await axios.get(
|
|
183
|
-
'https://platform.ringcentral.com/restapi/v1.0/account/~/extension/~',
|
|
184
|
-
{ headers: { Authorization: `Bearer ${rcAccessToken}` } }
|
|
185
|
-
);
|
|
189
|
+
const resp = await axios.get('https://platform.ringcentral.com/restapi/v1.0/account/~/extension/~', { headers: { Authorization: `Bearer ${rcAccessToken}` } });
|
|
186
190
|
return resp.data?.id?.toString() ?? null;
|
|
187
191
|
}
|
|
188
|
-
|
|
189
192
|
/**
|
|
190
193
|
* Resolve rcExtensionId for the current request.
|
|
191
194
|
* Checks CacheModel first (avoids RC API call on Lambda cold starts),
|
|
192
195
|
* falls back to a live RC API verification and persists the result.
|
|
193
196
|
*/
|
|
194
197
|
async function resolveSessionContext(rcAccessToken, openaiSessionId) {
|
|
195
|
-
if (!rcAccessToken)
|
|
196
|
-
|
|
198
|
+
if (!rcAccessToken)
|
|
199
|
+
return { rcExtensionId: null };
|
|
197
200
|
if (openaiSessionId) {
|
|
198
201
|
try {
|
|
199
202
|
const cached = await CacheModel.findByPk(`${openaiSessionId}-${RC_EXTENSION_CACHE_KEY}`);
|
|
200
203
|
if (cached?.data?.rcExtensionId && (!cached.expiry || cached.expiry > new Date())) {
|
|
201
204
|
return { rcExtensionId: cached.data.rcExtensionId };
|
|
202
205
|
}
|
|
203
|
-
}
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
204
208
|
logger.warn('CacheModel lookup failed:', { message: err.message });
|
|
205
209
|
}
|
|
206
210
|
}
|
|
207
|
-
|
|
208
211
|
let rcExtensionId = null;
|
|
209
212
|
try {
|
|
210
213
|
rcExtensionId = await resolveRcExtensionId(rcAccessToken);
|
|
@@ -218,13 +221,19 @@ async function resolveSessionContext(rcAccessToken, openaiSessionId) {
|
|
|
218
221
|
expiry: new Date(Date.now() + 24 * 60 * 60 * 1000), // 24h TTL
|
|
219
222
|
});
|
|
220
223
|
}
|
|
221
|
-
}
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
222
226
|
logger.warn('Failed to resolve RC extension ID:', { message: err.message });
|
|
227
|
+
return {
|
|
228
|
+
rcExtensionId: null,
|
|
229
|
+
rcTokenError: buildMcpOAuthError({
|
|
230
|
+
message: MCP_OAUTH_INVALID_TOKEN_MESSAGE,
|
|
231
|
+
errorDetails: err.message,
|
|
232
|
+
}),
|
|
233
|
+
};
|
|
223
234
|
}
|
|
224
|
-
|
|
225
235
|
return { rcExtensionId };
|
|
226
236
|
}
|
|
227
|
-
|
|
228
237
|
/**
|
|
229
238
|
* Build the tools list to return in tools/list responses.
|
|
230
239
|
* Injects schema metadata and stamps WIDGET_URI into getPublicConnectors _meta.
|
|
@@ -244,7 +253,6 @@ function getToolsList() {
|
|
|
244
253
|
return def;
|
|
245
254
|
});
|
|
246
255
|
}
|
|
247
|
-
|
|
248
256
|
function getStructuredContent(result) {
|
|
249
257
|
if (result?.structuredContent && typeof result.structuredContent === 'object' && !Array.isArray(result.structuredContent)) {
|
|
250
258
|
return result.structuredContent;
|
|
@@ -254,7 +262,6 @@ function getStructuredContent(result) {
|
|
|
254
262
|
}
|
|
255
263
|
return { result: result ?? null };
|
|
256
264
|
}
|
|
257
|
-
|
|
258
265
|
function buildToolResult(toolDefinition, result) {
|
|
259
266
|
const structuredContent = getStructuredContent(result);
|
|
260
267
|
const responseResult = {
|
|
@@ -262,17 +269,14 @@ function buildToolResult(toolDefinition, result) {
|
|
|
262
269
|
? result.content
|
|
263
270
|
: [{ type: 'text', text: JSON.stringify(structuredContent, null, 2) }],
|
|
264
271
|
};
|
|
265
|
-
|
|
266
272
|
if (toolDefinition?.outputSchema || outputSchemas[toolDefinition?.name] || result?.structuredContent) {
|
|
267
273
|
responseResult.structuredContent = structuredContent;
|
|
268
274
|
}
|
|
269
275
|
if (structuredContent?.success === false) {
|
|
270
276
|
responseResult.isError = true;
|
|
271
277
|
}
|
|
272
|
-
|
|
273
278
|
return responseResult;
|
|
274
279
|
}
|
|
275
|
-
|
|
276
280
|
/**
|
|
277
281
|
* Handle incoming MCP HTTP requests.
|
|
278
282
|
* Stateless: each POST is handled independently with no session state between requests.
|
|
@@ -281,12 +285,9 @@ async function handleMcpRequest(req, res) {
|
|
|
281
285
|
try {
|
|
282
286
|
const { method, params, id } = req.body;
|
|
283
287
|
logger.info('Received MCP request:', { method });
|
|
284
|
-
|
|
285
288
|
const rcAccessToken = req.headers['authorization']?.split('Bearer ')?.[1];
|
|
286
289
|
const openaiSessionId = params?._meta?.['openai/session'] ?? null;
|
|
287
|
-
|
|
288
290
|
let response;
|
|
289
|
-
|
|
290
291
|
switch (method) {
|
|
291
292
|
case 'initialize':
|
|
292
293
|
response = {
|
|
@@ -305,7 +306,6 @@ async function handleMcpRequest(req, res) {
|
|
|
305
306
|
},
|
|
306
307
|
};
|
|
307
308
|
break;
|
|
308
|
-
|
|
309
309
|
case 'tools/list':
|
|
310
310
|
response = {
|
|
311
311
|
jsonrpc: '2.0',
|
|
@@ -313,15 +313,22 @@ async function handleMcpRequest(req, res) {
|
|
|
313
313
|
result: { tools: getToolsList() },
|
|
314
314
|
};
|
|
315
315
|
break;
|
|
316
|
-
|
|
317
316
|
case 'tools/call': {
|
|
318
317
|
const { name: toolName, arguments: args } = params;
|
|
319
318
|
const toolArgs = { ...(args || {}) };
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (openaiSessionId)
|
|
323
|
-
|
|
324
|
-
const { rcExtensionId } = await resolveSessionContext(rcAccessToken, openaiSessionId);
|
|
319
|
+
if (rcAccessToken)
|
|
320
|
+
toolArgs.rcAccessToken = rcAccessToken;
|
|
321
|
+
if (openaiSessionId)
|
|
322
|
+
toolArgs.openaiSessionId = openaiSessionId;
|
|
323
|
+
const { rcExtensionId, rcTokenError } = await resolveSessionContext(rcAccessToken, openaiSessionId);
|
|
324
|
+
if (rcTokenError) {
|
|
325
|
+
response = {
|
|
326
|
+
jsonrpc: '2.0',
|
|
327
|
+
id,
|
|
328
|
+
result: buildToolResult({ outputSchema: standardToolResultOutputSchema }, rcTokenError),
|
|
329
|
+
};
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
325
332
|
if (rcExtensionId) {
|
|
326
333
|
toolArgs.rcExtensionId = rcExtensionId;
|
|
327
334
|
if (!toolArgs.jwtToken) {
|
|
@@ -378,19 +385,18 @@ async function handleMcpRequest(req, res) {
|
|
|
378
385
|
}
|
|
379
386
|
}
|
|
380
387
|
}
|
|
381
|
-
|
|
382
388
|
try {
|
|
383
389
|
const tool = tools.tools.find(t => t.definition.name === toolName);
|
|
384
|
-
if (!tool)
|
|
385
|
-
|
|
390
|
+
if (!tool)
|
|
391
|
+
throw new Error(`Tool not found: ${toolName}`);
|
|
386
392
|
const result = await tool.execute(toolArgs);
|
|
387
|
-
|
|
388
393
|
response = {
|
|
389
394
|
jsonrpc: '2.0',
|
|
390
395
|
id,
|
|
391
396
|
result: buildToolResult(tool.definition, result),
|
|
392
397
|
};
|
|
393
|
-
}
|
|
398
|
+
}
|
|
399
|
+
catch (toolError) {
|
|
394
400
|
response = {
|
|
395
401
|
jsonrpc: '2.0',
|
|
396
402
|
id,
|
|
@@ -402,23 +408,21 @@ async function handleMcpRequest(req, res) {
|
|
|
402
408
|
}
|
|
403
409
|
break;
|
|
404
410
|
}
|
|
405
|
-
|
|
406
411
|
case 'resources/list':
|
|
407
412
|
response = {
|
|
408
413
|
jsonrpc: '2.0',
|
|
409
414
|
id,
|
|
410
415
|
result: {
|
|
411
416
|
resources: [{
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
417
|
+
uri: WIDGET_URI,
|
|
418
|
+
name: 'connector-list-widget',
|
|
419
|
+
title: 'ConnectorList',
|
|
420
|
+
description: 'ChatGPT widget for connector selection',
|
|
421
|
+
mimeType: 'text/html+skybridge',
|
|
422
|
+
}],
|
|
418
423
|
},
|
|
419
424
|
};
|
|
420
425
|
break;
|
|
421
|
-
|
|
422
426
|
case 'resources/read': {
|
|
423
427
|
const uri = params?.uri;
|
|
424
428
|
if (!uri?.startsWith('ui://widget/')) {
|
|
@@ -429,45 +433,44 @@ async function handleMcpRequest(req, res) {
|
|
|
429
433
|
};
|
|
430
434
|
break;
|
|
431
435
|
}
|
|
432
|
-
|
|
433
436
|
const appUrl = process.env.APP_SERVER || 'http://localhost:6066';
|
|
434
437
|
const distPath = path.join(__dirname, 'ui', 'dist', 'index.html');
|
|
435
438
|
const devPath = path.join(__dirname, 'ui', 'index.html');
|
|
436
439
|
let htmlContent;
|
|
437
|
-
try {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
+
try {
|
|
441
|
+
htmlContent = fs.readFileSync(distPath, 'utf8');
|
|
442
|
+
}
|
|
443
|
+
catch {
|
|
444
|
+
htmlContent = fs.readFileSync(devPath, 'utf8');
|
|
445
|
+
}
|
|
440
446
|
response = {
|
|
441
447
|
jsonrpc: '2.0',
|
|
442
448
|
id,
|
|
443
449
|
result: {
|
|
444
450
|
contents: [{
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
451
|
+
uri: WIDGET_URI,
|
|
452
|
+
mimeType: 'text/html+skybridge',
|
|
453
|
+
text: htmlContent,
|
|
454
|
+
_meta: {
|
|
455
|
+
'openai/widgetPrefersBorder': true,
|
|
456
|
+
'openai/widgetDomain': appUrl,
|
|
457
|
+
'openai/widgetCSP': {
|
|
458
|
+
connect_domains: [appUrl, 'https://appconnect.labs.ringcentral.com'],
|
|
459
|
+
resource_domains: [appUrl],
|
|
460
|
+
},
|
|
454
461
|
},
|
|
455
|
-
},
|
|
456
|
-
}],
|
|
462
|
+
}],
|
|
457
463
|
},
|
|
458
464
|
};
|
|
459
465
|
break;
|
|
460
466
|
}
|
|
461
|
-
|
|
462
467
|
case 'ping':
|
|
463
468
|
response = { jsonrpc: '2.0', id, result: {} };
|
|
464
469
|
break;
|
|
465
|
-
|
|
466
470
|
case 'notifications/initialized':
|
|
467
471
|
case 'notifications/cancelled':
|
|
468
472
|
// JSON-RPC notifications — no id, no response expected
|
|
469
473
|
return res.status(200).end();
|
|
470
|
-
|
|
471
474
|
default:
|
|
472
475
|
response = {
|
|
473
476
|
jsonrpc: '2.0',
|
|
@@ -475,9 +478,9 @@ async function handleMcpRequest(req, res) {
|
|
|
475
478
|
error: { code: JSON_RPC_METHOD_NOT_FOUND, message: `Method not found: ${method}` },
|
|
476
479
|
};
|
|
477
480
|
}
|
|
478
|
-
|
|
479
481
|
res.status(200).json(response);
|
|
480
|
-
}
|
|
482
|
+
}
|
|
483
|
+
catch (error) {
|
|
481
484
|
logger.error('Error handling MCP request:', { stack: error.stack });
|
|
482
485
|
res.status(200).json({
|
|
483
486
|
jsonrpc: '2.0',
|
|
@@ -490,7 +493,6 @@ async function handleMcpRequest(req, res) {
|
|
|
490
493
|
});
|
|
491
494
|
}
|
|
492
495
|
}
|
|
493
|
-
|
|
494
496
|
/**
|
|
495
497
|
* Handle widget tool calls via direct HTTP (bypasses MCP protocol).
|
|
496
498
|
* The ChatGPT postMessage bridge does not forward tool arguments,
|
|
@@ -499,25 +501,34 @@ async function handleMcpRequest(req, res) {
|
|
|
499
501
|
async function handleWidgetToolCall(req, res) {
|
|
500
502
|
try {
|
|
501
503
|
logger.info('Widget tool call received. body:', JSON.stringify(req.body));
|
|
502
|
-
|
|
503
504
|
const { tool: toolName, toolArgs: args } = req.body || {};
|
|
504
|
-
|
|
505
505
|
logger.info('Widget tool call parsed:', { toolName, args: JSON.stringify(args) });
|
|
506
|
-
|
|
506
|
+
const widgetContext = verifyWidgetSessionToken(getWidgetSessionToken(req));
|
|
507
|
+
if (!widgetContext) {
|
|
508
|
+
return res.status(401).json({ success: false, error: 'Invalid widget session' });
|
|
509
|
+
}
|
|
507
510
|
if (!toolName) {
|
|
508
511
|
return res.status(400).json({ success: false, error: 'Missing tool name' });
|
|
509
512
|
}
|
|
510
|
-
|
|
511
|
-
const allWidgetCallable = [...tools.tools, ...tools.widgetTools];
|
|
512
|
-
const tool = allWidgetCallable.find(t => t.definition.name === toolName);
|
|
513
|
+
const tool = tools.widgetTools.find(t => t.definition.name === toolName);
|
|
513
514
|
if (!tool) {
|
|
514
515
|
return res.status(404).json({ success: false, error: `Unknown tool: ${toolName}` });
|
|
515
516
|
}
|
|
516
|
-
|
|
517
|
-
|
|
517
|
+
const toolArgs = args && typeof args === 'object' ? args : {};
|
|
518
|
+
if (widgetContext.openaiSessionId &&
|
|
519
|
+
toolArgs.sessionId &&
|
|
520
|
+
toolArgs.sessionId !== widgetContext.openaiSessionId) {
|
|
521
|
+
return res.status(403).json({ success: false, error: 'Widget session mismatch' });
|
|
522
|
+
}
|
|
523
|
+
const result = await tool.execute({
|
|
524
|
+
...toolArgs,
|
|
525
|
+
rcExtensionId: widgetContext.rcExtensionId,
|
|
526
|
+
openaiSessionId: widgetContext.openaiSessionId,
|
|
527
|
+
});
|
|
518
528
|
logger.info('Widget tool call result:', { toolName, success: result?.success });
|
|
519
529
|
res.json(result);
|
|
520
|
-
}
|
|
530
|
+
}
|
|
531
|
+
catch (error) {
|
|
521
532
|
logger.error('Widget tool call error:', { stack: error.stack });
|
|
522
533
|
res.status(500).json({
|
|
523
534
|
success: false,
|
|
@@ -525,6 +536,5 @@ async function handleWidgetToolCall(req, res) {
|
|
|
525
536
|
});
|
|
526
537
|
}
|
|
527
538
|
}
|
|
528
|
-
|
|
529
539
|
exports.handleMcpRequest = handleMcpRequest;
|
|
530
540
|
exports.handleWidgetToolCall = handleWidgetToolCall;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
// @ts-check
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const jwt = /** @type {any} */ (require('../../lib/jwt'));
|
|
5
|
+
const connectorRegistry = /** @type {any} */ (require('../../connector/registry'));
|
|
6
|
+
const appointmentCore = /** @type {any} */ (require('../../handlers/appointment'));
|
|
5
7
|
/**
|
|
6
8
|
* MCP Tool: Cancel Appointment
|
|
7
9
|
*
|
|
8
10
|
* Cancels (deletes) an existing appointment/event in the CRM platform.
|
|
9
11
|
*/
|
|
10
|
-
|
|
11
12
|
const toolDefinition = {
|
|
12
13
|
name: 'cancelAppointment',
|
|
13
14
|
description: '⚠️ REQUIRES CRM CONNECTION. | Cancel an existing appointment or event in the CRM platform by its ID. This action is destructive — the appointment will be removed.',
|
|
@@ -27,51 +28,42 @@ const toolDefinition = {
|
|
|
27
28
|
destructiveHint: true
|
|
28
29
|
}
|
|
29
30
|
};
|
|
30
|
-
|
|
31
31
|
/**
|
|
32
32
|
* Execute the cancelAppointment tool
|
|
33
33
|
* @param {Object} args
|
|
34
34
|
* @param {string} args.jwtToken - Injected server-side JWT token
|
|
35
35
|
* @param {string} args.appointmentId - CRM appointment ID to cancel
|
|
36
|
-
* @returns {
|
|
36
|
+
* @returns {Promise<any>} Result with cancelled appointment data
|
|
37
37
|
*/
|
|
38
38
|
async function execute(args) {
|
|
39
39
|
try {
|
|
40
40
|
const { jwtToken, appointmentId } = args;
|
|
41
|
-
|
|
42
41
|
if (!jwtToken) {
|
|
43
42
|
throw new Error('Please go to Settings and authorize CRM platform');
|
|
44
43
|
}
|
|
45
|
-
|
|
46
44
|
if (!appointmentId) {
|
|
47
45
|
throw new Error('appointmentId is required');
|
|
48
46
|
}
|
|
49
|
-
|
|
50
47
|
const decodedToken = jwt.decodeJwt(jwtToken);
|
|
51
48
|
if (!decodedToken) {
|
|
52
49
|
throw new Error('Invalid JWT token');
|
|
53
50
|
}
|
|
54
51
|
const { id: userId, platform } = decodedToken;
|
|
55
|
-
|
|
56
52
|
if (!userId) {
|
|
57
53
|
throw new Error('Invalid JWT token: userId not found');
|
|
58
54
|
}
|
|
59
|
-
|
|
60
55
|
const platformModule = connectorRegistry.getConnector(platform);
|
|
61
56
|
if (!platformModule) {
|
|
62
57
|
throw new Error(`Platform connector not found for: ${platform}`);
|
|
63
58
|
}
|
|
64
|
-
|
|
65
59
|
if (!platformModule.cancelAppointment) {
|
|
66
60
|
throw new Error(`cancelAppointment is not implemented for platform: ${platform}`);
|
|
67
61
|
}
|
|
68
|
-
|
|
69
62
|
const { successful, appointment, returnMessage } = await appointmentCore.cancelAppointment({
|
|
70
63
|
platform,
|
|
71
64
|
userId,
|
|
72
65
|
appointmentId
|
|
73
66
|
});
|
|
74
|
-
|
|
75
67
|
if (successful) {
|
|
76
68
|
return {
|
|
77
69
|
success: true,
|
|
@@ -96,6 +88,5 @@ async function execute(args) {
|
|
|
96
88
|
};
|
|
97
89
|
}
|
|
98
90
|
}
|
|
99
|
-
|
|
100
91
|
exports.definition = toolDefinition;
|
|
101
92
|
exports.execute = execute;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
// @ts-check
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const { getAuthSession: rawGetAuthSession } = require('../../lib/authSession');
|
|
5
|
+
const getAuthSession = /** @type {any} */ (rawGetAuthSession);
|
|
6
|
+
const { LlmSessionModel: RawLlmSessionModel } = require('../../models/llmSessionModel');
|
|
7
|
+
const LlmSessionModel = /** @type {any} */ (RawLlmSessionModel);
|
|
4
8
|
/**
|
|
5
9
|
* MCP Tool: Check Auth Status
|
|
6
10
|
*
|
|
7
11
|
* Polls the status of an ongoing OAuth authentication session
|
|
8
12
|
*/
|
|
9
|
-
|
|
10
13
|
const toolDefinition = {
|
|
11
14
|
name: 'checkAuthStatus',
|
|
12
15
|
description: 'Check the status of an ongoing OAuth authentication session. Poll this after user clicks the auth link.',
|
|
@@ -26,13 +29,12 @@ const toolDefinition = {
|
|
|
26
29
|
destructiveHint: false
|
|
27
30
|
}
|
|
28
31
|
};
|
|
29
|
-
|
|
30
32
|
/**
|
|
31
33
|
* Execute the checkAuthStatus tool
|
|
32
34
|
* @param {Object} args - The tool arguments
|
|
33
35
|
* @param {string} args.sessionId - The session ID to check
|
|
34
36
|
* @param {string} args.rcExtensionId - The RC extension ID
|
|
35
|
-
* @returns {
|
|
37
|
+
* @returns {Promise<any>} Result object with authentication status
|
|
36
38
|
*/
|
|
37
39
|
async function execute(args) {
|
|
38
40
|
try {
|
|
@@ -44,16 +46,26 @@ async function execute(args) {
|
|
|
44
46
|
throw new Error('rcExtensionId is required');
|
|
45
47
|
}
|
|
46
48
|
const session = await getAuthSession(sessionId);
|
|
47
|
-
|
|
48
49
|
if (!session) {
|
|
49
50
|
return {
|
|
50
51
|
success: false,
|
|
51
52
|
error: 'CRM auth session not found or expired. Ask the user to start the auth flow again.'
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
+
if (session.rcExtensionId && session.rcExtensionId !== rcExtensionId) {
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
error: 'CRM auth session does not belong to this RingCentral extension.'
|
|
59
|
+
};
|
|
60
|
+
}
|
|
55
61
|
switch (session.status) {
|
|
56
62
|
case 'completed':
|
|
63
|
+
if (!session.jwtToken) {
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
error: 'CRM auth session completed without a CRM token.'
|
|
67
|
+
};
|
|
68
|
+
}
|
|
57
69
|
await LlmSessionModel.upsert({
|
|
58
70
|
id: rcExtensionId,
|
|
59
71
|
jwtToken: session.jwtToken,
|
|
@@ -62,12 +74,10 @@ async function execute(args) {
|
|
|
62
74
|
return {
|
|
63
75
|
data: {
|
|
64
76
|
status: 'completed',
|
|
65
|
-
jwtToken: session.jwtToken,
|
|
66
77
|
userInfo: session.userInfo,
|
|
67
|
-
message: '
|
|
78
|
+
message: 'Authentication successful. CRM token stored server-side for future tool calls.'
|
|
68
79
|
}
|
|
69
80
|
};
|
|
70
|
-
|
|
71
81
|
case 'expired':
|
|
72
82
|
return {
|
|
73
83
|
data: {
|
|
@@ -75,7 +85,6 @@ async function execute(args) {
|
|
|
75
85
|
errorMessage: 'Authentication session expired. Ask the user to start the auth flow again.'
|
|
76
86
|
}
|
|
77
87
|
};
|
|
78
|
-
|
|
79
88
|
case 'failed':
|
|
80
89
|
return {
|
|
81
90
|
data: {
|
|
@@ -83,7 +92,6 @@ async function execute(args) {
|
|
|
83
92
|
errorMessage: session.errorMessage || 'Unknown error'
|
|
84
93
|
}
|
|
85
94
|
};
|
|
86
|
-
|
|
87
95
|
case 'pending':
|
|
88
96
|
default:
|
|
89
97
|
return {
|
|
@@ -100,6 +108,5 @@ async function execute(args) {
|
|
|
100
108
|
};
|
|
101
109
|
}
|
|
102
110
|
}
|
|
103
|
-
|
|
104
111
|
exports.definition = toolDefinition;
|
|
105
112
|
exports.execute = execute;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
// @ts-check
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const jwt = /** @type {any} */ (require('../../lib/jwt'));
|
|
5
|
+
const connectorRegistry = /** @type {any} */ (require('../../connector/registry'));
|
|
6
|
+
const appointmentCore = /** @type {any} */ (require('../../handlers/appointment'));
|
|
5
7
|
/**
|
|
6
8
|
* MCP Tool: Confirm Appointment
|
|
7
9
|
*
|
|
8
10
|
* Marks an existing appointment/event as confirmed in the CRM platform.
|
|
9
11
|
*/
|
|
10
|
-
|
|
11
12
|
const toolDefinition = {
|
|
12
13
|
name: 'confirmAppointment',
|
|
13
14
|
description: '⚠️ REQUIRES CRM CONNECTION. | Confirm an existing appointment or event in the CRM platform by its ID. Returns the updated appointment details.',
|
|
@@ -27,51 +28,42 @@ const toolDefinition = {
|
|
|
27
28
|
destructiveHint: false
|
|
28
29
|
}
|
|
29
30
|
};
|
|
30
|
-
|
|
31
31
|
/**
|
|
32
32
|
* Execute the confirmAppointment tool
|
|
33
33
|
* @param {Object} args
|
|
34
34
|
* @param {string} args.jwtToken - Injected server-side JWT token
|
|
35
35
|
* @param {string} args.appointmentId - CRM appointment ID to confirm
|
|
36
|
-
* @returns {
|
|
36
|
+
* @returns {Promise<any>} Result with updated appointment data
|
|
37
37
|
*/
|
|
38
38
|
async function execute(args) {
|
|
39
39
|
try {
|
|
40
40
|
const { jwtToken, appointmentId } = args;
|
|
41
|
-
|
|
42
41
|
if (!jwtToken) {
|
|
43
42
|
throw new Error('Please go to Settings and authorize CRM platform');
|
|
44
43
|
}
|
|
45
|
-
|
|
46
44
|
if (!appointmentId) {
|
|
47
45
|
throw new Error('appointmentId is required');
|
|
48
46
|
}
|
|
49
|
-
|
|
50
47
|
const decodedToken = jwt.decodeJwt(jwtToken);
|
|
51
48
|
if (!decodedToken) {
|
|
52
49
|
throw new Error('Invalid JWT token');
|
|
53
50
|
}
|
|
54
51
|
const { id: userId, platform } = decodedToken;
|
|
55
|
-
|
|
56
52
|
if (!userId) {
|
|
57
53
|
throw new Error('Invalid JWT token: userId not found');
|
|
58
54
|
}
|
|
59
|
-
|
|
60
55
|
const platformModule = connectorRegistry.getConnector(platform);
|
|
61
56
|
if (!platformModule) {
|
|
62
57
|
throw new Error(`Platform connector not found for: ${platform}`);
|
|
63
58
|
}
|
|
64
|
-
|
|
65
59
|
if (!platformModule.confirmAppointment) {
|
|
66
60
|
throw new Error(`confirmAppointment is not implemented for platform: ${platform}`);
|
|
67
61
|
}
|
|
68
|
-
|
|
69
62
|
const { successful, appointment, returnMessage } = await appointmentCore.confirmAppointment({
|
|
70
63
|
platform,
|
|
71
64
|
userId,
|
|
72
65
|
appointmentId
|
|
73
66
|
});
|
|
74
|
-
|
|
75
67
|
if (successful) {
|
|
76
68
|
return {
|
|
77
69
|
success: true,
|
|
@@ -96,6 +88,5 @@ async function execute(args) {
|
|
|
96
88
|
};
|
|
97
89
|
}
|
|
98
90
|
}
|
|
99
|
-
|
|
100
91
|
exports.definition = toolDefinition;
|
|
101
92
|
exports.execute = execute;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|