@aiwerk/mcp-bridge 2.8.23 → 2.8.25
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/README.md +57 -33
- package/dist/bin/mcp-bridge.js +27 -3
- package/dist/src/catalog-client.d.ts +1 -0
- package/dist/src/mcp-router.d.ts +5 -0
- package/dist/src/mcp-router.js +39 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
🌐 **[aiwerkmcp.com](https://aiwerkmcp.com)** — Learn more about the AIWerk MCP Platform
|
|
10
10
|
|
|
11
|
-
Works with **Claude Desktop**, **Cursor**, **Windsurf**, **Cline**, **OpenClaw**, or any MCP client.
|
|
11
|
+
Works with **Claude Code**, **Codex (OpenAI)**, **Claude Desktop**, **Cursor**, **Windsurf**, **Cline**, **OpenClaw**, or any MCP client.
|
|
12
12
|
|
|
13
13
|
## Why?
|
|
14
14
|
|
|
@@ -39,8 +39,8 @@ npm install -g @aiwerk/mcp-bridge
|
|
|
39
39
|
## Quick Start
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
# 1. Initialize config
|
|
43
|
-
mcp-bridge init
|
|
42
|
+
# 1. Initialize config and register with Claude Code
|
|
43
|
+
mcp-bridge init --register claude-code
|
|
44
44
|
|
|
45
45
|
# 2. Install a server from the catalog
|
|
46
46
|
mcp-bridge install todoist
|
|
@@ -48,8 +48,7 @@ mcp-bridge install todoist
|
|
|
48
48
|
# 3. Add your API key
|
|
49
49
|
echo "TODOIST_API_TOKEN=your-token" >> ~/.mcp-bridge/.env
|
|
50
50
|
|
|
51
|
-
# 4.
|
|
52
|
-
mcp-bridge
|
|
51
|
+
# 4. Restart Claude Code — bridge is ready
|
|
53
52
|
```
|
|
54
53
|
|
|
55
54
|
## Use with Claude Desktop
|
|
@@ -418,9 +417,24 @@ Returns promoted tools (sorted by frequency) and full usage stats. All tracking
|
|
|
418
417
|
| Mode | Tools exposed | Best for |
|
|
419
418
|
|------|--------------|----------|
|
|
420
419
|
| `router` (default) | Single `mcp` meta-tool | 3+ servers, token-conscious agents |
|
|
421
|
-
| `direct` | All tools individually |
|
|
420
|
+
| `direct` | All tools individually | Clients with deferred/lazy tool loading (Claude Code), few servers |
|
|
422
421
|
|
|
423
|
-
|
|
422
|
+
Switch modes via CLI or config:
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
mcp-bridge init --mode direct # all tools exposed individually
|
|
426
|
+
mcp-bridge init --mode router # single mcp meta-tool (default)
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Or set in `~/.mcp-bridge/config.json`:
|
|
430
|
+
|
|
431
|
+
```json
|
|
432
|
+
{ "mode": "direct" }
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**Router mode** — the agent calls `mcp(server="todoist", action="list")` to discover, then `mcp(server="todoist", tool="find-tasks", params={...})` to execute. Best when you have many servers and want minimal token usage.
|
|
436
|
+
|
|
437
|
+
**Direct mode** — all tools from all servers are registered individually as `todoist_find_tasks`, `github_list_repos`, etc. The bridge still provides unified config, catalog install, OAuth2, security, retries, and reconnection. Ideal for clients that support deferred/lazy tool loading, where tools are registered but not loaded into context until needed.
|
|
424
438
|
|
|
425
439
|
### Multi-Server Tool Resolution
|
|
426
440
|
|
|
@@ -558,12 +572,16 @@ mcp-bridge # Start in stdio mode (default)
|
|
|
558
572
|
mcp-bridge --sse --port 3000 # Start as SSE server
|
|
559
573
|
mcp-bridge --http --port 3000 # Start as HTTP server
|
|
560
574
|
mcp-bridge --verbose # Info-level logs to stderr
|
|
561
|
-
mcp-bridge --debug # Full
|
|
575
|
+
mcp-bridge --debug # Full debug metadata in tool responses
|
|
562
576
|
mcp-bridge --config ./my.json # Custom config file
|
|
563
577
|
|
|
564
|
-
mcp-bridge init # Create ~/.mcp-bridge/ with template
|
|
565
|
-
mcp-bridge
|
|
566
|
-
mcp-bridge
|
|
578
|
+
mcp-bridge init # Create ~/.mcp-bridge/ with template config
|
|
579
|
+
mcp-bridge init --register claude-code # Init + register with Claude Code
|
|
580
|
+
mcp-bridge init --register codex # Init + register with Codex
|
|
581
|
+
mcp-bridge init --register cursor # Init + register with Cursor
|
|
582
|
+
mcp-bridge init --register windsurf # Init + register with Windsurf
|
|
583
|
+
mcp-bridge install <server> # Install from online catalog
|
|
584
|
+
mcp-bridge catalog # Browse 100+ available servers
|
|
567
585
|
mcp-bridge servers # List configured servers
|
|
568
586
|
mcp-bridge search <query> # Search catalog by keyword
|
|
569
587
|
mcp-bridge update [--check] # Check for / install updates
|
|
@@ -574,33 +592,36 @@ mcp-bridge auth logout <server> # Remove stored token
|
|
|
574
592
|
mcp-bridge auth status # Show auth status for all servers
|
|
575
593
|
```
|
|
576
594
|
|
|
595
|
+
## Agent Integration
|
|
596
|
+
|
|
597
|
+
When connected to an MCP client (Claude Code, Codex, Cursor, etc.), the bridge exposes a single `mcp` meta-tool. Agents can discover and install servers at runtime:
|
|
598
|
+
|
|
599
|
+
```
|
|
600
|
+
mcp(action="search", params={query: "task management"}) # Search catalog
|
|
601
|
+
mcp(action="install", params={name: "todoist"}) # Install server (persisted to config)
|
|
602
|
+
mcp(action="catalog") # Browse all servers
|
|
603
|
+
mcp(action="list", server="todoist") # Discover tools on a server
|
|
604
|
+
mcp(action="call", server="todoist", tool="find-tasks", params={query: "today"})
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
The tool description automatically includes all connected servers with their descriptions, so agents know which server to use for what. New servers installed via the bridge are persisted to `~/.mcp-bridge/config.json` and survive restarts.
|
|
608
|
+
|
|
577
609
|
## Server Catalog
|
|
578
610
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
| Server | Transport | Description |
|
|
582
|
-
|--------|-----------|-------------|
|
|
583
|
-
| todoist | stdio | Task management |
|
|
584
|
-
| github | stdio | Repos, issues, PRs |
|
|
585
|
-
| notion | stdio | Pages and databases |
|
|
586
|
-
| stripe | stdio | Payments and billing |
|
|
587
|
-
| linear | stdio | Project management |
|
|
588
|
-
| google-maps | stdio | Places, geocoding, directions |
|
|
589
|
-
| hetzner | stdio | Cloud infrastructure |
|
|
590
|
-
| miro | stdio | Collaborative whiteboard |
|
|
591
|
-
| wise | stdio | International payments |
|
|
592
|
-
| tavily | stdio | AI-optimized web search |
|
|
593
|
-
| apify | streamable-http | Web scraping and automation |
|
|
594
|
-
| atlassian | stdio | Confluence and Jira |
|
|
595
|
-
| chrome-devtools | stdio | Chrome browser automation |
|
|
596
|
-
| hostinger | sse | Web hosting management |
|
|
611
|
+
Browse and install from the [AIWerk MCP Catalog](https://catalog.aiwerk.ch) with 100+ verified, signed recipes:
|
|
597
612
|
|
|
598
613
|
```bash
|
|
599
|
-
mcp-bridge
|
|
600
|
-
mcp-bridge
|
|
601
|
-
mcp-bridge
|
|
614
|
+
mcp-bridge catalog # Browse all 100+ servers
|
|
615
|
+
mcp-bridge search payments # Search by keyword
|
|
616
|
+
mcp-bridge install todoist # Install from catalog
|
|
602
617
|
```
|
|
603
618
|
|
|
619
|
+
Popular servers include: todoist, github, notion, stripe, linear, google-maps, slack, supabase, mongodb, playwright, docker, and many more.
|
|
620
|
+
|
|
621
|
+
All catalog recipes are Ed25519 signed and security-audited. The bridge verifies signatures before installation.
|
|
622
|
+
|
|
623
|
+
> **Note**: The bundled `servers/` directory is deprecated. All servers now come from the online catalog.
|
|
624
|
+
|
|
604
625
|
## Library Usage
|
|
605
626
|
|
|
606
627
|
Use as a dependency in your own MCP server or OpenClaw plugin:
|
|
@@ -667,11 +688,14 @@ For production deployments with high security requirements, consider adding an e
|
|
|
667
688
|
| ✅ | OAuth2 Client Credentials | 2.1.0 |
|
|
668
689
|
| ✅ | OAuth2 Authorization Code + PKCE | 2.5.0 |
|
|
669
690
|
| ✅ | OAuth2 Device Code flow (headless) | 2.6.0 |
|
|
670
|
-
|
|
|
691
|
+
| ✅ | Agent-driven discovery (search/install at runtime) | 2.8.6 |
|
|
671
692
|
| 🔜 | Hosted bridge (bridge.aiwerk.ch) | planned |
|
|
672
693
|
| ✅ | Remote catalog integration | 2.8.0 |
|
|
694
|
+
| ✅ | CLI online catalog | 2.8.23 |
|
|
695
|
+
| ✅ | Debug mode (_debug metadata) | 2.8.4 |
|
|
673
696
|
| 🔜 | OpenTelemetry / Prometheus metrics | planned |
|
|
674
697
|
| 🔜 | PII redaction | planned |
|
|
698
|
+
| 🔜 | Skill system (recipe.json skills for agents) | planned |
|
|
675
699
|
|
|
676
700
|
See [docs/hosted-bridge-spec.md](docs/hosted-bridge-spec.md) for the hosted bridge architecture.
|
|
677
701
|
|
package/dist/bin/mcp-bridge.js
CHANGED
|
@@ -106,6 +106,14 @@ function parseArgs(argv) {
|
|
|
106
106
|
}
|
|
107
107
|
args.register = argv[i];
|
|
108
108
|
break;
|
|
109
|
+
case "--mode":
|
|
110
|
+
i++;
|
|
111
|
+
if (argv[i] !== "router" && argv[i] !== "direct") {
|
|
112
|
+
process.stderr.write("Error: --mode must be 'router' or 'direct'\n");
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
args.mode = argv[i];
|
|
116
|
+
break;
|
|
109
117
|
case "--daily":
|
|
110
118
|
i++;
|
|
111
119
|
args.daily = parseInt(argv[i], 10);
|
|
@@ -179,7 +187,7 @@ Usage:
|
|
|
179
187
|
mcp-bridge Start in stdio mode (default)
|
|
180
188
|
mcp-bridge --sse --port 3000 Start as SSE server
|
|
181
189
|
mcp-bridge --http --port 3000 Start as streamable-http server
|
|
182
|
-
mcp-bridge init [--register <client>] Create config + optionally register
|
|
190
|
+
mcp-bridge init [--register <client>] [--mode router|direct] Create config + optionally register
|
|
183
191
|
mcp-bridge install <server> Install a server from the catalog
|
|
184
192
|
mcp-bridge catalog [--offline] List available servers
|
|
185
193
|
mcp-bridge servers List configured servers
|
|
@@ -211,8 +219,24 @@ function whichCmd(name) {
|
|
|
211
219
|
return false;
|
|
212
220
|
}
|
|
213
221
|
}
|
|
214
|
-
function cmdInit(logger, register) {
|
|
222
|
+
function cmdInit(logger, register, mode) {
|
|
215
223
|
initConfigDir(logger);
|
|
224
|
+
// Apply --mode to config
|
|
225
|
+
if (mode) {
|
|
226
|
+
const configPath = join(homedir(), ".mcp-bridge", "config.json");
|
|
227
|
+
if (existsSync(configPath)) {
|
|
228
|
+
try {
|
|
229
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
230
|
+
if (raw.mode !== mode) {
|
|
231
|
+
raw.mode = mode;
|
|
232
|
+
writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
|
|
233
|
+
process.stdout.write(`Mode set to "${mode}" in ${configPath}\n`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch { /* ignore parse errors */ }
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// If --register is specified, do both mode + register
|
|
216
240
|
const isGlobal = __dirname.includes("node_modules") && (__dirname.includes("/lib/node_modules/") || __dirname.includes("\\lib\\node_modules\\"));
|
|
217
241
|
const bridgeCmd = isGlobal ? "mcp-bridge" : "node";
|
|
218
242
|
const bridgeArgs = isGlobal ? ["serve"] : [join(__dirname, "..", "bin", "mcp-bridge.js"), "serve"];
|
|
@@ -766,7 +790,7 @@ async function main() {
|
|
|
766
790
|
printHelp();
|
|
767
791
|
break;
|
|
768
792
|
case "init":
|
|
769
|
-
cmdInit(logger, args.register);
|
|
793
|
+
cmdInit(logger, args.register, args.mode);
|
|
770
794
|
break;
|
|
771
795
|
case "catalog":
|
|
772
796
|
await cmdCatalog(logger, args.offline);
|
package/dist/src/mcp-router.d.ts
CHANGED
|
@@ -110,6 +110,11 @@ export type RouterDispatchResponse = {
|
|
|
110
110
|
message: string;
|
|
111
111
|
missingEnvVars?: string[];
|
|
112
112
|
credentialsUrl?: string;
|
|
113
|
+
} | {
|
|
114
|
+
action: "set-mode";
|
|
115
|
+
mode: string;
|
|
116
|
+
message: string;
|
|
117
|
+
requiresRestart?: boolean;
|
|
113
118
|
} | {
|
|
114
119
|
action: "intent";
|
|
115
120
|
intent: string;
|
package/dist/src/mcp-router.js
CHANGED
|
@@ -77,7 +77,7 @@ export class McpRouter {
|
|
|
77
77
|
return desc ? `${name} (${desc})` : name;
|
|
78
78
|
})
|
|
79
79
|
.join(", ");
|
|
80
|
-
return `MCP server multiplexer 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. If the user mentions a specific tool by name, the call action auto-connects and works without listing first.`;
|
|
80
|
+
return `MCP server multiplexer 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 {
|
|
@@ -165,6 +165,10 @@ export class McpRouter {
|
|
|
165
165
|
if (!serverName) {
|
|
166
166
|
return this.error("invalid_params", "server name is required for action=install (pass as server field or params.name)");
|
|
167
167
|
}
|
|
168
|
+
// Sanitize serverName: only lowercase alphanumeric + hyphens (matches recipe spec id format)
|
|
169
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(serverName)) {
|
|
170
|
+
return this.error("invalid_params", `Invalid server name "${serverName}". Must match /^[a-z0-9][a-z0-9-]*$/ (lowercase alphanumeric + hyphens).`);
|
|
171
|
+
}
|
|
168
172
|
if (this.servers[serverName]) {
|
|
169
173
|
return { action: "install", server: serverName, installed: true, message: `Server "${serverName}" is already configured.` };
|
|
170
174
|
}
|
|
@@ -336,8 +340,41 @@ export class McpRouter {
|
|
|
336
340
|
return this.error("connection_failed", `Failed to connect to ${server}: ${error instanceof Error ? error.message : String(error)}`);
|
|
337
341
|
}
|
|
338
342
|
}
|
|
343
|
+
// Set mode (persists to config, requires bridge restart to take effect)
|
|
344
|
+
if (normalizedAction === "set-mode") {
|
|
345
|
+
const newMode = params?.mode;
|
|
346
|
+
if (newMode !== "router" && newMode !== "direct") {
|
|
347
|
+
return this.error("invalid_params", "mode must be 'router' or 'direct'");
|
|
348
|
+
}
|
|
349
|
+
try {
|
|
350
|
+
const os = await import("os");
|
|
351
|
+
const fs = await import("fs");
|
|
352
|
+
const path = await import("path");
|
|
353
|
+
const configPath = path.join(os.homedir(), ".mcp-bridge", "config.json");
|
|
354
|
+
if (fs.existsSync(configPath)) {
|
|
355
|
+
const raw = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
356
|
+
const oldMode = raw.mode || "router";
|
|
357
|
+
if (oldMode === newMode) {
|
|
358
|
+
return { action: "set-mode", mode: newMode, message: `Already in "${newMode}" mode.` };
|
|
359
|
+
}
|
|
360
|
+
raw.mode = newMode;
|
|
361
|
+
fs.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
|
|
362
|
+
this.logger.info(`Mode changed from "${oldMode}" to "${newMode}" in ${configPath}`);
|
|
363
|
+
return {
|
|
364
|
+
action: "set-mode",
|
|
365
|
+
mode: newMode,
|
|
366
|
+
message: `Mode changed to "${newMode}". Restart the bridge for changes to take effect.`,
|
|
367
|
+
requiresRestart: true,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
return this.error("mcp_error", "Config file not found");
|
|
371
|
+
}
|
|
372
|
+
catch (err) {
|
|
373
|
+
return this.error("mcp_error", `Failed to set mode: ${err instanceof Error ? err.message : String(err)}`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
339
376
|
if (normalizedAction !== "call") {
|
|
340
|
-
return this.error("invalid_params", `action must be one of: list, call, batch, refresh, schema, intent, status, promotions, search, catalog, install`);
|
|
377
|
+
return this.error("invalid_params", `action must be one of: list, call, batch, refresh, schema, intent, status, promotions, search, catalog, install, set-mode`);
|
|
341
378
|
}
|
|
342
379
|
if (!tool) {
|
|
343
380
|
return this.error("invalid_params", "tool is required for action=call");
|