@juspay/neurolink 9.27.0 → 9.28.0
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/CHANGELOG.md +6 -0
- package/README.md +59 -9
- package/dist/cli/commands/config.d.ts +4 -4
- package/dist/cli/commands/mcp.d.ts +87 -0
- package/dist/cli/commands/mcp.js +1524 -0
- package/dist/cli/loop/optionsSchema.js +4 -0
- package/dist/core/modules/ToolsManager.js +29 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +27 -1
- package/dist/lib/core/modules/ToolsManager.js +29 -2
- package/dist/lib/index.d.ts +2 -1
- package/dist/lib/index.js +27 -1
- package/dist/lib/mcp/agentExposure.d.ts +228 -0
- package/dist/lib/mcp/agentExposure.js +357 -0
- package/dist/lib/mcp/batching/index.d.ts +11 -0
- package/dist/lib/mcp/batching/index.js +11 -0
- package/dist/lib/mcp/batching/requestBatcher.d.ts +202 -0
- package/dist/lib/mcp/batching/requestBatcher.js +442 -0
- package/dist/lib/mcp/caching/index.d.ts +11 -0
- package/dist/lib/mcp/caching/index.js +11 -0
- package/dist/lib/mcp/caching/toolCache.d.ts +221 -0
- package/dist/lib/mcp/caching/toolCache.js +434 -0
- package/dist/lib/mcp/elicitation/elicitationManager.d.ts +169 -0
- package/dist/lib/mcp/elicitation/elicitationManager.js +377 -0
- package/dist/lib/mcp/elicitation/index.d.ts +11 -0
- package/dist/lib/mcp/elicitation/index.js +12 -0
- package/dist/lib/mcp/elicitation/types.d.ts +278 -0
- package/dist/lib/mcp/elicitation/types.js +11 -0
- package/dist/lib/mcp/elicitationProtocol.d.ts +228 -0
- package/dist/lib/mcp/elicitationProtocol.js +376 -0
- package/dist/lib/mcp/enhancedToolDiscovery.d.ts +205 -0
- package/dist/lib/mcp/enhancedToolDiscovery.js +482 -0
- package/dist/lib/mcp/index.d.ts +38 -1
- package/dist/lib/mcp/index.js +36 -3
- package/dist/lib/mcp/mcpRegistryClient.d.ts +332 -0
- package/dist/lib/mcp/mcpRegistryClient.js +489 -0
- package/dist/lib/mcp/mcpServerBase.d.ts +227 -0
- package/dist/lib/mcp/mcpServerBase.js +374 -0
- package/dist/lib/mcp/multiServerManager.d.ts +310 -0
- package/dist/lib/mcp/multiServerManager.js +580 -0
- package/dist/lib/mcp/routing/index.d.ts +11 -0
- package/dist/lib/mcp/routing/index.js +11 -0
- package/dist/lib/mcp/routing/toolRouter.d.ts +219 -0
- package/dist/lib/mcp/routing/toolRouter.js +417 -0
- package/dist/lib/mcp/serverCapabilities.d.ts +341 -0
- package/dist/lib/mcp/serverCapabilities.js +503 -0
- package/dist/lib/mcp/toolAnnotations.d.ts +154 -0
- package/dist/lib/mcp/toolAnnotations.js +240 -0
- package/dist/lib/mcp/toolConverter.d.ts +178 -0
- package/dist/lib/mcp/toolConverter.js +259 -0
- package/dist/lib/mcp/toolIntegration.d.ts +136 -0
- package/dist/lib/mcp/toolIntegration.js +335 -0
- package/dist/lib/neurolink.d.ts +275 -2
- package/dist/lib/neurolink.js +596 -56
- package/dist/lib/providers/litellm.d.ts +10 -0
- package/dist/lib/providers/litellm.js +104 -2
- package/dist/lib/types/configTypes.d.ts +56 -0
- package/dist/lib/types/generateTypes.d.ts +4 -0
- package/dist/lib/types/index.d.ts +1 -1
- package/dist/lib/types/modelTypes.d.ts +6 -6
- package/dist/lib/types/streamTypes.d.ts +2 -0
- package/dist/lib/types/tools.d.ts +2 -0
- package/dist/lib/utils/pricing.js +177 -17
- package/dist/lib/utils/schemaConversion.d.ts +6 -1
- package/dist/lib/utils/schemaConversion.js +50 -28
- package/dist/lib/workflow/config.d.ts +16 -16
- package/dist/mcp/agentExposure.d.ts +228 -0
- package/dist/mcp/agentExposure.js +356 -0
- package/dist/mcp/batching/index.d.ts +11 -0
- package/dist/mcp/batching/index.js +10 -0
- package/dist/mcp/batching/requestBatcher.d.ts +202 -0
- package/dist/mcp/batching/requestBatcher.js +441 -0
- package/dist/mcp/caching/index.d.ts +11 -0
- package/dist/mcp/caching/index.js +10 -0
- package/dist/mcp/caching/toolCache.d.ts +221 -0
- package/dist/mcp/caching/toolCache.js +433 -0
- package/dist/mcp/elicitation/elicitationManager.d.ts +169 -0
- package/dist/mcp/elicitation/elicitationManager.js +376 -0
- package/dist/mcp/elicitation/index.d.ts +11 -0
- package/dist/mcp/elicitation/index.js +11 -0
- package/dist/mcp/elicitation/types.d.ts +278 -0
- package/dist/mcp/elicitation/types.js +10 -0
- package/dist/mcp/elicitationProtocol.d.ts +228 -0
- package/dist/mcp/elicitationProtocol.js +375 -0
- package/dist/mcp/enhancedToolDiscovery.d.ts +205 -0
- package/dist/mcp/enhancedToolDiscovery.js +481 -0
- package/dist/mcp/index.d.ts +38 -1
- package/dist/mcp/index.js +36 -3
- package/dist/mcp/mcpRegistryClient.d.ts +332 -0
- package/dist/mcp/mcpRegistryClient.js +488 -0
- package/dist/mcp/mcpServerBase.d.ts +227 -0
- package/dist/mcp/mcpServerBase.js +373 -0
- package/dist/mcp/multiServerManager.d.ts +310 -0
- package/dist/mcp/multiServerManager.js +579 -0
- package/dist/mcp/routing/index.d.ts +11 -0
- package/dist/mcp/routing/index.js +10 -0
- package/dist/mcp/routing/toolRouter.d.ts +219 -0
- package/dist/mcp/routing/toolRouter.js +416 -0
- package/dist/mcp/serverCapabilities.d.ts +341 -0
- package/dist/mcp/serverCapabilities.js +502 -0
- package/dist/mcp/toolAnnotations.d.ts +154 -0
- package/dist/mcp/toolAnnotations.js +239 -0
- package/dist/mcp/toolConverter.d.ts +178 -0
- package/dist/mcp/toolConverter.js +258 -0
- package/dist/mcp/toolIntegration.d.ts +136 -0
- package/dist/mcp/toolIntegration.js +334 -0
- package/dist/neurolink.d.ts +275 -2
- package/dist/neurolink.js +596 -56
- package/dist/providers/litellm.d.ts +10 -0
- package/dist/providers/litellm.js +104 -2
- package/dist/types/configTypes.d.ts +56 -0
- package/dist/types/generateTypes.d.ts +4 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/streamTypes.d.ts +2 -0
- package/dist/types/tools.d.ts +2 -0
- package/dist/utils/pricing.js +177 -17
- package/dist/utils/schemaConversion.d.ts +6 -1
- package/dist/utils/schemaConversion.js +50 -28
- package/package.json +1 -1
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Registry Client
|
|
3
|
+
*
|
|
4
|
+
* Client for discovering MCP servers from centralized registries.
|
|
5
|
+
* Supports multiple registry sources including:
|
|
6
|
+
* - Official MCP Registry
|
|
7
|
+
* - NPM packages
|
|
8
|
+
* - GitHub repositories
|
|
9
|
+
* - Custom registries
|
|
10
|
+
*
|
|
11
|
+
* @module mcp/mcpRegistryClient
|
|
12
|
+
* @since 8.39.0
|
|
13
|
+
*/
|
|
14
|
+
import { EventEmitter } from "events";
|
|
15
|
+
/**
|
|
16
|
+
* Well-known MCP servers catalog
|
|
17
|
+
*/
|
|
18
|
+
const WELL_KNOWN_SERVERS = [
|
|
19
|
+
{
|
|
20
|
+
id: "filesystem",
|
|
21
|
+
name: "Filesystem",
|
|
22
|
+
description: "File system operations - read, write, create, list directories",
|
|
23
|
+
version: "1.0.0",
|
|
24
|
+
npmPackage: "@modelcontextprotocol/server-filesystem",
|
|
25
|
+
command: "npx",
|
|
26
|
+
args: ["-y", "@modelcontextprotocol/server-filesystem"],
|
|
27
|
+
transports: ["stdio"],
|
|
28
|
+
categories: ["file-system"],
|
|
29
|
+
tags: ["files", "directories", "read", "write"],
|
|
30
|
+
tools: ["read_file", "write_file", "list_directory", "create_directory"],
|
|
31
|
+
verified: true,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "github",
|
|
35
|
+
name: "GitHub",
|
|
36
|
+
description: "GitHub repository management and file operations",
|
|
37
|
+
version: "1.0.0",
|
|
38
|
+
npmPackage: "@modelcontextprotocol/server-github",
|
|
39
|
+
command: "npx",
|
|
40
|
+
args: ["-y", "@modelcontextprotocol/server-github"],
|
|
41
|
+
requiredEnvVars: ["GITHUB_PERSONAL_ACCESS_TOKEN"],
|
|
42
|
+
transports: ["stdio"],
|
|
43
|
+
categories: ["version-control", "api"],
|
|
44
|
+
tags: ["github", "git", "repositories", "issues", "pull-requests"],
|
|
45
|
+
tools: [
|
|
46
|
+
"create_repository",
|
|
47
|
+
"list_commits",
|
|
48
|
+
"create_issue",
|
|
49
|
+
"create_pull_request",
|
|
50
|
+
],
|
|
51
|
+
verified: true,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "postgres",
|
|
55
|
+
name: "PostgreSQL",
|
|
56
|
+
description: "PostgreSQL database query and management",
|
|
57
|
+
version: "1.0.0",
|
|
58
|
+
npmPackage: "@modelcontextprotocol/server-postgres",
|
|
59
|
+
command: "npx",
|
|
60
|
+
args: ["-y", "@modelcontextprotocol/server-postgres"],
|
|
61
|
+
requiredEnvVars: ["DATABASE_URL"],
|
|
62
|
+
transports: ["stdio"],
|
|
63
|
+
categories: ["database"],
|
|
64
|
+
tags: ["postgres", "postgresql", "sql", "database", "query"],
|
|
65
|
+
tools: ["query", "list_tables", "describe_table"],
|
|
66
|
+
verified: true,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: "sqlite",
|
|
70
|
+
name: "SQLite",
|
|
71
|
+
description: "SQLite database operations and queries",
|
|
72
|
+
version: "1.0.0",
|
|
73
|
+
npmPackage: "@modelcontextprotocol/server-sqlite",
|
|
74
|
+
command: "npx",
|
|
75
|
+
args: ["-y", "@modelcontextprotocol/server-sqlite"],
|
|
76
|
+
transports: ["stdio"],
|
|
77
|
+
categories: ["database"],
|
|
78
|
+
tags: ["sqlite", "sql", "database", "local"],
|
|
79
|
+
tools: ["query", "list_tables", "describe_table"],
|
|
80
|
+
verified: true,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "brave-search",
|
|
84
|
+
name: "Brave Search",
|
|
85
|
+
description: "Web search using Brave Search API",
|
|
86
|
+
version: "1.0.0",
|
|
87
|
+
npmPackage: "@modelcontextprotocol/server-brave-search",
|
|
88
|
+
command: "npx",
|
|
89
|
+
args: ["-y", "@modelcontextprotocol/server-brave-search"],
|
|
90
|
+
requiredEnvVars: ["BRAVE_API_KEY"],
|
|
91
|
+
transports: ["stdio"],
|
|
92
|
+
categories: ["search", "api"],
|
|
93
|
+
tags: ["search", "web", "brave", "internet"],
|
|
94
|
+
tools: ["web_search", "local_search"],
|
|
95
|
+
verified: true,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: "puppeteer",
|
|
99
|
+
name: "Puppeteer",
|
|
100
|
+
description: "Web scraping and browser automation",
|
|
101
|
+
version: "1.0.0",
|
|
102
|
+
npmPackage: "@modelcontextprotocol/server-puppeteer",
|
|
103
|
+
command: "npx",
|
|
104
|
+
args: ["-y", "@modelcontextprotocol/server-puppeteer"],
|
|
105
|
+
transports: ["stdio"],
|
|
106
|
+
categories: ["automation", "web"],
|
|
107
|
+
tags: ["browser", "scraping", "automation", "puppeteer"],
|
|
108
|
+
tools: ["navigate", "screenshot", "click", "type", "get_content"],
|
|
109
|
+
verified: true,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: "git",
|
|
113
|
+
name: "Git",
|
|
114
|
+
description: "Git repository operations and version control",
|
|
115
|
+
version: "1.0.0",
|
|
116
|
+
npmPackage: "@modelcontextprotocol/server-git",
|
|
117
|
+
command: "npx",
|
|
118
|
+
args: ["-y", "@modelcontextprotocol/server-git"],
|
|
119
|
+
transports: ["stdio"],
|
|
120
|
+
categories: ["version-control"],
|
|
121
|
+
tags: ["git", "vcs", "commits", "branches"],
|
|
122
|
+
tools: ["git_status", "git_log", "git_diff", "git_commit"],
|
|
123
|
+
verified: true,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: "memory",
|
|
127
|
+
name: "Memory",
|
|
128
|
+
description: "Persistent memory and knowledge storage",
|
|
129
|
+
version: "1.0.0",
|
|
130
|
+
npmPackage: "@modelcontextprotocol/server-memory",
|
|
131
|
+
command: "npx",
|
|
132
|
+
args: ["-y", "@modelcontextprotocol/server-memory"],
|
|
133
|
+
transports: ["stdio"],
|
|
134
|
+
categories: ["memory", "storage"],
|
|
135
|
+
tags: ["memory", "knowledge", "storage", "persistent"],
|
|
136
|
+
tools: ["store", "retrieve", "search", "delete"],
|
|
137
|
+
verified: true,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: "slack",
|
|
141
|
+
name: "Slack",
|
|
142
|
+
description: "Slack workspace integration",
|
|
143
|
+
version: "1.0.0",
|
|
144
|
+
npmPackage: "@modelcontextprotocol/server-slack",
|
|
145
|
+
command: "npx",
|
|
146
|
+
args: ["-y", "@modelcontextprotocol/server-slack"],
|
|
147
|
+
requiredEnvVars: ["SLACK_BOT_TOKEN"],
|
|
148
|
+
transports: ["stdio"],
|
|
149
|
+
categories: ["communication", "api"],
|
|
150
|
+
tags: ["slack", "messaging", "chat", "team"],
|
|
151
|
+
tools: ["send_message", "list_channels", "get_channel_history"],
|
|
152
|
+
verified: true,
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: "google-drive",
|
|
156
|
+
name: "Google Drive",
|
|
157
|
+
description: "Google Drive file management",
|
|
158
|
+
version: "1.0.0",
|
|
159
|
+
npmPackage: "@modelcontextprotocol/server-gdrive",
|
|
160
|
+
command: "npx",
|
|
161
|
+
args: ["-y", "@modelcontextprotocol/server-gdrive"],
|
|
162
|
+
transports: ["stdio"],
|
|
163
|
+
categories: ["file-system", "api"],
|
|
164
|
+
tags: ["google", "drive", "files", "cloud"],
|
|
165
|
+
tools: ["list_files", "read_file", "create_file", "search_files"],
|
|
166
|
+
verified: true,
|
|
167
|
+
},
|
|
168
|
+
];
|
|
169
|
+
/**
|
|
170
|
+
* MCP Registry Client
|
|
171
|
+
*
|
|
172
|
+
* Provides methods to discover and install MCP servers from registries.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* const client = new MCPRegistryClient();
|
|
177
|
+
*
|
|
178
|
+
* // Search for servers
|
|
179
|
+
* const results = await client.search({ query: "database" });
|
|
180
|
+
*
|
|
181
|
+
* // Get server details
|
|
182
|
+
* const entry = await client.getEntry("postgres");
|
|
183
|
+
*
|
|
184
|
+
* // Convert to MCPServerInfo
|
|
185
|
+
* const serverInfo = client.toServerInfo(entry);
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
export class MCPRegistryClient extends EventEmitter {
|
|
189
|
+
config;
|
|
190
|
+
cache = new Map();
|
|
191
|
+
customEntries = new Map();
|
|
192
|
+
constructor(config = {}) {
|
|
193
|
+
super();
|
|
194
|
+
this.config = {
|
|
195
|
+
registries: config.registries ?? [
|
|
196
|
+
{ type: "official", enableCache: true },
|
|
197
|
+
],
|
|
198
|
+
enableCache: config.enableCache ?? true,
|
|
199
|
+
defaultCacheTTL: config.defaultCacheTTL ?? 3600000, // 1 hour
|
|
200
|
+
timeout: config.timeout ?? 10000,
|
|
201
|
+
userAgent: config.userAgent ?? "NeuroLink-MCP-Registry-Client/1.0",
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Search the registry
|
|
206
|
+
*/
|
|
207
|
+
async search(options = {}) {
|
|
208
|
+
const { query, categories, tags, transport, verifiedOnly = false, sortBy = "downloads", sortDirection = "desc", limit: rawLimit = 25, offset: rawOffset = 0, } = options;
|
|
209
|
+
const limit = Math.max(1, rawLimit);
|
|
210
|
+
const offset = Math.max(0, rawOffset);
|
|
211
|
+
// Get all entries (from cache or fetch)
|
|
212
|
+
let entries = await this.getAllEntries();
|
|
213
|
+
// Apply filters
|
|
214
|
+
if (query) {
|
|
215
|
+
const searchLower = query.toLowerCase();
|
|
216
|
+
entries = entries.filter((e) => e.name.toLowerCase().includes(searchLower) ||
|
|
217
|
+
e.description.toLowerCase().includes(searchLower) ||
|
|
218
|
+
e.tags?.some((t) => t.toLowerCase().includes(searchLower)));
|
|
219
|
+
}
|
|
220
|
+
if (categories?.length) {
|
|
221
|
+
entries = entries.filter((e) => e.categories?.some((c) => categories.includes(c)));
|
|
222
|
+
}
|
|
223
|
+
if (tags?.length) {
|
|
224
|
+
entries = entries.filter((e) => e.tags?.some((t) => tags.includes(t)));
|
|
225
|
+
}
|
|
226
|
+
if (transport) {
|
|
227
|
+
entries = entries.filter((e) => e.transports?.includes(transport));
|
|
228
|
+
}
|
|
229
|
+
if (verifiedOnly) {
|
|
230
|
+
entries = entries.filter((e) => e.verified);
|
|
231
|
+
}
|
|
232
|
+
// Sort
|
|
233
|
+
entries.sort((a, b) => {
|
|
234
|
+
let comparison = 0;
|
|
235
|
+
switch (sortBy) {
|
|
236
|
+
case "name":
|
|
237
|
+
comparison = a.name.localeCompare(b.name);
|
|
238
|
+
break;
|
|
239
|
+
case "downloads":
|
|
240
|
+
comparison = (a.downloads ?? 0) - (b.downloads ?? 0);
|
|
241
|
+
break;
|
|
242
|
+
case "stars":
|
|
243
|
+
comparison = (a.stars ?? 0) - (b.stars ?? 0);
|
|
244
|
+
break;
|
|
245
|
+
case "lastUpdated":
|
|
246
|
+
comparison = (a.lastUpdated ?? "").localeCompare(b.lastUpdated ?? "");
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
return sortDirection === "desc" ? -comparison : comparison;
|
|
250
|
+
});
|
|
251
|
+
const totalCount = entries.length;
|
|
252
|
+
// Apply pagination
|
|
253
|
+
entries = entries.slice(offset, offset + limit);
|
|
254
|
+
return {
|
|
255
|
+
entries,
|
|
256
|
+
totalCount,
|
|
257
|
+
page: Math.floor(offset / limit) + 1,
|
|
258
|
+
pageSize: limit,
|
|
259
|
+
hasMore: offset + entries.length < totalCount,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get a specific entry by ID
|
|
264
|
+
*/
|
|
265
|
+
async getEntry(id) {
|
|
266
|
+
// Check custom entries first
|
|
267
|
+
if (this.customEntries.has(id)) {
|
|
268
|
+
return this.customEntries.get(id);
|
|
269
|
+
}
|
|
270
|
+
// Check well-known servers
|
|
271
|
+
const wellKnown = WELL_KNOWN_SERVERS.find((s) => s.id === id);
|
|
272
|
+
if (wellKnown) {
|
|
273
|
+
return wellKnown;
|
|
274
|
+
}
|
|
275
|
+
// TODO: Fetch from remote registry
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get all available entries
|
|
280
|
+
*/
|
|
281
|
+
async getAllEntries() {
|
|
282
|
+
const cacheKey = "all-entries";
|
|
283
|
+
// Check cache
|
|
284
|
+
if (this.config.enableCache) {
|
|
285
|
+
const cached = this.cache.get(cacheKey);
|
|
286
|
+
if (cached &&
|
|
287
|
+
Date.now() - cached.timestamp < this.config.defaultCacheTTL) {
|
|
288
|
+
return cached.data;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Combine well-known servers and custom entries, deduplicating by ID.
|
|
292
|
+
// Custom entries take precedence over well-known servers.
|
|
293
|
+
const customIds = new Set(this.customEntries.keys());
|
|
294
|
+
const allEntries = [
|
|
295
|
+
...WELL_KNOWN_SERVERS.filter((entry) => !customIds.has(entry.id)),
|
|
296
|
+
...Array.from(this.customEntries.values()),
|
|
297
|
+
];
|
|
298
|
+
// Cache the result
|
|
299
|
+
if (this.config.enableCache) {
|
|
300
|
+
this.cache.set(cacheKey, { data: allEntries, timestamp: Date.now() });
|
|
301
|
+
}
|
|
302
|
+
return allEntries;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Get entries by category
|
|
306
|
+
*/
|
|
307
|
+
async getByCategory(category) {
|
|
308
|
+
const entries = await this.getAllEntries();
|
|
309
|
+
return entries.filter((e) => e.categories?.includes(category));
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get entries by tag
|
|
313
|
+
*/
|
|
314
|
+
async getByTag(tag) {
|
|
315
|
+
const entries = await this.getAllEntries();
|
|
316
|
+
return entries.filter((e) => e.tags?.includes(tag));
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Get all categories
|
|
320
|
+
*/
|
|
321
|
+
async getCategories() {
|
|
322
|
+
const entries = await this.getAllEntries();
|
|
323
|
+
const categories = new Set();
|
|
324
|
+
for (const entry of entries) {
|
|
325
|
+
for (const category of entry.categories ?? []) {
|
|
326
|
+
categories.add(category);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return Array.from(categories).sort();
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Get all tags
|
|
333
|
+
*/
|
|
334
|
+
async getTags() {
|
|
335
|
+
const entries = await this.getAllEntries();
|
|
336
|
+
const tags = new Set();
|
|
337
|
+
for (const entry of entries) {
|
|
338
|
+
for (const tag of entry.tags ?? []) {
|
|
339
|
+
tags.add(tag);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return Array.from(tags).sort();
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Convert registry entry to MCPServerInfo
|
|
346
|
+
*/
|
|
347
|
+
toServerInfo(entry) {
|
|
348
|
+
return {
|
|
349
|
+
id: entry.id,
|
|
350
|
+
name: entry.name,
|
|
351
|
+
description: entry.description,
|
|
352
|
+
command: entry.command,
|
|
353
|
+
args: entry.args,
|
|
354
|
+
transport: entry.transports?.[0] ?? "stdio",
|
|
355
|
+
status: "stopped",
|
|
356
|
+
tools: entry.tools?.map((name) => ({
|
|
357
|
+
name,
|
|
358
|
+
description: `Tool: ${name}`,
|
|
359
|
+
})) ?? [],
|
|
360
|
+
metadata: {
|
|
361
|
+
...entry.metadata,
|
|
362
|
+
version: entry.version,
|
|
363
|
+
author: entry.author,
|
|
364
|
+
license: entry.license,
|
|
365
|
+
homepage: entry.homepage,
|
|
366
|
+
repository: entry.repository,
|
|
367
|
+
npmPackage: entry.npmPackage,
|
|
368
|
+
requiredEnvVars: entry.requiredEnvVars,
|
|
369
|
+
categories: entry.categories,
|
|
370
|
+
tags: entry.tags,
|
|
371
|
+
verified: entry.verified,
|
|
372
|
+
},
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Add a custom registry entry
|
|
377
|
+
*/
|
|
378
|
+
addCustomEntry(entry) {
|
|
379
|
+
this.customEntries.set(entry.id, entry);
|
|
380
|
+
this.clearCache();
|
|
381
|
+
this.emit("entryAdded", { entry });
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Remove a custom registry entry
|
|
385
|
+
*/
|
|
386
|
+
removeCustomEntry(id) {
|
|
387
|
+
const removed = this.customEntries.delete(id);
|
|
388
|
+
if (removed) {
|
|
389
|
+
this.clearCache();
|
|
390
|
+
this.emit("entryRemoved", { id });
|
|
391
|
+
}
|
|
392
|
+
return removed;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Add a registry configuration
|
|
396
|
+
*/
|
|
397
|
+
addRegistry(config) {
|
|
398
|
+
this.config.registries.push(config);
|
|
399
|
+
this.clearCache();
|
|
400
|
+
const { authToken: _, ...safeConfig } = config;
|
|
401
|
+
this.emit("registryAdded", { config: safeConfig });
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Clear the cache
|
|
405
|
+
*/
|
|
406
|
+
clearCache() {
|
|
407
|
+
this.cache.clear();
|
|
408
|
+
this.emit("cacheCleared");
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Check if required environment variables are set
|
|
412
|
+
*/
|
|
413
|
+
checkRequiredEnvVars(entry) {
|
|
414
|
+
const missing = [];
|
|
415
|
+
for (const envVar of entry.requiredEnvVars ?? []) {
|
|
416
|
+
if (!process.env[envVar]) {
|
|
417
|
+
missing.push(envVar);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return {
|
|
421
|
+
ready: missing.length === 0,
|
|
422
|
+
missing,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Get installation command for an entry
|
|
427
|
+
*/
|
|
428
|
+
getInstallCommand(entry) {
|
|
429
|
+
if (entry.installCommand) {
|
|
430
|
+
return entry.installCommand;
|
|
431
|
+
}
|
|
432
|
+
if (entry.npmPackage) {
|
|
433
|
+
return `npx -y ${entry.npmPackage}`;
|
|
434
|
+
}
|
|
435
|
+
return undefined;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Get popular servers
|
|
439
|
+
*/
|
|
440
|
+
async getPopularServers(limit = 10) {
|
|
441
|
+
const result = await this.search({
|
|
442
|
+
sortBy: "downloads",
|
|
443
|
+
sortDirection: "desc",
|
|
444
|
+
limit,
|
|
445
|
+
});
|
|
446
|
+
return result.entries;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Get verified servers
|
|
450
|
+
*/
|
|
451
|
+
async getVerifiedServers() {
|
|
452
|
+
const result = await this.search({
|
|
453
|
+
verifiedOnly: true,
|
|
454
|
+
});
|
|
455
|
+
return result.entries;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Get statistics
|
|
459
|
+
*/
|
|
460
|
+
async getStatistics() {
|
|
461
|
+
const entries = await this.getAllEntries();
|
|
462
|
+
const categories = await this.getCategories();
|
|
463
|
+
const tags = await this.getTags();
|
|
464
|
+
return {
|
|
465
|
+
totalEntries: entries.length,
|
|
466
|
+
verifiedEntries: entries.filter((e) => e.verified).length,
|
|
467
|
+
categories: categories.length,
|
|
468
|
+
tags: tags.length,
|
|
469
|
+
customEntries: this.customEntries.size,
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Global MCP registry client instance
|
|
475
|
+
*/
|
|
476
|
+
export const globalMCPRegistryClient = new MCPRegistryClient();
|
|
477
|
+
/**
|
|
478
|
+
* Quick lookup function for well-known servers
|
|
479
|
+
*/
|
|
480
|
+
export function getWellKnownServer(id) {
|
|
481
|
+
return WELL_KNOWN_SERVERS.find((s) => s.id === id);
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Get all well-known servers
|
|
485
|
+
*/
|
|
486
|
+
export function getAllWellKnownServers() {
|
|
487
|
+
return [...WELL_KNOWN_SERVERS];
|
|
488
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Base Class
|
|
3
|
+
*
|
|
4
|
+
* Abstract base class for creating custom MCP servers with consistent patterns
|
|
5
|
+
* for tool registration, execution, and lifecycle management.
|
|
6
|
+
*
|
|
7
|
+
* Implements Mastra-style MCPServerBase features including:
|
|
8
|
+
* - Tool annotation support (readOnlyHint, destructiveHint, idempotentHint)
|
|
9
|
+
* - Lifecycle hooks (onInit, onStart, onStop)
|
|
10
|
+
* - Event emission for tool operations
|
|
11
|
+
* - Conversion to MCPServerInfo format
|
|
12
|
+
*
|
|
13
|
+
* @module mcp/mcpServerBase
|
|
14
|
+
* @since 8.39.0
|
|
15
|
+
*/
|
|
16
|
+
import { EventEmitter } from "events";
|
|
17
|
+
import type { JsonValue } from "../types/common.js";
|
|
18
|
+
import type { MCPServerInfo, MCPTransportType, MCPServerCategory, NeuroLinkExecutionContext, ToolResult } from "../types/mcpTypes.js";
|
|
19
|
+
import type { MCPToolAnnotations, MCPServerTool } from "./toolAnnotations.js";
|
|
20
|
+
/**
|
|
21
|
+
* MCPServerBase configuration
|
|
22
|
+
*/
|
|
23
|
+
export type MCPServerBaseConfig = {
|
|
24
|
+
/**
|
|
25
|
+
* Unique server identifier
|
|
26
|
+
*/
|
|
27
|
+
id: string;
|
|
28
|
+
/**
|
|
29
|
+
* Human-readable server name
|
|
30
|
+
*/
|
|
31
|
+
name: string;
|
|
32
|
+
/**
|
|
33
|
+
* Server description
|
|
34
|
+
*/
|
|
35
|
+
description?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Server version
|
|
38
|
+
*/
|
|
39
|
+
version?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Server category for organization
|
|
42
|
+
*/
|
|
43
|
+
category?: MCPServerCategory;
|
|
44
|
+
/**
|
|
45
|
+
* Transport protocol preference
|
|
46
|
+
*/
|
|
47
|
+
transport?: MCPTransportType;
|
|
48
|
+
/**
|
|
49
|
+
* Custom metadata
|
|
50
|
+
*/
|
|
51
|
+
metadata?: Record<string, JsonValue>;
|
|
52
|
+
/**
|
|
53
|
+
* Default timeout for tool execution in milliseconds (default: 30000)
|
|
54
|
+
*/
|
|
55
|
+
defaultTimeoutMs?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Global tool annotations applied to all tools
|
|
58
|
+
*/
|
|
59
|
+
defaultAnnotations?: MCPToolAnnotations;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Server lifecycle events
|
|
63
|
+
*/
|
|
64
|
+
export type MCPServerEvents = {
|
|
65
|
+
toolRegistered: {
|
|
66
|
+
toolName: string;
|
|
67
|
+
tool: MCPServerTool;
|
|
68
|
+
};
|
|
69
|
+
toolExecuted: {
|
|
70
|
+
toolName: string;
|
|
71
|
+
duration: number;
|
|
72
|
+
success: boolean;
|
|
73
|
+
};
|
|
74
|
+
toolError: {
|
|
75
|
+
toolName: string;
|
|
76
|
+
error: Error;
|
|
77
|
+
};
|
|
78
|
+
serverReady: {
|
|
79
|
+
tools: string[];
|
|
80
|
+
};
|
|
81
|
+
serverStopped: {
|
|
82
|
+
reason?: string;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Abstract base class for MCP servers
|
|
87
|
+
*
|
|
88
|
+
* Provides a foundation for creating custom MCP servers with consistent
|
|
89
|
+
* patterns for tool registration, execution, and lifecycle management.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* class MyCustomServer extends MCPServerBase {
|
|
94
|
+
* constructor() {
|
|
95
|
+
* super({
|
|
96
|
+
* id: "my-custom-server",
|
|
97
|
+
* name: "My Custom Server",
|
|
98
|
+
* description: "Provides custom functionality",
|
|
99
|
+
* category: "custom",
|
|
100
|
+
* });
|
|
101
|
+
*
|
|
102
|
+
* // Register tools in constructor or init
|
|
103
|
+
* this.registerTool({
|
|
104
|
+
* name: "myTool",
|
|
105
|
+
* description: "Does something useful",
|
|
106
|
+
* annotations: {
|
|
107
|
+
* readOnlyHint: true,
|
|
108
|
+
* idempotentHint: true,
|
|
109
|
+
* },
|
|
110
|
+
* execute: async (params, context) => {
|
|
111
|
+
* return { success: true, data: "result" };
|
|
112
|
+
* },
|
|
113
|
+
* });
|
|
114
|
+
* }
|
|
115
|
+
* }
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export declare abstract class MCPServerBase extends EventEmitter {
|
|
119
|
+
protected readonly config: Required<MCPServerBaseConfig>;
|
|
120
|
+
protected readonly tools: Map<string, MCPServerTool>;
|
|
121
|
+
protected isInitialized: boolean;
|
|
122
|
+
protected isRunning: boolean;
|
|
123
|
+
constructor(config: MCPServerBaseConfig);
|
|
124
|
+
/**
|
|
125
|
+
* Initialize the server
|
|
126
|
+
* Override in subclasses for async initialization
|
|
127
|
+
*/
|
|
128
|
+
init(): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Hook for subclass initialization
|
|
131
|
+
* Override to perform async setup
|
|
132
|
+
*/
|
|
133
|
+
protected onInit(): Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Start the server
|
|
136
|
+
*/
|
|
137
|
+
start(): Promise<void>;
|
|
138
|
+
/**
|
|
139
|
+
* Hook for subclass start logic
|
|
140
|
+
*/
|
|
141
|
+
protected onStart(): Promise<void>;
|
|
142
|
+
/**
|
|
143
|
+
* Stop the server
|
|
144
|
+
*/
|
|
145
|
+
stop(reason?: string): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Hook for subclass stop logic
|
|
148
|
+
*/
|
|
149
|
+
protected onStop(): Promise<void>;
|
|
150
|
+
/**
|
|
151
|
+
* Register a tool with the server
|
|
152
|
+
*/
|
|
153
|
+
registerTool(tool: MCPServerTool): this;
|
|
154
|
+
/**
|
|
155
|
+
* Register multiple tools at once
|
|
156
|
+
*/
|
|
157
|
+
registerTools(tools: MCPServerTool[]): this;
|
|
158
|
+
/**
|
|
159
|
+
* Validate tool configuration
|
|
160
|
+
*/
|
|
161
|
+
protected validateTool(tool: MCPServerTool): void;
|
|
162
|
+
/**
|
|
163
|
+
* Execute a tool by name
|
|
164
|
+
*/
|
|
165
|
+
executeTool(toolName: string, params: unknown, context?: NeuroLinkExecutionContext): Promise<ToolResult>;
|
|
166
|
+
/**
|
|
167
|
+
* Type guard to check if result is a ToolResult
|
|
168
|
+
*/
|
|
169
|
+
private isToolResult;
|
|
170
|
+
/**
|
|
171
|
+
* Get all registered tools
|
|
172
|
+
*/
|
|
173
|
+
getTools(): MCPServerTool[];
|
|
174
|
+
/**
|
|
175
|
+
* Get a specific tool by name
|
|
176
|
+
*/
|
|
177
|
+
getTool(name: string): MCPServerTool | undefined;
|
|
178
|
+
/**
|
|
179
|
+
* Check if a tool exists
|
|
180
|
+
*/
|
|
181
|
+
hasTool(name: string): boolean;
|
|
182
|
+
/**
|
|
183
|
+
* Remove a tool
|
|
184
|
+
*/
|
|
185
|
+
removeTool(name: string): boolean;
|
|
186
|
+
/**
|
|
187
|
+
* Get server info in MCPServerInfo format
|
|
188
|
+
*/
|
|
189
|
+
toServerInfo(): MCPServerInfo;
|
|
190
|
+
/**
|
|
191
|
+
* Get tools filtered by annotations
|
|
192
|
+
*/
|
|
193
|
+
getToolsByAnnotation(annotation: keyof MCPToolAnnotations, value: boolean | string | number | string[]): MCPServerTool[];
|
|
194
|
+
/**
|
|
195
|
+
* Get read-only tools
|
|
196
|
+
*/
|
|
197
|
+
getReadOnlyTools(): MCPServerTool[];
|
|
198
|
+
/**
|
|
199
|
+
* Get destructive tools
|
|
200
|
+
*/
|
|
201
|
+
getDestructiveTools(): MCPServerTool[];
|
|
202
|
+
/**
|
|
203
|
+
* Get idempotent tools
|
|
204
|
+
*/
|
|
205
|
+
getIdempotentTools(): MCPServerTool[];
|
|
206
|
+
/**
|
|
207
|
+
* Get tools that require confirmation
|
|
208
|
+
*/
|
|
209
|
+
getToolsRequiringConfirmation(): MCPServerTool[];
|
|
210
|
+
/**
|
|
211
|
+
* Server identification
|
|
212
|
+
*/
|
|
213
|
+
get id(): string;
|
|
214
|
+
get name(): string;
|
|
215
|
+
get description(): string;
|
|
216
|
+
get version(): string;
|
|
217
|
+
get category(): MCPServerCategory;
|
|
218
|
+
/**
|
|
219
|
+
* Check if server is initialized
|
|
220
|
+
*/
|
|
221
|
+
get initialized(): boolean;
|
|
222
|
+
/**
|
|
223
|
+
* Check if server is running
|
|
224
|
+
*/
|
|
225
|
+
get running(): boolean;
|
|
226
|
+
}
|
|
227
|
+
export type { MCPToolAnnotations, MCPServerTool } from "./toolAnnotations.js";
|