@aiwerk/mcp-bridge 1.0.0 → 1.0.2

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.
Files changed (63) hide show
  1. package/dist/bin/mcp-bridge.d.ts +2 -0
  2. package/dist/bin/mcp-bridge.js +320 -0
  3. package/dist/src/config.d.ts +19 -0
  4. package/dist/src/config.js +145 -0
  5. package/{src/index.ts → dist/src/index.d.ts} +1 -30
  6. package/dist/src/index.js +21 -0
  7. package/dist/src/mcp-router.d.ts +65 -0
  8. package/dist/src/mcp-router.js +271 -0
  9. package/dist/src/protocol.d.ts +4 -0
  10. package/dist/src/protocol.js +58 -0
  11. package/dist/src/schema-convert.d.ts +11 -0
  12. package/dist/src/schema-convert.js +150 -0
  13. package/dist/src/standalone-server.d.ts +30 -0
  14. package/dist/src/standalone-server.js +312 -0
  15. package/dist/src/tool-naming.d.ts +3 -0
  16. package/dist/src/tool-naming.js +38 -0
  17. package/dist/src/transport-base.d.ts +76 -0
  18. package/dist/src/transport-base.js +163 -0
  19. package/dist/src/transport-sse.d.ts +16 -0
  20. package/dist/src/transport-sse.js +207 -0
  21. package/dist/src/transport-stdio.d.ts +20 -0
  22. package/dist/src/transport-stdio.js +281 -0
  23. package/dist/src/transport-streamable-http.d.ts +11 -0
  24. package/dist/src/transport-streamable-http.js +164 -0
  25. package/dist/src/types.d.ts +72 -0
  26. package/dist/src/types.js +4 -0
  27. package/dist/src/update-checker.d.ts +25 -0
  28. package/dist/src/update-checker.js +132 -0
  29. package/package.json +19 -4
  30. package/scripts/install-server.ps1 +25 -58
  31. package/scripts/install-server.sh +37 -90
  32. package/servers/apify/README.md +6 -6
  33. package/servers/github/README.md +6 -6
  34. package/servers/google-maps/README.md +6 -6
  35. package/servers/hetzner/README.md +6 -6
  36. package/servers/hostinger/README.md +6 -6
  37. package/servers/linear/README.md +6 -6
  38. package/servers/miro/README.md +6 -6
  39. package/servers/notion/README.md +6 -6
  40. package/servers/stripe/README.md +6 -6
  41. package/servers/tavily/README.md +6 -6
  42. package/servers/todoist/README.md +6 -6
  43. package/servers/wise/README.md +6 -6
  44. package/bin/mcp-bridge.js +0 -9
  45. package/bin/mcp-bridge.ts +0 -335
  46. package/src/config.ts +0 -168
  47. package/src/mcp-router.ts +0 -366
  48. package/src/protocol.ts +0 -69
  49. package/src/schema-convert.ts +0 -178
  50. package/src/standalone-server.ts +0 -385
  51. package/src/tool-naming.ts +0 -51
  52. package/src/transport-base.ts +0 -199
  53. package/src/transport-sse.ts +0 -230
  54. package/src/transport-stdio.ts +0 -312
  55. package/src/transport-streamable-http.ts +0 -188
  56. package/src/types.ts +0 -88
  57. package/src/update-checker.ts +0 -155
  58. package/tests/collision.test.ts +0 -60
  59. package/tests/env-resolve.test.ts +0 -68
  60. package/tests/mcp-router.test.ts +0 -301
  61. package/tests/schema-convert.test.ts +0 -70
  62. package/tests/transport-base.test.ts +0 -214
  63. package/tsconfig.json +0 -15
@@ -10,21 +10,21 @@ Official GitHub MCP server running in Docker.
10
10
 
11
11
  ### Linux / macOS
12
12
  ```bash
13
- cd ~/.openclaw/extensions/mcp-client/servers/github
14
- chmod +x install.sh && ./install.sh
13
+ # Using mcp-bridge CLI:
14
+ mcp-bridge install github
15
15
  ```
16
16
 
17
17
  ### Windows (PowerShell)
18
18
  ```powershell
19
- cd $env:USERPROFILE\.openclaw\extensions\mcp-client\servers\github
20
- .\install.ps1
19
+ # Using mcp-bridge CLI:
20
+ mcp-bridge install github
21
21
  ```
