@aiwerk/mcp-bridge 2.8.4 → 2.8.6
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/bin/mcp-bridge.js
CHANGED
|
@@ -195,6 +195,26 @@ All logs go to stderr. Stdout is reserved for the MCP protocol (stdio mode).
|
|
|
195
195
|
}
|
|
196
196
|
function cmdInit(logger) {
|
|
197
197
|
initConfigDir(logger);
|
|
198
|
+
// Check if installed globally
|
|
199
|
+
const isGlobal = __dirname.includes("node_modules") && !__dirname.includes(homedir());
|
|
200
|
+
process.stdout.write(`
|
|
201
|
+
Next step: add mcp-bridge to your MCP client.
|
|
202
|
+
|
|
203
|
+
Add this to your client's MCP server config:
|
|
204
|
+
|
|
205
|
+
{
|
|
206
|
+
"mcp-bridge": {
|
|
207
|
+
"command": "${isGlobal ? "mcp-bridge" : "node"}",
|
|
208
|
+
"args": ${isGlobal ? '["serve"]' : `["${join(__dirname, "..", "bin", "mcp-bridge.js")}", "serve"]`}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
Supported clients: Claude Code (~/.claude/settings.json),
|
|
213
|
+
Cursor (~/.cursor/mcp.json), Claude Desktop, Windsurf, OpenClaw, etc.
|
|
214
|
+
${!isGlobal ? "\nTip: Install globally for a cleaner setup:\n npm install -g @aiwerk/mcp-bridge\n" : ""}
|
|
215
|
+
After adding, restart your client. The bridge will appear as an 'mcp' tool
|
|
216
|
+
with search, install, and catalog actions to discover and add MCP servers.
|
|
217
|
+
`);
|
|
198
218
|
}
|
|
199
219
|
function cmdCatalog(logger) {
|
|
200
220
|
const catalogPath = join(PACKAGE_ROOT, "servers", "index.json");
|
package/dist/src/mcp-router.d.ts
CHANGED
|
@@ -74,6 +74,32 @@ export type RouterDispatchResponse = {
|
|
|
74
74
|
callCount: number;
|
|
75
75
|
lastCall: string;
|
|
76
76
|
}>;
|
|
77
|
+
} | {
|
|
78
|
+
action: "search";
|
|
79
|
+
query: string;
|
|
80
|
+
results: Array<{
|
|
81
|
+
id: string;
|
|
82
|
+
name: string;
|
|
83
|
+
description: string;
|
|
84
|
+
category?: string;
|
|
85
|
+
auth?: string;
|
|
86
|
+
}>;
|
|
87
|
+
} | {
|
|
88
|
+
action: "catalog";
|
|
89
|
+
recipes: Array<{
|
|
90
|
+
id: string;
|
|
91
|
+
name: string;
|
|
92
|
+
description: string;
|
|
93
|
+
category?: string;
|
|
94
|
+
auth?: string;
|
|
95
|
+
}>;
|
|
96
|
+
} | {
|
|
97
|
+
action: "install";
|
|
98
|
+
server: string;
|
|
99
|
+
installed: boolean;
|
|
100
|
+
message: string;
|
|
101
|
+
missingEnvVars?: string[];
|
|
102
|
+
credentialsUrl?: string;
|
|
77
103
|
} | {
|
|
78
104
|
action: "intent";
|
|
79
105
|
intent: string;
|
|
@@ -122,6 +148,7 @@ export declare class McpRouter {
|
|
|
122
148
|
private readonly tokenManager;
|
|
123
149
|
private readonly rateLimiter;
|
|
124
150
|
private readonly requestIdState;
|
|
151
|
+
private readonly catalogClient;
|
|
125
152
|
private intentRouter;
|
|
126
153
|
private promotion;
|
|
127
154
|
constructor(servers: Record<string, McpServerConfig>, clientConfig: McpClientConfig, logger: Logger, transportRefs?: Partial<RouterTransportRefs>);
|
package/dist/src/mcp-router.js
CHANGED
|
@@ -13,6 +13,8 @@ import { ToolResolver } from "./tool-resolution.js";
|
|
|
13
13
|
import { OAuth2TokenManager } from "./oauth2-token-manager.js";
|
|
14
14
|
import { FileTokenStore } from "./token-store.js";
|
|
15
15
|
import { RateLimiter } from "./rate-limiter.js";
|
|
16
|
+
import { CatalogClient } from "./catalog-client.js";
|
|
17
|
+
import { recipeToServerConfig, collectRequiredEnvVars } from "./config.js";
|
|
16
18
|
const DEFAULT_IDLE_TIMEOUT_MS = 10 * 60 * 1000;
|
|
17
19
|
const DEFAULT_CONNECT_ERROR_COOLDOWN_MS = 10 * 1000;
|
|
18
20
|
const DEFAULT_MAX_CONCURRENT = 5;
|
|
@@ -33,6 +35,7 @@ export class McpRouter {
|
|
|
33
35
|
tokenManager;
|
|
34
36
|
rateLimiter;
|
|
35
37
|
requestIdState = { value: 0 };
|
|
38
|
+
catalogClient;
|
|
36
39
|
intentRouter = null;
|
|
37
40
|
promotion = null;
|
|
38
41
|
constructor(servers, clientConfig, logger, transportRefs) {
|
|
@@ -58,6 +61,7 @@ export class McpRouter {
|
|
|
58
61
|
this.toolResolver = new ToolResolver(Object.keys(servers));
|
|
59
62
|
this.tokenManager = new OAuth2TokenManager(logger, new FileTokenStore());
|
|
60
63
|
this.rateLimiter = new RateLimiter();
|
|
64
|
+
this.catalogClient = new CatalogClient({ logger });
|
|
61
65
|
if (clientConfig.adaptivePromotion?.enabled) {
|
|
62
66
|
this.promotion = new AdaptivePromotion(clientConfig.adaptivePromotion, logger);
|
|
63
67
|
}
|
|
@@ -94,6 +98,100 @@ export class McpRouter {
|
|
|
94
98
|
}
|
|
95
99
|
return this.resolveIntent(intent);
|
|
96
100
|
}
|
|
101
|
+
// Search catalog
|
|
102
|
+
if (normalizedAction === "search") {
|
|
103
|
+
const query = params?.query || server || tool;
|
|
104
|
+
if (!query) {
|
|
105
|
+
return this.error("invalid_params", "query is required for action=search (pass as params.query or server field)");
|
|
106
|
+
}
|
|
107
|
+
if (!this.catalogClient) {
|
|
108
|
+
return this.error("mcp_error", "Catalog client not available");
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
const results = await this.catalogClient.search(query);
|
|
112
|
+
return {
|
|
113
|
+
action: "search",
|
|
114
|
+
query,
|
|
115
|
+
results: results.map(r => ({
|
|
116
|
+
id: r.name,
|
|
117
|
+
name: r.name,
|
|
118
|
+
description: r.description || "",
|
|
119
|
+
category: r.category,
|
|
120
|
+
auth: "none", // Search results don't include auth info
|
|
121
|
+
}))
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
return this.error("mcp_error", `Catalog search failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Browse catalog
|
|
129
|
+
if (normalizedAction === "catalog") {
|
|
130
|
+
if (!this.catalogClient) {
|
|
131
|
+
return this.error("mcp_error", "Catalog client not available");
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const recipeList = await this.catalogClient.list();
|
|
135
|
+
return {
|
|
136
|
+
action: "catalog",
|
|
137
|
+
recipes: recipeList.results.map(r => ({
|
|
138
|
+
id: r.name,
|
|
139
|
+
name: r.name,
|
|
140
|
+
description: r.description || "",
|
|
141
|
+
category: r.category,
|
|
142
|
+
auth: "none", // List results don't include auth info
|
|
143
|
+
}))
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
return this.error("mcp_error", `Catalog browse failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Install server from catalog (runtime only, not persisted to config file)
|
|
151
|
+
if (normalizedAction === "install") {
|
|
152
|
+
const serverName = server || params?.server;
|
|
153
|
+
if (!serverName) {
|
|
154
|
+
return this.error("invalid_params", "server name is required for action=install");
|
|
155
|
+
}
|
|
156
|
+
if (this.servers[serverName]) {
|
|
157
|
+
return { action: "install", server: serverName, installed: true, message: `Server "${serverName}" is already configured.` };
|
|
158
|
+
}
|
|
159
|
+
if (!this.catalogClient) {
|
|
160
|
+
return this.error("mcp_error", "Catalog client not available");
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
const recipe = await this.catalogClient.resolve(serverName);
|
|
164
|
+
const serverConfig = recipeToServerConfig(recipe);
|
|
165
|
+
if (!serverConfig) {
|
|
166
|
+
return this.error("mcp_error", `Unsupported recipe format for "${serverName}"`);
|
|
167
|
+
}
|
|
168
|
+
// Check env vars
|
|
169
|
+
const requiredVars = collectRequiredEnvVars(recipe);
|
|
170
|
+
const missing = requiredVars.filter(v => !process.env[v]);
|
|
171
|
+
// Add to runtime config
|
|
172
|
+
this.servers[serverName] = serverConfig;
|
|
173
|
+
// Also update clientConfig.servers so generateDescription includes it
|
|
174
|
+
this.clientConfig.servers[serverName] = serverConfig;
|
|
175
|
+
if (missing.length > 0) {
|
|
176
|
+
return {
|
|
177
|
+
action: "install",
|
|
178
|
+
server: serverName,
|
|
179
|
+
installed: true,
|
|
180
|
+
message: `Server "${serverName}" added (runtime). Missing env vars: ${missing.join(", ")}. Set them before calling.`,
|
|
181
|
+
missingEnvVars: missing,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
action: "install",
|
|
186
|
+
server: serverName,
|
|
187
|
+
installed: true,
|
|
188
|
+
message: `Server "${serverName}" installed and ready to use.`
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
return this.error("mcp_error", `Install failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
97
195
|
if (normalizedAction === "batch") {
|
|
98
196
|
const calls = params?.calls;
|
|
99
197
|
if (!Array.isArray(calls) || calls.length === 0) {
|
|
@@ -206,7 +304,7 @@ export class McpRouter {
|
|
|
206
304
|
}
|
|
207
305
|
}
|
|
208
306
|
if (normalizedAction !== "call") {
|
|
209
|
-
return this.error("invalid_params", `action must be one of: list, call, batch, refresh, schema, intent, status, promotions`);
|
|
307
|
+
return this.error("invalid_params", `action must be one of: list, call, batch, refresh, schema, intent, status, promotions, search, catalog, install`);
|
|
210
308
|
}
|
|
211
309
|
if (!tool) {
|
|
212
310
|
return this.error("invalid_params", "tool is required for action=call");
|
|
@@ -221,7 +221,7 @@ export class StandaloneServer {
|
|
|
221
221
|
type: "object",
|
|
222
222
|
properties: {
|
|
223
223
|
server: { type: "string", description: "Server name" },
|
|
224
|
-
action: { type: "string", description: "list | call | batch | refresh | status | intent | schema | promotions" },
|
|
224
|
+
action: { type: "string", description: "list | call | batch | refresh | status | intent | schema | promotions | search | catalog | install" },
|
|
225
225
|
tool: { type: "string", description: "Tool name for action=call/schema" },
|
|
226
226
|
params: { type: "object", description: "Tool arguments" },
|
|
227
227
|
calls: {
|