@egain/egain-mcp-server 1.0.6 → 1.0.11

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 +191 -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 +174 -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 +185 -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** (includes npm and npx) - 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.11",
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.11 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,20 @@ 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
+ }
41240
41141
  return false;
41241
41142
  }
41242
41143
  }
@@ -41362,26 +41263,7 @@ class AuthenticationHook {
41362
41263
  }));
41363
41264
  console.error("\uD83D\uDD0D Starting browser URL monitoring for authorization code...");
41364
41265
  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
- }
41266
+ await this.monitorBrowserWithRetry();
41385
41267
  });
41386
41268
  } catch (error) {
41387
41269
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -41459,30 +41341,7 @@ class AuthenticationHook {
41459
41341
  }));
41460
41342
  console.error("\uD83D\uDD0D Starting browser URL monitoring for authorization code...");
41461
41343
  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
- }
41344
+ await this.monitorBrowserWithRetry();
41486
41345
  });
41487
41346
  } catch (error) {
41488
41347
  console.error("❌ Error processing authentication request:", error);
@@ -41539,8 +41398,14 @@ class AuthenticationHook {
41539
41398
  console.error("\uD83C\uDF89 Authentication complete! Stopping config server...");
41540
41399
  this.stopConfigServer();
41541
41400
  } catch (authError) {
41542
- console.error(" Token exchange error:", authError);
41543
- this.stopConfigServer();
41401
+ const isOAuthError = authError instanceof Error && authError.message.includes("OAuth error:");
41402
+ if (isOAuthError) {
41403
+ console.error("❌ OAuth authentication error:", authError.message);
41404
+ console.error("\uD83D\uDCA1 The configuration server will remain running. Please try again with correct credentials.");
41405
+ } else {
41406
+ console.error("❌ Token exchange error:", authError);
41407
+ this.stopConfigServer();
41408
+ }
41544
41409
  }
41545
41410
  });
41546
41411
  res.writeHead(200, { "Content-Type": "text/html" });
@@ -41607,6 +41472,120 @@ class AuthenticationHook {
41607
41472
  });
41608
41473
  });
41609
41474
  }