22
22
 
23
23
  ### Manual Setup
24
24
  1. Get your token: https://github.com/settings/tokens
25
25
  2. Add to .env: `GITHUB_MCP_TOKEN=your_token`
26
- 3. Add config to openclaw.json (see config.json)
27
- 4. Restart gateway
26
+ 3. Add config to ~/.mcp-bridge/config.json (see config.json)
27
+ 4. Restart mcp-bridge
28
28
 
29
29
  ## What you get
30
30
  - Repository browsing and search tools
@@ -10,21 +10,21 @@ Google Maps MCP tools for places, geocoding, and routing.
10
10
 
11
11
  ### Linux / macOS
12
12
  ```bash
13
- cd ~/.openclaw/extensions/mcp-client/servers/google-maps
14
- chmod +x install.sh && ./install.sh
13
+ # Using mcp-bridge CLI:
14
+ mcp-bridge install google-maps
15
15
  ```
16
16
 
17
17
  ### Windows (PowerShell)
18
18
  ```powershell
19
- cd $env:USERPROFILE\.openclaw\extensions\mcp-client\servers\google-maps
20
- .\install.ps1
19
+ # Using mcp-bridge CLI:
20
+ mcp-bridge install google-maps
21
21
  ```
22
22
 
23
23
  ### Manual Setup
24
24
  1. Get your token: https://console.cloud.google.com/apis/credentials
25
25
  2. Add to .env: `GOOGLE_MAPS_API_KEY=your_token`
26
- 3. Add config to openclaw.json (see config.json)
27
- 4. Restart gateway
26
+ 3. Add config to ~/.mcp-bridge/config.json (see config.json)
27
+ 4. Restart mcp-bridge
28
28
 
29
29
  ## What you get
30
30
  - Geocoding and reverse geocoding
@@ -11,21 +11,21 @@ Hetzner Cloud MCP server built from source.
11
11
 
12
12
  ### Linux / macOS
13
13
  ```bash
14
- cd ~/.openclaw/extensions/mcp-client/servers/hetzner
15
- chmod +x install.sh && ./install.sh
14
+ # Using mcp-bridge CLI:
15
+ mcp-bridge install hetzner
16
16
  ```
17
17
 
18
18
  ### Windows (PowerShell)
19
19
  ```powershell
20
- cd $env:USERPROFILE\.openclaw\extensions\mcp-client\servers\hetzner
21
- .\install.ps1
20
+ # Using mcp-bridge CLI:
21
+ mcp-bridge install hetzner
22
22
  ```
23
23
 
24
24
  ### Manual Setup
25
25
  1. Get your token: https://console.hetzner.cloud/
26
26
  2. Add to .env: `HETZNER_API_TOKEN=your_token`
27
- 3. Add config to openclaw.json (see config.json)
28
- 4. Restart gateway
27
+ 3. Add config to ~/.mcp-bridge/config.json (see config.json)
28
+ 4. Restart mcp-bridge
29
29
 
30
30
  ## What you get
31
31
  - Server lifecycle tools
@@ -10,21 +10,21 @@ Hostinger MCP tools for hosting operations.
10
10
 
11
11
  ### Linux / macOS
12
12
  ```bash
13
- cd ~/.openclaw/extensions/mcp-client/servers/hostinger
14
- chmod +x install.sh && ./install.sh
13
+ # Using mcp-bridge CLI:
14
+ mcp-bridge install hostinger
15
15
  ```
16
16
 
17
17
  ### Windows (PowerShell)
18
18
  ```powershell
19
- cd $env:USERPROFILE\.openclaw\extensions\mcp-client\servers\hostinger
20
- .\install.ps1
19
+ # Using mcp-bridge CLI:
20
+ mcp-bridge install hostinger
21
21
  ```
22
22
 
23
23
  ### Manual Setup
24
24
  1. Get your token: https://hpanel.hostinger.com/api
25
25
  2. Add to .env: `HOSTINGER_API_TOKEN=your_token`
26
- 3. Add config to openclaw.json (see config.json)
27
- 4. Restart gateway
26
+ 3. Add config to ~/.mcp-bridge/config.json (see config.json)
27
+ 4. Restart mcp-bridge
28
28
 
29
29
  ## What you get
30
30
  - Hosting and site management tools
@@ -10,21 +10,21 @@ Linear issue and project management MCP server.
10
10
 
