@mastra/mcp-registry-registry 0.0.1-alpha.1
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/LICENSE.md +46 -0
- package/dist/_tsup-dts-rollup.d.ts +243 -0
- package/dist/stdio.d.ts +1 -0
- package/dist/stdio.js +575 -0
- package/package.json +52 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Elastic License 2.0 (ELv2)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Mastra AI, Inc.
|
|
4
|
+
|
|
5
|
+
**Acceptance**
|
|
6
|
+
By using the software, you agree to all of the terms and conditions below.
|
|
7
|
+
|
|
8
|
+
**Copyright License**
|
|
9
|
+
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations and conditions below
|
|
10
|
+
|
|
11
|
+
**Limitations**
|
|
12
|
+
You may not provide the software to third parties as a hosted or managed service, where the service provides users with access to any substantial set of the features or functionality of the software.
|
|
13
|
+
|
|
14
|
+
You may not move, change, disable, or circumvent the license key functionality in the software, and you may not remove or obscure any functionality in the software that is protected by the license key.
|
|
15
|
+
|
|
16
|
+
You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law.
|
|
17
|
+
|
|
18
|
+
**Patents**
|
|
19
|
+
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
20
|
+
|
|
21
|
+
**Notices**
|
|
22
|
+
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms.
|
|
23
|
+
|
|
24
|
+
If you modify the software, you must include in any modified copies of the software prominent notices stating that you have modified the software.
|
|
25
|
+
|
|
26
|
+
**No Other Rights**
|
|
27
|
+
These terms do not imply any licenses other than those expressly granted in these terms.
|
|
28
|
+
|
|
29
|
+
**Termination**
|
|
30
|
+
If you use the software in violation of these terms, such use is not licensed, and your licenses will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your licenses will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your licenses to terminate automatically and permanently.
|
|
31
|
+
|
|
32
|
+
**No Liability**
|
|
33
|
+
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
|
|
34
|
+
|
|
35
|
+
**Definitions**
|
|
36
|
+
The _licensor_ is the entity offering these terms, and the _software_ is the software the licensor makes available under these terms, including any portion of it.
|
|
37
|
+
|
|
38
|
+
_you_ refers to the individual or entity agreeing to these terms.
|
|
39
|
+
|
|
40
|
+
_your company_ is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. _control_ means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
41
|
+
|
|
42
|
+
_your licenses_ are all the licenses granted to you for the software under these terms.
|
|
43
|
+
|
|
44
|
+
_use_ means anything you do with the software requiring one of your licenses.
|
|
45
|
+
|
|
46
|
+
_trademark_ means trademarks, service marks, and similar rights.
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export declare function createServerEntry(data: Record<string, unknown>): ServerEntry;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Fetches servers from a registry's servers_url endpoint
|
|
8
|
+
*/
|
|
9
|
+
declare function fetchServersFromRegistry(registryId: string): Promise<ServerEntry[]>;
|
|
10
|
+
export { fetchServersFromRegistry }
|
|
11
|
+
export { fetchServersFromRegistry as fetchServersFromRegistry_alias_1 }
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Filters registry entries based on provided criteria
|
|
15
|
+
*/
|
|
16
|
+
declare function filterRegistries(registries: RegistryEntry[], filters: {
|
|
17
|
+
id?: string;
|
|
18
|
+
tag?: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
}): RegistryEntry[];
|
|
21
|
+
export { filterRegistries }
|
|
22
|
+
export { filterRegistries as filterRegistries_alias_1 }
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Filters server entries based on provided criteria
|
|
26
|
+
*/
|
|
27
|
+
declare function filterServers(servers: ServerEntry[], filters: {
|
|
28
|
+
tag?: string;
|
|
29
|
+
search?: string;
|
|
30
|
+
}): ServerEntry[];
|
|
31
|
+
export { filterServers }
|
|
32
|
+
export { filterServers as filterServers_alias_1 }
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Formats registry entries for API response
|
|
36
|
+
*/
|
|
37
|
+
declare function formatRegistryResponse(registries: RegistryEntry[], detailed?: boolean): any;
|
|
38
|
+
export { formatRegistryResponse }
|
|
39
|
+
export { formatRegistryResponse as formatRegistryResponse_alias_1 }
|
|
40
|
+
|
|
41
|
+
export declare function fromPackageRoot(relativePath: string): string;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Main function to get registry listings with optional filtering
|
|
45
|
+
*/
|
|
46
|
+
declare function getRegistryListings(filters?: {
|
|
47
|
+
id?: string;
|
|
48
|
+
tag?: string;
|
|
49
|
+
name?: string;
|
|
50
|
+
}, options?: {
|
|
51
|
+
detailed?: boolean;
|
|
52
|
+
}): Promise<any>;
|
|
53
|
+
export { getRegistryListings }
|
|
54
|
+
export { getRegistryListings as getRegistryListings_alias_1 }
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Main function to get servers from a registry with optional filtering
|
|
58
|
+
*/
|
|
59
|
+
declare function getServersFromRegistry(registryId: string, filters?: {
|
|
60
|
+
tag?: string;
|
|
61
|
+
search?: string;
|
|
62
|
+
}): Promise<any>;
|
|
63
|
+
export { getServersFromRegistry }
|
|
64
|
+
export { getServersFromRegistry as getServersFromRegistry_alias_1 }
|
|
65
|
+
|
|
66
|
+
export declare const listInputSchema: z.ZodObject<{
|
|
67
|
+
id: z.ZodOptional<z.ZodString>;
|
|
68
|
+
tag: z.ZodOptional<z.ZodString>;
|
|
69
|
+
name: z.ZodOptional<z.ZodString>;
|
|
70
|
+
detailed: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
71
|
+
}, "strip", z.ZodTypeAny, {
|
|
72
|
+
detailed: boolean;
|
|
73
|
+
id?: string | undefined;
|
|
74
|
+
name?: string | undefined;
|
|
75
|
+
tag?: string | undefined;
|
|
76
|
+
}, {
|
|
77
|
+
id?: string | undefined;
|
|
78
|
+
name?: string | undefined;
|
|
79
|
+
tag?: string | undefined;
|
|
80
|
+
detailed?: boolean | undefined;
|
|
81
|
+
}>;
|
|
82
|
+
|
|
83
|
+
export declare const listTool: {
|
|
84
|
+
name: string;
|
|
85
|
+
description: string;
|
|
86
|
+
execute(input: ListToolInput): Promise<{
|
|
87
|
+
content: {
|
|
88
|
+
type: string;
|
|
89
|
+
text: string;
|
|
90
|
+
}[];
|
|
91
|
+
isError?: undefined;
|
|
92
|
+
} | {
|
|
93
|
+
content: {
|
|
94
|
+
type: string;
|
|
95
|
+
text: string;
|
|
96
|
+
}[];
|
|
97
|
+
isError: boolean;
|
|
98
|
+
}>;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export declare type ListToolInput = z.infer<typeof listInputSchema>;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Returns the registry data from the registry.ts file
|
|
105
|
+
*/
|
|
106
|
+
declare function loadRegistryData(): Promise<RegistryFile>;
|
|
107
|
+
export { loadRegistryData }
|
|
108
|
+
export { loadRegistryData as loadRegistryData_alias_1 }
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Post-processor for Apify registry
|
|
112
|
+
* Handles the specific format of Apify's store data
|
|
113
|
+
*/
|
|
114
|
+
export declare function processApifyServers(data: any): ServerEntry[];
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Post-processor for APITracker registry
|
|
118
|
+
* Handles the specific format of APITracker's server data
|
|
119
|
+
*/
|
|
120
|
+
export declare function processApiTrackerServers(data: unknown): ServerEntry[];
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Default processor for registry server data
|
|
124
|
+
* Handles common formats that might be encountered
|
|
125
|
+
*/
|
|
126
|
+
export declare function processDefaultServers(data: unknown): ServerEntry[];
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Post-processor for Fleur registry
|
|
130
|
+
* Handles the specific format of Fleur's app data
|
|
131
|
+
*/
|
|
132
|
+
export declare function processFleurServers(data: unknown): ServerEntry[];
|
|
133
|
+
|
|
134
|
+
export declare function processMcpRunServers(data: any): ServerEntry[];
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Post-processor for Pulse MCP registry
|
|
138
|
+
* Handles the specific format of Pulse MCP's server data
|
|
139
|
+
*/
|
|
140
|
+
export declare function processPulseMcpServers(data: any): ServerEntry[];
|
|
141
|
+
|
|
142
|
+
declare const registryData: RegistryFile;
|
|
143
|
+
export { registryData }
|
|
144
|
+
export { registryData as registryData_alias_1 }
|
|
145
|
+
|
|
146
|
+
export declare interface RegistryEntry {
|
|
147
|
+
id: string;
|
|
148
|
+
name: string;
|
|
149
|
+
description: string;
|
|
150
|
+
url: string;
|
|
151
|
+
servers_url?: string;
|
|
152
|
+
tags?: string[];
|
|
153
|
+
count?: number | string;
|
|
154
|
+
postProcessServers?: (data: unknown) => ServerEntry[];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export declare interface RegistryFile {
|
|
158
|
+
registries: RegistryEntry[];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export declare function runServer(): Promise<void>;
|
|
162
|
+
|
|
163
|
+
export declare const server: Server<{
|
|
164
|
+
method: string;
|
|
165
|
+
params?: {
|
|
166
|
+
[x: string]: unknown;
|
|
167
|
+
_meta?: {
|
|
168
|
+
[x: string]: unknown;
|
|
169
|
+
progressToken?: string | number | undefined;
|
|
170
|
+
} | undefined;
|
|
171
|
+
} | undefined;
|
|
172
|
+
}, {
|
|
173
|
+
method: string;
|
|
174
|
+
params?: {
|
|
175
|
+
[x: string]: unknown;
|
|
176
|
+
_meta?: {
|
|
177
|
+
[x: string]: unknown;
|
|
178
|
+
} | undefined;
|
|
179
|
+
} | undefined;
|
|
180
|
+
}, {
|
|
181
|
+
[x: string]: unknown;
|
|
182
|
+
_meta?: {
|
|
183
|
+
[x: string]: unknown;
|
|
184
|
+
} | undefined;
|
|
185
|
+
}>;
|
|
186
|
+
|
|
187
|
+
export declare type ServerEntry = z.infer<typeof ServerEntrySchema>;
|
|
188
|
+
|
|
189
|
+
export declare const ServerEntrySchema: z.ZodObject<{
|
|
190
|
+
id: z.ZodString;
|
|
191
|
+
name: z.ZodString;
|
|
192
|
+
description: z.ZodString;
|
|
193
|
+
createdAt: z.ZodString;
|
|
194
|
+
updatedAt: z.ZodString;
|
|
195
|
+
}, "strip", z.ZodTypeAny, {
|
|
196
|
+
id: string;
|
|
197
|
+
name: string;
|
|
198
|
+
description: string;
|
|
199
|
+
createdAt: string;
|
|
200
|
+
updatedAt: string;
|
|
201
|
+
}, {
|
|
202
|
+
id: string;
|
|
203
|
+
name: string;
|
|
204
|
+
description: string;
|
|
205
|
+
createdAt: string;
|
|
206
|
+
updatedAt: string;
|
|
207
|
+
}>;
|
|
208
|
+
|
|
209
|
+
export declare const serversInputSchema: z.ZodObject<{
|
|
210
|
+
registryId: z.ZodString;
|
|
211
|
+
tag: z.ZodOptional<z.ZodString>;
|
|
212
|
+
search: z.ZodOptional<z.ZodString>;
|
|
213
|
+
}, "strip", z.ZodTypeAny, {
|
|
214
|
+
registryId: string;
|
|
215
|
+
tag?: string | undefined;
|
|
216
|
+
search?: string | undefined;
|
|
217
|
+
}, {
|
|
218
|
+
registryId: string;
|
|
219
|
+
tag?: string | undefined;
|
|
220
|
+
search?: string | undefined;
|
|
221
|
+
}>;
|
|
222
|
+
|
|
223
|
+
export declare const serversTool: {
|
|
224
|
+
name: string;
|
|
225
|
+
description: string;
|
|
226
|
+
execute(input: ServersToolInput): Promise<{
|
|
227
|
+
content: {
|
|
228
|
+
type: string;
|
|
229
|
+
text: string;
|
|
230
|
+
}[];
|
|
231
|
+
isError?: undefined;
|
|
232
|
+
} | {
|
|
233
|
+
content: {
|
|
234
|
+
type: string;
|
|
235
|
+
text: string;
|
|
236
|
+
}[];
|
|
237
|
+
isError: boolean;
|
|
238
|
+
}>;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export declare type ServersToolInput = z.infer<typeof serversInputSchema>;
|
|
242
|
+
|
|
243
|
+
export { }
|
package/dist/stdio.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/stdio.js
ADDED
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
|
|
11
|
+
// src/registry/processors/apify.ts
|
|
12
|
+
function processApifyServers(data) {
|
|
13
|
+
const apifyData = data?.data?.items || [];
|
|
14
|
+
if (!Array.isArray(apifyData)) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
return apifyData.filter((item) => item && item.name).map((item) => {
|
|
18
|
+
const stats = item.stats || {};
|
|
19
|
+
const server2 = {
|
|
20
|
+
id: item.name || "unknown",
|
|
21
|
+
name: item.title,
|
|
22
|
+
description: item.description || "No description available",
|
|
23
|
+
createdAt: "",
|
|
24
|
+
// Apify doesn't provide creation date
|
|
25
|
+
updatedAt: stats.lastRunStartedAt || ""
|
|
26
|
+
};
|
|
27
|
+
return server2;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/registry/processors/utils.ts
|
|
32
|
+
function createServerEntry(data) {
|
|
33
|
+
const metaDescription = typeof data.meta === "object" && data.meta !== null ? data.meta.description : void 0;
|
|
34
|
+
return {
|
|
35
|
+
id: data.id || data.name || data.slug || "unknown",
|
|
36
|
+
name: data.name || data.id || data.slug || "Unknown Server",
|
|
37
|
+
description: data.description || metaDescription || "No description available",
|
|
38
|
+
createdAt: data.createdAt || data.created_at || "",
|
|
39
|
+
updatedAt: data.updatedAt || data.updated_at || ""
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/registry/processors/apitracker.ts
|
|
44
|
+
function processApiTrackerServers(data) {
|
|
45
|
+
if (!data || typeof data !== "object") {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
const servers = [];
|
|
49
|
+
if (typeof data === "object" && data !== null) {
|
|
50
|
+
const dataObj = data;
|
|
51
|
+
let serversList = [];
|
|
52
|
+
if (Array.isArray(dataObj.servers)) {
|
|
53
|
+
serversList = dataObj.servers;
|
|
54
|
+
} else if (Array.isArray(dataObj.items)) {
|
|
55
|
+
serversList = dataObj.items;
|
|
56
|
+
} else if (Array.isArray(data)) {
|
|
57
|
+
serversList = data;
|
|
58
|
+
}
|
|
59
|
+
for (const item of serversList) {
|
|
60
|
+
if (typeof item === "object" && item !== null) {
|
|
61
|
+
servers.push(createServerEntry(item));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return servers;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/registry/processors/fleur.ts
|
|
69
|
+
function processFleurServers(data) {
|
|
70
|
+
if (!data || typeof data !== "object") {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
const servers = [];
|
|
74
|
+
if (Array.isArray(data)) {
|
|
75
|
+
for (const item of data) {
|
|
76
|
+
if (typeof item === "object" && item !== null) {
|
|
77
|
+
const server2 = createServerEntry(item);
|
|
78
|
+
if (item.appId) {
|
|
79
|
+
server2.id = item.appId;
|
|
80
|
+
}
|
|
81
|
+
servers.push(server2);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return servers;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/registry/processors/mcprun.ts
|
|
89
|
+
function processMcpRunServers(data) {
|
|
90
|
+
const serversData = data;
|
|
91
|
+
if (!Array.isArray(serversData)) {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
return serversData.filter((item) => item && item.slug).map((item) => {
|
|
95
|
+
const server2 = {
|
|
96
|
+
id: item.slug,
|
|
97
|
+
name: item.slug,
|
|
98
|
+
description: item?.meta?.description,
|
|
99
|
+
createdAt: item?.created_at,
|
|
100
|
+
updatedAt: item?.updated_at
|
|
101
|
+
};
|
|
102
|
+
return server2;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/registry/processors/pulse.ts
|
|
107
|
+
function processPulseMcpServers(data) {
|
|
108
|
+
const serversData = data?.servers || [];
|
|
109
|
+
if (!Array.isArray(serversData)) {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
return serversData.filter((item) => item && item.name).map((item) => {
|
|
113
|
+
const server2 = {
|
|
114
|
+
id: item.name || "unknown",
|
|
115
|
+
name: item.name || "Unknown Server",
|
|
116
|
+
description: item.short_description.slice(0, 300) || item.EXPERIMENTAL_ai_generated_description.slice(0, 300) || "No description available",
|
|
117
|
+
createdAt: "",
|
|
118
|
+
// Pulse MCP doesn't provide creation date
|
|
119
|
+
updatedAt: ""
|
|
120
|
+
// Pulse MCP doesn't provide update date
|
|
121
|
+
};
|
|
122
|
+
return server2;
|
|
123
|
+
}).slice(0, 1e3);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/registry/registry.ts
|
|
127
|
+
var registryData = {
|
|
128
|
+
registries: [
|
|
129
|
+
{
|
|
130
|
+
id: "apitracker",
|
|
131
|
+
name: "apitracker",
|
|
132
|
+
description: "Discover the best APIs and developer resources",
|
|
133
|
+
url: "https://apitracker.com/",
|
|
134
|
+
servers_url: "https://apitracker.io/api/mcp-servers",
|
|
135
|
+
tags: ["verified"],
|
|
136
|
+
postProcessServers: processApiTrackerServers
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: "apify",
|
|
140
|
+
name: "Apify",
|
|
141
|
+
description: "Your full\u2011stack platform for web scraping",
|
|
142
|
+
url: "https://apify.com/",
|
|
143
|
+
servers_url: "https://api.apify.com/v2/store",
|
|
144
|
+
tags: ["verified"],
|
|
145
|
+
postProcessServers: processApifyServers
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: "fleur",
|
|
149
|
+
name: "Fleur",
|
|
150
|
+
description: "Fleur is the app store for Claude",
|
|
151
|
+
url: "https://www.fleurmcp.com/",
|
|
152
|
+
servers_url: "https://raw.githubusercontent.com/fleuristes/app-registry/refs/heads/main/apps.json",
|
|
153
|
+
tags: ["verified"],
|
|
154
|
+
postProcessServers: processFleurServers
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: "modelcontextprotocol-servers",
|
|
158
|
+
name: "modelcontextprotocol/servers",
|
|
159
|
+
description: "This repository is a collection of reference implementations for the Model Context Protocol (MCP).",
|
|
160
|
+
url: "https://github.com/modelcontextprotocol/servers",
|
|
161
|
+
tags: ["official"],
|
|
162
|
+
count: 307
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: "awesome-mcp-servers",
|
|
166
|
+
name: "Awesome MCP servers",
|
|
167
|
+
description: "A curated list of awesome Model Context Protocol (MCP) servers.",
|
|
168
|
+
url: "https://github.com/punkpeye/awesome-mcp-servers",
|
|
169
|
+
tags: ["open-source"],
|
|
170
|
+
count: 370
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: "cline-bot",
|
|
174
|
+
name: "Cline.bot",
|
|
175
|
+
description: "MCP servers for Cline.bot",
|
|
176
|
+
url: "https://cline.bot/mcp-marketplace",
|
|
177
|
+
tags: ["verified"]
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: "cursor-mcp-registry",
|
|
181
|
+
name: "Cursor MCP Registry",
|
|
182
|
+
description: "Browse MCPs or post a MCP to reach 250,000+ monthly active developers.",
|
|
183
|
+
url: "https://cursor.directory/mcp",
|
|
184
|
+
tags: ["verified"],
|
|
185
|
+
count: "1800+"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: "glama-mcp-server",
|
|
189
|
+
name: "Glama MCP Server",
|
|
190
|
+
description: "Production-ready and experimental MCP servers that extend AI capabilities.",
|
|
191
|
+
url: "https://glama.ai/mcp/servers",
|
|
192
|
+
tags: ["open-source"],
|
|
193
|
+
count: 3457
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: "gumloop",
|
|
197
|
+
name: "Gumloop",
|
|
198
|
+
description: "An exhaustive list of MCP servers.",
|
|
199
|
+
url: "https://www.gumloop.com/mcp",
|
|
200
|
+
tags: ["open-source"],
|
|
201
|
+
count: 20
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: "mcp-composio",
|
|
205
|
+
name: "MCP Composio",
|
|
206
|
+
description: "Instantly Connect to 100+ Managed MCP Servers with Built-In Auth",
|
|
207
|
+
url: "https://mcp.composio.dev/",
|
|
208
|
+
tags: ["verified"],
|
|
209
|
+
count: "100+"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: "mcp-market",
|
|
213
|
+
name: "MCP Market",
|
|
214
|
+
description: "Explore our curated collection of MCP servers to connect AI to your favorite tools.",
|
|
215
|
+
url: "https://mcpmarket.com/",
|
|
216
|
+
count: 12454
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
id: "mcp-run",
|
|
220
|
+
name: "MCP Run",
|
|
221
|
+
description: "One platform for vertical AI across your entire organization.",
|
|
222
|
+
url: "https://www.mcp.run/",
|
|
223
|
+
servers_url: "https://www.mcp.run/api/servlets",
|
|
224
|
+
tags: ["verified"],
|
|
225
|
+
postProcessServers: processMcpRunServers
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
id: "mcp-servers-org",
|
|
229
|
+
name: "MCP Servers",
|
|
230
|
+
description: "A collection of servers for the Model Context Protocol.",
|
|
231
|
+
url: "https://mcpservers.org/",
|
|
232
|
+
tags: ["open-source"],
|
|
233
|
+
count: 212
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
id: "mcp-get",
|
|
237
|
+
name: "MCP-Get",
|
|
238
|
+
description: "mcp-get helps you easily install protocol servers.",
|
|
239
|
+
url: "https://mcp-get.com/",
|
|
240
|
+
tags: ["open-source"],
|
|
241
|
+
count: 69
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: "mcp-so",
|
|
245
|
+
name: "MCP.so",
|
|
246
|
+
description: "Find Awesome MCP Servers and Clients",
|
|
247
|
+
url: "https://mcp.so/",
|
|
248
|
+
tags: ["verified"],
|
|
249
|
+
count: 7682
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
id: "opentools",
|
|
253
|
+
name: "OpenTools",
|
|
254
|
+
description: "This registry documents the capabilities of 400+ tools across 160+ MCP servers.",
|
|
255
|
+
url: "https://opentools.com/registry",
|
|
256
|
+
tags: ["verified"],
|
|
257
|
+
count: 171
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
id: "pulse-mcp",
|
|
261
|
+
name: "Pulse MCP",
|
|
262
|
+
description: "Browse and discover MCP use cases, servers, clients, and news.",
|
|
263
|
+
url: "https://www.pulsemcp.com/",
|
|
264
|
+
servers_url: "https://api.pulsemcp.com/v0beta/servers",
|
|
265
|
+
tags: ["verified"],
|
|
266
|
+
count: 3653,
|
|
267
|
+
postProcessServers: processPulseMcpServers
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
id: "smithery",
|
|
271
|
+
name: "Smithery",
|
|
272
|
+
description: "Extend your agent with 4,274 capabilities via Model Context Protocol servers.",
|
|
273
|
+
url: "https://smithery.ai/",
|
|
274
|
+
servers_url: "https://registry.smithery.ai/servers",
|
|
275
|
+
tags: ["verified"],
|
|
276
|
+
count: 4274
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
id: "zapier-mcp",
|
|
280
|
+
name: "Zapier MCP",
|
|
281
|
+
description: "Connect your AI to any app with Zapier MCP",
|
|
282
|
+
url: "https://zapier.com/mcp",
|
|
283
|
+
tags: ["verified"]
|
|
284
|
+
}
|
|
285
|
+
]
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// src/registry/list-registries.ts
|
|
289
|
+
var RegistryEntrySchema = z.object({
|
|
290
|
+
id: z.string(),
|
|
291
|
+
name: z.string(),
|
|
292
|
+
description: z.string(),
|
|
293
|
+
url: z.string().url(),
|
|
294
|
+
servers_url: z.string().url().optional(),
|
|
295
|
+
tags: z.array(z.string()).optional(),
|
|
296
|
+
count: z.union([z.number(), z.string()]).optional()
|
|
297
|
+
});
|
|
298
|
+
var RegistryFileSchema = z.object({
|
|
299
|
+
registries: z.array(RegistryEntrySchema)
|
|
300
|
+
});
|
|
301
|
+
async function loadRegistryData() {
|
|
302
|
+
try {
|
|
303
|
+
return RegistryFileSchema.parse(registryData);
|
|
304
|
+
} catch (error) {
|
|
305
|
+
console.error("Error loading registry data:", error);
|
|
306
|
+
return { registries: [] };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function filterRegistries(registries, filters) {
|
|
310
|
+
let filteredRegistries = [...registries];
|
|
311
|
+
if (filters.id) {
|
|
312
|
+
filteredRegistries = filteredRegistries.filter((registry) => registry.id === filters.id);
|
|
313
|
+
}
|
|
314
|
+
if (filters.tag) {
|
|
315
|
+
filteredRegistries = filteredRegistries.filter((registry) => registry.tags?.includes(filters.tag));
|
|
316
|
+
}
|
|
317
|
+
if (filters.name) {
|
|
318
|
+
const searchTerm = filters.name.toLowerCase();
|
|
319
|
+
filteredRegistries = filteredRegistries.filter((registry) => registry.name.toLowerCase().includes(searchTerm));
|
|
320
|
+
}
|
|
321
|
+
return filteredRegistries;
|
|
322
|
+
}
|
|
323
|
+
function formatRegistryResponse(registries, detailed = false) {
|
|
324
|
+
if (registries.length === 0) {
|
|
325
|
+
return {
|
|
326
|
+
count: 0,
|
|
327
|
+
registries: []
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
if (detailed) {
|
|
331
|
+
return {
|
|
332
|
+
count: registries.length,
|
|
333
|
+
registries: registries.map((registry) => ({
|
|
334
|
+
id: registry.id,
|
|
335
|
+
name: registry.name,
|
|
336
|
+
description: registry.description,
|
|
337
|
+
url: registry.url,
|
|
338
|
+
servers_url: registry.servers_url,
|
|
339
|
+
tags: registry.tags || [],
|
|
340
|
+
count: registry.count
|
|
341
|
+
}))
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
count: registries.length,
|
|
346
|
+
registries: registries.map((registry) => ({
|
|
347
|
+
id: registry.id,
|
|
348
|
+
name: registry.name,
|
|
349
|
+
description: registry.description
|
|
350
|
+
}))
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
async function getRegistryListings(filters = {}, options = {}) {
|
|
354
|
+
try {
|
|
355
|
+
const registryData2 = await loadRegistryData();
|
|
356
|
+
const filteredRegistries = filterRegistries(registryData2.registries, filters);
|
|
357
|
+
return formatRegistryResponse(filteredRegistries, options.detailed);
|
|
358
|
+
} catch (error) {
|
|
359
|
+
console.error("Error getting registry listings:", error);
|
|
360
|
+
throw error;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// src/tools/list.ts
|
|
365
|
+
var listInputSchema = z.object({
|
|
366
|
+
id: z.string().optional(),
|
|
367
|
+
tag: z.string().optional(),
|
|
368
|
+
name: z.string().optional(),
|
|
369
|
+
detailed: z.boolean().optional().default(false)
|
|
370
|
+
});
|
|
371
|
+
var listTool = {
|
|
372
|
+
name: "registryList",
|
|
373
|
+
description: "List available MCP registries. Can filter by ID, tag, or name and provide detailed or summary views.",
|
|
374
|
+
async execute(input) {
|
|
375
|
+
try {
|
|
376
|
+
const result = await getRegistryListings(
|
|
377
|
+
{
|
|
378
|
+
id: input.id,
|
|
379
|
+
tag: input.tag,
|
|
380
|
+
name: input.name
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
detailed: input.detailed
|
|
384
|
+
}
|
|
385
|
+
);
|
|
386
|
+
return {
|
|
387
|
+
content: [
|
|
388
|
+
{
|
|
389
|
+
type: "text",
|
|
390
|
+
text: JSON.stringify(result, null, 2)
|
|
391
|
+
}
|
|
392
|
+
]
|
|
393
|
+
};
|
|
394
|
+
} catch (error) {
|
|
395
|
+
return {
|
|
396
|
+
content: [
|
|
397
|
+
{
|
|
398
|
+
type: "text",
|
|
399
|
+
text: `Error listing registries: ${error instanceof Error ? error.message : String(error)}`
|
|
400
|
+
}
|
|
401
|
+
],
|
|
402
|
+
isError: true
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
// src/registry/fetch-servers.ts
|
|
409
|
+
async function fetchServersFromRegistry(registryId) {
|
|
410
|
+
try {
|
|
411
|
+
const registry = registryData.registries.find((r) => r.id === registryId);
|
|
412
|
+
if (!registry) {
|
|
413
|
+
throw new Error(`Registry with ID "${registryId}" not found.`);
|
|
414
|
+
}
|
|
415
|
+
if (!registry.servers_url) {
|
|
416
|
+
throw new Error(`Registry "${registry.name}" does not have a servers endpoint.`);
|
|
417
|
+
}
|
|
418
|
+
console.log(`Fetching servers from ${registry.name} at ${registry.servers_url}`);
|
|
419
|
+
const response = await fetch(registry.servers_url);
|
|
420
|
+
if (!response.ok) {
|
|
421
|
+
throw new Error(`Failed to fetch servers from ${registry.servers_url}: ${response.statusText}`);
|
|
422
|
+
}
|
|
423
|
+
const data = await response.json();
|
|
424
|
+
if (registry.postProcessServers) {
|
|
425
|
+
console.log(`Using custom post-processor for ${registry.name}`);
|
|
426
|
+
return registry.postProcessServers(data);
|
|
427
|
+
}
|
|
428
|
+
throw new Error(`No post-processor found for registry ${registry.name}`);
|
|
429
|
+
} catch (error) {
|
|
430
|
+
console.error("Error fetching servers:", error);
|
|
431
|
+
throw error;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
function filterServers(servers, filters) {
|
|
435
|
+
let filteredServers = [...servers];
|
|
436
|
+
if (filters.search) {
|
|
437
|
+
const searchTerm = filters.search.toLowerCase();
|
|
438
|
+
filteredServers = filteredServers.filter(
|
|
439
|
+
(server2) => server2.name.toLowerCase().includes(searchTerm) || server2.description.toLowerCase().includes(searchTerm)
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
return filteredServers;
|
|
443
|
+
}
|
|
444
|
+
async function getServersFromRegistry(registryId, filters = {}) {
|
|
445
|
+
try {
|
|
446
|
+
const servers = await fetchServersFromRegistry(registryId);
|
|
447
|
+
return filterServers(servers, filters);
|
|
448
|
+
} catch (error) {
|
|
449
|
+
console.error("Error getting servers from registry:", error);
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// src/tools/servers.ts
|
|
455
|
+
var serversInputSchema = z.object({
|
|
456
|
+
registryId: z.string(),
|
|
457
|
+
tag: z.string().optional(),
|
|
458
|
+
search: z.string().optional()
|
|
459
|
+
});
|
|
460
|
+
var serversTool = {
|
|
461
|
+
name: "registryServers",
|
|
462
|
+
description: "Get servers from a specific MCP registry. Can filter by tag or search term.",
|
|
463
|
+
async execute(input) {
|
|
464
|
+
try {
|
|
465
|
+
const result = await getServersFromRegistry(input.registryId, {
|
|
466
|
+
search: input.search
|
|
467
|
+
});
|
|
468
|
+
return {
|
|
469
|
+
content: [
|
|
470
|
+
{
|
|
471
|
+
type: "text",
|
|
472
|
+
text: JSON.stringify(result, null, 2)
|
|
473
|
+
}
|
|
474
|
+
]
|
|
475
|
+
};
|
|
476
|
+
} catch (error) {
|
|
477
|
+
return {
|
|
478
|
+
content: [
|
|
479
|
+
{
|
|
480
|
+
type: "text",
|
|
481
|
+
text: `Error fetching servers: ${error instanceof Error ? error.message : String(error)}`
|
|
482
|
+
}
|
|
483
|
+
],
|
|
484
|
+
isError: true
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
490
|
+
function fromPackageRoot(relativePath) {
|
|
491
|
+
return path.resolve(__dirname, "..", relativePath);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// src/server.ts
|
|
495
|
+
var server = new Server(
|
|
496
|
+
{
|
|
497
|
+
name: "Registry Registry Server",
|
|
498
|
+
version: JSON.parse(await fs.readFile(fromPackageRoot(`package.json`), "utf8")).version
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
capabilities: {
|
|
502
|
+
tools: {}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
);
|
|
506
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
507
|
+
tools: [
|
|
508
|
+
{
|
|
509
|
+
name: "registryList",
|
|
510
|
+
description: listTool.description,
|
|
511
|
+
inputSchema: zodToJsonSchema(listInputSchema)
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
name: "registryServers",
|
|
515
|
+
description: serversTool.description,
|
|
516
|
+
inputSchema: zodToJsonSchema(serversInputSchema)
|
|
517
|
+
}
|
|
518
|
+
]
|
|
519
|
+
}));
|
|
520
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
521
|
+
try {
|
|
522
|
+
switch (request.params.name) {
|
|
523
|
+
case "registryList": {
|
|
524
|
+
const args = listInputSchema.parse(request.params.arguments);
|
|
525
|
+
return await listTool.execute(args);
|
|
526
|
+
}
|
|
527
|
+
case "registryServers": {
|
|
528
|
+
const args = serversInputSchema.parse(request.params.arguments);
|
|
529
|
+
return await serversTool.execute(args);
|
|
530
|
+
}
|
|
531
|
+
default:
|
|
532
|
+
return {
|
|
533
|
+
content: [
|
|
534
|
+
{
|
|
535
|
+
type: "text",
|
|
536
|
+
text: `Unknown tool: ${request.params.name}`
|
|
537
|
+
}
|
|
538
|
+
],
|
|
539
|
+
isError: true
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
} catch (error) {
|
|
543
|
+
if (error instanceof z.ZodError) {
|
|
544
|
+
return {
|
|
545
|
+
content: [
|
|
546
|
+
{
|
|
547
|
+
type: "text",
|
|
548
|
+
text: `Invalid arguments: ${error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ")}`
|
|
549
|
+
}
|
|
550
|
+
],
|
|
551
|
+
isError: true
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
return {
|
|
555
|
+
content: [
|
|
556
|
+
{
|
|
557
|
+
type: "text",
|
|
558
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
559
|
+
}
|
|
560
|
+
],
|
|
561
|
+
isError: true
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
async function runServer() {
|
|
566
|
+
const transport = new StdioServerTransport();
|
|
567
|
+
await server.connect(transport);
|
|
568
|
+
console.error("Registry Registry MCP Server running on stdio");
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// src/stdio.ts
|
|
572
|
+
runServer().catch((error) => {
|
|
573
|
+
console.error("Failed to start server:", error);
|
|
574
|
+
process.exit(1);
|
|
575
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mastra/mcp-registry-registry",
|
|
3
|
+
"version": "0.0.1-alpha.1",
|
|
4
|
+
"description": "MCP server for registry registry services.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": "dist/stdio.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"./package.json": "./package.json"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [],
|
|
23
|
+
"author": "",
|
|
24
|
+
"license": "Elastic-2.0",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.9.0",
|
|
27
|
+
"uuid": "^11.1.0",
|
|
28
|
+
"zod": "^3.22.4",
|
|
29
|
+
"zod-to-json-schema": "^3.22.4",
|
|
30
|
+
"@mastra/core": "^0.8.3-alpha.2"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@hono/node-server": "^1.13.8",
|
|
34
|
+
"@types/node": "^20.11.24",
|
|
35
|
+
"@wong2/mcp-cli": "^1.6.0",
|
|
36
|
+
"cross-env": "^7.0.3",
|
|
37
|
+
"eslint": "^9.23.0",
|
|
38
|
+
"hono": "^4.7.4",
|
|
39
|
+
"tsup": "^8.4.0",
|
|
40
|
+
"tsx": "^4.19.3",
|
|
41
|
+
"typescript": "^5.3.3",
|
|
42
|
+
"vitest": "^3.0.9",
|
|
43
|
+
"@internal/lint": "0.0.2-alpha.0",
|
|
44
|
+
"@mastra/mcp": "^0.3.10-alpha.3"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build:cli": "tsup src/stdio.ts --format esm --experimental-dts --treeshake=smallest --splitting",
|
|
48
|
+
"pretest": "pnpm turbo build --filter @mastra/mcp-registry-registry",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"lint": "eslint ."
|
|
51
|
+
}
|
|
52
|
+
}
|