UNPKG

@makingchatbots/genesys-cloud-mcp-server

Version:

A Model Context Protocol (MCP) server exposing Genesys Cloud tools for LLMs, including sentiment analysis, conversation search, topic detection and more.

120 lines (119 loc) 5.33 kB
import { z } from "zod"; import { createTool } from "../utils/createTool.js"; import { errorResult } from "../utils/errorResult.js"; import { isUnauthorisedError } from "../utils/genesys/isUnauthorisedError.js"; import { chunks } from "./chunks.js"; const MAX_IDS_ALLOWED_BY_API = 50; const paramsSchema = z.object({ conversationId: z .string() .uuid() .describe("A UUID for a conversation. (e.g., 00000000-0000-0000-0000-000000000000)"), }); export const conversationTopics = ({ speechTextAnalyticsApi, analyticsApi }) => createTool({ schema: { name: "conversation_topics", annotations: { title: "Conversation Topics" }, description: "Retrieves Speech and Text Analytics topics detected for a specific conversation. Topics represent business-level intents (e.g. cancellation, billing enquiry) inferred from recognised phrases in the customer-agent interaction.", paramsSchema, }, call: async ({ conversationId }) => { let conversationDetails; try { conversationDetails = await analyticsApi.getAnalyticsConversationDetails(conversationId); } catch (error) { const errorMessage = isUnauthorisedError(error) ? "Failed to retrieve conversation topics: Unauthorised access. Please check API credentials or permissions" : `Failed to retrieve conversation topics: ${error instanceof Error ? error.message : JSON.stringify(error)}`; return errorResult(errorMessage); } if (!conversationDetails.conversationStart || !conversationDetails.conversationEnd) { return errorResult("Unable to find conversation Start and End date needed for retrieving topics"); } // Widen the time range either side to ensure the conversation timeframe is enclosed. // Conversation not returned if either only partially covered by interval, or matched exactly. const startDate = new Date(conversationDetails.conversationStart); startDate.setMinutes(startDate.getMinutes() - 10); const endDate = new Date(conversationDetails.conversationEnd); endDate.setMinutes(endDate.getMinutes() + 10); let jobDetails; try { jobDetails = await analyticsApi.postAnalyticsTranscriptsAggregatesQuery({ interval: `${startDate.toISOString()}/${endDate.toISOString()}`, filter: { type: "and", predicates: [ { dimension: "conversationId", value: conversationId, }, { dimension: "resultsBy", value: "communication", }, ], }, groupBy: ["topicId"], metrics: ["nTopicCommunications"], }); } catch (error) { const errorMessage = isUnauthorisedError(error) ? "Failed to retrieve conversation topics: Unauthorised access. Please check API credentials or permissions" : `Failed to retrieve conversation topics: ${error instanceof Error ? error.message : JSON.stringify(error)}`; return errorResult(errorMessage); } const topicIds = new Set(); for (const result of jobDetails.results ?? []) { if (result.group?.topicId) { topicIds.add(result.group.topicId); } } if (topicIds.size === 0) { return { content: [ { type: "text", text: `Conversation ID: ${conversationId}\nNo detected topics for this conversation.`, }, ], }; } const topics = []; try { for (const topicIdChunk of chunks(Array.from(topicIds.values()), MAX_IDS_ALLOWED_BY_API)) { const topicsListings = await speechTextAnalyticsApi.getSpeechandtextanalyticsTopics({ ids: topicIdChunk, pageSize: MAX_IDS_ALLOWED_BY_API, }); topics.push(...(topicsListings.entities ?? [])); } } catch (error) { const errorMessage = isUnauthorisedError(error) ? "Failed to retrieve conversation topics: Unauthorised access. Please check API credentials or permissions" : `Failed to retrieve conversation topics: ${error instanceof Error ? error.message : JSON.stringify(error)}`; return errorResult(errorMessage); } const topicNames = topics .filter((topic) => topic.name && topic.description) .map(({ name, description }) => ({ name: name ?? "", description: description ?? "", })); return { content: [ { type: "text", text: JSON.stringify({ conversationId: conversationId, detectedTopics: topicNames, }), }, ], }; }, });