11
11
  ### Linux / macOS
12
12
  ```bash
13
- cd ~/.openclaw/extensions/mcp-client/servers/linear
14
- chmod +x install.sh && ./install.sh
13
+ # Using mcp-bridge CLI:
14
+ mcp-bridge install linear
15
15
  ```
16
16
 
17
17
  ### Windows (PowerShell)
18
18
  ```powershell
19
- cd $env:USERPROFILE\.openclaw\extensions\mcp-client\servers\linear
20
- .\install.ps1
19
+ # Using mcp-bridge CLI:
20
+ mcp-bridge install linear
21
21
  ```
22
22
 
23
23
  ### Manual Setup
24
24
  1. Get your token: https://linear.app/settings/api
25
25
  2. Add to .env: `LINEAR_API_KEY=your_token`
26
- 3. Add config to openclaw.json (see config.json)
27
- 4. Restart gateway
26
+ 3. Add config to ~/.mcp-bridge/config.json (see config.json)
27
+ 4. Restart mcp-bridge
28
28
 
29
29
  ## What you get
30
30
  - Issue create/update/search tools
@@ -10,21 +10,21 @@ Miro board MCP tools for collaborative whiteboards.
10
10
 
11
11
  ### Linux / macOS
12
12
  ```bash
13
- cd ~/.openclaw/extensions/mcp-client/servers/miro
14
- chmod +x install.sh && ./install.sh
13
+ # Using mcp-bridge CLI:
14
+ mcp-bridge install miro
15
15
  ```
16
16
 
17
17
  ### Windows (PowerShell)
18
18
  ```powershell
19
- cd $env:USERPROFILE\.openclaw\extensions\mcp-client\servers\miro
20
- .\install.ps1
19
+ # Using mcp-bridge CLI:
20
+ mcp-bridge install miro
21
21
  ```
22
22
 
23
23
  ### Manual Setup
24
24
  1. Get your token: https://miro.com/app/settings/user-profile/apps
25
25
  2. Add to .env: `MIRO_API_TOKEN=your_token`
26
- 3. Add config to openclaw.json (see config.json)
27
- 4. Restart gateway
26
+ 3. Add config to ~/.mcp-bridge/config.json (see config.json)
27
+ 4. Restart mcp-bridge
28
28
 
29
29
  ## What you get
30
30
  - Board content read tools
@@ -12,21 +12,21 @@ Official Notion integration for reading and managing your Notion workspace — p
12
12
 
13
13
  ### Linux / macOS
14
14
  ```bash
15
- cd ~/.openclaw/extensions/mcp-client/servers/notion
16
- chmod +x install.sh && ./install.sh
15
+ # Using mcp-bridge CLI:
16
+ mcp-bridge install notion
17
17
  ```
18
18
 
19
19
  ### Windows (PowerShell)
20
20
  ```powershell
21
- cd $env:USERPROFILE\.openclaw\extensions\mcp-client\servers\notion
22
- .\install.ps1
21
+ # Using mcp-bridge CLI:
22
+ mcp-bridge install notion
23
23
  ```
24
24
 
25
25
  ### Manual Setup
26
26
  1. Get your token: https://www.notion.so/my-integrations
27
27
  2. Add to .env: `NOTION_API_KEY=ntn_xxxxx`
28
- 3. Add config to openclaw.json (see config.json)
29
- 4. Restart gateway
28
+ 3. Add config to ~/.mcp-bridge/config.json (see config.json)
29
+ 4. Restart mcp-bridge
30
30
 
31
31
  ## What you get
32
32
  - 22 tools: search, pages, databases, blocks, users, comments
@@ -10,21 +10,21 @@ Stripe MCP server for billing and payments operations.
10
10
 
11
11
  ### Linux / macOS
12
12
  ```bash
13
- cd ~/.openclaw/extensions/mcp-client/servers/stripe
14
- chmod +x install.sh && ./install.sh
13
+ # Using mcp-bridge CLI:
14
+ mcp-bridge install stripe
15
15
  ```
16
16
 
17
17
  ### Windows (PowerShell)
18
18
  ```powershell
19
- cd $env:USERPROFILE\.openclaw\extensions\mcp-client\servers\stripe
20
- .\install.ps1
19
+ # Using mcp-bridge CLI:
20
+ mcp-bridge install stripe
21
21
  ```
