Skip to content

Commit a2f1273

Browse files
authored
Add tool to retrieve call quality (#10)
Adds a tool for retrieving the call quality of multiple conversation IDs (`voice_call_quality`)
1 parent 30fc5cc commit a2f1273

File tree

7 files changed

+259
-14
lines changed

7 files changed

+259
-14
lines changed

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ A Model Context Protocol (MCP) server for Genesys Cloud's Platform API.
1010
An overview of the tools that this MPC server makes available. Read more about each specific tool
1111
in the [tools doc](/docs/tools.md).
1212

13-
| Tool | Description |
14-
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------- |
15-
| [Search Queues](/docs/tools.md#search-queues) | Searches for queues by their name (supports wildcards) |
16-
| [Query Queue Volumes](/docs/tools.md#query-queue-volumes) | Determines conversation volumes and member count by Queue IDs |
17-
| [Sample Conversations By Queue](/docs/tools.md#sample-conversations-by-queue) | Extracts a representative sample of Conversation IDs for a Queue ID |
13+
| Tool | Description |
14+
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
15+
| [Search Queues](/docs/tools.md#search-queues) | Searches for queues by their name (supports wildcards) |
16+
| [Query Queue Volumes](/docs/tools.md#query-queue-volumes) | Retrieves conversation volumes and member count by Queue IDs |
17+
| [Sample Conversations By Queue](/docs/tools.md#sample-conversations-by-queue) | Retrieves a representative sample of Conversation IDs for a Queue ID |
18+
| [Voice Call Quality](/docs/tools.md#voice-call-quality) | Retrieves voice call quality metrics for one or more conversations by ID |
1819

1920
## Authentication
2021

docs/tools.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ or listing available queues.
2424
Required permission:
2525
* `routing:queue:view`
2626

27-
Platform API endpoints used:
27+
Platform API endpoint used:
2828
* [`GET /api/v2/routing/queues`](https://developer.genesys.cloud/routing/routing/#get-api-v2-routing-queues)
2929

3030
## Query Queue Volumes
@@ -76,3 +76,26 @@ Platform API endpoints used:
7676
* [`POST /api/v2/analytics/conversations/details/jobs`](https://developer.genesys.cloud/analyticsdatamanagement/analytics/analytics-apis#post-api-v2-analytics-conversations-details-jobs)
7777
* [`GET /api/v2/analytics/conversations/details/jobs/{jobId}`](https://developer.genesys.cloud/analyticsdatamanagement/analytics/analytics-apis#get-api-v2-analytics-conversations-details-jobs--jobId-)
7878
* [`GET /api/v2/analytics/conversations/details/jobs/{jobId}/results`](https://developer.genesys.cloud/analyticsdatamanagement/analytics/analytics-apis#get-api-v2-analytics-conversations-details-jobs--jobId--results)
79+
80+
## Voice Call Quality
81+
82+
Retrieves voice call quality metrics for one or more conversations by ID. This tool specifically focuses
83+
on voice interactions and returns the minimum Mean Opinion Score (MOS) observed in each conversation, helping
84+
identify degraded or poor-quality voice calls.
85+
86+
Read more [about MOS scores and how they're determined](https://developer.genesys.cloud/analyticsdatamanagement/analytics/detail/call-quality).
87+
88+
[Source file](/src/tools/voiceCallQuality.ts).
89+
90+
### Inputs
91+
92+
* `conversationIds`
93+
* A list of up to 100 conversation IDs to evaluate voice call quality for.
94+
95+
### Security
96+
97+
Required Permissions:
98+
* `analytics:conversationDetail:view`
99+
100+
Platform API endpoint used:
101+
* [`GET /api/v2/analytics/conversations/details`](https://developer.genesys.cloud/analyticsdatamanagement/analytics/analytics-apis#get-api-v2-analytics-conversations-details)

package-lock.json

Lines changed: 27 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@makingchatbots/genesys-cloud-mcp-server",
3-
"version": "0.0.2",
3+
"version": "0.0.3",
44
"description": "A MCP server for connecting LLMs to Genesys Cloud's Platform API",
55
"exports": "./dist/index.js",
66
"type": "module",
@@ -34,7 +34,7 @@
3434
"prepublishOnly": "npm run test && npm run build"
3535
},
3636
"dependencies": {
37-
"@modelcontextprotocol/sdk": "^1.11.0",
37+
"@modelcontextprotocol/sdk": "^1.11.1",
3838
"purecloud-platform-client-v2": "^220.0.0",
3939
"zod": "^3.24.4"
4040
},
@@ -50,6 +50,7 @@
5050
"eslint-import-resolver-typescript": "^4.3.4",
5151
"lint-staged": "^15.5.1",
5252
"prettier": "^3.5.3",
53+
"tsx": "^4.19.4",
5354
"typescript": "^5.8.3",
5455
"typescript-eslint": "^8.31.1",
5556
"vitest": "^3.1.3"

src/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { searchQueues } from "./tools/searchQueues.js";
66
import { loadConfig } from "./loadConfig.js";
77
import { sampleConversationsByQueue } from "./tools/sampleConversationsByQueue.js";
88
import { queryQueueVolumes } from "./tools/queryQueueVolumes.js";
9+
import { voiceCallQuality } from "./tools/voiceCallQuality.js";
910

1011
const configResult = loadConfig(process.env);
1112
if (!configResult.success) {
@@ -67,6 +68,21 @@ server.tool(
6768
platformClient.ApiClient.instance,
6869
),
6970
);
71+
const voiceCallQualityTool = voiceCallQuality({
72+
analyticsApi: new platformClient.AnalyticsApi(),
73+
});
74+
server.tool(
75+
voiceCallQualityTool.schema.name,
76+
voiceCallQualityTool.schema.description,
77+
voiceCallQualityTool.schema.paramsSchema.shape,
78+
config.mockingEnabled
79+
? voiceCallQualityTool.mockCall
80+
: withAuth(
81+
voiceCallQualityTool.call,
82+
config.genesysCloud,
83+
platformClient.ApiClient.instance,
84+
),
85+
);
7086

7187
const transport = new StdioServerTransport();
7288
await server.connect(transport);

src/tools/voiceCallQuality.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { z } from "zod";
2+
import { createTool, type ToolFactory } from "./utils/createTool.js";
3+
import { isUnauthorisedError } from "./utils/genesys/isUnauthorisedError.js";
4+
import { type AnalyticsApi } from "purecloud-platform-client-v2";
5+
import { type CallToolResult } from "@modelcontextprotocol/sdk/types.js";
6+
7+
interface Dependencies {
8+
readonly analyticsApi: AnalyticsApi;
9+
}
10+
11+
const paramsSchema = z.object({
12+
conversationIds: z
13+
.array(
14+
z
15+
.string()
16+
.uuid()
17+
.describe(
18+
"A unique ID for a Genesys Cloud conversation. Must be a valid UUID.",
19+
),
20+
)
21+
.min(1)
22+
.max(100)
23+
.describe(
24+
"A list of up to 100 conversation IDs to evaluate voice call quality for.",
25+
),
26+
});
27+
28+
function errorResult(errorMessage: string): CallToolResult {
29+
return {
30+
isError: true,
31+
content: [
32+
{
33+
type: "text",
34+
text: errorMessage,
35+
},
36+
],
37+
};
38+
}
39+
40+
export const voiceCallQuality: ToolFactory<
41+
Dependencies,
42+
typeof paramsSchema
43+
> = ({ analyticsApi }) =>
44+
createTool({
45+
schema: {
46+
name: "voice_call_quality",
47+
description:
48+
"Retrieves voice call quality metrics for one or more conversations by ID. This tool specifically focuses on voice interactions and returns the minimum Mean Opinion Score (MOS) observed in each conversation, helping identify degraded or poor-quality voice calls.",
49+
paramsSchema,
50+
},
51+
call: async ({ conversationIds }) => {
52+
try {
53+
const conversationDetails =
54+
await analyticsApi.getAnalyticsConversationsDetails({
55+
id: conversationIds,
56+
});
57+
58+
const output: string[] = [
59+
"Call Quality Report for voice conversations.",
60+
"",
61+
"MOS Quality Legend:",
62+
" Poor: MOS < 3.5",
63+
" Acceptable: 3.5 ≤ MOS < 4.3",
64+
" Excellent: MOS ≥ 4.3",
65+
"",
66+
];
67+
68+
for (const convo of conversationDetails.conversations ?? []) {
69+
if (!convo.conversationId || !convo.mediaStatsMinConversationMos) {
70+
continue;
71+
}
72+
73+
const mos = convo.mediaStatsMinConversationMos;
74+
let qualityLabel = "Unknown";
75+
76+
if (mos < 3.5) {
77+
qualityLabel = "Poor";
78+
} else if (mos < 4.3) {
79+
qualityLabel = "Acceptable";
80+
} else {
81+
qualityLabel = "Excellent";
82+
}
83+
84+
output.push(
85+
`• Conversation ID: ${convo.conversationId}\n • Minimum MOS: ${mos.toFixed(2)} (${qualityLabel})`,
86+
);
87+
}
88+
89+
return {
90+
content: [
91+
{
92+
type: "text",
93+
text:
94+
output.length > 0
95+
? [
96+
`Call Quality Report for ${String(conversationIds.length)} conversation(s):`,
97+
...output,
98+
].join("\n\n")
99+
: "No valid call quality data found for the given conversation IDs.",
100+
},
101+
],
102+
};
103+
} catch (error: unknown) {
104+
const message = isUnauthorisedError(error)
105+
? "Failed to query conversations call quality: Unauthorised access. Please check API credentials or permissions."
106+
: `Failed to query conversations call quality: ${error instanceof Error ? error.message : JSON.stringify(error)}`;
107+
108+
return errorResult(message);
109+
}
110+
},
111+
mockCall: async ({ conversationIds }) => {
112+
return Promise.resolve({
113+
content: [
114+
{
115+
type: "text",
116+
text: [
117+
`Call Quality Report for ${String(conversationIds.length)} conversation(s):`,
118+
...conversationIds.map(
119+
(id, index) =>
120+
`• Conversation ID: ${id}\n • Minimum MOS: ${(3 + index * 0.5).toFixed(2)}`,
121+
),
122+
].join("\n\n"),
123+
},
124+
],
125+
});
126+
},
127+
});

tests/voiceCallQuality.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
3+
import { join } from "path";
4+
import { afterEach, describe, expect, test } from "vitest";
5+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
6+
7+
describe("voice call quality tool", () => {
8+
let client: Client | null = null;
9+
10+
afterEach(async () => {
11+
if (client) await client.close();
12+
});
13+
14+
test("mock", async () => {
15+
// Debugging server possible by setting breakpoint inside js file
16+
17+
const transport = new StdioClientTransport({
18+
command: "node",
19+
args: ["--inspect", join(__dirname, "../dist/index.js")],
20+
env: {
21+
// Provides path for node binary to be used in test
22+
PATH: process.env.PATH!,
23+
MOCKING_ENABLED: "true",
24+
},
25+
});
26+
27+
client = new Client({
28+
name: "test-client",
29+
version: "1.0.0",
30+
});
31+
32+
await client.connect(transport);
33+
34+
const queueName = "Test";
35+
const result = await client.callTool({
36+
name: "voice_call_quality",
37+
arguments: {
38+
conversationIds: [
39+
"00000000-0000-0000-0000-000000000001",
40+
"00000000-0000-0000-0000-000000000002",
41+
],
42+
},
43+
});
44+
45+
const text = (result as CallToolResult).content[0].text;
46+
expect(text).toStrictEqual(
47+
`Call Quality Report for 2 conversation(s):
48+
49+
• Conversation ID: 00000000-0000-0000-0000-000000000001
50+
• Minimum MOS: 3.00
51+
52+
• Conversation ID: 00000000-0000-0000-0000-000000000002
53+
• Minimum MOS: 3.50`,
54+
);
55+
});
56+
});

0 commit comments

Comments
 (0)