41475
+ async monitorBrowserWithRetry() {
41476
+ const platform = process.platform;
41477
+ const timeout = 120;
41478
+ const startTime = Date.now();
41479
+ let oAuthErrorLogged = false;
41480
+ let lastUrl = "";
41481
+ let lastErrorUrl = null;
41482
+ if (platform === "darwin") {
41483
+ console.error(`\uD83D\uDD0D Monitoring ${this.detectedBrowser} for authorization code...`);
41484
+ } else if (platform === "win32") {
41485
+ console.error(`\uD83D\uDD0D Monitoring ${this.detectedBrowser} for authorization code...`);
41486
+ }
41487
+ while (true) {
41488
+ try {
41489
+ if (Date.now() - startTime >= timeout * 1000) {
41490
+ throw new Error("Authentication timeout. Please try again.");
41491
+ }
41492
+ let currentUrl = "";
41493
+ if (platform === "darwin") {
41494
+ const script = `
41495
+ tell application "${this.detectedBrowser}"
41496
+ try
41497
+ set currentURL to URL of active tab of front window
41498
+ return currentURL
41499
+ on error
41500
+ return ""
41501
+ end try
41502
+ end tell
41503
+ `;
41504
+ const { stdout } = await execAsync(`osascript -e '${script}'`);
41505
+ currentUrl = stdout.trim();
41506
+ } else if (platform === "win32") {
41507
+ const browserProcessName = this.detectedBrowser.replace(".exe", "");
41508
+ const psScript = `
41509
+ $process = Get-Process -Name "${browserProcessName}" -ErrorAction SilentlyContinue |
41510
+ Where-Object { $_.MainWindowHandle -ne 0 } |
41511
+ Select-Object -First 1
41512
+ if ($process) {
41513
+ $process.MainWindowTitle
41514
+ }
41515
+ `.replace(/\n\s+/g, " ");
41516
+ const { stdout } = await execAsync(`powershell -Command "${psScript}"`);
41517
+ currentUrl = stdout.trim();
41518
+ }
41519
+ if (currentUrl && currentUrl !== lastUrl) {
41520
+ lastUrl = currentUrl;
41521
+ console.error(`\uD83D\uDD0D Current URL: ${currentUrl}`);
41522
+ }
41523
+ if (currentUrl && currentUrl.includes("code=")) {
41524
+ const codeMatch = currentUrl.match(/[?&]code=([^&]+)/);
41525
+ if (codeMatch && codeMatch[1]) {
41526
+ const code = decodeURIComponent(codeMatch[1]);
41527
+ console.error("✅ Found authorization code in URL!");
41528
+ console.error(`\uD83D\uDD11 Extracted authorization code (first 20 chars): ${code.substring(0, 20)}...`);
41529
+ setImmediate(async () => {
41530
+ try {
41531
+ if (platform === "darwin") {
41532
+ await execAsync(`osascript -e 'tell application "${this.detectedBrowser}" to close front window'`);
41533
+ } else if (platform === "win32") {
41534
+ const browserProcessName = this.detectedBrowser.replace(".exe", "");
41535
+ await execAsync(`powershell -Command "Stop-Process -Name '${browserProcessName}' -Force"`);
41536
+ }
41537
+ } catch (closeError) {}
41538
+ });
41539
+ console.error("✅ Authorization code detected:", code.substring(0, 10) + "...");
41540
+ const accessToken = await this.getUserAccessToken(code);
41541
+ console.error("✅ Access token received");
41542
+ this.token = accessToken;
41543
+ if (this.portalCacheHook) {
41544
+ try {
41545
+ const fakeRequest = new Request(this.authConfig.environmentUrl, {
41546
+ headers: { Authorization: `Bearer ${accessToken}` }
41547
+ });
41548
+ await this.portalCacheHook.ensureCacheInitialized(fakeRequest);
41549
+ console.error("✅ Cache initialization completed");
41550
+ } catch (error) {
41551
+ console.error("⚠️ Cache initialization failed:", error);
41552
+ }
41553
+ }
41554
+ console.error("\uD83C\uDF89 Authentication complete! Stopping config server...");
41555
+ this.stopConfigServer();
41556
+ return;
41557
+ }
41558
+ }
41559
+ if (currentUrl && currentUrl.includes("error=")) {
41560
+ if (currentUrl !== lastErrorUrl) {
41561
+ lastErrorUrl = currentUrl;
41562
+ const errorMatch = currentUrl.match(/[?&]error=([^&]+)/);
41563
+ const errorDescMatch = currentUrl.match(/error_description=([^&]+)/);
41564
+ const error = errorMatch && errorMatch[1] ? decodeURIComponent(errorMatch[1]) : "unknown_error";
41565
+ const errorDesc = errorDescMatch && errorDescMatch[1] ? decodeURIComponent(errorDescMatch[1]) : "No description";
41566
+ if (!oAuthErrorLogged) {
41567
+ console.error("❌ OAuth authentication error:", `${error} - ${errorDesc}`);
41568
+ console.error("\uD83D\uDCA1 The configuration server will remain running. Please try again with correct credentials.");
41569
+ console.error("\uD83D\uDD0D Continuing to monitor browser for authorization code...");
41570
+ oAuthErrorLogged = true;
41571
+ }
41572
+ }
41573
+ } else {
41574
+ if (lastErrorUrl !== null) {
41575
+ lastErrorUrl = null;
41576
+ oAuthErrorLogged = false;
41577
+ }
41578
+ }
41579
+ await new Promise((resolve) => setTimeout(resolve, 500));
41580
+ } catch (error) {
41581
+ if (!(error instanceof Error && error.message.includes("OAuth error:"))) {
41582
+ console.error("❌ Authentication monitoring error:", error);
41583
+ this.stopConfigServer();
41584
+ return;
41585
+ }
41586
+ }
41587
+ }
41588
+ }
41610
41589
  stopConfigServer() {
41611
41590
  if (this.configServer) {
41612
41591
  console.error("\uD83D\uDEAA Stopping configuration server...");
@@ -46810,14 +46789,55 @@ var init_getPortals2 = __esm(() => {
46810
46789
  name: "get-portals",
46811
46790
  description: `Get All Portals Accessible To User
46812
46791
 
46792
+ Get All Portals Accessible to User
46793
+
46813
46794
  ## 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.
46795
+ The Get All Portals Accessible to User API allows a user to fetch all portals accessible to the user across all departments.
46796
+ - If no access tags are specified for a portal, any user can access the portal.
46797
+ - 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.
46798
+ - Global users (partition) cannot be assigned user profiles; their access is limited to portals without access restrictions.
46799
+ - The only articles returned are associated to an Article type when the parameter “Include in browse on portals” is set to "Yes".
46800
+ - 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.
46801
+
46802
+ ## Pagination behavior (CRITICAL for AI assistants)
46803
+
46804
+ **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.
46805
+
46806
+ ### Automatic pagination is REQUIRED when:
46807
+ - User asks to find a portal by name (e.g., "business portal", "Master portal")
46808
+ - User requests to list or see all portals
46809
+ - You need to resolve a natural portal name to its ID
46810
+
46811
+ ### How to detect more pages exist:
46812
+ The response includes \`paginationInfo\` with:
46813
+ - \`count\`: Total number of items across all pages
46814
+ - \`pagenum\`: Current page number
46815
+ - \`pagesize\`: Items per page (default: 25)
46816
+
46817
+ **Check for more pages if ANY of these are true:**
46818
+ 1. The number of portals returned equals \`pagesize\` (e.g., exactly 25 portals returned)
46819
+ 2. \`paginationInfo.count > (pagenum * pagesize)\` - there are more items beyond this page
46820
+ 3. The response includes a \`link\` array with a \`next\` relation
46821
+
46822
+ ### Required pagination workflow:
46823
+ 1. Start with \`$pagenum=1\` and \`$pagesize=25\` (default)
46824
+ 2. After receiving the response, check \`paginationInfo\`
46825
+ 3. **If more pages exist** (using the checks above), automatically call this endpoint again with \`$pagenum=2\`, then \`$pagenum=3\`, etc.
46826
+ 4. Continue incrementing \`$pagenum\` until:
46827
+ - A page returns fewer portals than \`pagesize\` (indicating the last page)
46828
+ - A page returns zero portals
46829
+ - \`pagenum * pagesize >= paginationInfo.count\` (if count represents total items)
46830
+ 5. Merge all portals from all pages by unique portal ID
46831
+ 6. Only then search through the complete merged list or report results to the user
46832
+
46833
+ ### Example scenario:
46834
+ If you search for "business portal" and the first page returns 25 portals but none match:
46835
+ - DO NOT immediately tell the user the portal doesn't exist
46836
+ - Check \`paginationInfo.count\` - if it's > 25, automatically fetch page 2
46837
+ - Continue fetching until all pages are retrieved
46838
+ - Search the complete merged list before concluding the portal doesn't exist
46839
+
46840
+ This ensures reliable portal name-to-ID resolution and prevents false "not found" errors.
46821
46841
  `,
46822
46842
  annotations: {
46823
46843
  destructiveHint: false,
@@ -47817,7 +47837,7 @@ The Search API is a hybrid search service that combines semantic understanding w
47817
47837
  function createMCPServer(deps) {
47818
47838
  const server = new McpServer({
47819
47839
  name: "EgainMcp",
47820
- version: "1.0.6"
47840
+ version: "1.0.11"
47821
47841
  });
47822
47842
  const getClient = deps.getSDK || (() => new EgainMcpCore({
47823
47843
  security: deps.security,
@@ -49064,7 +49084,7 @@ var routes = ln({
49064
49084
  var app = _e(routes, {
49065
49085
  name: "mcp",
49066
49086
  versionInfo: {
49067
- currentVersion: "1.0.6"
49087
+ currentVersion: "1.0.11"
49068
49088
  }
49069
49089
  });
49070
49090
  Yt(app, process3.argv.slice(2), buildContext(process3));
@@ -49072,5 +49092,5 @@ export {
49072
49092
  app
49073
49093
  };
49074
49094
 
49075
- //# debugId=3CD281DB81F8829C64756E2164756E21
49095
+ //# debugId=2754684247616B6C64756E2164756E21
49076
49096
  //# sourceMappingURL=mcp-server.js.map