22
22
 
23
23
  ### Manual Setup
24
24
  1. Get your token: https://dashboard.stripe.com/apikeys
25
25
  2. Add to .env: `STRIPE_API_KEY=your_token`
26
- 3. Add config to openclaw.json (see config.json)
27
- 4. Restart gateway
26
+ 3. Add config to ~/.mcp-bridge/config.json (see config.json)
27
+ 4. Restart mcp-bridge
28
28
 
29
29
  ## What you get
30
30
  - Customer and subscription tools
@@ -10,21 +10,21 @@ Tavily MCP search and extraction tools.
10
10
 
11
11
  ### Linux / macOS
12
12
  ```bash
13
- cd ~/.openclaw/extensions/mcp-client/servers/tavily
14
- chmod +x install.sh && ./install.sh
13
+ # Using mcp-bridge CLI:
14
+ mcp-bridge install tavily
15
15
  ```
16
16
 
17
17
  ### Windows (PowerShell)
18
18
  ```powershell
19
- cd $env:USERPROFILE\.openclaw\extensions\mcp-client\servers\tavily
20
- .\install.ps1
19
+ # Using mcp-bridge CLI:
20
+ mcp-bridge install tavily
21
21
  ```
22
22
 
23
23
  ### Manual Setup
24
24
  1. Get your token: https://app.tavily.com/home
25
25
  2. Add to .env: `TAVILY_API_KEY=your_token`
26
- 3. Add config to openclaw.json (see config.json)
27
- 4. Restart gateway
26
+ 3. Add config to ~/.mcp-bridge/config.json (see config.json)
27
+ 4. Restart mcp-bridge
28
28
 
29
29
  ## What you get
30
30
  - Web search tools
@@ -10,21 +10,21 @@ Todoist MCP server for tasks, projects, and productivity workflows.
10
10
 
11
11
  ### Linux / macOS
12
12
  ```bash
13
- cd ~/.openclaw/extensions/mcp-client/servers/todoist
14
- chmod +x install.sh && ./install.sh
13
+ # Using mcp-bridge CLI:
14
+ mcp-bridge install todoist
15
15
  ```
16
16
 
17
17
  ### Windows (PowerShell)
18
18
  ```powershell
19
- cd $env:USERPROFILE\.openclaw\extensions\mcp-client\servers\todoist
20
- .\install.ps1
19
+ # Using mcp-bridge CLI:
20
+ mcp-bridge install todoist
21
21
  ```
22
22
 
23
23
  ### Manual Setup
24
24
  1. Get your token: https://app.todoist.com/app/settings/integrations/developer
25
25
  2. Add to .env: `TODOIST_API_TOKEN=your_token`
26
- 3. Add config to openclaw.json (see config.json)
27
- 4. Restart gateway
26
+ 3. Add config to ~/.mcp-bridge/config.json (see config.json)
27
+ 4. Restart mcp-bridge
28
28
 
29
29
  ## What you get
30
30
  - Task and project CRUD tools
@@ -11,21 +11,21 @@ Wise MCP server for multi-currency account and transfer workflows.
11
11
 
12
12
  ### Linux / macOS
13
13
  ```bash
14
- cd ~/.openclaw/extensions/mcp-client/servers/wise
15
- chmod +x install.sh && ./install.sh
14
+ # Using mcp-bridge CLI:
15
+ mcp-bridge install wise
16
16
  ```
17
17
 
18
18
  ### Windows (PowerShell)
19
19
  ```powershell
20
- cd $env:USERPROFILE\.openclaw\extensions\mcp-client\servers\wise
21
- .\install.ps1
20
+ # Using mcp-bridge CLI:
21
+ mcp-bridge install wise
22
22
  ```
23
23
 
24
24
  ### Manual Setup
25
25
  1. Get your token: https://wise.com/settings/api-tokens
26
26
  2. Add to .env: `WISE_API_TOKEN=your_token`
27
- 3. Add config to openclaw.json (see config.json)
28
- 4. Restart gateway
27
+ 3. Add config to ~/.mcp-bridge/config.json (see config.json)
28
+ 4. Restart mcp-bridge
29
29
 
30
30
  ## What you get
31
31
  - Profile and balance lookup tools
