@toolsdk.ai/registry 1.0.124 → 1.0.125

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 (30) hide show
  1. package/dist/api/index.js +4 -0
  2. package/dist/domains/package/package-handler.d.ts +2 -0
  3. package/dist/domains/package/package-handler.js +1 -1
  4. package/dist/domains/package/package-so.js +10 -3
  5. package/dist/domains/package/package-so.test.js +24 -5
  6. package/dist/domains/registry/__tests__/federated-registry-provider.test.d.ts +1 -0
  7. package/dist/domains/registry/__tests__/federated-registry-provider.test.js +125 -0
  8. package/dist/domains/registry/__tests__/local-registry-provider.test.d.ts +1 -0
  9. package/dist/domains/registry/__tests__/local-registry-provider.test.js +80 -0
  10. package/dist/domains/registry/__tests__/official-registry-provider.integration.test.d.ts +1 -0
  11. package/dist/domains/registry/__tests__/official-registry-provider.integration.test.js +70 -0
  12. package/dist/domains/registry/__tests__/registry-utils.test.d.ts +1 -0
  13. package/dist/domains/registry/__tests__/registry-utils.test.js +307 -0
  14. package/dist/domains/registry/index.d.ts +8 -0
  15. package/dist/domains/registry/index.js +9 -0
  16. package/dist/domains/registry/providers/federated-registry-provider.d.ts +25 -0
  17. package/dist/domains/registry/providers/federated-registry-provider.js +49 -0
  18. package/dist/domains/registry/providers/local-registry-provider.d.ts +23 -0
  19. package/dist/domains/registry/providers/local-registry-provider.js +35 -0
  20. package/dist/domains/registry/providers/official-registry-provider.d.ts +34 -0
  21. package/dist/domains/registry/providers/official-registry-provider.js +83 -0
  22. package/dist/domains/registry/registry-factory.d.ts +21 -0
  23. package/dist/domains/registry/registry-factory.js +52 -0
  24. package/dist/domains/registry/registry-schema.d.ts +586 -0
  25. package/dist/domains/registry/registry-schema.js +39 -0
  26. package/dist/domains/registry/registry-types.d.ts +23 -0
  27. package/dist/domains/registry/registry-types.js +1 -0
  28. package/dist/domains/registry/registry-utils.d.ts +14 -0
  29. package/dist/domains/registry/registry-utils.js +50 -0
  30. package/package.json +1 -1
package/dist/api/index.js CHANGED
@@ -4,11 +4,15 @@ import { serve } from "@hono/node-server";
4
4
  import { swaggerUI } from "@hono/swagger-ui";
5
5
  import { OpenAPIHono } from "@hono/zod-openapi";
6
6
  import { configRoutes } from "../domains/config/config-route";
7
+ import { repository } from "../domains/package/package-handler";
7
8
  import { packageRoutes } from "../domains/package/package-route";
9
+ import { initRegistryFactory } from "../domains/registry/registry-factory";
8
10
  import { searchRoutes } from "../domains/search/search-route";
9
11
  import { SearchSO } from "../domains/search/search-so";
10
12
  import { getServerPort, isSearchEnabled } from "../shared/config/environment";
11
13
  import { getDirname } from "../shared/utils";
