@egain/egain-mcp-server 1.0.6 → 1.0.12
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 +22 -0
- package/bin/mcp-server.js +201 -171
- package/bin/mcp-server.js.map +9 -9
- package/esm/src/funcs/getPortals.d.ts +48 -7
- package/esm/src/funcs/getPortals.d.ts.map +1 -1
- package/esm/src/funcs/getPortals.js +48 -7
- package/esm/src/funcs/getPortals.js.map +1 -1
- package/esm/src/hooks/auth-hook.d.ts +6 -1
- package/esm/src/hooks/auth-hook.d.ts.map +1 -1
- package/esm/src/hooks/auth-hook.js +189 -197
- package/esm/src/hooks/auth-hook.js.map +1 -1
- package/esm/src/hooks/tooltip-images.d.ts +10 -0
- package/esm/src/hooks/tooltip-images.d.ts.map +1 -0
- package/esm/src/hooks/tooltip-images.js +12 -0
- package/esm/src/hooks/tooltip-images.js.map +1 -0
- package/esm/src/lib/config.d.ts +2 -2
- package/esm/src/lib/config.js +2 -2
- package/esm/src/lib/config.js.map +1 -1
- package/esm/src/mcp-server/mcp-server.js +1 -1
- package/esm/src/mcp-server/mcp-server.js.map +1 -1
- package/esm/src/mcp-server/server.js +1 -1
- package/esm/src/mcp-server/server.js.map +1 -1
- package/esm/src/mcp-server/tools/getPortals.d.ts.map +1 -1
- package/esm/src/mcp-server/tools/getPortals.js +48 -7
- package/esm/src/mcp-server/tools/getPortals.js.map +1 -1
- package/esm/src/models/getmyportalsop.d.ts +1 -1
- package/esm/src/models/getmyportalsop.d.ts.map +1 -1
- package/manifest.json +2 -2
- package/package.json +1 -1
- package/src/funcs/getPortals.ts +48 -7
- package/src/hooks/auth-hook.ts +200 -224
- package/src/lib/config.ts +2 -2
- package/src/mcp-server/mcp-server.ts +1 -1
- package/src/mcp-server/server.ts +1 -1
- package/src/mcp-server/tools/getPortals.ts +48 -7
- package/src/models/getmyportalsop.ts +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ Learn more about the tools and usage of the MCP in the [eGain MCP guide](https:/
|
|
|
23
23
|
<!-- No Table of Contents [toc] -->
|
|
24
24
|
|
|
25
25
|
### Prerequisites
|
|
26
|
+
- **Node.js version 20+** - Required for running the MCP server. Download from [nodejs.org](https://nodejs.org/)
|
|
26
27
|
- eGain platform version 21.22 or newer.
|
|
27
28
|
- Access mirrors the user's permissions: MCP only sees content that user can see (portal/article visibility).
|
|
28
29
|
- AI Services must be enabled for your tenant and the target portal, or AI tools will not run.
|
|
@@ -116,6 +117,27 @@ You'll need to enter your authentication configuration values in the browser for
|
|
|
116
117
|
- **Configuration problems?** → [FAQ: Configuration Issues](./help/faq.md#configuration-issues)
|
|
117
118
|
- **Tool/Query problems?** → [FAQ: MCP Tool Issues](./help/faq.md#mcp-tool-issues)
|
|
118
119
|
|
|
120
|
+
### Token Issues (Expired/Stuck Tokens)
|
|
121
|
+
|
|
122
|
+
If you're experiencing issues with expired tokens or authentication failures:
|
|
123
|
+
|
|
124
|
+
When using `npx`, token files (`.bearer_token` and `.bearer_token_metadata`) are stored in the directory where you run `npx` from (or where `package.json` exists). To find them:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Search your home directory
|
|
128
|
+
find ~ -name ".bearer_token" -o -name ".bearer_token_metadata" 2>/dev/null
|
|
129
|
+
|
|
130
|
+
# Or search from your current directory
|
|
131
|
+
find . -name ".bearer_token" -o -name ".bearer_token_metadata" 2>/dev/null
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Once found, delete them:
|
|
135
|
+
```bash
|
|
136
|
+
rm /path/to/.bearer_token
|
|
137
|
+
rm /path/to/.bearer_token_metadata
|
|
138
|
+
```
|
|
139
|
+
This will search common locations and show you exactly where your token files are.
|
|
140
|
+
|
|
119
141
|
### Common Setup Hurdles
|
|
120
142
|
- **Can't find API Domain?** → [FAQ: Finding API Domain](./help/faq.md#q-i-cant-find-my-api-domain-or-scope-prefix-where-is-it)
|
|
121
143
|
- **Browser didn't open?** → [FAQ: No auth popup](./help/faq.md#no-auth-popup-appears)
|
package/bin/mcp-server.js
CHANGED
|
@@ -4046,9 +4046,9 @@ var init_config = __esm(() => {
|
|
|
4046
4046
|
SDK_METADATA = {
|
|
4047
4047
|
language: "typescript",
|
|
4048
4048
|
openapiDocVersion: "1.0.0",
|
|
4049
|
-
sdkVersion: "1.0.
|
|
4049
|
+
sdkVersion: "1.0.12",
|
|
4050
4050
|
genVersion: "2.723.8",
|
|
4051
|
-
userAgent: "speakeasy-sdk/mcp-typescript 1.0.
|
|
4051
|
+
userAgent: "speakeasy-sdk/mcp-typescript 1.0.12 2.723.8 1.0.0 @egain/egain-mcp-server"
|
|
4052
4052
|
};
|
|
4053
4053
|
});
|
|
4054
4054
|
|
|
@@ -40991,119 +40991,6 @@ class AuthenticationHook {
|
|
|
40991
40991
|
const fullUrl = `${baseUrl}?${existingParams.toString()}`;
|
|
40992
40992
|
return fullUrl;
|
|
40993
40993
|
}
|
|
40994
|
-
async monitorBrowserForAuthCode() {
|
|
40995
|
-
const platform = process.platform;
|
|
40996
|
-
const timeout = 120;
|
|
40997
|
-
const startTime = Date.now();
|
|
40998
|
-
if (platform === "darwin") {
|
|
40999
|
-
console.error(`\uD83D\uDD0D Monitoring ${this.detectedBrowser} for authorization code...`);
|
|
41000
|
-
let lastUrl = "";
|
|
41001
|
-
while (Date.now() - startTime < timeout * 1000) {
|
|
41002
|
-
try {
|
|
41003
|
-
const script = `
|
|
41004
|
-
tell application "${this.detectedBrowser}"
|
|
41005
|
-
try
|
|
41006
|
-
set currentURL to URL of active tab of front window
|
|
41007
|
-
return currentURL
|
|
41008
|
-
on error
|
|
41009
|
-
return ""
|
|
41010
|
-
end try
|
|
41011
|
-
end tell
|
|
41012
|
-
`;
|
|
41013
|
-
const { stdout } = await execAsync(`osascript -e '${script}'`);
|
|
41014
|
-
const currentUrl = stdout.trim();
|
|
41015
|
-
if (currentUrl && currentUrl !== lastUrl) {
|
|
41016
|
-
lastUrl = currentUrl;
|
|
41017
|
-
console.error(`\uD83D\uDD0D Current URL: ${currentUrl}`);
|
|
41018
|
-
}
|
|
41019
|
-
if (currentUrl && currentUrl.includes("code=")) {
|
|
41020
|
-
console.error("✅ Found authorization code in URL!");
|
|
41021
|
-
const codeMatch = currentUrl.match(/[?&]code=([^&]+)/);
|
|
41022
|
-
if (codeMatch && codeMatch[1]) {
|
|
41023
|
-
const code = decodeURIComponent(codeMatch[1]);
|
|
41024
|
-
console.error(`\uD83D\uDD11 Extracted authorization code (first 20 chars): ${code.substring(0, 20)}...`);
|
|
41025
|
-
console.error(` Code length: ${code.length} characters`);
|
|
41026
|
-
setImmediate(async () => {
|
|
41027
|
-
try {
|
|
41028
|
-
await execAsync(`osascript -e 'tell application "${this.detectedBrowser}" to close front window'`);
|
|
41029
|
-
console.error("✅ Browser window closed");
|
|
41030
|
-
} catch (closeError) {
|
|
41031
|
-
console.error("⚠️ Could not close browser window:", closeError);
|
|
41032
|
-
}
|
|
41033
|
-
});
|
|
41034
|
-
return code;
|
|
41035
|
-
}
|
|
41036
|
-
}
|
|
41037
|
-
if (currentUrl && currentUrl.includes("error=")) {
|
|
41038
|
-
const errorMatch = currentUrl.match(/[?&]error=([^&]+)/);
|
|
41039
|
-
const errorDescMatch = currentUrl.match(/error_description=([^&]+)/);
|
|
41040
|
-
const error = errorMatch && errorMatch[1] ? decodeURIComponent(errorMatch[1]) : "unknown_error";
|
|
41041
|
-
const errorDesc = errorDescMatch && errorDescMatch[1] ? decodeURIComponent(errorDescMatch[1]) : "No description";
|
|
41042
|
-
throw new Error(`OAuth error: ${error} - ${errorDesc}`);
|
|
41043
|
-
}
|
|
41044
|
-
} catch (error) {
|
|
41045
|
-
if (error instanceof Error && error.message.includes("OAuth error:")) {
|
|
41046
|
-
throw error;
|
|
41047
|
-
}
|
|
41048
|
-
}
|
|
41049
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
41050
|
-
}
|
|
41051
|
-
throw new Error("Authentication timeout. Please try again.");
|
|
41052
|
-
} else if (platform === "win32") {
|
|
41053
|
-
console.error(`\uD83D\uDD0D Monitoring ${this.detectedBrowser} for authorization code...`);
|
|
41054
|
-
let lastTitle = "";
|
|
41055
|
-
while (Date.now() - startTime < timeout * 1000) {
|
|
41056
|
-
try {
|
|
41057
|
-
const browserProcessName = this.detectedBrowser.replace(".exe", "");
|
|
41058
|
-
const psScript = `
|
|
41059
|
-
$process = Get-Process -Name "${browserProcessName}" -ErrorAction SilentlyContinue |
|
|
41060
|
-
Where-Object { $_.MainWindowHandle -ne 0 } |
|
|
41061
|
-
Select-Object -First 1
|
|
41062
|
-
if ($process) {
|
|
41063
|
-
$process.MainWindowTitle
|
|
41064
|
-
}
|
|
41065
|
-
`.replace(/\n\s+/g, " ");
|
|
41066
|
-
const { stdout } = await execAsync(`powershell -Command "${psScript}"`);
|
|
41067
|
-
const windowTitle = stdout.trim();
|
|
41068
|
-
if (windowTitle && windowTitle !== lastTitle) {
|
|
41069
|
-
lastTitle = windowTitle;
|
|
41070
|
-
console.error(`\uD83D\uDD0D Browser window: ${windowTitle.substring(0, 100)}...`);
|
|
41071
|
-
if (windowTitle.includes("code=") || windowTitle.includes("localhost:3333")) {
|
|
41072
|
-
console.error("✅ Detected OAuth callback!");
|
|
41073
|
-
const codeMatch = windowTitle.match(/code=([^&\s]+)/);
|
|
41074
|
-
if (codeMatch && codeMatch[1]) {
|
|
41075
|
-
const code = decodeURIComponent(codeMatch[1]);
|
|
41076
|
-
console.error(`\uD83D\uDD11 Extracted authorization code (first 20 chars): ${code.substring(0, 20)}...`);
|
|
41077
|
-
console.error(` Code length: ${code.length} characters`);
|
|
41078
|
-
setImmediate(async () => {
|
|
41079
|
-
try {
|
|
41080
|
-
await execAsync(`powershell -Command "Stop-Process -Name '${browserProcessName}' -Force"`);
|
|
41081
|
-
console.error("✅ Browser window closed");
|
|
41082
|
-
} catch (closeError) {
|
|
41083
|
-
console.error("⚠️ Could not close browser window:", closeError);
|
|
41084
|
-
}
|
|
41085
|
-
});
|
|
41086
|
-
return code;
|
|
41087
|
-
}
|
|
41088
|
-
}
|
|
41089
|
-
if (windowTitle.includes("error=")) {
|
|
41090
|
-
const errorMatch = windowTitle.match(/error=([^&\s]+)/);
|
|
41091
|
-
const error = errorMatch && errorMatch[1] ? decodeURIComponent(errorMatch[1]) : "unknown_error";
|
|
41092
|
-
throw new Error(`OAuth error: ${error}`);
|
|
41093
|
-
}
|
|
41094
|
-
}
|
|
41095
|
-
} catch (error) {
|
|
41096
|
-
if (error instanceof Error && error.message.includes("OAuth error:")) {
|
|
41097
|
-
throw error;
|
|
41098
|
-
}
|
|
41099
|
-
}
|
|
41100
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
41101
|
-
}
|
|
41102
|
-
throw new Error("Authentication timeout. The browser window title did not show the authorization code. Please ensure your redirect URL is http://localhost:3333/callback for automatic detection on Windows.");
|
|
41103
|
-
} else {
|
|
41104
|
-
throw new Error("Linux is not supported. Use macOS or Windows for automatic authentication.");
|
|
41105
|
-
}
|
|
41106
|
-
}
|
|
41107
40994
|
async getUserAccessToken(code) {
|
|
41108
40995
|
const { clientId, clientSecret, redirectUri, accessUrl } = this.authConfig;
|
|
41109
40996
|
console.error("\uD83D\uDD04 Starting token exchange...");
|
|
@@ -41237,6 +41124,21 @@ class AuthenticationHook {
|
|
|
41237
41124
|
return true;
|
|
41238
41125
|
} else {
|
|
41239
41126
|
console.error(`⏰ AUTH: Token expires in ${Math.round(timeUntilExpiry / 1000)} seconds - treating as expired`);
|
|
41127
|
+
const projectRoot2 = getProjectRoot();
|
|
41128
|
+
const tokenPath = path.join(projectRoot2, ".bearer_token");
|
|
41129
|
+
try {
|
|
41130
|
+
if (fs.existsSync(tokenPath)) {
|
|
41131
|
+
fs.unlinkSync(tokenPath);
|
|
41132
|
+
console.error("\uD83D\uDDD1️ Deleted expired bearer token file");
|
|
41133
|
+
}
|
|
41134
|
+
if (fs.existsSync(metadataPath)) {
|
|
41135
|
+
fs.unlinkSync(metadataPath);
|
|
41136
|
+
console.error("\uD83D\uDDD1️ Deleted expired bearer token metadata file");
|
|
41137
|
+
}
|
|
41138
|
+
} catch (error) {
|
|
41139
|
+
console.error("⚠️ Failed to delete expired token files:", error);
|
|
41140
|
+
}
|
|
41141
|
+
this.token = null;
|
|
41240
41142
|
return false;
|
|
41241
41143
|
}
|
|
41242
41144
|
}
|
|
@@ -41255,9 +41157,17 @@ class AuthenticationHook {
|
|
|
41255
41157
|
console.error(`\uD83D\uDD11 Found existing bearer token at: ${tokenPath}`);
|
|
41256
41158
|
return token;
|
|
41257
41159
|
}
|
|
41160
|
+
} else {
|
|
41161
|
+
if (this.token) {
|
|
41162
|
+
console.error("\uD83D\uDDD1️ Token file deleted, clearing in-memory token");
|
|
41163
|
+
this.token = null;
|
|
41164
|
+
}
|
|
41258
41165
|
}
|
|
41259
41166
|
} catch (error) {
|
|
41260
41167
|
console.error("Could not load existing token:", error);
|
|
41168
|
+
if (this.token) {
|
|
41169
|
+
this.token = null;
|
|
41170
|
+
}
|
|
41261
41171
|
}
|
|
41262
41172
|
return null;
|
|
41263
41173
|
}
|
|
@@ -41362,26 +41272,7 @@ class AuthenticationHook {
|
|
|
41362
41272
|
}));
|
|
41363
41273
|
console.error("\uD83D\uDD0D Starting browser URL monitoring for authorization code...");
|
|
41364
41274
|
setImmediate(async () => {
|
|
41365
|
-
|
|
41366
|
-
const code = await this.monitorBrowserForAuthCode();
|
|
41367
|
-
console.error("✅ Authorization code detected:", code.substring(0, 10) + "...");
|
|
41368
|
-
const accessToken = await this.getUserAccessToken(code);
|
|
41369
|
-
console.error("✅ Access token received");
|
|
41370
|
-
this.token = accessToken;
|
|
41371
|
-
if (this.portalCacheHook) {
|
|
41372
|
-
try {
|
|
41373
|
-
const fakeRequest = new Request(this.authConfig.environmentUrl, {
|
|
41374
|
-
headers: { Authorization: `Bearer ${accessToken}` }
|
|
41375
|
-
});
|
|
41376
|
-
await this.portalCacheHook.ensureCacheInitialized(fakeRequest);
|
|
41377
|
-
} catch (error) {}
|
|
41378
|
-
}
|
|
41379
|
-
console.error("\uD83C\uDF89 Authentication complete! Stopping config server...");
|
|
41380
|
-
this.stopConfigServer();
|
|
41381
|
-
} catch (authError) {
|
|
41382
|
-
console.error("❌ Authentication monitoring error:", authError);
|
|
41383
|
-
this.stopConfigServer();
|
|
41384
|
-
}
|
|
41275
|
+
await this.monitorBrowserWithRetry();
|
|
41385
41276
|
});
|
|
41386
41277
|
} catch (error) {
|
|
41387
41278
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
@@ -41459,30 +41350,7 @@ class AuthenticationHook {
|
|
|
41459
41350
|
}));
|
|
41460
41351
|
console.error("\uD83D\uDD0D Starting browser URL monitoring for authorization code...");
|
|
41461
41352
|
setImmediate(async () => {
|
|
41462
|
-
|
|
41463
|
-
const code = await this.monitorBrowserForAuthCode();
|
|
41464
|
-
console.error("✅ Authorization code detected:", code.substring(0, 10) + "...");
|
|
41465
|
-
const accessToken = await this.getUserAccessToken(code);
|
|
41466
|
-
console.error("✅ Access token received");
|
|
41467
|
-
this.token = accessToken;
|
|
41468
|
-
if (this.portalCacheHook) {
|
|
41469
|
-
console.error("\uD83D\uDD04 Triggering cache initialization...");
|
|
41470
|
-
try {
|
|
41471
|
-
const fakeRequest = new Request(this.authConfig.environmentUrl, {
|
|
41472
|
-
headers: { Authorization: `Bearer ${accessToken}` }
|
|
41473
|
-
});
|
|
41474
|
-
await this.portalCacheHook.ensureCacheInitialized(fakeRequest);
|
|
41475
|
-
console.error("✅ Cache initialization completed");
|
|
41476
|
-
} catch (error) {
|
|
41477
|
-
console.error("⚠️ Cache initialization failed:", error);
|
|
41478
|
-
}
|
|
41479
|
-
}
|
|
41480
|
-
console.error("\uD83C\uDF89 Authentication complete! Stopping config server...");
|
|
41481
|
-
this.stopConfigServer();
|
|
41482
|
-
} catch (authError) {
|
|
41483
|
-
console.error("❌ Authentication monitoring error:", authError);
|
|
41484
|
-
this.stopConfigServer();
|
|
41485
|
-
}
|
|
41353
|
+
await this.monitorBrowserWithRetry();
|
|
41486
41354
|
});
|
|
41487
41355
|
} catch (error) {
|
|
41488
41356
|
console.error("❌ Error processing authentication request:", error);
|
|
@@ -41539,8 +41407,14 @@ class AuthenticationHook {
|
|
|
41539
41407
|
console.error("\uD83C\uDF89 Authentication complete! Stopping config server...");
|
|
41540
41408
|
this.stopConfigServer();
|
|
41541
41409
|
} catch (authError) {
|
|
41542
|
-
|
|
41543
|
-
|
|
41410
|
+
const isOAuthError = authError instanceof Error && authError.message.includes("OAuth error:");
|
|
41411
|
+
if (isOAuthError) {
|
|
41412
|
+
console.error("❌ OAuth authentication error:", authError.message);
|
|
41413
|
+
console.error("\uD83D\uDCA1 The configuration server will remain running. Please try again with correct credentials.");
|
|
41414
|
+
} else {
|
|
41415
|
+
console.error("❌ Token exchange error:", authError);
|
|
41416
|
+
this.stopConfigServer();
|
|
41417
|
+
}
|
|
41544
41418
|
}
|
|
41545
41419
|
});
|
|
41546
41420
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
@@ -41607,6 +41481,120 @@ class AuthenticationHook {
|
|
|
41607
41481
|
});
|
|
41608
41482
|
});
|
|
41609
41483
|
}
|
|
41484
|
+
async monitorBrowserWithRetry() {
|
|
41485
|
+
const platform = process.platform;
|
|
41486
|
+
const timeout = 120;
|
|
41487
|
+
const startTime = Date.now();
|
|
41488
|
+
let oAuthErrorLogged = false;
|
|
41489
|
+
let lastUrl = "";
|
|
41490
|
+
let lastErrorUrl = null;
|
|
41491
|
+
if (platform === "darwin") {
|
|
41492
|
+
console.error(`\uD83D\uDD0D Monitoring ${this.detectedBrowser} for authorization code...`);
|
|
41493
|
+
} else if (platform === "win32") {
|
|
41494
|
+
console.error(`\uD83D\uDD0D Monitoring ${this.detectedBrowser} for authorization code...`);
|
|
41495
|
+
}
|
|
41496
|
+
while (true) {
|
|
41497
|
+
try {
|
|
41498
|
+
if (Date.now() - startTime >= timeout * 1000) {
|
|
41499
|
+
throw new Error("Authentication timeout. Please try again.");
|
|
41500
|
+
}
|
|
41501
|
+
let currentUrl = "";
|
|
41502
|
+
if (platform === "darwin") {
|
|
41503
|
+
const script = `
|
|
41504
|
+
tell application "${this.detectedBrowser}"
|
|
41505
|
+
try
|
|
41506
|
+
set currentURL to URL of active tab of front window
|
|
41507
|
+
return currentURL
|
|
41508
|
+
on error
|
|
41509
|
+
return ""
|
|
41510
|
+
end try
|
|
41511
|
+
end tell
|
|
41512
|
+
`;
|
|
41513
|
+
const { stdout } = await execAsync(`osascript -e '${script}'`);
|
|
41514
|
+
currentUrl = stdout.trim();
|
|
41515
|
+
} else if (platform === "win32") {
|
|
41516
|
+
const browserProcessName = this.detectedBrowser.replace(".exe", "");
|
|
41517
|
+
const psScript = `
|
|
41518
|
+
$process = Get-Process -Name "${browserProcessName}" -ErrorAction SilentlyContinue |
|
|
41519
|
+
Where-Object { $_.MainWindowHandle -ne 0 } |
|
|
41520
|
+
Select-Object -First 1
|
|
41521
|
+
if ($process) {
|
|
41522
|
+
$process.MainWindowTitle
|
|
41523
|
+
}
|
|
41524
|
+
`.replace(/\n\s+/g, " ");
|
|
41525
|
+
const { stdout } = await execAsync(`powershell -Command "${psScript}"`);
|
|
41526
|
+
currentUrl = stdout.trim();
|
|
41527
|
+
}
|
|
41528
|
+
if (currentUrl && currentUrl !== lastUrl) {
|
|
41529
|
+
lastUrl = currentUrl;
|
|
41530
|
+
console.error(`\uD83D\uDD0D Current URL: ${currentUrl}`);
|
|
41531
|
+
}
|
|
41532
|
+
if (currentUrl && currentUrl.includes("code=")) {
|
|
41533
|
+
const codeMatch = currentUrl.match(/[?&]code=([^&]+)/);
|
|
41534
|
+
if (codeMatch && codeMatch[1]) {
|
|
41535
|
+
const code = decodeURIComponent(codeMatch[1]);
|
|
41536
|
+
console.error("✅ Found authorization code in URL!");
|
|
41537
|
+
console.error(`\uD83D\uDD11 Extracted authorization code (first 20 chars): ${code.substring(0, 20)}...`);
|
|
41538
|
+
setImmediate(async () => {
|
|
41539
|
+
try {
|
|
41540
|
+
if (platform === "darwin") {
|
|
41541
|
+
await execAsync(`osascript -e 'tell application "${this.detectedBrowser}" to close front window'`);
|
|
41542
|
+
} else if (platform === "win32") {
|
|
41543
|
+
const browserProcessName = this.detectedBrowser.replace(".exe", "");
|
|
41544
|
+
await execAsync(`powershell -Command "Stop-Process -Name '${browserProcessName}' -Force"`);
|
|
41545
|
+
}
|
|
41546
|
+
} catch (closeError) {}
|
|
41547
|
+
});
|
|
41548
|
+
console.error("✅ Authorization code detected:", code.substring(0, 10) + "...");
|
|
41549
|
+
const accessToken = await this.getUserAccessToken(code);
|
|
41550
|
+
console.error("✅ Access token received");
|
|
41551
|
+
this.token = accessToken;
|
|
41552
|
+
if (this.portalCacheHook) {
|
|
41553
|
+
try {
|
|
41554
|
+
const fakeRequest = new Request(this.authConfig.environmentUrl, {
|
|
41555
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
41556
|
+
});
|
|
41557
|
+
await this.portalCacheHook.ensureCacheInitialized(fakeRequest);
|
|
41558
|
+
console.error("✅ Cache initialization completed");
|
|
41559
|
+
} catch (error) {
|
|
41560
|
+
console.error("⚠️ Cache initialization failed:", error);
|
|
41561
|
+
}
|
|
41562
|
+
}
|
|
41563
|
+
console.error("\uD83C\uDF89 Authentication complete! Stopping config server...");
|
|
41564
|
+
this.stopConfigServer();
|
|
41565
|
+
return;
|
|
41566
|
+
}
|
|
41567
|
+
}
|
|
41568
|
+
if (currentUrl && currentUrl.includes("error=")) {
|
|
41569
|
+
if (currentUrl !== lastErrorUrl) {
|
|
41570
|
+
lastErrorUrl = currentUrl;
|
|
41571
|
+
const errorMatch = currentUrl.match(/[?&]error=([^&]+)/);
|
|
41572
|
+
const errorDescMatch = currentUrl.match(/error_description=([^&]+)/);
|
|
41573
|
+
const error = errorMatch && errorMatch[1] ? decodeURIComponent(errorMatch[1]) : "unknown_error";
|
|
41574
|
+
const errorDesc = errorDescMatch && errorDescMatch[1] ? decodeURIComponent(errorDescMatch[1]) : "No description";
|
|
41575
|
+
if (!oAuthErrorLogged) {
|
|
41576
|
+
console.error("❌ OAuth authentication error:", `${error} - ${errorDesc}`);
|
|
41577
|
+
console.error("\uD83D\uDCA1 The configuration server will remain running. Please try again with correct credentials.");
|
|
41578
|
+
console.error("\uD83D\uDD0D Continuing to monitor browser for authorization code...");
|
|
41579
|
+
oAuthErrorLogged = true;
|
|
41580
|
+
}
|
|
41581
|
+
}
|
|
41582
|
+
} else {
|
|
41583
|
+
if (lastErrorUrl !== null) {
|
|
41584
|
+
lastErrorUrl = null;
|
|
41585
|
+
oAuthErrorLogged = false;
|
|
41586
|
+
}
|
|
41587
|
+
}
|
|
41588
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
41589
|
+
} catch (error) {
|
|
41590
|
+
if (!(error instanceof Error && error.message.includes("OAuth error:"))) {
|
|
41591
|
+
console.error("❌ Authentication monitoring error:", error);
|
|
41592
|
+
this.stopConfigServer();
|
|
41593
|
+
return;
|
|
41594
|
+
}
|
|
41595
|
+
}
|
|
41596
|
+
}
|
|
41597
|
+
}
|
|
41610
41598
|
stopConfigServer() {
|
|
41611
41599
|
if (this.configServer) {
|
|
41612
41600
|
console.error("\uD83D\uDEAA Stopping configuration server...");
|
|
@@ -41742,6 +41730,7 @@ class AuthenticationHook {
|
|
|
41742
41730
|
}
|
|
41743
41731
|
} else {
|
|
41744
41732
|
console.error("⏰ Existing token is expired or not found, proceeding with fresh login...");
|
|
41733
|
+
this.token = null;
|
|
41745
41734
|
}
|
|
41746
41735
|
const hasConfig = this.authConfig.environmentUrl && this.authConfig.clientId && this.authConfig.redirectUri && this.authConfig.authUrl && this.authConfig.accessUrl;
|
|
41747
41736
|
if (!hasConfig) {
|
|
@@ -46810,14 +46799,55 @@ var init_getPortals2 = __esm(() => {
|
|
|
46810
46799
|
name: "get-portals",
|
|
46811
46800
|
description: `Get All Portals Accessible To User
|
|
46812
46801
|
|
|
46802
|
+
Get All Portals Accessible to User
|
|
46803
|
+
|
|
46813
46804
|
## Overview
|
|
46814
|
-
|
|
46815
|
-
|
|
46816
|
-
|
|
46817
|
-
|
|
46818
|
-
|
|
46819
|
-
|
|
46820
|
-
|
|
46805
|
+
The Get All Portals Accessible to User API allows a user to fetch all portals accessible to the user across all departments.
|
|
46806
|
+
- If no access tags are specified for a portal, any user can access the portal.
|
|
46807
|
+
- If access tags are specified for a portal, users with a user profile that allows access can access the portal. For users with multiple user profiles, the user profile that allows access does not need to be the active user profile.
|
|
46808
|
+
- Global users (partition) cannot be assigned user profiles; their access is limited to portals without access restrictions.
|
|
46809
|
+
- The only articles returned are associated to an Article type when the parameter “Include in browse on portals” is set to "Yes".
|
|
46810
|
+
- When the \`shortUrlTemplate\` query parameter is provided, the API filters accessible portals according to the specified language and template name. A portal short URL specific to the \`shortUrlTemplate\` value is returned in the response when available. If there is no short URL for a language, the portal object returns an empty \`shortURL\` field.
|
|
46811
|
+
|
|
46812
|
+
## Pagination behavior (CRITICAL for AI assistants)
|
|
46813
|
+
|
|
46814
|
+
**IMPORTANT**: This endpoint is paginated. When searching for a portal by name or listing portals, you MUST automatically fetch ALL pages before concluding that a portal doesn't exist.
|
|
46815
|
+
|
|
46816
|
+
### Automatic pagination is REQUIRED when:
|
|
46817
|
+
- User asks to find a portal by name (e.g., "business portal", "Master portal")
|
|
46818
|
+
- User requests to list or see all portals
|
|
46819
|
+
- You need to resolve a natural portal name to its ID
|
|
46820
|
+
|
|
46821
|
+
### How to detect more pages exist:
|
|
46822
|
+
The response includes \`paginationInfo\` with:
|
|
46823
|
+
- \`count\`: Total number of items across all pages
|
|
46824
|
+
- \`pagenum\`: Current page number
|
|
46825
|
+
- \`pagesize\`: Items per page (default: 25)
|
|
46826
|
+
|
|
46827
|
+
**Check for more pages if ANY of these are true:**
|
|
46828
|
+
1. The number of portals returned equals \`pagesize\` (e.g., exactly 25 portals returned)
|
|
46829
|
+
2. \`paginationInfo.count > (pagenum * pagesize)\` - there are more items beyond this page
|
|
46830
|
+
3. The response includes a \`link\` array with a \`next\` relation
|
|
46831
|
+
|
|
46832
|
+
### Required pagination workflow:
|
|
46833
|
+
1. Start with \`$pagenum=1\` and \`$pagesize=25\` (default)
|
|
46834
|
+
2. After receiving the response, check \`paginationInfo\`
|
|
46835
|
+
3. **If more pages exist** (using the checks above), automatically call this endpoint again with \`$pagenum=2\`, then \`$pagenum=3\`, etc.
|
|
46836
|
+
4. Continue incrementing \`$pagenum\` until:
|
|
46837
|
+
- A page returns fewer portals than \`pagesize\` (indicating the last page)
|
|
46838
|
+
- A page returns zero portals
|
|
46839
|
+
- \`pagenum * pagesize >= paginationInfo.count\` (if count represents total items)
|
|
46840
|
+
5. Merge all portals from all pages by unique portal ID
|
|
46841
|
+
6. Only then search through the complete merged list or report results to the user
|
|
46842
|
+
|
|
46843
|
+
### Example scenario:
|
|
46844
|
+
If you search for "business portal" and the first page returns 25 portals but none match:
|
|
46845
|
+
- DO NOT immediately tell the user the portal doesn't exist
|
|
46846
|
+
- Check \`paginationInfo.count\` - if it's > 25, automatically fetch page 2
|
|
46847
|
+
- Continue fetching until all pages are retrieved
|
|
46848
|
+
- Search the complete merged list before concluding the portal doesn't exist
|
|
46849
|
+
|
|
46850
|
+
This ensures reliable portal name-to-ID resolution and prevents false "not found" errors.
|
|
46821
46851
|
`,
|
|
46822
46852
|
annotations: {
|
|
46823
46853
|
destructiveHint: false,
|
|
@@ -47817,7 +47847,7 @@ The Search API is a hybrid search service that combines semantic understanding w
|
|
|
47817
47847
|
function createMCPServer(deps) {
|
|
47818
47848
|
const server = new McpServer({
|
|
47819
47849
|
name: "EgainMcp",
|
|
47820
|
-
version: "1.0.
|
|
47850
|
+
version: "1.0.12"
|
|
47821
47851
|
});
|
|
47822
47852
|
const getClient = deps.getSDK || (() => new EgainMcpCore({
|
|
47823
47853
|
security: deps.security,
|
|
@@ -49064,7 +49094,7 @@ var routes = ln({
|
|
|
49064
49094
|
var app = _e(routes, {
|
|
49065
49095
|
name: "mcp",
|
|
49066
49096
|
versionInfo: {
|
|
49067
|
-
currentVersion: "1.0.
|
|
49097
|
+
currentVersion: "1.0.12"
|
|
49068
49098
|
}
|
|
49069
49099
|
});
|
|
49070
49100
|
Yt(app, process3.argv.slice(2), buildContext(process3));
|
|
@@ -49072,5 +49102,5 @@ export {
|
|
|
49072
49102
|
app
|
|
49073
49103
|
};
|
|
49074
49104
|
|
|
49075
|
-
//# debugId=
|
|
49105
|
+
//# debugId=4532247C421ADCA364756E2164756E21
|
|
49076
49106
|
//# sourceMappingURL=mcp-server.js.map
|