package/bin/mcp-bridge.js DELETED
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // Bootstrap: run the TypeScript entry point via tsx
4
- import { register } from "node:module";
5
- import { pathToFileURL } from "node:url";
6
-
7
- register("tsx/esm", pathToFileURL("./"));
8
-
9
- const { default: _ } = await import("./mcp-bridge.ts");
package/bin/mcp-bridge.ts DELETED
@@ -1,335 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { readFileSync, existsSync } from "fs";
4
- import { join, dirname, resolve } from "path";
5
- import { fileURLToPath } from "url";
6
- import { execSync } from "child_process";
7
- import { loadConfig, initConfigDir, getConfigDir } from "../src/config.js";
8
- import { StandaloneServer } from "../src/standalone-server.js";
9
- import { PACKAGE_VERSION } from "../src/protocol.js";
10
- import { checkForUpdate, runUpdate } from "../src/update-checker.js";
11
- import type { Logger } from "../src/types.js";
12
-
13
- const __filename = fileURLToPath(import.meta.url);
14
- const __dirname = dirname(__filename);
15
-
16
- // -- Logger ---------------------------------------------------------------
17
-
18
- type LogLevel = "error" | "warn" | "info" | "debug";
19
-
20
- function createLogger(level: LogLevel): Logger {
21
- const levels: Record<LogLevel, number> = { error: 0, warn: 1, info: 2, debug: 3 };
22
- const threshold = levels[level];
23
- const ts = () => new Date().toISOString().replace("T", " ").replace("Z", "");
24
-
25
- return {
26
- error: (...args: unknown[]) => {
27
- if (threshold >= 0) process.stderr.write(`[${ts()}] [ERROR] ${args.map(String).join(" ")}\n`);
28
- },
29
- warn: (...args: unknown[]) => {
30
- if (threshold >= 1) process.stderr.write(`[${ts()}] [WARN] ${args.map(String).join(" ")}\n`);
31
- },
32
- info: (...args: unknown[]) => {
33
- if (threshold >= 2) process.stderr.write(`[${ts()}] [INFO] ${args.map(String).join(" ")}\n`);
34
- },
35
- debug: (...args: unknown[]) => {
36
- if (threshold >= 3) process.stderr.write(`[${ts()}] [DEBUG] ${args.map(String).join(" ")}\n`);
37
- },
38
- };
39
- }
40
-
41
- // -- Arg parsing ----------------------------------------------------------
42
-
43
- interface CliArgs {
44
- command: "serve" | "init" | "install" | "catalog" | "servers" | "search" | "update" | "version" | "help";
45
- sse: boolean;
46
- http: boolean;
47
- port: number;
48
- configPath?: string;
49
- verbose: boolean;
50
- debug: boolean;
51
- positional: string[];
52
- checkOnly: boolean;
53
- offline: boolean;
54
- }
55
-
56
- function parseArgs(argv: string[]): CliArgs {
57
- const args: CliArgs = {
58
- command: "serve",
59
- sse: false,
60
- http: false,
61
- port: 3000,
62
- verbose: false,
63
- debug: false,
64
- positional: [],
65
- checkOnly: false,
66
- offline: false,
67
- };
68
-
69
- let i = 0;
70
- while (i < argv.length) {
71
- const arg = argv[i];
72
- switch (arg) {
73
- case "--sse": args.sse = true; break;
74
- case "--http": args.http = true; break;
75
- case "--port":
76
- i++;
77
- args.port = parseInt(argv[i], 10);
78
- if (isNaN(args.port)) { process.stderr.write("Error: --port requires a number\n"); process.exit(1); }
79
- break;
80
- case "--config":
81
- i++;
82
- args.configPath = resolve(argv[i]);
83
- break;
84
- case "--verbose": args.verbose = true; break;
85
- case "--debug": args.debug = true; break;
86
- case "--version": args.command = "version"; break;
87
- case "--help": case "-h": args.command = "help"; break;
88
- case "--check": args.checkOnly = true; break;
89
- case "--offline": args.offline = true; break;
90
- case "init": args.command = "init"; break;
91
- case "install": args.command = "install"; break;
92
- case "catalog": args.command = "catalog"; break;
93
- case "servers": args.command = "servers"; break;
94
- case "search": args.command = "search"; break;
95
- case "update": args.command = "update"; break;
96
- default:
97
- if (!arg.startsWith("-")) {
98
- args.positional.push(arg);
99
- }
100
- break;
101
- }
102
- i++;
103
- }
104
-
105
- return args;
106
- }
107
-
108
- // -- Commands -------------------------------------------------------------
109
-
110
- function printVersion(): void {
111
- process.stdout.write(`mcp-bridge ${PACKAGE_VERSION}\n`);
112
- }
113
-
114
- function printHelp(): void {
115
- process.stdout.write(`
116
- mcp-bridge v${PACKAGE_VERSION} — MCP server multiplexer
117
-
118
- Usage:
119
- mcp-bridge Start in stdio mode (default)
120
- mcp-bridge --sse --port 3000 Start as SSE server
121
- mcp-bridge --http --port 3000 Start as streamable-http server
122
- mcp-bridge init Create ~/.mcp-bridge/ with config template
123
- mcp-bridge install <server> Install a server from the catalog
124
- mcp-bridge catalog [--offline] List available servers
125
- mcp-bridge servers List configured servers
126
- mcp-bridge search <query> Search catalog by keyword
127
- mcp-bridge update [--check] Check for / install updates
128
-
129
- Options:
130
- --config PATH Custom config file (default: ~/.mcp-bridge/config.json)
131
- --verbose Info-level logs to stderr
132
- --debug Full protocol-level logs to stderr
133
- --version Print version
134
- --help Show this help
135
-
136
- All logs go to stderr. Stdout is reserved for the MCP protocol (stdio mode).
137
- `);
138
- }
139
-
140
- function cmdInit(logger: Logger): void {
141
- initConfigDir(logger);
142
- }
143
-
144
- function cmdCatalog(logger: Logger, offline: boolean): void {
145
- const catalogPath = join(__dirname, "..", "servers", "index.json");
146
- if (!existsSync(catalogPath)) {
147
- logger.error("Server catalog not found");
148
- process.exit(1);
149
- }
150
-
151
- const catalog = JSON.parse(readFileSync(catalogPath, "utf-8"));
152
- const servers = catalog.servers || {};
153
-
154
- process.stdout.write("\nAvailable servers:\n\n");
155
- process.stdout.write(" Server Transport Description\n");
156
- process.stdout.write(" " + "─".repeat(60) + "\n");
157
-
158
- for (const [name, info] of Object.entries(servers) as [string, any][]) {
159
- const padded = name.padEnd(16);
160
- const transport = (info.transport || "stdio").padEnd(13);
161
- process.stdout.write(` ${padded}${transport}${info.description || ""}\n`);
162
- }
163
- process.stdout.write("\n");
164
- }
165
-
166
- function cmdServers(logger: Logger, configPath?: string): void {
167
- try {
168
- const config = loadConfig({ configPath, logger });
169
- const servers = config.servers || {};
170
- const entries = Object.entries(servers);
171
-
172
- if (entries.length === 0) {
173
- process.stdout.write("No servers configured.\n");
174
- return;
175
- }
176
-
177
- process.stdout.write("\nConfigured servers:\n\n");
178
- process.stdout.write(" Server Transport Description\n");
179
- process.stdout.write(" " + "─".repeat(60) + "\n");
180
-
181
- for (const [name, serverConfig] of entries) {
182
- const padded = name.padEnd(16);
183
- const transport = serverConfig.transport.padEnd(13);
184
- process.stdout.write(` ${padded}${transport}${serverConfig.description || ""}\n`);
185
- }
186
- process.stdout.write("\n");
187
- } catch (err) {
188
- logger.error(err instanceof Error ? err.message : String(err));
189
- process.exit(1);
190
- }
191
- }
192
-
193
- function cmdSearch(query: string, logger: Logger): void {
194
- const catalogPath = join(__dirname, "..", "servers", "index.json");
195
- if (!existsSync(catalogPath)) {
196
- logger.error("Server catalog not found");
197
- process.exit(1);
198
- }
199
-
200
- const catalog = JSON.parse(readFileSync(catalogPath, "utf-8"));
201
- const servers = catalog.servers || {};
202
- const lowerQuery = query.toLowerCase();
203
-
204
- const matches = Object.entries(servers).filter(([name, info]: [string, any]) => {
205
- return name.toLowerCase().includes(lowerQuery) ||
206
- (info.description || "").toLowerCase().includes(lowerQuery);
207
- });
208
-
209
- if (matches.length === 0) {
210
- process.stdout.write(`No servers matching "${query}"\n`);
211
- return;
212
- }
213
-
214
- process.stdout.write(`\nSearch results for "${query}":\n\n`);
215
- for (const [i, [name, info]] of matches.entries() as any) {
216
- process.stdout.write(` ${i + 1} ${name.padEnd(16)}${(info as any).description || ""}\n`);
217
- }
218
- process.stdout.write("\n");
219
- }
220
-
221
- function cmdInstall(serverName: string, logger: Logger): void {
222
- const scriptPath = join(__dirname, "..", "scripts", "install-server.sh");
223
- if (!existsSync(scriptPath)) {
224
- logger.error("Install script not found");
225
- process.exit(1);
226
- }
227
-
228
- try {
229
- execSync(`bash "${scriptPath}" "${serverName}"`, { stdio: "inherit" });
230
- } catch (err) {
231
- process.exit(1);
232
- }
233
- }
234
-
235
- async function cmdUpdate(logger: Logger, checkOnly: boolean): Promise<void> {
236
- if (checkOnly) {
237
- const info = await checkForUpdate(logger);
238
- if (info.updateAvailable) {
239
- process.stdout.write(`Update available: ${info.currentVersion} → ${info.latestVersion}\n`);
240
- process.stdout.write(`Run 'mcp-bridge update' to install.\n`);
241
- } else {
242
- process.stdout.write(`mcp-bridge ${info.currentVersion} is up to date.\n`);
243
- }
244
- return;
245
- }
246
-
247
- const result = await runUpdate(logger);
248
- process.stdout.write(result + "\n");
249
- }
250
-
251
- async function cmdServe(args: CliArgs, logger: Logger): Promise<void> {
252
- let config;
253
- try {
254
- config = loadConfig({ configPath: args.configPath, logger });
255
- } catch (err) {
256
- logger.error(err instanceof Error ? err.message : String(err));
257
- process.exit(1);
258
- }
259
-
260
- // HTTP modes: require auth
261
- if ((args.sse || args.http) && !config.http?.auth?.token) {
262
- logger.error("HTTP auth not configured. Set http.auth in config or use stdio mode.");
263
- process.exit(1);
264
- }
265
-
266
- const server = new StandaloneServer(config, logger);
267
-
268
- // Graceful shutdown
269
- const shutdown = async () => {
270
- await server.shutdown();
271
- process.exit(0);
272
- };
273
- process.on("SIGTERM", shutdown);
274
- process.on("SIGINT", shutdown);
275
-
276
- if (args.sse || args.http) {
277
- // SSE/HTTP mode: not yet implemented in standalone, show message
278
- logger.error("SSE and HTTP server modes are not yet implemented. Use stdio mode (default).");
279
- process.exit(1);
280
- }
281
-
282
- // Default: stdio mode
283
- await server.startStdio();
284
- }
285
-
286
- // -- Main -----------------------------------------------------------------
287
-
288
- async function main(): Promise<void> {
289
- const args = parseArgs(process.argv.slice(2));
290
- const logLevel: LogLevel = args.debug ? "debug" : args.verbose ? "info" : "warn";
291
- const logger = createLogger(logLevel);
292
-
293
- switch (args.command) {
294
- case "version":
295
- printVersion();
296
- break;
297
- case "help":
298
- printHelp();
299
- break;
300
- case "init":
301
- cmdInit(logger);
302
- break;
303
- case "catalog":
304
- cmdCatalog(logger, args.offline);
305
- break;
306
- case "servers":
307
- cmdServers(logger, args.configPath);
308
- break;
309
- case "search":
310
- if (args.positional.length === 0) {
311
- process.stderr.write("Usage: mcp-bridge search <query>\n");
312
- process.exit(1);
313
- }
314
- cmdSearch(args.positional[0], logger);
315
- break;
316
- case "install":
317
- if (args.positional.length === 0) {
318
- process.stderr.write("Usage: mcp-bridge install <server>\n");
319
- process.exit(1);
320
- }
321
- cmdInstall(args.positional[0], logger);
322
- break;
323
- case "update":
324
- await cmdUpdate(logger, args.checkOnly);
325
- break;
326
- case "serve":
327
- await cmdServe(args, logger);
328
- break;
329
- }
330
- }
331
-
332
- main().catch(err => {
333
- process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}\n`);
334
- process.exit(1);
335
- });