Skip to content

Commit 482ff83

Browse files
authored
Remove auth from tool listing (#23)
1 parent 5f56442 commit 482ff83

17 files changed

+222
-202
lines changed

package-lock.json

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

package.json

Lines changed: 4 additions & 4 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.11",
3+
"version": "0.0.12",
44
"description": "A Model Context Protocol (MCP) server exposing Genesys Cloud tools for LLMs, including sentiment analysis, conversation search, topic detection and more.",
55
"bin": "./dist/cli.js",
66
"type": "module",
@@ -36,11 +36,11 @@
3636
"test:pack": "npm run build && npm pack --pack-destination ./dist"
3737
},
3838
"dependencies": {
39-
"@modelcontextprotocol/sdk": "^1.12.1",
39+
"@modelcontextprotocol/sdk": "^1.13.0",
4040
"date-fns": "^4.1.0",
41-
"purecloud-platform-client-v2": "^223.0.0",
41+
"purecloud-platform-client-v2": "^224.0.0",
4242
"table": "^6.9.0",
43-
"zod": "^3.25.56"
43+
"zod": "^3.25.67"
4444
},
4545
"devDependencies": {
4646
"@eslint/eslintrc": "^3.3.1",
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { type ApiClientClass } from "purecloud-platform-client-v2";
2+
import { type ToolCall } from "../tools/utils/createTool.js";
3+
import { ConfigRetriever } from "../createConfigRetriever.js";
4+
import { errorResult } from "../tools/utils/errorResult.js";
5+
import { z } from "zod";
6+
7+
let isAuthenticated = false;
8+
9+
type AuthResult =
10+
| { authenticated: true }
11+
| { authenticated: false; reason: string };
12+
13+
async function authenticate(
14+
apiClient: ApiClientClass,
15+
configRetriever: ConfigRetriever,
16+
): Promise<AuthResult> {
17+
const config = configRetriever.getGenesysCloudConfig();
18+
if (!config.success) {
19+
return { authenticated: false, reason: config.reason };
20+
}
21+
const authConfig = config.value;
22+
23+
try {
24+
apiClient.setEnvironment(authConfig.region);
25+
await apiClient.loginClientCredentialsGrant(
26+
authConfig.oAuthClientId,
27+
authConfig.oAuthClientSecret,
28+
);
29+
} catch (e: unknown) {
30+
return {
31+
authenticated: false,
32+
reason: e instanceof Error ? e.message : String(e),
33+
};
34+
}
35+
36+
return {
37+
authenticated: true,
38+
};
39+
}
40+
41+
export const OAuthClientCredentialsWrapper = (
42+
configRetriever: ConfigRetriever,
43+
apiClient: ApiClientClass,
44+
) => {
45+
return function <Schema extends z.Schema = z.Schema>(
46+
call: ToolCall<Schema>,
47+
): ToolCall<Schema> {
48+
return async (input: Schema) => {
49+
if (!isAuthenticated) {
50+
const authResult = await authenticate(apiClient, configRetriever);
51+
if (authResult.authenticated) {
52+
isAuthenticated = true;
53+
} else {
54+
return errorResult(
55+
`Failed to authenticate with Genesys Cloud. Reason:\n${authResult.reason}`,
56+
);
57+
}
58+
}
59+
60+
return call(input);
61+
};
62+
};
63+
};

src/createConfigRetriever.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { z } from "zod";
2+
3+
export interface GenesysCloudConfig {
4+
readonly region: string;
5+
readonly oAuthClientId: string;
6+
readonly oAuthClientSecret: string;
7+
}
8+
9+
export interface ConfigRetriever {
10+
readonly getGenesysCloudConfig: () => Result<GenesysCloudConfig>;
11+
}
12+
13+
export interface SuccessResult<T> {
14+
success: true;
15+
value: T;
16+
}
17+
18+
export interface ErrorResult {
19+
success: false;
20+
reason: string;
21+
}
22+
23+
export type Result<T> = SuccessResult<T> | ErrorResult;
24+
25+
const genesysAuthConfigSchema = z.object({
26+
GENESYSCLOUD_REGION: z.string({
27+
required_error: "Missing environment variable: GENESYSCLOUD_REGION",
28+
}),
29+
GENESYSCLOUD_OAUTHCLIENT_ID: z.string({
30+
required_error: "Missing environment variable: GENESYSCLOUD_OAUTHCLIENT_ID",
31+
}),
32+
GENESYSCLOUD_OAUTHCLIENT_SECRET: z.string({
33+
required_error:
34+
"Missing environment variable: GENESYSCLOUD_OAUTHCLIENT_SECRET",
35+
}),
36+
});
37+
38+
export function createConfigRetriever(env: NodeJS.ProcessEnv): ConfigRetriever {
39+
return {
40+
getGenesysCloudConfig: () => {
41+
const genesysAuthConfig = genesysAuthConfigSchema.safeParse(env);
42+
if (!genesysAuthConfig.success) {
43+
const failureReason = [
44+
"Failed to parse environment variables",
45+
...genesysAuthConfig.error.issues.map((i) => i.message),
46+
].join("\n");
47+
48+
return {
49+
success: false,
50+
reason: failureReason,
51+
};
52+
}
53+
54+
return {
55+
success: true,
56+
value: {
57+
region: genesysAuthConfig.data.GENESYSCLOUD_REGION,
58+
oAuthClientId: genesysAuthConfig.data.GENESYSCLOUD_OAUTHCLIENT_ID,
59+
oAuthClientSecret:
60+
genesysAuthConfig.data.GENESYSCLOUD_OAUTHCLIENT_SECRET,
61+
},
62+
};
63+
},
64+
};
65+
}

0 commit comments

Comments
 (0)