@aiwerk/mcp-bridge 2.8.25 → 2.8.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/mcp-router.js +2 -2
- package/dist/src/standalone-server.js +73 -10
- package/package.json +1 -1
package/dist/src/mcp-router.js
CHANGED
|
@@ -69,7 +69,7 @@ export class McpRouter {
|
|
|
69
69
|
static generateDescription(servers) {
|
|
70
70
|
const serverNames = Object.keys(servers);
|
|
71
71
|
if (serverNames.length === 0) {
|
|
72
|
-
return "MCP server
|
|
72
|
+
return "MCP server manager with no servers configured yet. To add MCP servers, always use this tool first (not npm install): action='search' to find servers in the verified catalog (100+ signed, security-audited recipes), action='install' to add a server by name, action='catalog' to browse all available servers.";
|
|
73
73
|
}
|
|
74
74
|
const serverList = serverNames
|
|
75
75
|
.map((name) => {
|
|
@@ -77,7 +77,7 @@ export class McpRouter {
|
|
|
77
77
|
return desc ? `${name} (${desc})` : name;
|
|
78
78
|
})
|
|
79
79
|
.join(", ");
|
|
80
|
-
return `MCP server
|
|
80
|
+
return `MCP server manager with ${serverNames.length} connected servers: ${serverList}. Actions: 'call' to execute a tool, 'list' to discover tools on a server, 'batch' for multiple calls in one round-trip, 'status' to check connections, 'refresh' to re-discover tools. To add new MCP servers, always use this tool first (not npm install): 'search' to find servers in the verified catalog (100+ signed, security-audited recipes), 'install' to add a server by name. Use 'set-mode' with params.mode='direct' to expose all tools individually (requires restart). If the user mentions a specific tool by name, the call action auto-connects and works without listing first.`;
|
|
81
81
|
}
|
|
82
82
|
async dispatch(server, action = "call", tool, params) {
|
|
83
83
|
try {
|
|
@@ -244,14 +244,31 @@ export class StandaloneServer {
|
|
|
244
244
|
}
|
|
245
245
|
};
|
|
246
246
|
}
|
|
247
|
-
// Direct mode:
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
247
|
+
// Direct mode: return tools lazily
|
|
248
|
+
// If already discovered, use real tool list. Otherwise, generate placeholder
|
|
249
|
+
// tools from config descriptions (no child process startup on tools/list).
|
|
250
|
+
if (this.directTools.length > 0) {
|
|
251
|
+
const tools = this.directTools.map(t => ({
|
|
252
|
+
name: t.registeredName,
|
|
253
|
+
description: t.description,
|
|
254
|
+
inputSchema: t.inputSchema
|
|
255
|
+
}));
|
|
256
|
+
return { jsonrpc: "2.0", id, result: { tools } };
|
|
257
|
+
}
|
|
258
|
+
// Lazy: generate tool entries from server config (no connect yet)
|
|
259
|
+
const placeholderTools = [];
|
|
260
|
+
const globalNames = new Set();
|
|
261
|
+
for (const [serverName, serverConfig] of Object.entries(this.config.servers)) {
|
|
262
|
+
const desc = serverConfig.description || serverName;
|
|
263
|
+
const registeredName = pickRegisteredToolName(serverName, "call", this.config.toolPrefix, new Set(), globalNames, this.logger);
|
|
264
|
+
globalNames.add(registeredName);
|
|
265
|
+
placeholderTools.push({
|
|
266
|
+
name: registeredName,
|
|
267
|
+
description: `[${serverName}] ${desc} — tools will be discovered on first call. Use this tool to trigger discovery.`,
|
|
268
|
+
inputSchema: { type: "object", properties: { _discover: { type: "boolean", description: "Set to true to discover all tools from this server" } } }
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
return { jsonrpc: "2.0", id, result: { tools: placeholderTools } };
|
|
255
272
|
}
|
|
256
273
|
async handleToolsCall(id, params) {
|
|
257
274
|
const toolName = params?.name;
|
|
@@ -295,7 +312,28 @@ export class StandaloneServer {
|
|
|
295
312
|
};
|
|
296
313
|
}
|
|
297
314
|
// Direct mode: find and call the tool
|
|
298
|
-
|
|
315
|
+
let entry = this.directTools.find(t => t.registeredName === toolName);
|
|
316
|
+
// Lazy discovery: if tool not found, maybe we haven't connected yet
|
|
317
|
+
if (!entry) {
|
|
318
|
+
// Check if this looks like a placeholder tool (serverName_call pattern) or just unknown
|
|
319
|
+
// Try full discovery if we haven't done it yet
|
|
320
|
+
if (this.directTools.length === 0 || toolArgs?._discover) {
|
|
321
|
+
this.logger.info(`[mcp-bridge] Lazy discovery triggered by tool call: ${toolName}`);
|
|
322
|
+
await this.discoverDirectTools();
|
|
323
|
+
entry = this.directTools.find(t => t.registeredName === toolName);
|
|
324
|
+
// If the original call was a placeholder, send back the discovered tools list
|
|
325
|
+
if (!entry && toolArgs?._discover) {
|
|
326
|
+
const discovered = this.directTools.map(t => `${t.registeredName}: ${t.description}`);
|
|
327
|
+
return {
|
|
328
|
+
jsonrpc: "2.0",
|
|
329
|
+
id,
|
|
330
|
+
result: {
|
|
331
|
+
content: [{ type: "text", text: `Discovered ${this.directTools.length} tools:\n${discovered.join("\n")}` }]
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
299
337
|
if (!entry) {
|
|
300
338
|
return {
|
|
301
339
|
jsonrpc: "2.0",
|
|
@@ -308,7 +346,32 @@ export class StandaloneServer {
|
|
|
308
346
|
};
|
|
309
347
|
}
|
|
310
348
|
try {
|
|
311
|
-
|
|
349
|
+
let conn = this.directConnections.get(entry.serverName);
|
|
350
|
+
// Lazy connect: if server not connected yet, connect now
|
|
351
|
+
if (!conn || !conn.transport.isConnected()) {
|
|
352
|
+
const serverConfig = this.config.servers[entry.serverName];
|
|
353
|
+
if (serverConfig) {
|
|
354
|
+
try {
|
|
355
|
+
this.logger.info(`[mcp-bridge] Lazy connecting to ${entry.serverName}...`);
|
|
356
|
+
const transport = this.createTransport(entry.serverName, serverConfig);
|
|
357
|
+
await transport.connect();
|
|
358
|
+
await initializeProtocol(transport, PACKAGE_VERSION);
|
|
359
|
+
conn = { transport, initialized: true };
|
|
360
|
+
this.directConnections.set(entry.serverName, conn);
|
|
361
|
+
}
|
|
362
|
+
catch (connErr) {
|
|
363
|
+
return {
|
|
364
|
+
jsonrpc: "2.0",
|
|
365
|
+
id,
|
|
366
|
+
error: {
|
|
367
|
+
code: -32001,
|
|
368
|
+
message: `Failed to connect to ${entry.serverName}: ${connErr instanceof Error ? connErr.message : String(connErr)}`,
|
|
369
|
+
data: { errorType: "connection_failed", server: entry.serverName, retriable: true }
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
312
375
|
if (!conn || !conn.transport.isConnected()) {
|
|
313
376
|
return {
|
|
314
377
|
jsonrpc: "2.0",
|