14
+ // Initialize Registry Factory with the local repository
15
+ initRegistryFactory(repository);
12
16
  const initializeSearchService = async () => {
13
17
  try {
14
18
  await SearchSO.getInstance();
@@ -1,4 +1,6 @@
1
1
  import type { MCPSandboxProvider } from "../sandbox/sandbox-types";
2
+ import { PackageRepository } from "./package-repository";
3
+ export declare const repository: PackageRepository;
2
4
  export declare const packageHandler: {
3
5
  getPackageDetail: (packageName: string, sandboxProvider?: MCPSandboxProvider) => Promise<{
4
6
  success: boolean;
@@ -6,7 +6,7 @@ import { PackageRepository } from "./package-repository";
6
6
  import { PackageSO } from "./package-so";
7
7
  const __dirname = getDirname(import.meta.url);
8
8
  const packagesDir = path.join(__dirname, "../../../packages");
9
- const repository = new PackageRepository(packagesDir);
9
+ export const repository = new PackageRepository(packagesDir);
10
10
  export const packageHandler = {
11
11
  getPackageDetail: async (packageName, sandboxProvider) => {
12
12
  try {
@@ -1,5 +1,6 @@
1
+ import { getRegistryProvider } from "../registry/registry-factory";
1
2
  export class PackageSO {
2
- constructor(_packageName, _config, _packageInfo, _repository, _executor) {
3
+ constructor(_packageName, _config, _packageInfo, _executor) {
3
4
  this._packageName = _packageName;
4
5
  this._config = _config;
5
6
  this._packageInfo = _packageInfo;
@@ -24,10 +25,16 @@ export class PackageSO {
24
25
  return this._config;
25
26
  }
26
27
  static async init(packageName, repository, executor) {
27
- const config = repository.getPackageConfig(packageName);
28
+ // Use FederatedRegistryProvider, which checks for local packages first and falls back to the official registry if not found locally.
29
+ const provider = getRegistryProvider("FEDERATED");
30
+ const config = await provider.getPackageConfig(packageName);
31
+ if (!config) {
32
+ throw new Error(`Package '${packageName}' not found`);
33
+ }
34
+ // Get package metadata (category, validated) from local repository index if available.
28
35
  const allPackages = repository.getAllPackages();
29
36
  const packageInfo = allPackages[packageName] || {};
30
- return new PackageSO(packageName, config, packageInfo, repository, executor);
37
+ return new PackageSO(packageName, config, packageInfo, executor);
31
38
  }
32
39
  async getTools() {
33
40
  return await this._executor.listTools(this.packageName);
@@ -1,15 +1,20 @@
1
1
  import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { initRegistryFactory, resetRegistryFactory } from "../registry/registry-factory";
2
3
  import { PackageSO } from "./package-so";
3
4
  describe("PackageSO", () => {
4
5
  let mockRepository;
5
6
  let mockExecutor;
6
7
  beforeEach(() => {
8
+ // Reset factory before each test
9
+ resetRegistryFactory();
7
10
  // Mock PackageRepository
8
11
  mockRepository = {
9
12
  getPackageConfig: vi.fn(),
10
13
  getAllPackages: vi.fn(),
11
14
  exists: vi.fn(),
12
15
  };
16
+ // Initialize Registry Factory with mock repository
17
+ initRegistryFactory(mockRepository);
13
18
  // Mock ToolExecutor
14
19
  mockExecutor = {
15
20
  listTools: vi.fn(),
@@ -32,6 +37,7 @@ describe("PackageSO", () => {
32
37
  category: "filesystem",
33
38
  validated: true,
34
39
  };
40
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
35
41
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
36
42
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({
37
43
  [packageName]: mockPackageInfo,
@@ -44,6 +50,7 @@ describe("PackageSO", () => {
44
50
  expect(packageSO.description).toBe("A server for filesystem operations");
45
51
  expect(packageSO.category).toBe("filesystem");
46
52
  expect(packageSO.validated).toBe(true);
53
+ expect(mockRepository.exists).toHaveBeenCalledWith(packageName);
47
54
  expect(mockRepository.getPackageConfig).toHaveBeenCalledWith(packageName);
48
55
  expect(mockRepository.getAllPackages).toHaveBeenCalled();
49
56
  });
@@ -57,6 +64,7 @@ describe("PackageSO", () => {
57
64
  name: "New Package",
58
65
  description: "A new package",
59
66
  };
67
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
60
68
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
61
69
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({});
62
70
  // Act
@@ -77,6 +85,7 @@ describe("PackageSO", () => {
77
85
  name: "Test Package",
78
86
  description: null,
79
87
  };
88
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
80
89
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
81
90
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({});
82
91
  // Act
@@ -119,6 +128,7 @@ describe("PackageSO", () => {
119
128
  },
120
129
  },
121
130
  ];
131
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
122
132
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
123
133
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({});
124
134
  vi.spyOn(mockExecutor, "listTools").mockResolvedValue(mockTools);
@@ -142,6 +152,7 @@ describe("PackageSO", () => {
142
152
  description: "Test description",
143
153
  };
144
154
  const errorMessage = "Failed to list tools";
155
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
145
156
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
146
157
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({});
147
158
  vi.spyOn(mockExecutor, "listTools").mockRejectedValue(new Error(errorMessage));
@@ -165,6 +176,7 @@ describe("PackageSO", () => {
165
176
  name: "Test Package",
166
177
  description: "Test description",
167
178
  };
179
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
168
180
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
169
181
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({});
170
182
  vi.spyOn(mockExecutor, "executeTool").mockResolvedValue(mockResult);
@@ -194,6 +206,7 @@ describe("PackageSO", () => {
194
206
  name: "Test Package",
195
207
  description: "Test description",
196
208
  };
209
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
197
210
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
198
211
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({});
199
212
  vi.spyOn(mockExecutor, "executeTool").mockResolvedValue(mockResult);
@@ -222,6 +235,7 @@ describe("PackageSO", () => {
222
235
  name: "Test Package",
223
236
  description: "Test description",
224
237
  };
238
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
225
239
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
226
240
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({});
227
241
  vi.spyOn(mockExecutor, "executeTool").mockRejectedValue(new Error(errorMessage));
@@ -256,6 +270,7 @@ describe("PackageSO", () => {
256
270
  },
257
271
  },
258
272
  ];
273
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
259
274
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
260
275
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({
261
276
  [packageName]: mockPackageInfo,
@@ -266,11 +281,11 @@ describe("PackageSO", () => {
266
281
  const detail = await packageSO.getDetailWithTools();
267
282
  // Assert
268
283
  expect(detail).toEqual({
284
+ type: "mcp-server",
285
+ runtime: "node",
269
286
  name: "Test Package",
270
287
  packageName: "@test/package",
271
288
  description: "A test package for demonstration",
272
- category: "testing",
273
- validated: true,
274
289
  tools: mockTools,
275
290
  });
276
291
  });
@@ -284,6 +299,7 @@ describe("PackageSO", () => {
284
299
  name: "Test Package",
285
300
  description: "Test description",
286
301
  };
302
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
287
303
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
288
304
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({});
289
305
  vi.spyOn(mockExecutor, "listTools").mockRejectedValue(new Error("Failed to get tools"));
@@ -309,6 +325,7 @@ describe("PackageSO", () => {
309
325
  description: "A minimal package",
310
326
  };
311
327
  const mockTools = [];
328
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
312
329
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
313
330
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({});
314
331
  vi.spyOn(mockExecutor, "listTools").mockResolvedValue(mockTools);
@@ -317,12 +334,12 @@ describe("PackageSO", () => {
317
334
  const detail = await packageSO.getDetailWithTools();
318
335
  // Assert
319
336
  expect(detail).toEqual({
337
+ type: "mcp-server",
338
+ runtime: "node",
320
339
  name: "Minimal Package",
321
340
  packageName: "@test/minimal-package",
322
341
  description: "A minimal package",
323
- category: undefined,
324
- validated: undefined,
325
- tools: mockTools,
342
+ tools: [],
326
343
  });
327
344
  });
328
345
  });
@@ -342,6 +359,7 @@ describe("PackageSO", () => {
342
359
  category: "test-category",
343
360
  validated: false,
344
361
  };
362
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
345
363
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
346
364
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({
347
365
  [packageName]: mockPackageInfo,
@@ -366,6 +384,7 @@ describe("PackageSO", () => {
366
384
  name: "Test Package",
367
385
  description: "Test description",
368
386
  };
387
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
369
388
  vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
370
389
  vi.spyOn(mockRepository, "getAllPackages").mockReturnValue({});
371
390
  // Act
@@ -0,0 +1,125 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { FederatedRegistryProvider } from "../providers/federated-registry-provider";
3
+ describe("FederatedRegistryProvider", () => {
4
+ let mockLocalProvider;
5
+ let mockOfficialProvider;
6
+ let provider;
7
+ beforeEach(() => {
8
+ // Mock LocalRegistryProvider
9
+ mockLocalProvider = {
10
+ getPackageConfig: vi.fn(),
11
+ exists: vi.fn(),
12
+ };
13
+ // Mock OfficialRegistryProvider
14
+ mockOfficialProvider = {
15
+ getPackageConfig: vi.fn(),
16
+ exists: vi.fn(),
17
+ search: vi.fn(),
18
+ };
19
+ provider = new FederatedRegistryProvider(mockLocalProvider, mockOfficialProvider);
20
+ });
21
+ describe("getPackageConfig", () => {
22
+ it("should return local config when package exists locally", async () => {
23
+ // Arrange
24
+ const packageName = "@modelcontextprotocol/server-filesystem";
25
+ const mockConfig = {
26
+ type: "mcp-server",
27
+ runtime: "node",
28
+ packageName,
29
+ name: "Filesystem Server",
30
+ description: "A server for filesystem operations",
31
+ };
32
+ vi.spyOn(mockLocalProvider, "getPackageConfig").mockResolvedValue(mockConfig);
33
+ // Act
34
+ const result = await provider.getPackageConfig(packageName);
35
+ // Assert
36
+ expect(result).toEqual(mockConfig);
37
+ expect(mockLocalProvider.getPackageConfig).toHaveBeenCalledWith(packageName);
38
+ expect(mockOfficialProvider.getPackageConfig).not.toHaveBeenCalled();
39
+ });
40
+ it("should query official provider when local returns null", async () => {
41
+ // Arrange
42
+ const packageName = "@toolsdk.ai/tavily-mcp";
43
+ const officialConfig = {
44
+ type: "mcp-server",
45
+ runtime: "node",
46
+ packageName,
47
+ name: "Tavily MCP Server",
48
+ description: "MCP server for Tavily search",
49
+ };
50
+ vi.spyOn(mockLocalProvider, "getPackageConfig").mockResolvedValue(null);
51
+ vi.spyOn(mockOfficialProvider, "getPackageConfig").mockResolvedValue(officialConfig);
52
+ // Act
53
+ const result = await provider.getPackageConfig(packageName);
54
+ // Assert
55
+ expect(result).toEqual(officialConfig);
56
+ expect(mockLocalProvider.getPackageConfig).toHaveBeenCalledWith(packageName);
57
+ expect(mockOfficialProvider.getPackageConfig).toHaveBeenCalledWith(packageName);
58
+ });
59
+ it("should return null when both providers return null", async () => {
60
+ // Arrange
61
+ const packageName = "non-existent-package";
62
+ vi.spyOn(mockLocalProvider, "getPackageConfig").mockResolvedValue(null);
63
+ vi.spyOn(mockOfficialProvider, "getPackageConfig").mockResolvedValue(null);
64
+ // Act
65
+ const result = await provider.getPackageConfig(packageName);
66
+ // Assert
67
+ expect(result).toBeNull();
68
+ });
69
+ it("should return null when official provider throws error", async () => {
70
+ // Arrange
71
+ const packageName = "@toolsdk.ai/tavily-mcp";
72
+ vi.spyOn(mockLocalProvider, "getPackageConfig").mockResolvedValue(null);
73
+ vi.spyOn(mockOfficialProvider, "getPackageConfig").mockRejectedValue(new Error("Network error"));
74
+ // Act
75
+ const result = await provider.getPackageConfig(packageName);
76
+ // Assert
77
+ expect(result).toBeNull();
78
+ });
79
+ });
80
+ describe("exists", () => {
81
+ it("should return true when package exists locally", async () => {
82
+ // Arrange
83
+ const packageName = "@modelcontextprotocol/server-filesystem";
84
+ vi.spyOn(mockLocalProvider, "exists").mockResolvedValue(true);
85
+ // Act
86
+ const result = await provider.exists(packageName);
87
+ // Assert
88
+ expect(result).toBe(true);
89
+ expect(mockLocalProvider.exists).toHaveBeenCalledWith(packageName);
90
+ expect(mockOfficialProvider.exists).not.toHaveBeenCalled();
91
+ });
92
+ it("should check official provider when local returns false", async () => {
93
+ // Arrange
94
+ const packageName = "@toolsdk.ai/tavily-mcp";
95
+ vi.spyOn(mockLocalProvider, "exists").mockResolvedValue(false);
96
+ vi.spyOn(mockOfficialProvider, "exists").mockResolvedValue(true);
97
+ // Act
98
+ const result = await provider.exists(packageName);
99
+ // Assert
100
+ expect(result).toBe(true);
101
+ expect(mockLocalProvider.exists).toHaveBeenCalledWith(packageName);
102
+ expect(mockOfficialProvider.exists).toHaveBeenCalledWith(packageName);
103
+ });
104
+ it("should return false when both providers return false", async () => {
105
+ // Arrange
106
+ const packageName = "non-existent-package";
107
+ vi.spyOn(mockLocalProvider, "exists").mockResolvedValue(false);
108
+ vi.spyOn(mockOfficialProvider, "exists").mockResolvedValue(false);
109
+ // Act
110
+ const result = await provider.exists(packageName);
111
+ // Assert
112
+ expect(result).toBe(false);
113
+ });
114
+ it("should return false when official provider throws error", async () => {
115
+ // Arrange
116
+ const packageName = "@toolsdk.ai/tavily-mcp";
117
+ vi.spyOn(mockLocalProvider, "exists").mockResolvedValue(false);
118
+ vi.spyOn(mockOfficialProvider, "exists").mockRejectedValue(new Error("Network error"));
119
+ // Act
120
+ const result = await provider.exists(packageName);
121
+ // Assert
122
+ expect(result).toBe(false);
123
+ });
124
+ });
125
+ });
@@ -0,0 +1,80 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { LocalRegistryProvider } from "../providers/local-registry-provider";
3
+ describe("LocalRegistryProvider", () => {
4
+ let mockRepository;
5
+ let provider;
6
+ beforeEach(() => {
7
+ // Mock PackageRepository
8
+ mockRepository = {
9
+ getPackageConfig: vi.fn(),
10
+ getAllPackages: vi.fn(),
11
+ exists: vi.fn(),
12
+ };
13
+ provider = new LocalRegistryProvider(mockRepository);
14
+ });
15
+ describe("getPackageConfig", () => {
16
+ it("should return package config when package exists", async () => {
17
+ // Arrange
18
+ const packageName = "@modelcontextprotocol/server-filesystem";
19
+ const mockConfig = {
20
+ type: "mcp-server",
21
+ runtime: "node",
22
+ packageName,
23
+ name: "Filesystem Server",
24
+ description: "A server for filesystem operations",
25
+ };
26
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
27
+ vi.spyOn(mockRepository, "getPackageConfig").mockReturnValue(mockConfig);
28
+ // Act
29
+ const result = await provider.getPackageConfig(packageName);
30
+ // Assert
31
+ expect(result).toEqual(mockConfig);
32
+ expect(mockRepository.exists).toHaveBeenCalledWith(packageName);
33
+ expect(mockRepository.getPackageConfig).toHaveBeenCalledWith(packageName);
34
+ });
35
+ it("should return null when package does not exist", async () => {
36
+ // Arrange
37
+ const packageName = "non-existent-package";
38
+ vi.spyOn(mockRepository, "exists").mockReturnValue(false);
39
+ // Act
40
+ const result = await provider.getPackageConfig(packageName);
41
+ // Assert
42
+ expect(result).toBeNull();
43
+ expect(mockRepository.exists).toHaveBeenCalledWith(packageName);
44
+ expect(mockRepository.getPackageConfig).not.toHaveBeenCalled();
45
+ });
46
+ it("should return null when getPackageConfig throws error", async () => {
47
+ // Arrange
48
+ const packageName = "@modelcontextprotocol/server-filesystem";
49
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
50
+ vi.spyOn(mockRepository, "getPackageConfig").mockImplementation(() => {
51
+ throw new Error("File read error");
52
+ });
53
+ // Act
54
+ const result = await provider.getPackageConfig(packageName);
55
+ // Assert
56
+ expect(result).toBeNull();
57
+ });
58
+ });
59
+ describe("exists", () => {
60
+ it("should return true when package exists", async () => {
61
+ // Arrange
62
+ const packageName = "@modelcontextprotocol/server-filesystem";
63
+ vi.spyOn(mockRepository, "exists").mockReturnValue(true);
64
+ // Act
65
+ const result = await provider.exists(packageName);
66
+ // Assert
67
+ expect(result).toBe(true);
68
+ expect(mockRepository.exists).toHaveBeenCalledWith(packageName);
69
+ });
70
+ it("should return false when package does not exist", async () => {
71
+ // Arrange
72
+ const packageName = "non-existent-package";
73
+ vi.spyOn(mockRepository, "exists").mockReturnValue(false);
74
+ // Act
75
+ const result = await provider.exists(packageName);
76
+ // Assert
77
+ expect(result).toBe(false);
78
+ });
79
+ });
80
+ });
@@ -0,0 +1,70 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { OfficialRegistryProvider } from "../providers/official-registry-provider";
3
+ /**
4
+ * Integration tests for OfficialRegistryProvider
5
+ * These tests call the real official API
6
+ */
7
+ describe("OfficialRegistryProvider - Integration", () => {
8
+ const provider = new OfficialRegistryProvider();
9
+ describe("search", () => {
10
+ it("should search and return results from official API", async () => {
11
+ // Act - search for tavily
12
+ const results = await provider.search("tavily");
13
+ // Assert
14
+ expect(results).toBeDefined();
15
+ expect(Array.isArray(results)).toBe(true);
16
+ // Log results for debugging
17
+ console.log(`Found ${results.length} results for 'tavily'`);
18
+ if (results.length > 0) {
19
+ console.log("First result:", JSON.stringify(results[0], null, 2));
20
+ }
21
+ }, 10000); // 10s timeout for network call
22
+ it("should return empty array for non-existent package", async () => {
23
+ // Act
24
+ const results = await provider.search("non-existent-package-xyz-123");
25
+ // Assert
26
+ expect(results).toBeDefined();
27
+ expect(Array.isArray(results)).toBe(true);
28
+ expect(results.length).toBe(0);
29
+ }, 10000);
30
+ });
31
+ describe("getPackageConfig", () => {
32
+ it("should get config for tavily-mcp package", async () => {
33
+ // Act
34
+ const config = await provider.getPackageConfig("tavily");
35
+ // Assert
36
+ if (config) {
37
+ console.log("Tavily package config:", JSON.stringify(config, null, 2));
38
+ expect(config.type).toBe("mcp-server");
39
+ expect(config.runtime).toBe("node");
40
+ expect(config.packageName).toBeDefined();
41
+ expect(config.name).toBeDefined();
42
+ }
43
+ else {
44
+ console.log("No tavily package found");
45
+ }
46
+ }, 10000);
47
+ it("should return null for non-existent package", async () => {
48
+ // Act
49
+ const config = await provider.getPackageConfig("non-existent-package-xyz-123");
50
+ // Assert
51
+ expect(config).toBeNull();
52
+ }, 10000);
53
+ });
54
+ describe("exists", () => {
55
+ it("should return true for existing package", async () => {
56
+ // Act
57
+ const exists = await provider.exists("tavily");
58
+ // Assert
59
+ console.log(`Tavily exists: ${exists}`);
60
+ // We expect it to exist, but don't fail the test if the API changes
61
+ expect(typeof exists).toBe("boolean");
62
+ }, 10000);
63
+ it("should return false for non-existent package", async () => {
64
+ // Act
65
+ const exists = await provider.exists("non-existent-package-xyz-123");
66
+ // Assert
67
+ expect(exists).toBe(false);
68
+ }, 10000);
69
+ });
70
+ });