@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
@@ -0,0 +1,307 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { transformAndFilterServers, transformServer } from "../registry-utils";
3
+ describe("registry-utils", () => {
4
+ describe("transformServer", () => {
5
+ it("should transform npm+stdio package correctly", () => {
6
+ // Arrange
7
+ const officialServer = {
8
+ name: "io.github.Seey215/tavily-mcp",
9
+ title: "Tavily MCP Server",
10
+ description: "MCP server for advanced web search using Tavily API.",
11
+ repository: {
12
+ url: "https://github.com/Seey215/tavily-mcp",
13
+ },
14
+ version: "0.2.9",
15
+ packages: [
16
+ {
17
+ registryType: "npm",
18
+ identifier: "@toolsdk.ai/tavily-mcp",
19
+ version: "0.2.9",
20
+ transport: {
21
+ type: "stdio",
22
+ },
23
+ environmentVariables: [
24
+ {
25
+ name: "TAVILY_API_KEY",
26
+ description: "Your TAVILY_API_KEY",
27
+ isRequired: true,
28
+ isSecret: true,
29
+ },
30
+ ],
31
+ },
32
+ ],
33
+ };
34
+ // Act
35
+ const result = transformServer(officialServer);
36
+ // Assert
37
+ expect(result).not.toBeNull();
38
+ expect(result).toMatchObject({
39
+ type: "mcp-server",
40
+ runtime: "node",
41
+ packageName: "@toolsdk.ai/tavily-mcp",
42
+ packageVersion: "0.2.9",
43
+ name: "Tavily MCP Server",
44
+ description: "MCP server for advanced web search using Tavily API.",
45
+ url: "https://github.com/Seey215/tavily-mcp",
46
+ env: {
47
+ TAVILY_API_KEY: {
48
+ description: "Your TAVILY_API_KEY",
49
+ required: true,
50
+ },
51
+ },
52
+ });
53
+ });
54
+ it("should use title as name if available", () => {
55
+ // Arrange
56
+ const officialServer = {
57
+ name: "io.github.test/package",
58
+ title: "Test Package Title",
59
+ packages: [
60
+ {
61
+ registryType: "npm",
62
+ identifier: "@test/package",
63
+ transport: {
64
+ type: "stdio",
65
+ },
66
+ },
67
+ ],
68
+ };
69
+ // Act
70
+ const result = transformServer(officialServer);
71
+ // Assert
72
+ expect(result === null || result === void 0 ? void 0 : result.name).toBe("Test Package Title");
73
+ });
74
+ it("should use name if title is not available", () => {
75
+ // Arrange
76
+ const officialServer = {
77
+ name: "io.github.test/package",
78
+ packages: [
79
+ {
80
+ registryType: "npm",
81
+ identifier: "@test/package",
82
+ transport: {
83
+ type: "stdio",
84
+ },
85
+ },
86
+ ],
87
+ };
88
+ // Act
89
+ const result = transformServer(officialServer);
90
+ // Assert
91
+ expect(result === null || result === void 0 ? void 0 : result.name).toBe("io.github.test/package");
92
+ });
93
+ it("should return null for non-npm packages", () => {
94
+ // Arrange
95
+ const officialServer = {
96
+ name: "io.github.test/docker-package",
97
+ packages: [
98
+ {
99
+ registryType: "docker",
100
+ identifier: "test/package",
101
+ transport: {
102
+ type: "stdio",
103
+ },
104
+ },
105
+ ],
106
+ };
107
+ // Act
108
+ const result = transformServer(officialServer);
109
+ // Assert
110
+ expect(result).toBeNull();
111
+ });
112
+ it("should return null for non-stdio transport", () => {
113
+ // Arrange
114
+ const officialServer = {
115
+ name: "io.github.test/sse-package",
116
+ packages: [
117
+ {
118
+ registryType: "npm",
119
+ identifier: "@test/package",
120
+ transport: {
121
+ type: "sse",
122
+ },
123
+ },
124
+ ],
125
+ };
126
+ // Act
127
+ const result = transformServer(officialServer);
128
+ // Assert
129
+ expect(result).toBeNull();
130
+ });
131
+ it("should select first npm+stdio package when multiple packages exist", () => {
132
+ // Arrange
133
+ const officialServer = {
134
+ name: "io.github.test/multi-package",
135
+ packages: [
136
+ {
137
+ registryType: "docker",
138
+ identifier: "test/docker",
139
+ transport: {
140
+ type: "stdio",
141
+ },
142
+ },
143
+ {
144
+ registryType: "npm",
145
+ identifier: "@test/first-npm",
146
+ transport: {
147
+ type: "stdio",
148
+ },
149
+ },
150
+ {
151
+ registryType: "npm",
152
+ identifier: "@test/second-npm",
153
+ transport: {
154
+ type: "stdio",
155
+ },
156
+ },
157
+ ],
158
+ };
159
+ // Act
160
+ const result = transformServer(officialServer);
161
+ // Assert
162
+ expect(result).not.toBeNull();
163
+ expect(result === null || result === void 0 ? void 0 : result.packageName).toBe("@test/first-npm");
164
+ });
165
+ it("should handle empty environment variables", () => {
166
+ // Arrange
167
+ const officialServer = {
168
+ name: "io.github.test/no-env",
169
+ packages: [
170
+ {
171
+ registryType: "npm",
172
+ identifier: "@test/package",
173
+ transport: {
174
+ type: "stdio",
175
+ },
176
+ },
177
+ ],
178
+ };
179
+ // Act
180
+ const result = transformServer(officialServer);
181
+ // Assert
182
+ expect(result).not.toBeNull();
183
+ expect(result === null || result === void 0 ? void 0 : result.env).toBeUndefined();
184
+ });
185
+ it("should handle optional environment variable fields", () => {
186
+ // Arrange
187
+ const officialServer = {
188
+ name: "io.github.test/package",
189
+ packages: [
190
+ {
191
+ registryType: "npm",
192
+ identifier: "@test/package",
193
+ transport: {
194
+ type: "stdio",
195
+ },
196
+ environmentVariables: [
197
+ {
198
+ name: "API_KEY",
199
+ // description and isRequired are optional
200
+ },
201
+ ],
202
+ },
203
+ ],
204
+ };
205
+ // Act
206
+ const result = transformServer(officialServer);
207
+ // Assert
208
+ expect(result).not.toBeNull();
209
+ expect(result === null || result === void 0 ? void 0 : result.env).toEqual({
210
+ API_KEY: {
211
+ description: "",
212
+ required: false,
213
+ },
214
+ });
215
+ });
216
+ });
217
+ describe("transformAndFilterServers", () => {
218
+ it("should transform and filter multiple servers", () => {
219
+ // Arrange
220
+ const servers = [
221
+ {
222
+ name: "io.github.test/npm-stdio",
223
+ packages: [
224
+ {
225
+ registryType: "npm",
226
+ identifier: "@test/npm-stdio",
227
+ transport: { type: "stdio" },
228
+ },
229
+ ],
230
+ },
231
+ {
232
+ name: "io.github.test/docker",
233
+ packages: [
234
+ {
235
+ registryType: "docker",
236
+ identifier: "test/docker",
237
+ transport: { type: "stdio" },
238
+ },
239
+ ],
240
+ },
241
+ {
242
+ name: "io.github.test/npm-sse",
243
+ packages: [
244
+ {
245
+ registryType: "npm",
246
+ identifier: "@test/npm-sse",
247
+ transport: { type: "sse" },
248
+ },
249
+ ],
250
+ },
251
+ {
252
+ name: "io.github.test/another-npm-stdio",
253
+ packages: [
254
+ {
255
+ registryType: "npm",
256
+ identifier: "@test/another-npm-stdio",
257
+ transport: { type: "stdio" },
258
+ },
259
+ ],
260
+ },
261
+ ];
262
+ // Act
263
+ const result = transformAndFilterServers(servers);
264
+ // Assert
265
+ expect(result).toHaveLength(2);
266
+ expect(result[0].packageName).toBe("@test/npm-stdio");
267
+ expect(result[1].packageName).toBe("@test/another-npm-stdio");
268
+ });
269
+ it("should return empty array when no servers match criteria", () => {
270
+ // Arrange
271
+ const servers = [
272
+ {
273
+ name: "io.github.test/docker",
274
+ packages: [
275
+ {
276
+ registryType: "docker",
277
+ identifier: "test/docker",
278
+ transport: { type: "stdio" },
279
+ },
280
+ ],
281
+ },
282
+ {
283
+ name: "io.github.test/npm-sse",
284
+ packages: [
285
+ {
286
+ registryType: "npm",
287
+ identifier: "@test/npm-sse",
288
+ transport: { type: "sse" },
289
+ },
290
+ ],
291
+ },
292
+ ];
293
+ // Act
294
+ const result = transformAndFilterServers(servers);
295
+ // Assert
296
+ expect(result).toHaveLength(0);
297
+ });
298
+ it("should handle empty array", () => {
299
+ // Arrange
300
+ const servers = [];
301
+ // Act
302
+ const result = transformAndFilterServers(servers);
303
+ // Assert
304
+ expect(result).toHaveLength(0);
305
+ });
306
+ });
307
+ });
@@ -0,0 +1,8 @@
1
+ export { FederatedRegistryProvider } from "./providers/federated-registry-provider";
2
+ export { LocalRegistryProvider } from "./providers/local-registry-provider";
3
+ export { OfficialRegistryProvider } from "./providers/official-registry-provider";
4
+ export type { RegistryProviderType } from "./registry-factory";
5
+ export { getRegistryProvider, initRegistryFactory, resetRegistryFactory, } from "./registry-factory";
6
+ export type { OfficialEnvironmentVariable, OfficialPackage, OfficialRepository, OfficialSearchResponse, OfficialServer, OfficialServerItem, OfficialTransport, } from "./registry-schema";
7
+ export type { IRegistryProvider, RegistrySource } from "./registry-types";
8
+ export { transformAndFilterServers, transformServer } from "./registry-utils";
@@ -0,0 +1,9 @@
1
+ // Types and interfaces
2
+ export { FederatedRegistryProvider } from "./providers/federated-registry-provider";
3
+ // Providers
4
+ export { LocalRegistryProvider } from "./providers/local-registry-provider";
5
+ export { OfficialRegistryProvider } from "./providers/official-registry-provider";
6
+ // Factory
7
+ export { getRegistryProvider, initRegistryFactory, resetRegistryFactory, } from "./registry-factory";
8
+ // Utils
9
+ export { transformAndFilterServers, transformServer } from "./registry-utils";
@@ -0,0 +1,25 @@
1
+ import type { MCPServerPackageConfig } from "../../package/package-types";
2
+ import type { IRegistryProvider } from "../registry-types";
3
+ import type { LocalRegistryProvider } from "./local-registry-provider";
4
+ import type { OfficialRegistryProvider } from "./official-registry-provider";
5
+ /**
6
+ * Federated Registry Provider
7
+ * Implements local-first federated query strategy
8
+ */
9
+ export declare class FederatedRegistryProvider implements IRegistryProvider {
10
+ private readonly localProvider;
11
+ private readonly officialProvider;
12
+ constructor(localProvider: LocalRegistryProvider, officialProvider: OfficialRegistryProvider);
13
+ /**
14
+ * Get package configuration (local first)
15
+ * @param packageName - Package name
16
+ * @returns Package configuration, null if not found
17
+ */
18
+ getPackageConfig(packageName: string): Promise<MCPServerPackageConfig | null>;
19
+ /**
20
+ * Check if package exists
21
+ * @param packageName - Package name
22
+ * @returns Whether the package exists
23
+ */
24
+ exists(packageName: string): Promise<boolean>;
25
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Federated Registry Provider
3
+ * Implements local-first federated query strategy
4
+ */
5
+ export class FederatedRegistryProvider {
6
+ constructor(localProvider, officialProvider) {
7
+ this.localProvider = localProvider;
8
+ this.officialProvider = officialProvider;
9
+ }
10
+ /**
11
+ * Get package configuration (local first)
12
+ * @param packageName - Package name
13
+ * @returns Package configuration, null if not found
14
+ */
15
+ async getPackageConfig(packageName) {
16
+ // 1. Query local first
17
+ const localConfig = await this.localProvider.getPackageConfig(packageName);
18
+ if (localConfig) {
19
+ return localConfig;
20
+ }
21
+ // 2. If not found locally, query official
22
+ try {
23
+ const officialConfig = await this.officialProvider.getPackageConfig(packageName);
24
+ return officialConfig;
25
+ }
26
+ catch (error) {
27
+ console.warn(`[FederatedRegistry] Failed to fetch from official: ${error}`);
28
+ return null; // Official API failed, return null
29
+ }
30
+ }
31
+ /**
32
+ * Check if package exists
33
+ * @param packageName - Package name
34
+ * @returns Whether the package exists
35
+ */
36
+ async exists(packageName) {
37
+ // 1. Check local first
38
+ if (await this.localProvider.exists(packageName)) {
39
+ return true;
40
+ }
41
+ // 2. Then check official
42
+ try {
43
+ return await this.officialProvider.exists(packageName);
44
+ }
45
+ catch (_a) {
46
+ return false;
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,23 @@
1
+ import type { PackageRepository } from "../../package/package-repository";
2
+ import type { MCPServerPackageConfig } from "../../package/package-types";
3
+ import type { IRegistryProvider } from "../registry-types";
4
+ /**
5
+ * Local Registry Provider adapter
6
+ * Wraps PackageRepository as an async interface
7
+ */
8
+ export declare class LocalRegistryProvider implements IRegistryProvider {
9
+ private readonly packageRepository;
10
+ constructor(packageRepository: PackageRepository);
11
+ /**
12
+ * Get package configuration
13
+ * @param packageName - Package name
14
+ * @returns Package configuration, null if not found
15
+ */
16
+ getPackageConfig(packageName: string): Promise<MCPServerPackageConfig | null>;
17
+ /**
18
+ * Check if package exists
19
+ * @param packageName - Package name
20
+ * @returns Whether the package exists
21
+ */
22
+ exists(packageName: string): Promise<boolean>;
23
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Local Registry Provider adapter
3
+ * Wraps PackageRepository as an async interface
4
+ */
5
+ export class LocalRegistryProvider {
6
+ constructor(packageRepository) {
7
+ this.packageRepository = packageRepository;
8
+ }
9
+ /**
10
+ * Get package configuration
11
+ * @param packageName - Package name
12
+ * @returns Package configuration, null if not found
13
+ */
14
+ async getPackageConfig(packageName) {
15
+ if (!this.packageRepository.exists(packageName)) {
16
+ return null;
17
+ }
18
+ try {
19
+ const config = this.packageRepository.getPackageConfig(packageName);
20
+ return config;
21
+ }
22
+ catch (error) {
23
+ console.error(`[LocalRegistry] Failed to get package config for '${packageName}':`, error);
24
+ return null;
25
+ }
26
+ }
27
+ /**
28
+ * Check if package exists
29
+ * @param packageName - Package name
30
+ * @returns Whether the package exists
31
+ */
32
+ async exists(packageName) {
33
+ return this.packageRepository.exists(packageName);
34
+ }
35
+ }
@@ -0,0 +1,34 @@
1
+ import type { MCPServerPackageConfig } from "../../package/package-types";
2
+ import type { IRegistryProvider } from "../registry-types";
3
+ /**
4
+ * Official Registry Provider
5
+ * Responsible for calling official API and transforming data
6
+ */
7
+ export declare class OfficialRegistryProvider implements IRegistryProvider {
8
+ private readonly baseUrl;
9
+ private readonly timeout;
10
+ /**
11
+ * Get package configuration
12
+ * @param packageName - Package name (official Registry ID)
13
+ * @returns Package configuration, null if not found
14
+ */
15
+ getPackageConfig(packageName: string): Promise<MCPServerPackageConfig | null>;
16
+ /**
17
+ * Check if package exists
18
+ * @param packageName - Package name
19
+ * @returns Whether the package exists
20
+ */
21
+ exists(packageName: string): Promise<boolean>;
22
+ /**
23
+ * Search packages
24
+ * @param query - Search keyword
25
+ * @returns List of package configurations
26
+ */
27
+ search(query: string): Promise<MCPServerPackageConfig[]>;
28
+ /**
29
+ * Fetch data from official API
30
+ * @param endpoint - API endpoint
31
+ * @returns Response data
32
+ */
33
+ private fetchFromOfficial;
34
+ }
@@ -0,0 +1,83 @@
1
+ import { OfficialSearchResponseSchema, } from "../registry-schema";
2
+ import { transformAndFilterServers } from "../registry-utils";
3
+ /**
4
+ * Official Registry Provider
5
+ * Responsible for calling official API and transforming data
6
+ */
7
+ export class OfficialRegistryProvider {
8
+ constructor() {
9
+ this.baseUrl = "https://registry.modelcontextprotocol.io/v0.1";
10
+ this.timeout = 5000; // 5 second timeout
11
+ }
12
+ /**
13
+ * Get package configuration
14
+ * @param packageName - Package name (official Registry ID)
15
+ * @returns Package configuration, null if not found
16
+ */
17
+ async getPackageConfig(packageName) {
18
+ try {
19
+ // 1. Call search API
20
+ const searchResults = await this.search(packageName);
21
+ // 2. Return first result (if exists)
22
+ if (searchResults.length > 0) {
23
+ return searchResults[0];
24
+ }
25
+ return null;
26
+ }
27
+ catch (error) {
28
+ console.warn(`[OfficialRegistry] Failed to get package config for '${packageName}':`, error);
29
+ return null;
30
+ }
31
+ }
32
+ /**
33
+ * Check if package exists
34
+ * @param packageName - Package name
35
+ * @returns Whether the package exists
36
+ */
37
+ async exists(packageName) {
38
+ const config = await this.getPackageConfig(packageName);
39
+ return config !== null;
40
+ }
41
+ /**
42
+ * Search packages
43
+ * @param query - Search keyword
44
+ * @returns List of package configurations
45
+ */
46
+ async search(query) {
47
+ try {
48
+ const response = await this.fetchFromOfficial(`/servers?search=${encodeURIComponent(query)}`);
49
+ const servers = response.servers.map((item) => item.server);
50
+ return transformAndFilterServers(servers);
51
+ }
52
+ catch (error) {
53
+ console.error(`[OfficialRegistry] Search error for '${query}':`, error);
54
+ return [];
55
+ }
56
+ }
57
+ /**
58
+ * Fetch data from official API
59
+ * @param endpoint - API endpoint
60
+ * @returns Response data
61
+ */
62
+ async fetchFromOfficial(endpoint) {
63
+ const url = `${this.baseUrl}${endpoint}`;
64
+ const controller = new AbortController();
65
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
66
+ try {
67
+ const response = await fetch(url, {
68
+ signal: controller.signal,
69
+ headers: {
70
+ Accept: "application/json",
71
+ },
72
+ });
73
+ if (!response.ok) {
74
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
75
+ }
76
+ const data = await response.json();
77
+ return OfficialSearchResponseSchema.parse(data);
78
+ }
79
+ finally {
80
+ clearTimeout(timeoutId);
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,21 @@
1
+ import type { PackageRepository } from "../package/package-repository";
2
+ import type { IRegistryProvider } from "./registry-types";
3
+ /**
4
+ * Registry Provider type
5
+ */
6
+ export type RegistryProviderType = "LOCAL" | "OFFICIAL" | "FEDERATED";
7
+ /**
8
+ * Initialize Registry Factory
9
+ * @param packageRepository - Local package repository
10
+ */
11
+ export declare function initRegistryFactory(packageRepository: PackageRepository): void;
12
+ /**
13
+ * Get Registry Provider
14
+ * @param type - Provider type, defaults to FEDERATED
15
+ * @returns Registry Provider instance
16
+ */
17
+ export declare function getRegistryProvider(type?: RegistryProviderType): IRegistryProvider;
18
+ /**
19
+ * Reset factory (mainly used for testing)
20
+ */
21
+ export declare function resetRegistryFactory(): void;
@@ -0,0 +1,52 @@
1
+ import { FederatedRegistryProvider } from "./providers/federated-registry-provider";
2
+ import { LocalRegistryProvider } from "./providers/local-registry-provider";
3
+ import { OfficialRegistryProvider } from "./providers/official-registry-provider";
4
+ /**
5
+ * Registry Provider instance container
6
+ */
7
+ let localProvider = null;
8
+ let officialProvider = null;
9
+ let federatedProvider = null;
10
+ let initialized = false;
11
+ /**
12
+ * Initialize Registry Factory
13
+ * @param packageRepository - Local package repository
14
+ */
15
+ export function initRegistryFactory(packageRepository) {
16
+ if (initialized) {
17
+ return;
18
+ }
19
+ localProvider = new LocalRegistryProvider(packageRepository);
20
+ officialProvider = new OfficialRegistryProvider();
21
+ federatedProvider = new FederatedRegistryProvider(localProvider, officialProvider);
22
+ initialized = true;
23
+ }
24
+ /**
25
+ * Get Registry Provider
26
+ * @param type - Provider type, defaults to FEDERATED
27
+ * @returns Registry Provider instance
28
+ */
29
+ export function getRegistryProvider(type = "FEDERATED") {
30
+ if (!initialized || !localProvider || !officialProvider || !federatedProvider) {
31
+ throw new Error("RegistryFactory not initialized. Call initRegistryFactory() first.");
32
+ }
33
+ switch (type) {
34
+ case "LOCAL":
35
+ return localProvider;
36
+ case "OFFICIAL":
37
+ return officialProvider;
38
+ case "FEDERATED":
39
+ return federatedProvider;
40
+ default:
41
+ throw new Error(`Unknown provider type: ${type}`);
42
+ }
43
+ }
44
+ /**
45
+ * Reset factory (mainly used for testing)
46
+ */
47
+ export function resetRegistryFactory() {
48
+ localProvider = null;
49
+ officialProvider = null;
50
+ federatedProvider = null;
51
+ initialized = false;
52
+ }