@index9/mcp 4.0.1 → 4.0.2

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/dist/cli.js CHANGED
@@ -593,6 +593,13 @@ function loadConfig() {
593
593
  const env = process.env.INDEX9_API_BASE_URL?.trim();
594
594
  const baseUrl = env || DEFAULT_BASE_URL;
595
595
  const normalized = baseUrl.replace(/\/$/, "");
596
+ try {
597
+ new URL(normalized);
598
+ } catch {
599
+ throw new Error(
600
+ `Invalid INDEX9_API_BASE_URL: ${normalized}. Expected an absolute URL such as https://index9.dev`
601
+ );
602
+ }
596
603
  return {
597
604
  baseUrl: normalized,
598
605
  apiToken: process.env.INDEX9_API_TOKEN?.trim() || void 0,
@@ -602,23 +609,62 @@ function loadConfig() {
602
609
 
603
610
  // src/client.ts
604
611
  var RETRY_DELAYS_MS = [1e3, 2e3, 4e3];
612
+ var ATTEMPT_TIMEOUT_MS = 3e4;
605
613
  function isRetryable(status) {
606
614
  return status === 429 || status >= 500;
607
615
  }
608
616
  async function sleep(ms) {
609
617
  return new Promise((r) => setTimeout(r, ms));
610
618
  }
619
+ function isRetryableError(error) {
620
+ if (!(error instanceof Error)) return false;
621
+ if (error.name === "AbortError" || error.name === "TimeoutError") return true;
622
+ return error instanceof TypeError;
623
+ }
624
+ function toErrorMessage(error) {
625
+ if (error instanceof Error && error.message.trim()) return error.message;
626
+ return "Unknown error";
627
+ }
611
628
  async function fetchWithRetry(url, options) {
612
629
  let lastResponse = null;
630
+ let lastError;
613
631
  for (let i = 0; i <= RETRY_DELAYS_MS.length; i++) {
614
- const res = await fetch(url, options);
615
- lastResponse = res;
616
- if (res.ok || !isRetryable(res.status)) return res;
632
+ const timeoutController = new AbortController();
633
+ const timeoutId = setTimeout(() => {
634
+ timeoutController.abort(new DOMException("Request timed out", "AbortError"));
635
+ }, ATTEMPT_TIMEOUT_MS);
636
+ const externalSignal = options.signal;
637
+ const onAbort = () => {
638
+ timeoutController.abort(
639
+ externalSignal?.reason ?? new DOMException("Request aborted", "AbortError")
640
+ );
641
+ };
642
+ if (externalSignal?.aborted) {
643
+ onAbort();
644
+ } else {
645
+ externalSignal?.addEventListener("abort", onAbort, { once: true });
646
+ }
647
+ try {
648
+ const res = await fetch(url, { ...options, signal: timeoutController.signal });
649
+ lastResponse = res;
650
+ if (res.ok || !isRetryable(res.status)) return res;
651
+ } catch (error) {
652
+ lastError = error;
653
+ if (!isRetryableError(error)) {
654
+ throw new Error(`Request failed: ${toErrorMessage(error)}`);
655
+ }
656
+ } finally {
657
+ clearTimeout(timeoutId);
658
+ externalSignal?.removeEventListener("abort", onAbort);
659
+ }
617
660
  if (i < RETRY_DELAYS_MS.length) {
618
661
  await sleep(RETRY_DELAYS_MS[i]);
619
662
  }
620
663
  }
621
- return lastResponse;
664
+ if (lastResponse) return lastResponse;
665
+ throw new Error(
666
+ `Request failed after ${RETRY_DELAYS_MS.length + 1} attempts: ${toErrorMessage(lastError)}`
667
+ );
622
668
  }
623
669
  function buildUrl(baseUrl, path, params) {
624
670
  const url = new URL(path, baseUrl);
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": "0.3",
3
3
  "name": "index9",
4
- "version": "4.0.0",
4
+ "version": "4.0.1",
5
5
  "description": "Search, inspect, and benchmark 300+ AI models from your editor",
6
6
  "author": {
7
7
  "name": "Index9"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@index9/mcp",
3
- "version": "4.0.1",
3
+ "version": "4.0.2",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,13 +20,14 @@
20
20
  "access": "public"
21
21
  },
22
22
  "dependencies": {
23
- "@modelcontextprotocol/sdk": "^1.26.0",
23
+ "@modelcontextprotocol/sdk": "^1.29.0",
24
24
  "zod": "^4.3.6"
25
25
  },
26
26
  "devDependencies": {
27
- "@types/node": "^25.2.3",
27
+ "@types/node": "^25.6.0",
28
28
  "tsup": "^8.5.1",
29
- "typescript": "5.9.3",
29
+ "typescript": "6.0.3",
30
+ "vitest": "^4.1.5",
30
31
  "@index9/core": "2.3.1"
31
32
  },
32
33
  "engines": {
@@ -37,6 +38,6 @@
37
38
  "clean": "rm -rf dist",
38
39
  "lint": "tsc --noEmit",
39
40
  "start": "node dist/cli.js",
40
- "test": "echo 'No tests in @index9/mcp'"
41
+ "test": "vitest run"
41
42
  }
42
43
  }