@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.
Files changed (36) hide show
  1. package/README.md +22 -0
  2. package/bin/mcp-server.js +201 -171
  3. package/bin/mcp-server.js.map +9 -9
  4. package/esm/src/funcs/getPortals.d.ts +48 -7
  5. package/esm/src/funcs/getPortals.d.ts.map +1 -1
  6. package/esm/src/funcs/getPortals.js +48 -7
  7. package/esm/src/funcs/getPortals.js.map +1 -1
  8. package/esm/src/hooks/auth-hook.d.ts +6 -1
  9. package/esm/src/hooks/auth-hook.d.ts.map +1 -1
  10. package/esm/src/hooks/auth-hook.js +189 -197
  11. package/esm/src/hooks/auth-hook.js.map +1 -1
  12. package/esm/src/hooks/tooltip-images.d.ts +10 -0
  13. package/esm/src/hooks/tooltip-images.d.ts.map +1 -0
  14. package/esm/src/hooks/tooltip-images.js +12 -0
  15. package/esm/src/hooks/tooltip-images.js.map +1 -0
  16. package/esm/src/lib/config.d.ts +2 -2
  17. package/esm/src/lib/config.js +2 -2
  18. package/esm/src/lib/config.js.map +1 -1
  19. package/esm/src/mcp-server/mcp-server.js +1 -1
  20. package/esm/src/mcp-server/mcp-server.js.map +1 -1
  21. package/esm/src/mcp-server/server.js +1 -1
  22. package/esm/src/mcp-server/server.js.map +1 -1
  23. package/esm/src/mcp-server/tools/getPortals.d.ts.map +1 -1
  24. package/esm/src/mcp-server/tools/getPortals.js +48 -7
  25. package/esm/src/mcp-server/tools/getPortals.js.map +1 -1
  26. package/esm/src/models/getmyportalsop.d.ts +1 -1
  27. package/esm/src/models/getmyportalsop.d.ts.map +1 -1
  28. package/manifest.json +2 -2
  29. package/package.json +1 -1
  30. package/src/funcs/getPortals.ts +48 -7
  31. package/src/hooks/auth-hook.ts +200 -224
  32. package/src/lib/config.ts +2 -2
  33. package/src/mcp-server/mcp-server.ts +1 -1
  34. package/src/mcp-server/server.ts +1 -1
  35. package/src/mcp-server/tools/getPortals.ts +48 -7
  36. 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.6",
4049
+ sdkVersion: "1.0.12",
4050
4050
  genVersion: "2.723.8",
4051
- userAgent: "speakeasy-sdk/mcp-typescript 1.0.6 2.723.8 1.0.0 @egain/egain-mcp-server"
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
- try {
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
- try {
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
- console.error(" Token exchange error:", authError);
41543
- this.stopConfigServer();
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
- The Get All Portals Accessible to User API allows a user to fetch all portals accessible to user across all department.
46815
- * If no access tags are specified for a portal, then any user can access the portal.
46816
- * If access tags are specified for a portal, users with a user profile that allows access have access to the portal. For users with multiple user profiles, the user profile that allows access does not need to be the active user profile.
46817
- * All the global users(partition) cannot be assigned user profiles; their access is limited to portals without access restrictions.
46818
- * The only articles returned are associated to an Article type when the parameter, “Include in browse on portals” is set to "Yes".
46819
- * When the "shortUrlTemplate" query parameter is provided, the API filters accessible portals according to the specified language and template name. Portal Short URL specific to to the "shortUrlTemplate" query parameter value is returned in the response.
46820
- * When there is no short URL available for a specific language, the API returns a portal object with an empty "shortURL" field.
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.6"
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.6"
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=3CD281DB81F8829C64756E2164756E21
49105
+ //# debugId=4532247C421ADCA364756E2164756E21
49076
49106
  //# sourceMappingURL=mcp-server.js.map