@carbonvoice/cv-mcp-server 1.0.13 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/auth-middleware.js +203 -0
- package/dist/auth/auth-middleware.js.map +1 -0
- package/dist/auth/index.js +3 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/interfaces/index.js +18 -0
- package/dist/auth/interfaces/index.js.map +1 -0
- package/dist/auth/interfaces/user.interface.js +3 -0
- package/dist/auth/interfaces/user.interface.js.map +1 -0
- package/dist/config/env.js +19 -1
- package/dist/config/env.js.map +1 -0
- package/dist/config/index.js +1 -0
- package/dist/config/index.js.map +1 -0
- package/dist/constants.js +6 -1
- package/dist/constants.js.map +1 -0
- package/dist/cv-api.js +25 -0
- package/dist/cv-api.js.map +1 -0
- package/dist/generated/carbon-voice-api/CarbonVoiceSimplifiedAPI.zod.js +1 -0
- package/dist/generated/carbon-voice-api/CarbonVoiceSimplifiedAPI.zod.js.map +1 -0
- package/dist/generated/carbon-voice-api.js +75 -129
- package/dist/generated/carbon-voice-api.js.map +1 -0
- package/dist/generated/index.js +1 -0
- package/dist/generated/index.js.map +1 -0
- package/dist/generated/models/AIPrompt.js +1 -0
- package/dist/generated/models/AIPrompt.js.map +1 -0
- package/dist/generated/models/AIPromptControllerGetPromptsOwnerType.js +1 -0
- package/dist/generated/models/AIPromptControllerGetPromptsOwnerType.js.map +1 -0
- package/dist/generated/models/AIPromptControllerGetPromptsParams.js +1 -0
- package/dist/generated/models/AIPromptControllerGetPromptsParams.js.map +1 -0
- package/dist/generated/models/AIPromptOwnerType.js +1 -0
- package/dist/generated/models/AIPromptOwnerType.js.map +1 -0
- package/dist/generated/models/AIPromptResponseFormat.js +1 -0
- package/dist/generated/models/AIPromptResponseFormat.js.map +1 -0
- package/dist/generated/models/AIPromptWithMessagesResponse.js +1 -0
- package/dist/generated/models/AIPromptWithMessagesResponse.js.map +1 -0
- package/dist/generated/models/AIPromptWithMessagesResult.js +1 -0
- package/dist/generated/models/AIPromptWithMessagesResult.js.map +1 -0
- package/dist/generated/models/AIResponse.js +1 -0
- package/dist/generated/models/AIResponse.js.map +1 -0
- package/dist/generated/models/AIResponseControllerGetAllResponsesDirection.js +1 -0
- package/dist/generated/models/AIResponseControllerGetAllResponsesDirection.js.map +1 -0
- package/dist/generated/models/AIResponseControllerGetAllResponsesParams.js +1 -0
- package/dist/generated/models/AIResponseControllerGetAllResponsesParams.js.map +1 -0
- package/dist/generated/models/AIShareLinkResponse.js +1 -0
- package/dist/generated/models/AIShareLinkResponse.js.map +1 -0
- package/dist/generated/models/AddAttachmentsResponse.js +1 -0
- package/dist/generated/models/AddAttachmentsResponse.js.map +1 -0
- package/dist/generated/models/AddLinkAttachmentPayload.js +1 -0
- package/dist/generated/models/AddLinkAttachmentPayload.js.map +1 -0
- package/dist/generated/models/AddMessageToFolderPayload.js +1 -0
- package/dist/generated/models/AddMessageToFolderPayload.js.map +1 -0
- package/dist/generated/models/AllConversationsResponse.js +1 -0
- package/dist/generated/models/AllConversationsResponse.js.map +1 -0
- package/dist/generated/models/App.js +1 -0
- package/dist/generated/models/App.js.map +1 -0
- package/dist/generated/models/AppWebhooksAuthenticationHeader.js +1 -0
- package/dist/generated/models/AppWebhooksAuthenticationHeader.js.map +1 -0
- package/dist/generated/models/AppWebhooksUrlMode.js +1 -0
- package/dist/generated/models/AppWebhooksUrlMode.js.map +1 -0
- package/dist/generated/models/AsyncConversationStats.js +1 -0
- package/dist/generated/models/AsyncConversationStats.js.map +1 -0
- package/dist/generated/models/Attachment.js +1 -0
- package/dist/generated/models/Attachment.js.map +1 -0
- package/dist/generated/models/AttachmentLocation.js +1 -0
- package/dist/generated/models/AttachmentLocation.js.map +1 -0
- package/dist/generated/models/AttachmentType.js +1 -0
- package/dist/generated/models/AttachmentType.js.map +1 -0
- package/dist/generated/models/AudioModelV2.js +1 -0
- package/dist/generated/models/AudioModelV2.js.map +1 -0
- package/dist/generated/models/Conversation.js +1 -0
- package/dist/generated/models/Conversation.js.map +1 -0
- package/dist/generated/models/ConversationResponse.js +1 -0
- package/dist/generated/models/ConversationResponse.js.map +1 -0
- package/dist/generated/models/ConversationResponseType.js +1 -0
- package/dist/generated/models/ConversationResponseType.js.map +1 -0
- package/dist/generated/models/ConversationType.js +1 -0
- package/dist/generated/models/ConversationType.js.map +1 -0
- package/dist/generated/models/ConversationVisibility.js +1 -0
- package/dist/generated/models/ConversationVisibility.js.map +1 -0
- package/dist/generated/models/CreateAIPrompt.js +1 -0
- package/dist/generated/models/CreateAIPrompt.js.map +1 -0
- package/dist/generated/models/CreateAIPromptOwnerType.js +1 -0
- package/dist/generated/models/CreateAIPromptOwnerType.js.map +1 -0
- package/dist/generated/models/CreateAIPromptResponseFormat.js +1 -0
- package/dist/generated/models/CreateAIPromptResponseFormat.js.map +1 -0
- package/dist/generated/models/CreateAIResponse.js +1 -0
- package/dist/generated/models/CreateAIResponse.js.map +1 -0
- package/dist/generated/models/CreateConversationMessage.js +1 -0
- package/dist/generated/models/CreateConversationMessage.js.map +1 -0
- package/dist/generated/models/CreateConversationMessageFromMessageType.js +1 -0
- package/dist/generated/models/CreateConversationMessageFromMessageType.js.map +1 -0
- package/dist/generated/models/CreateFolderPayload.js +1 -0
- package/dist/generated/models/CreateFolderPayload.js.map +1 -0
- package/dist/generated/models/CreateFolderPayloadType.js +1 -0
- package/dist/generated/models/CreateFolderPayloadType.js.map +1 -0
- package/dist/generated/models/CreateShareLinkAIResponse.js +1 -0
- package/dist/generated/models/CreateShareLinkAIResponse.js.map +1 -0
- package/dist/generated/models/CreateVoicememoMessage.js +1 -0
- package/dist/generated/models/CreateVoicememoMessage.js.map +1 -0
- package/dist/generated/models/Folder.js +1 -0
- package/dist/generated/models/Folder.js.map +1 -0
- package/dist/generated/models/FolderType.js +1 -0
- package/dist/generated/models/FolderType.js.map +1 -0
- package/dist/generated/models/FolderWithMessages.js +1 -0
- package/dist/generated/models/FolderWithMessages.js.map +1 -0
- package/dist/generated/models/GetAllRootFoldersParams.js +1 -0
- package/dist/generated/models/GetAllRootFoldersParams.js.map +1 -0
- package/dist/generated/models/GetAllRootFoldersSortBy.js +1 -0
- package/dist/generated/models/GetAllRootFoldersSortBy.js.map +1 -0
- package/dist/generated/models/GetAllRootFoldersSortDirection.js +1 -0
- package/dist/generated/models/GetAllRootFoldersSortDirection.js.map +1 -0
- package/dist/generated/models/GetAllRootFoldersType.js +1 -0
- package/dist/generated/models/GetAllRootFoldersType.js.map +1 -0
- package/dist/generated/models/GetCountsGroupedByWorkspaceParams.js +1 -0
- package/dist/generated/models/GetCountsGroupedByWorkspaceParams.js.map +1 -0
- package/dist/generated/models/GetCountsGroupedByWorkspaceType.js +1 -0
- package/dist/generated/models/GetCountsGroupedByWorkspaceType.js.map +1 -0
- package/dist/generated/models/GetFolderByIdDirection.js +1 -0
- package/dist/generated/models/GetFolderByIdDirection.js.map +1 -0
- package/dist/generated/models/GetFolderByIdParams.js +1 -0
- package/dist/generated/models/GetFolderByIdParams.js.map +1 -0
- package/dist/generated/models/GetMessageByIdParams.js +1 -0
- package/dist/generated/models/GetMessageByIdParams.js.map +1 -0
- package/dist/generated/models/GetMessageResponse.js +1 -0
- package/dist/generated/models/GetMessageResponse.js.map +1 -0
- package/dist/generated/models/GetTenRecentAIPromptResponse.js +1 -0
- package/dist/generated/models/GetTenRecentAIPromptResponse.js.map +1 -0
- package/dist/generated/models/GetTenRecentMessagesResponse.js +1 -0
- package/dist/generated/models/GetTenRecentMessagesResponse.js.map +1 -0
- package/dist/generated/models/GetTenRecentMessagesResponseParams.js +1 -0
- package/dist/generated/models/GetTenRecentMessagesResponseParams.js.map +1 -0
- package/dist/generated/models/Label.js +1 -0
- package/dist/generated/models/Label.js.map +1 -0
- package/dist/generated/models/LabelBehavior.js +1 -0
- package/dist/generated/models/LabelBehavior.js.map +1 -0
- package/dist/generated/models/LabelType.js +1 -0
- package/dist/generated/models/LabelType.js.map +1 -0
- package/dist/generated/models/Language.js +1 -0
- package/dist/generated/models/Language.js.map +1 -0
- package/dist/generated/models/ListCountFoldersGroupedByWorkspace.js +1 -0
- package/dist/generated/models/ListCountFoldersGroupedByWorkspace.js.map +1 -0
- package/dist/generated/models/ListFoldersResponse.js +1 -0
- package/dist/generated/models/ListFoldersResponse.js.map +1 -0
- package/dist/generated/models/ListFoldersResponseSortBy.js +1 -0
- package/dist/generated/models/ListFoldersResponseSortBy.js.map +1 -0
- package/dist/generated/models/ListFoldersResponseSortDirection.js +1 -0
- package/dist/generated/models/ListFoldersResponseSortDirection.js.map +1 -0
- package/dist/generated/models/ListFoldersResponseType.js +1 -0
- package/dist/generated/models/ListFoldersResponseType.js.map +1 -0
- package/dist/generated/models/ListMessagesFilter.js +1 -0
- package/dist/generated/models/ListMessagesFilter.js.map +1 -0
- package/dist/generated/models/ListMessagesFilterType.js +1 -0
- package/dist/generated/models/ListMessagesFilterType.js.map +1 -0
- package/dist/generated/models/ListMessagesParams.js +1 -0
- package/dist/generated/models/ListMessagesParams.js.map +1 -0
- package/dist/generated/models/ListMessagesResponse.js +1 -0
- package/dist/generated/models/ListMessagesResponse.js.map +1 -0
- package/dist/generated/models/ListMessagesResponseSortDirection.js +1 -0
- package/dist/generated/models/ListMessagesResponseSortDirection.js.map +1 -0
- package/dist/generated/models/ListMessagesSortDirection.js +1 -0
- package/dist/generated/models/ListMessagesSortDirection.js.map +1 -0
- package/dist/generated/models/ListMessagesType.js +1 -0
- package/dist/generated/models/ListMessagesType.js.map +1 -0
- package/dist/generated/models/Message.js +1 -0
- package/dist/generated/models/Message.js.map +1 -0
- package/dist/generated/models/MessageStatus.js +1 -0
- package/dist/generated/models/MessageStatus.js.map +1 -0
- package/dist/generated/models/MessageType.js +1 -0
- package/dist/generated/models/MessageType.js.map +1 -0
- package/dist/generated/models/MessageV2.js +1 -0
- package/dist/generated/models/MessageV2.js.map +1 -0
- package/dist/generated/models/MessageV2AudioDelivery.js +1 -0
- package/dist/generated/models/MessageV2AudioDelivery.js.map +1 -0
- package/dist/generated/models/MessageV2Status.js +1 -0
- package/dist/generated/models/MessageV2Status.js.map +1 -0
- package/dist/generated/models/MessageV2Type.js +1 -0
- package/dist/generated/models/MessageV2Type.js.map +1 -0
- package/dist/generated/models/MessageV2UsersCaughtUp.js +1 -0
- package/dist/generated/models/MessageV2UsersCaughtUp.js.map +1 -0
- package/dist/generated/models/MessageV2UtmData.js +1 -0
- package/dist/generated/models/MessageV2UtmData.js.map +1 -0
- package/dist/generated/models/MoveFolderPayload.js +1 -0
- package/dist/generated/models/MoveFolderPayload.js.map +1 -0
- package/dist/generated/models/PromptResponse.js +1 -0
- package/dist/generated/models/PromptResponse.js.map +1 -0
- package/dist/generated/models/ReactionSummary.js +1 -0
- package/dist/generated/models/ReactionSummary.js.map +1 -0
- package/dist/generated/models/ReactionSummaryReactionCounts.js +1 -0
- package/dist/generated/models/ReactionSummaryReactionCounts.js.map +1 -0
- package/dist/generated/models/ResponseByLanguage.js +1 -0
- package/dist/generated/models/ResponseByLanguage.js.map +1 -0
- package/dist/generated/models/ResponseByLanguageJson.js +1 -0
- package/dist/generated/models/ResponseByLanguageJson.js.map +1 -0
- package/dist/generated/models/SearchUserParams.js +1 -0
- package/dist/generated/models/SearchUserParams.js.map +1 -0
- package/dist/generated/models/SearchUsersBody.js +1 -0
- package/dist/generated/models/SearchUsersBody.js.map +1 -0
- package/dist/generated/models/SendDirectMessage.js +1 -0
- package/dist/generated/models/SendDirectMessage.js.map +1 -0
- package/dist/generated/models/SendDirectMessageFromMessageType.js +1 -0
- package/dist/generated/models/SendDirectMessageFromMessageType.js.map +1 -0
- package/dist/generated/models/SimplifiedAIPrompt.js +1 -0
- package/dist/generated/models/SimplifiedAIPrompt.js.map +1 -0
- package/dist/generated/models/Stats.js +1 -0
- package/dist/generated/models/Stats.js.map +1 -0
- package/dist/generated/models/SubFolder.js +1 -0
- package/dist/generated/models/SubFolder.js.map +1 -0
- package/dist/generated/models/SubFolderType.js +1 -0
- package/dist/generated/models/SubFolderType.js.map +1 -0
- package/dist/generated/models/SubscribeUserPayload.js +1 -0
- package/dist/generated/models/SubscribeUserPayload.js.map +1 -0
- package/dist/generated/models/SubscribeUserPayloadSubscriptionsItem.js +1 -0
- package/dist/generated/models/SubscribeUserPayloadSubscriptionsItem.js.map +1 -0
- package/dist/generated/models/SubscribedUser.js +1 -0
- package/dist/generated/models/SubscribedUser.js.map +1 -0
- package/dist/generated/models/SubscribedUserSubscriptionsItem.js +1 -0
- package/dist/generated/models/SubscribedUserSubscriptionsItem.js.map +1 -0
- package/dist/generated/models/SubscriptionAction.js +1 -0
- package/dist/generated/models/SubscriptionAction.js.map +1 -0
- package/dist/generated/models/SubscriptionActionActionId.js +1 -0
- package/dist/generated/models/SubscriptionActionActionId.js.map +1 -0
- package/dist/generated/models/SubscriptionActionEntityType.js +1 -0
- package/dist/generated/models/SubscriptionActionEntityType.js.map +1 -0
- package/dist/generated/models/SubscriptionFilter.js +1 -0
- package/dist/generated/models/SubscriptionFilter.js.map +1 -0
- package/dist/generated/models/SubscriptionFilterOperator.js +1 -0
- package/dist/generated/models/SubscriptionFilterOperator.js.map +1 -0
- package/dist/generated/models/SubscriptionFilterValue.js +1 -0
- package/dist/generated/models/SubscriptionFilterValue.js.map +1 -0
- package/dist/generated/models/TextModel.js +1 -0
- package/dist/generated/models/TextModel.js.map +1 -0
- package/dist/generated/models/TextModelType.js +1 -0
- package/dist/generated/models/TextModelType.js.map +1 -0
- package/dist/generated/models/TimedText.js +1 -0
- package/dist/generated/models/TimedText.js.map +1 -0
- package/dist/generated/models/ToRecipient.js +1 -0
- package/dist/generated/models/ToRecipient.js.map +1 -0
- package/dist/generated/models/UpdateFolderNamePayload.js +1 -0
- package/dist/generated/models/UpdateFolderNamePayload.js.map +1 -0
- package/dist/generated/models/User.js +1 -0
- package/dist/generated/models/User.js.map +1 -0
- package/dist/generated/models/UserReaction.js +1 -0
- package/dist/generated/models/UserReaction.js.map +1 -0
- package/dist/generated/models/UserStats.js +1 -0
- package/dist/generated/models/UserStats.js.map +1 -0
- package/dist/generated/models/UsersNotAllowedReceiveNotifications.js +1 -0
- package/dist/generated/models/UsersNotAllowedReceiveNotifications.js.map +1 -0
- package/dist/generated/models/UsersNotAllowedReceiveNotificationsV2.js +1 -0
- package/dist/generated/models/UsersNotAllowedReceiveNotificationsV2.js.map +1 -0
- package/dist/generated/models/UtmData.js +1 -0
- package/dist/generated/models/UtmData.js.map +1 -0
- package/dist/generated/models/Voice.js +1 -0
- package/dist/generated/models/Voice.js.map +1 -0
- package/dist/generated/models/VoiceGender.js +1 -0
- package/dist/generated/models/VoiceGender.js.map +1 -0
- package/dist/generated/models/VoiceQuality.js +1 -0
- package/dist/generated/models/VoiceQuality.js.map +1 -0
- package/dist/generated/models/VoiceType.js +1 -0
- package/dist/generated/models/VoiceType.js.map +1 -0
- package/dist/generated/models/WorkspaceBasicInfo.js +1 -0
- package/dist/generated/models/WorkspaceBasicInfo.js.map +1 -0
- package/dist/generated/models/index.js +1 -0
- package/dist/generated/models/index.js.map +1 -0
- package/dist/interfaces/conversation.interface.js +1 -0
- package/dist/interfaces/conversation.interface.js.map +1 -0
- package/dist/interfaces/folder.interface.js +1 -0
- package/dist/interfaces/folder.interface.js.map +1 -0
- package/dist/interfaces/get-by-id.interface.js +1 -0
- package/dist/interfaces/get-by-id.interface.js.map +1 -0
- package/dist/interfaces/index.js +1 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interfaces/mcp-tool-response.interface.js +1 -0
- package/dist/interfaces/mcp-tool-response.interface.js.map +1 -0
- package/dist/interfaces/message.interface.js +1 -0
- package/dist/interfaces/message.interface.js.map +1 -0
- package/dist/schemas/conversation.js +1 -0
- package/dist/schemas/conversation.js.map +1 -0
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/message.js +1 -0
- package/dist/schemas/message.js.map +1 -0
- package/dist/server.js +109 -71
- package/dist/server.js.map +1 -0
- package/dist/transports/http/constants.js +5 -0
- package/dist/transports/http/constants.js.map +1 -0
- package/dist/transports/http/index.js +19 -0
- package/dist/transports/http/index.js.map +1 -0
- package/dist/transports/http/middleware/add-mcp-session-id.middleware.js +28 -0
- package/dist/transports/http/middleware/add-mcp-session-id.middleware.js.map +1 -0
- package/dist/transports/http/middleware/add-request-id.middlware.js +11 -0
- package/dist/transports/http/middleware/add-request-id.middlware.js.map +1 -0
- package/dist/transports/http/middleware/auth-error-logger.middleware.js +31 -0
- package/dist/transports/http/middleware/auth-error-logger.middleware.js.map +1 -0
- package/dist/transports/http/middleware/index.js +24 -0
- package/dist/transports/http/middleware/index.js.map +1 -0
- package/dist/transports/http/middleware/log-request.middlware.js +31 -0
- package/dist/transports/http/middleware/log-request.middlware.js.map +1 -0
- package/dist/transports/http/middleware/oauth-authorization-server.middleware.js +24 -0
- package/dist/transports/http/middleware/oauth-authorization-server.middleware.js.map +1 -0
- package/dist/transports/http/middleware/oauth-protected-resource.middleware.js +19 -0
- package/dist/transports/http/middleware/oauth-protected-resource.middleware.js.map +1 -0
- package/dist/transports/http/middleware/well-known-cors-headers.middleware.js +23 -0
- package/dist/transports/http/middleware/well-known-cors-headers.middleware.js.map +1 -0
- package/dist/transports/http/streamable.js +661 -0
- package/dist/transports/http/streamable.js.map +1 -0
- package/dist/transports/http/utils/get-or-create-session-id.js +19 -0
- package/dist/transports/http/utils/get-or-create-session-id.js.map +1 -0
- package/dist/transports/http/utils/index.js +18 -0
- package/dist/transports/http/utils/index.js.map +1 -0
- package/dist/transports/stdio/index.js +18 -0
- package/dist/transports/stdio/index.js.map +1 -0
- package/dist/transports/stdio/stdio.js +27 -0
- package/dist/transports/stdio/stdio.js.map +1 -0
- package/dist/utils/axios-instance.js +85 -32
- package/dist/utils/axios-instance.js.map +1 -0
- package/dist/utils/format-time-to-human.js +33 -0
- package/dist/utils/format-time-to-human.js.map +1 -0
- package/dist/utils/format-to-mcp-tool-response.js +1 -0
- package/dist/utils/format-to-mcp-tool-response.js.map +1 -0
- package/dist/utils/format-uptime.js +13 -0
- package/dist/utils/format-uptime.js.map +1 -0
- package/dist/utils/get-user-id-from-headers.js +11 -0
- package/dist/utils/get-user-id-from-headers.js.map +1 -0
- package/dist/utils/get-user-id-from-token.js +21 -0
- package/dist/utils/get-user-id-from-token.js.map +1 -0
- package/dist/utils/http-errors.js +34 -0
- package/dist/utils/http-errors.js.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.js +90 -45
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/obfuscate-auth-headers.js +18 -0
- package/dist/utils/obfuscate-auth-headers.js.map +1 -0
- package/dist/utils/zod-schema-transformer.js +1 -0
- package/dist/utils/zod-schema-transformer.js.map +1 -0
- package/dist/utils/zod-transformer.js +1 -0
- package/dist/utils/zod-transformer.js.map +1 -0
- package/package.json +34 -8
- package/dist/stdio.js +0 -39
- package/dist/utils/errors.js +0 -22
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const cors_1 = __importDefault(require("cors"));
|
|
8
|
+
const express_1 = __importDefault(require("express"));
|
|
9
|
+
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
10
|
+
const helmet_1 = __importDefault(require("helmet"));
|
|
11
|
+
const bearerAuth_js_1 = require("@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js");
|
|
12
|
+
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
13
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
14
|
+
const _1 = require(".");
|
|
15
|
+
const constants_1 = require("./constants");
|
|
16
|
+
const utils_1 = require("./utils");
|
|
17
|
+
const auth_middleware_1 = require("../../auth/auth-middleware");
|
|
18
|
+
const config_1 = require("../../config");
|
|
19
|
+
const constants_2 = require("../../constants");
|
|
20
|
+
const cv_api_1 = require("../../cv-api");
|
|
21
|
+
const server_1 = __importDefault(require("../../server"));
|
|
22
|
+
const utils_2 = require("../../utils");
|
|
23
|
+
const app = (0, express_1.default)();
|
|
24
|
+
const SESSION_TTL_MS = 1000 * 60 * 60 * 1; // 1 hour
|
|
25
|
+
/**
|
|
26
|
+
* Sets standard headers for all requests.
|
|
27
|
+
* @param _req - The request.
|
|
28
|
+
* @param res - The response.
|
|
29
|
+
* @param next - The next handler.
|
|
30
|
+
*/
|
|
31
|
+
function standardHeaders(_req, res, next) {
|
|
32
|
+
// Disables all caching
|
|
33
|
+
res.set('Cache-Control', 'no-store, no-cache, must-revalidate');
|
|
34
|
+
res.set('Pragma', 'no-cache');
|
|
35
|
+
// if (getConfig().baseUrl.startsWith('https://')) {
|
|
36
|
+
// // Only connect to this site and subdomains via HTTPS for the next two years
|
|
37
|
+
// // and also include in the preload list
|
|
38
|
+
// res.set('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload');
|
|
39
|
+
// }
|
|
40
|
+
// Set Content Security Policy
|
|
41
|
+
// As an API server, block everything
|
|
42
|
+
// See: https://stackoverflow.com/a/45631261/2051724
|
|
43
|
+
res.set('Content-Security-Policy', "default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none';");
|
|
44
|
+
// Disable browser features
|
|
45
|
+
res.set('Permissions-Policy', 'accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()');
|
|
46
|
+
// Never send the Referer header
|
|
47
|
+
res.set('Referrer-Policy', 'no-referrer');
|
|
48
|
+
// Prevent browsers from incorrectly detecting non-scripts as scripts
|
|
49
|
+
res.set('X-Content-Type-Options', 'nosniff');
|
|
50
|
+
// Disallow attempts to iframe site
|
|
51
|
+
res.set('X-Frame-Options', 'DENY');
|
|
52
|
+
// Block pages from loading when they detect reflected XSS attacks
|
|
53
|
+
res.set('X-XSS-Protection', '1; mode=block');
|
|
54
|
+
next();
|
|
55
|
+
}
|
|
56
|
+
app.set('x-powered-by', false);
|
|
57
|
+
// Trust proxy for rate limiting - only trust localhost and private networks
|
|
58
|
+
app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']);
|
|
59
|
+
// app.use(standardHeaders);
|
|
60
|
+
app.use((0, cors_1.default)());
|
|
61
|
+
// Security middlewares
|
|
62
|
+
app.use((0, helmet_1.default)());
|
|
63
|
+
app.use((0, express_rate_limit_1.default)({
|
|
64
|
+
windowMs: 60 * 1000, // 1 minute
|
|
65
|
+
max: 100, // limit each IP to 100 requests per windowMs (100 requests per minute)
|
|
66
|
+
standardHeaders: true,
|
|
67
|
+
// legacyHeaders: false, why??
|
|
68
|
+
}));
|
|
69
|
+
app.use(express_1.default.json({ limit: '1mb' }));
|
|
70
|
+
// Add request ID middleware
|
|
71
|
+
app.use(_1.addRequestIdMiddleware);
|
|
72
|
+
// Request logging middleware
|
|
73
|
+
app.use(_1.logRequest);
|
|
74
|
+
let carbonVoiceApiHealth = {
|
|
75
|
+
isHealthy: false,
|
|
76
|
+
lastChecked: new Date().toISOString(),
|
|
77
|
+
};
|
|
78
|
+
const sessions = new Map();
|
|
79
|
+
function createSession(transport, req, sessionId) {
|
|
80
|
+
var _a, _b, _c, _d, _e, _f;
|
|
81
|
+
// Should never happen
|
|
82
|
+
if (!((_b = (_a = req.auth) === null || _a === void 0 ? void 0 : _a.extra) === null || _b === void 0 ? void 0 : _b.user)) {
|
|
83
|
+
throw new Error('User not found in session creation');
|
|
84
|
+
}
|
|
85
|
+
// const sessionId = getOrCreateSessionId(req);
|
|
86
|
+
// Clean up after TTL
|
|
87
|
+
const timeout = setTimeout(() => {
|
|
88
|
+
utils_2.logger.info('⏰ Session timeout triggered', { sessionId });
|
|
89
|
+
destroySession(sessionId);
|
|
90
|
+
}, SESSION_TTL_MS);
|
|
91
|
+
const userId = (_d = (_c = req.auth) === null || _c === void 0 ? void 0 : _c.extra) === null || _d === void 0 ? void 0 : _d.user.id;
|
|
92
|
+
sessions.set(sessionId, {
|
|
93
|
+
transport,
|
|
94
|
+
timeout,
|
|
95
|
+
userId,
|
|
96
|
+
metrics: {
|
|
97
|
+
sessionId,
|
|
98
|
+
userId,
|
|
99
|
+
createdAt: new Date(),
|
|
100
|
+
expiresAt: new Date(Date.now() + SESSION_TTL_MS),
|
|
101
|
+
totalInteractions: 0,
|
|
102
|
+
totalToolCalls: 0,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
utils_2.logger.info('🆕 Session created', {
|
|
106
|
+
sessionId,
|
|
107
|
+
userId: (_f = (_e = req.auth) === null || _e === void 0 ? void 0 : _e.extra) === null || _f === void 0 ? void 0 : _f.user.id,
|
|
108
|
+
});
|
|
109
|
+
return sessionId;
|
|
110
|
+
}
|
|
111
|
+
function destroySession(sessionId) {
|
|
112
|
+
utils_2.logger.info('🔚 Destroying session', { sessionId });
|
|
113
|
+
const session = sessions.get(sessionId);
|
|
114
|
+
if (session && !session.destroying) {
|
|
115
|
+
// Mark session as being destroyed to prevent recursive calls
|
|
116
|
+
session.destroying = true;
|
|
117
|
+
const {} = session.metrics;
|
|
118
|
+
clearTimeout(session.timeout);
|
|
119
|
+
session.transport.close();
|
|
120
|
+
sessions.delete(sessionId);
|
|
121
|
+
const durationInSeconds = (new Date().getTime() - session.metrics.createdAt.getTime()) / 1000;
|
|
122
|
+
utils_2.logger.info('❌ Session destroyed', {
|
|
123
|
+
sessionId,
|
|
124
|
+
duration: (0, utils_2.formatTimeToHuman)(durationInSeconds),
|
|
125
|
+
createdAt: session.metrics.createdAt.toISOString(),
|
|
126
|
+
expiresAt: session.metrics.expiresAt.toISOString(),
|
|
127
|
+
totalInteractions: session.metrics.totalInteractions,
|
|
128
|
+
totalToolCalls: session.metrics.totalToolCalls,
|
|
129
|
+
userId: session.userId,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
else if (session === null || session === void 0 ? void 0 : session.destroying) {
|
|
133
|
+
utils_2.logger.debug('Session already being destroyed, skipping', { sessionId });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
app.get('/health', (req, res) => {
|
|
137
|
+
const response = {
|
|
138
|
+
status: carbonVoiceApiHealth.isHealthy ? 'healthy' : 'degraded',
|
|
139
|
+
timestamp: new Date().toISOString(),
|
|
140
|
+
uptime: (0, utils_2.formatProcessUptime)(),
|
|
141
|
+
dependencies: {
|
|
142
|
+
carbonVoiceApi: {
|
|
143
|
+
status: carbonVoiceApiHealth.isHealthy ? 'healthy' : 'unhealthy',
|
|
144
|
+
lastChecked: carbonVoiceApiHealth.lastChecked,
|
|
145
|
+
...(carbonVoiceApiHealth.error && {
|
|
146
|
+
error: carbonVoiceApiHealth.error,
|
|
147
|
+
}),
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
const logLevel = carbonVoiceApiHealth.isHealthy ? 'info' : 'warn';
|
|
152
|
+
utils_2.logger[logLevel]('Health check', response);
|
|
153
|
+
const statusCode = carbonVoiceApiHealth.isHealthy ? 200 : 503;
|
|
154
|
+
res.status(statusCode).json(response);
|
|
155
|
+
});
|
|
156
|
+
app.get('/info', (req, res) => {
|
|
157
|
+
utils_2.logger.info('Info', {
|
|
158
|
+
ENV_VARS: {
|
|
159
|
+
CARBON_VOICE_BASE_URL: config_1.env.CARBON_VOICE_BASE_URL,
|
|
160
|
+
LOG_LEVEL: config_1.env.LOG_LEVEL,
|
|
161
|
+
PORT: config_1.env.PORT,
|
|
162
|
+
ENVIRONMENT: config_1.env.ENVIRONMENT,
|
|
163
|
+
LOG_TRANSPORT: config_1.env.LOG_TRANSPORT,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
res.status(200).send('OK');
|
|
167
|
+
});
|
|
168
|
+
// Protected resource metadata (OAuth 2.1 RFC9728 compliant)
|
|
169
|
+
app.get('/.well-known/oauth-protected-resource', _1.wellKnownCorsHeaders, _1.oauthProtectedResource);
|
|
170
|
+
app.get('/.well-known/oauth-authorization-server', _1.wellKnownCorsHeaders, _1.oauthAuthorizationServer);
|
|
171
|
+
// Handle HEAD requests without auth
|
|
172
|
+
app.head('/', _1.logRequest, (req, res) => {
|
|
173
|
+
const mcpProtocolVersion = req.headers['mcp-protocol-version'] || types_js_1.LATEST_PROTOCOL_VERSION;
|
|
174
|
+
res
|
|
175
|
+
.status(200)
|
|
176
|
+
.set('Content-Type', 'application/json')
|
|
177
|
+
.set('MCP-Protocol-Version', mcpProtocolVersion)
|
|
178
|
+
.end();
|
|
179
|
+
});
|
|
180
|
+
// Single shared transport for all requests
|
|
181
|
+
// const sharedTransport = new StreamableHTTPServerTransport({
|
|
182
|
+
// sessionIdGenerator: undefined, // Stateless
|
|
183
|
+
// enableJsonResponse: true,
|
|
184
|
+
// });
|
|
185
|
+
// Add error handling
|
|
186
|
+
// sharedTransport.onerror = (error) => {
|
|
187
|
+
// logger.error('🚨 Transport error', { error: error.message });
|
|
188
|
+
// };
|
|
189
|
+
// sharedTransport.onclose = () => {
|
|
190
|
+
// logger.info('🔴 Transport closed for all requests');
|
|
191
|
+
// };
|
|
192
|
+
async function handleSessionRequest(req, res, session) {
|
|
193
|
+
var _a, _b, _c, _d;
|
|
194
|
+
if (!session) {
|
|
195
|
+
utils_2.logger.warn('❌ Session ID not found', {
|
|
196
|
+
sessionId: (0, utils_1.getOrCreateSessionId)(req),
|
|
197
|
+
userId: (_c = (_b = (_a = req.auth) === null || _a === void 0 ? void 0 : _a.extra) === null || _b === void 0 ? void 0 : _b.user) === null || _c === void 0 ? void 0 : _c.id,
|
|
198
|
+
headers: req.headers,
|
|
199
|
+
});
|
|
200
|
+
res.status(404).json({
|
|
201
|
+
jsonrpc: '2.0',
|
|
202
|
+
error: {
|
|
203
|
+
code: 404,
|
|
204
|
+
message: 'Session ID not found. Please reinitialize.',
|
|
205
|
+
},
|
|
206
|
+
id: null,
|
|
207
|
+
});
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
session.metrics.totalInteractions++;
|
|
211
|
+
if (((_d = req.body) === null || _d === void 0 ? void 0 : _d.method) === 'tools/call') {
|
|
212
|
+
session.metrics.totalToolCalls++;
|
|
213
|
+
}
|
|
214
|
+
utils_2.logger.info('🔁 Reusing session', session.metrics);
|
|
215
|
+
return session.transport.handleRequest(req, res, req.body);
|
|
216
|
+
}
|
|
217
|
+
app.post('/', _1.authErrorLogger, (0, bearerAuth_js_1.requireBearerAuth)({
|
|
218
|
+
verifier: (0, auth_middleware_1.createOAuthTokenVerifier)(),
|
|
219
|
+
requiredScopes: constants_1.REQUIRED_SCOPES,
|
|
220
|
+
resourceMetadataUrl: 'mcp', // FIXME: Add dynamic resource!
|
|
221
|
+
}), _1.addMcpSessionId, async (req, res, next) => {
|
|
222
|
+
var _a, _b, _c, _d, _e, _f;
|
|
223
|
+
try {
|
|
224
|
+
const sessionId = (0, utils_1.getOrCreateSessionId)(req);
|
|
225
|
+
const session = sessions.get(sessionId);
|
|
226
|
+
// Reuse existing session
|
|
227
|
+
if (session) {
|
|
228
|
+
// logger.info('🔁 Reusing session', { sessionId });
|
|
229
|
+
// await sessions
|
|
230
|
+
// .get(sessionId)!
|
|
231
|
+
// .transport!.handleRequest(req, res, req.body);
|
|
232
|
+
// return;
|
|
233
|
+
await handleSessionRequest(req, res, session);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
// Create New Session
|
|
237
|
+
if ((0, types_js_1.isInitializeRequest)(req.body)) {
|
|
238
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
|
239
|
+
sessionIdGenerator: () => (0, utils_1.getOrCreateSessionId)(req),
|
|
240
|
+
// sessionIdGenerator: undefined,
|
|
241
|
+
onsessioninitialized: (sessionId) => {
|
|
242
|
+
// const user = req.auth?.extra?.user;
|
|
243
|
+
var _a, _b, _c;
|
|
244
|
+
utils_2.logger.info('🆕 New session initialized', {
|
|
245
|
+
sessionId,
|
|
246
|
+
requestorHeaders: (0, utils_2.obfuscateAuthHeaders)(req.headers),
|
|
247
|
+
userId: (_c = (_b = (_a = req.auth) === null || _a === void 0 ? void 0 : _a.extra) === null || _b === void 0 ? void 0 : _b.user) === null || _c === void 0 ? void 0 : _c.id,
|
|
248
|
+
});
|
|
249
|
+
createSession(transport, req, sessionId);
|
|
250
|
+
},
|
|
251
|
+
enableJsonResponse: true,
|
|
252
|
+
});
|
|
253
|
+
transport.onclose = () => {
|
|
254
|
+
utils_2.logger.info('🔴 Transport onclose triggered', {
|
|
255
|
+
sessionId: transport.sessionId,
|
|
256
|
+
hasSessionId: !!transport.sessionId,
|
|
257
|
+
});
|
|
258
|
+
if (transport.sessionId)
|
|
259
|
+
destroySession(transport.sessionId);
|
|
260
|
+
};
|
|
261
|
+
// Add error handling for the transport
|
|
262
|
+
transport.onerror = (error) => {
|
|
263
|
+
var _a;
|
|
264
|
+
utils_2.logger.error('🚨 Transport error occurred', {
|
|
265
|
+
sessionId: transport.sessionId,
|
|
266
|
+
sessionMetrics: (_a = sessions.get(transport.sessionId)) === null || _a === void 0 ? void 0 : _a.metrics,
|
|
267
|
+
error: {
|
|
268
|
+
message: error.message,
|
|
269
|
+
name: error.name,
|
|
270
|
+
stack: error.stack,
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
};
|
|
274
|
+
await server_1.default.connect(transport);
|
|
275
|
+
await transport.handleRequest(req, res, req.body);
|
|
276
|
+
return;
|
|
277
|
+
// const session = sessions.get(transport!.sessionId!);
|
|
278
|
+
// await handleSessionRequest(req, res, session!);
|
|
279
|
+
}
|
|
280
|
+
// No session ID and no initialize request
|
|
281
|
+
// Should never happen since we are gonna always have a session ID
|
|
282
|
+
utils_2.logger.warn('❌ Session ID not found', {
|
|
283
|
+
sessionId,
|
|
284
|
+
userId: (_c = (_b = (_a = req.auth) === null || _a === void 0 ? void 0 : _a.extra) === null || _b === void 0 ? void 0 : _b.user) === null || _c === void 0 ? void 0 : _c.id,
|
|
285
|
+
headers: req.headers,
|
|
286
|
+
});
|
|
287
|
+
res.status(404).json({
|
|
288
|
+
jsonrpc: '2.0',
|
|
289
|
+
error: {
|
|
290
|
+
code: 404,
|
|
291
|
+
message: 'Session ID not found. Please reinitialize.',
|
|
292
|
+
},
|
|
293
|
+
id: null,
|
|
294
|
+
});
|
|
295
|
+
return;
|
|
296
|
+
// await handleSessionRequest(req, res, sessions.get(sessionId));
|
|
297
|
+
// await sharedTransport.handleRequest(req, res, req.body);
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
utils_2.logger.error('❌ Error in POST handler', {
|
|
301
|
+
error: {
|
|
302
|
+
message: error instanceof Error ? error.message : String(error),
|
|
303
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
304
|
+
},
|
|
305
|
+
method: req.method,
|
|
306
|
+
url: req.url,
|
|
307
|
+
sessionId: (0, utils_1.getOrCreateSessionId)(req),
|
|
308
|
+
hasInitializeRequest: (0, types_js_1.isInitializeRequest)(req.body),
|
|
309
|
+
userId: (_f = (_e = (_d = req.auth) === null || _d === void 0 ? void 0 : _d.extra) === null || _e === void 0 ? void 0 : _e.user) === null || _f === void 0 ? void 0 : _f.id,
|
|
310
|
+
});
|
|
311
|
+
next(error);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
// GET/DELETE : server-to-client (SSE) and session termination
|
|
315
|
+
// GET/DELETE : server-to-client (SSE) and session termination
|
|
316
|
+
async function handleSessionRequestGetDelete(req, res) {
|
|
317
|
+
try {
|
|
318
|
+
const sessionId = (0, utils_1.getOrCreateSessionId)(req);
|
|
319
|
+
const session = sessions.get(sessionId);
|
|
320
|
+
if (!session) {
|
|
321
|
+
utils_2.logger.warn('Invalid or missing session ID', { sessionId });
|
|
322
|
+
res.status(404).json({
|
|
323
|
+
jsonrpc: '2.0',
|
|
324
|
+
error: {
|
|
325
|
+
code: 404,
|
|
326
|
+
message: 'Session not found. Please reinitialize.',
|
|
327
|
+
},
|
|
328
|
+
id: null,
|
|
329
|
+
});
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
await session.transport.handleRequest(req, res, req.body);
|
|
333
|
+
if (req.method === 'DELETE') {
|
|
334
|
+
destroySession(sessionId);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
catch (err) {
|
|
338
|
+
utils_2.logger.error('❌ Error in handleSessionRequestGetDelete', {
|
|
339
|
+
error: {
|
|
340
|
+
message: err instanceof Error ? err.message : String(err),
|
|
341
|
+
stack: err instanceof Error ? err.stack : undefined,
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
// GET/DELETE : server-to-client (SSE) and session termination
|
|
347
|
+
app.get('/', _1.authErrorLogger, (0, bearerAuth_js_1.requireBearerAuth)({
|
|
348
|
+
verifier: (0, auth_middleware_1.createOAuthTokenVerifier)(),
|
|
349
|
+
requiredScopes: constants_1.REQUIRED_SCOPES,
|
|
350
|
+
resourceMetadataUrl: 'mcp', // FIXME: Add dynamic resource!
|
|
351
|
+
}), _1.addMcpSessionId, handleSessionRequestGetDelete);
|
|
352
|
+
app.delete('/', _1.authErrorLogger, (0, bearerAuth_js_1.requireBearerAuth)({
|
|
353
|
+
verifier: (0, auth_middleware_1.createOAuthTokenVerifier)(),
|
|
354
|
+
requiredScopes: constants_1.REQUIRED_SCOPES,
|
|
355
|
+
resourceMetadataUrl: 'mcp', // FIXME: Add dynamic resource!
|
|
356
|
+
}), _1.addMcpSessionId, handleSessionRequestGetDelete);
|
|
357
|
+
// app.get(
|
|
358
|
+
// '/',
|
|
359
|
+
// authErrorLogger,
|
|
360
|
+
// requireBearerAuth({
|
|
361
|
+
// verifier: createOAuthTokenVerifier(),
|
|
362
|
+
// requiredScopes: REQUIRED_SCOPES,
|
|
363
|
+
// resourceMetadataUrl: 'mcp', // FIXME: Add dynamic resource!
|
|
364
|
+
// }),
|
|
365
|
+
// addMcpSessionId,
|
|
366
|
+
// (req: AuthenticatedRequest, res: Response) => {
|
|
367
|
+
// return handleSessionRequest(
|
|
368
|
+
// req,
|
|
369
|
+
// res,
|
|
370
|
+
// sessions.get(getOrCreateSessionId(req)),
|
|
371
|
+
// );
|
|
372
|
+
// },
|
|
373
|
+
// );
|
|
374
|
+
// app.delete(
|
|
375
|
+
// '/',
|
|
376
|
+
// authErrorLogger,
|
|
377
|
+
// requireBearerAuth({
|
|
378
|
+
// verifier: createOAuthTokenVerifier(),
|
|
379
|
+
// requiredScopes: REQUIRED_SCOPES,
|
|
380
|
+
// resourceMetadataUrl: 'mcp', // FIXME: Add dynamic resource!
|
|
381
|
+
// }),
|
|
382
|
+
// addMcpSessionId,
|
|
383
|
+
// (req: AuthenticatedRequest, res: Response) => {
|
|
384
|
+
// destroySession(getOrCreateSessionId(req));
|
|
385
|
+
// },
|
|
386
|
+
// );
|
|
387
|
+
// For stateless servers, GET should return 405 Method Not Allowed
|
|
388
|
+
// app.get('/', (req, res) => {
|
|
389
|
+
// logger.warn('GET request to (not supported in stateless mode)');
|
|
390
|
+
// res.writeHead(405, {
|
|
391
|
+
// 'Content-Type': 'application/json',
|
|
392
|
+
// Allow: 'POST',
|
|
393
|
+
// });
|
|
394
|
+
// res.end(
|
|
395
|
+
// JSON.stringify({
|
|
396
|
+
// jsonrpc: '2.0',
|
|
397
|
+
// error: {
|
|
398
|
+
// code: -32601, // "Method not found"
|
|
399
|
+
// message: 'GET not supported in stateless mode; use POST at ',
|
|
400
|
+
// },
|
|
401
|
+
// id: null,
|
|
402
|
+
// }),
|
|
403
|
+
// );
|
|
404
|
+
// return;
|
|
405
|
+
// });
|
|
406
|
+
// For stateless servers, DELETE should return 405 Method Not Allowed
|
|
407
|
+
// app.delete('/', (req, res) => {
|
|
408
|
+
// logger.warn('DELETE request to (not supported in stateless mode)');
|
|
409
|
+
// res.status(405).json({
|
|
410
|
+
// jsonrpc: '2.0',
|
|
411
|
+
// error: {
|
|
412
|
+
// code: -32000,
|
|
413
|
+
// message: "Method not allowed. Stateless server doesn't support sessions.",
|
|
414
|
+
// },
|
|
415
|
+
// id: null,
|
|
416
|
+
// });
|
|
417
|
+
// });
|
|
418
|
+
// POST : client-to-server (with authentication)
|
|
419
|
+
// app.post(
|
|
420
|
+
// 'x',
|
|
421
|
+
// async (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
|
|
422
|
+
// logger.warn('Verifying access token');
|
|
423
|
+
// verifyAccessToken(req, res, next);
|
|
424
|
+
// logger.warn('Access token verified');
|
|
425
|
+
// try {
|
|
426
|
+
// // if (req.headers) {
|
|
427
|
+
// // throw new UnauthorizedException();
|
|
428
|
+
// // }
|
|
429
|
+
// const sessionId = getOrCreateSessionId(req);
|
|
430
|
+
// // Reuse existing session
|
|
431
|
+
// if (sessionId && sessions.has(sessionId)) {
|
|
432
|
+
// logger.info('Reusing session', { sessionId });
|
|
433
|
+
// await sessions
|
|
434
|
+
// .get(sessionId)!
|
|
435
|
+
// .transport!.handleRequest(req, res, req.body);
|
|
436
|
+
// return;
|
|
437
|
+
// }
|
|
438
|
+
// // Create New Session
|
|
439
|
+
// if (!sessionId && isInitializeRequest(req.body)) {
|
|
440
|
+
// const requestorHeaders = req.headers;
|
|
441
|
+
// // TODO: The place I can see info about client is: user-agent
|
|
442
|
+
// const transport = new StreamableHTTPServerTransport({
|
|
443
|
+
// sessionIdGenerator: () => randomUUID(),
|
|
444
|
+
// onsessioninitialized: (transportSessionId: string) => {
|
|
445
|
+
// logger.info('New session initialized', {
|
|
446
|
+
// sessionId: transportSessionId,
|
|
447
|
+
// requestorHeaders,
|
|
448
|
+
// userId: req.auth?.extra?.user?.id,
|
|
449
|
+
// });
|
|
450
|
+
// const sessionId = createSession(transport!, req.auth?.extra?.user);
|
|
451
|
+
// if (req.auth?.extra?.user) {
|
|
452
|
+
// setUserContext(sessionId, req.auth?.extra?.user);
|
|
453
|
+
// }
|
|
454
|
+
// },
|
|
455
|
+
// enableJsonResponse: true,
|
|
456
|
+
// });
|
|
457
|
+
// transport.onclose = () => {
|
|
458
|
+
// if (transport!.sessionId) destroySession(transport!.sessionId);
|
|
459
|
+
// };
|
|
460
|
+
// await server.connect(transport);
|
|
461
|
+
// await transport.handleRequest(req, res, req.body);
|
|
462
|
+
// return;
|
|
463
|
+
// }
|
|
464
|
+
// // No session ID and no initialize request
|
|
465
|
+
// logger.warn('Bad request: No valid session ID provided', {
|
|
466
|
+
// sessionId,
|
|
467
|
+
// headers: req.headers,
|
|
468
|
+
// });
|
|
469
|
+
// res.status(404).json({
|
|
470
|
+
// jsonrpc: '2.0',
|
|
471
|
+
// error: {
|
|
472
|
+
// code: 404,
|
|
473
|
+
// message:
|
|
474
|
+
// 'Session Not Found or Expired. Please reinitialize with a new session ID.',
|
|
475
|
+
// },
|
|
476
|
+
// id: null,
|
|
477
|
+
// });
|
|
478
|
+
// } catch (err) {
|
|
479
|
+
// logger.error('Error handling request', { error: err });
|
|
480
|
+
// return next(err);
|
|
481
|
+
// }
|
|
482
|
+
// },
|
|
483
|
+
// );
|
|
484
|
+
// GET/DELETE : server-to-client (SSE) and session termination
|
|
485
|
+
// async function handleSessionRequestWasWorking(
|
|
486
|
+
// req: AuthenticatedRequest,
|
|
487
|
+
// res: Response,
|
|
488
|
+
// next: NextFunction,
|
|
489
|
+
// ) {
|
|
490
|
+
// try {
|
|
491
|
+
// // const sessionId = getOrCreateSessionId(req);
|
|
492
|
+
// // if (!sessionId || !sessions.has(sessionId)) {
|
|
493
|
+
// // logger.warn('Invalid or missing session ID', { sessionId });
|
|
494
|
+
// // res.status(404).json({
|
|
495
|
+
// // jsonrpc: '2.0',
|
|
496
|
+
// // error: {
|
|
497
|
+
// // code: 404,
|
|
498
|
+
// // message: 'Session not found. Please reinitialize.',
|
|
499
|
+
// // },
|
|
500
|
+
// // id: null,
|
|
501
|
+
// // });
|
|
502
|
+
// // return;
|
|
503
|
+
// // }
|
|
504
|
+
// // Add SSE-specific headers for GET requests (which are used for SSE)
|
|
505
|
+
// if (req.method === 'GET') {
|
|
506
|
+
// res.setHeader('Content-Type', 'text/event-stream');
|
|
507
|
+
// res.setHeader('Cache-Control', 'no-cache');
|
|
508
|
+
// res.setHeader('Connection', 'keep-alive');
|
|
509
|
+
// res.setHeader('Access-Control-Allow-Origin', '*');
|
|
510
|
+
// res.setHeader('Access-Control-Allow-Headers', 'Cache-Control');
|
|
511
|
+
// res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
512
|
+
// }
|
|
513
|
+
// // const transport = sessions.get(sessionId)!.transport;
|
|
514
|
+
// await sharedTransport.handleRequest(req, res, req.body);
|
|
515
|
+
// // if (req.method === 'DELETE') {
|
|
516
|
+
// // // destroySession(sessionId);
|
|
517
|
+
// // }
|
|
518
|
+
// } catch (err) {
|
|
519
|
+
// logger.error('❌ Error in handleSessionRequest', {
|
|
520
|
+
// error: {
|
|
521
|
+
// message: err instanceof Error ? err.message : String(err),
|
|
522
|
+
// stack: err instanceof Error ? err.stack : undefined,
|
|
523
|
+
// },
|
|
524
|
+
// method: req.method,
|
|
525
|
+
// url: req.url,
|
|
526
|
+
// sessionId: getOrCreateSessionId(req),
|
|
527
|
+
// });
|
|
528
|
+
// next(err);
|
|
529
|
+
// }
|
|
530
|
+
// }
|
|
531
|
+
// app.get('/oauth/authorize', (req, res) => {
|
|
532
|
+
// logger.info('OAuth authorize!!!', {
|
|
533
|
+
// url: req.url,
|
|
534
|
+
// method: req.method,
|
|
535
|
+
// headers: req.headers,
|
|
536
|
+
// });
|
|
537
|
+
// throw new Error('Not implemented');
|
|
538
|
+
// });
|
|
539
|
+
// Error handler middleware
|
|
540
|
+
// app.use((err: Error, req: Request, res: Response, _next: NextFunction) => {
|
|
541
|
+
// if (err instanceof HttpError) {
|
|
542
|
+
// res.status(err.status).json({
|
|
543
|
+
// jsonrpc: '2.0',
|
|
544
|
+
// error: { code: err.status, message: err.message },
|
|
545
|
+
// id: null,
|
|
546
|
+
// });
|
|
547
|
+
// return;
|
|
548
|
+
// }
|
|
549
|
+
// logger.error('Unhandled error', {
|
|
550
|
+
// error: { ...err, stack: err.stack },
|
|
551
|
+
// errorMessage: err.message,
|
|
552
|
+
// url: req.url,
|
|
553
|
+
// method: req.method,
|
|
554
|
+
// });
|
|
555
|
+
// if (!res.headersSent) {
|
|
556
|
+
// res.status(500).json({
|
|
557
|
+
// jsonrpc: '2.0',
|
|
558
|
+
// error: { code: -32603, message: 'Internal server error' },
|
|
559
|
+
// id: null,
|
|
560
|
+
// });
|
|
561
|
+
// }
|
|
562
|
+
// });
|
|
563
|
+
// Graceful shutdown
|
|
564
|
+
function shutdown() {
|
|
565
|
+
utils_2.logger.info('Shutting down server...');
|
|
566
|
+
// Clear the heartbeat interval
|
|
567
|
+
clearInterval(heartbeatInterval);
|
|
568
|
+
// Clean up all sessions
|
|
569
|
+
for (const sessionId of sessions.keys()) {
|
|
570
|
+
destroySession(sessionId);
|
|
571
|
+
}
|
|
572
|
+
process.exit(0);
|
|
573
|
+
}
|
|
574
|
+
process.on('SIGINT', shutdown);
|
|
575
|
+
process.on('SIGTERM', shutdown);
|
|
576
|
+
process.once('SIGUSR2', () => {
|
|
577
|
+
utils_2.logger.info('SIGUSR2 received, shutting down...');
|
|
578
|
+
// shutdown();
|
|
579
|
+
// After cleanup, re-emit the signal to let nodemon restart the process
|
|
580
|
+
process.kill(process.pid, 'SIGUSR2');
|
|
581
|
+
});
|
|
582
|
+
// Start server
|
|
583
|
+
const PORT = config_1.env.PORT || 3005;
|
|
584
|
+
const serverInstance = app.listen(PORT, async () => {
|
|
585
|
+
// Connect server once at startup
|
|
586
|
+
// await server.connect(sharedTransport);
|
|
587
|
+
// Initialize Carbon Voice API health status
|
|
588
|
+
const isApiWorking = await (0, cv_api_1.isCarbonVoiceApiWorking)();
|
|
589
|
+
carbonVoiceApiHealth = {
|
|
590
|
+
isHealthy: isApiWorking,
|
|
591
|
+
lastChecked: new Date().toISOString(),
|
|
592
|
+
};
|
|
593
|
+
const logLevel = isApiWorking ? 'info' : 'warn';
|
|
594
|
+
const icon = isApiWorking ? '✅ ' : '⚠️ ';
|
|
595
|
+
utils_2.logger[logLevel](`${icon} MCP HTTP Server started on port ${PORT}`, {
|
|
596
|
+
name: constants_2.SERVICE_NAME,
|
|
597
|
+
version: constants_2.SERVICE_VERSION,
|
|
598
|
+
processId: process.pid,
|
|
599
|
+
nodeVersion: process.version,
|
|
600
|
+
totalSessions: sessions.size,
|
|
601
|
+
carbonVoiceApiHealth,
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
serverInstance.on('error', (error) => {
|
|
605
|
+
utils_2.logger.error('❌ Error on MCP HTTP Server', { error });
|
|
606
|
+
});
|
|
607
|
+
// Add additional process-level monitoring
|
|
608
|
+
process.on('uncaughtException', (error) => {
|
|
609
|
+
utils_2.logger.error('🚨 Uncaught Exception detected', {
|
|
610
|
+
error: error.message,
|
|
611
|
+
stack: error.stack,
|
|
612
|
+
name: error.name,
|
|
613
|
+
processId: process.pid,
|
|
614
|
+
totalSessions: sessions.size,
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
618
|
+
utils_2.logger.error('🚨 Unhandled Promise Rejection detected', {
|
|
619
|
+
reason: reason instanceof Error ? reason.message : String(reason),
|
|
620
|
+
stack: reason instanceof Error ? reason.stack : undefined,
|
|
621
|
+
promise: promise.toString(),
|
|
622
|
+
processId: process.pid,
|
|
623
|
+
totalSessions: sessions.size,
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
// Log every 30 seconds to show the server is alive
|
|
627
|
+
const heartbeatInterval = setInterval(async () => {
|
|
628
|
+
try {
|
|
629
|
+
const isApiWorking = await (0, cv_api_1.isCarbonVoiceApiWorking)();
|
|
630
|
+
// Update Carbon Voice API health cache
|
|
631
|
+
carbonVoiceApiHealth = {
|
|
632
|
+
isHealthy: isApiWorking,
|
|
633
|
+
lastChecked: new Date().toISOString(),
|
|
634
|
+
...(carbonVoiceApiHealth.error && isApiWorking && { error: undefined }), // Clear error if now healthy
|
|
635
|
+
};
|
|
636
|
+
utils_2.logger.info('💓 Server heartbeat', {
|
|
637
|
+
totalSessions: sessions.size,
|
|
638
|
+
isCarbonVoiceApiWorking: isApiWorking,
|
|
639
|
+
uptime: (0, utils_2.formatProcessUptime)(),
|
|
640
|
+
memoryUsage: process.memoryUsage(),
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
catch (error) {
|
|
644
|
+
// Update cache with error information
|
|
645
|
+
carbonVoiceApiHealth = {
|
|
646
|
+
isHealthy: false,
|
|
647
|
+
lastChecked: new Date().toISOString(),
|
|
648
|
+
error: error instanceof Error
|
|
649
|
+
? error.message
|
|
650
|
+
: 'Unknown error checking API health',
|
|
651
|
+
};
|
|
652
|
+
utils_2.logger.warn('💓 Server heartbeat - Carbon Voice API check failed', {
|
|
653
|
+
totalSessions: sessions.size,
|
|
654
|
+
isCarbonVoiceApiWorking: false,
|
|
655
|
+
uptime: (0, utils_2.formatProcessUptime)(),
|
|
656
|
+
memoryUsage: process.memoryUsage(),
|
|
657
|
+
error: carbonVoiceApiHealth.error,
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
}, 30000);
|
|
661
|
+
//# sourceMappingURL=streamable.js.map
|