@loop_ouroboros/mcp-hub-lite 1.2.2 → 1.2.3

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.
@@ -244,3 +244,141 @@ export async function listServers() {
244
244
  instances: serverInstances[server.name] || []
245
245
  }));
246
246
  }
247
+ /**
248
+ * Installs a new MCP server via the web API.
249
+ *
250
+ * This function sends a POST request to the /web/servers endpoint to add a new
251
+ * server configuration. If the instance selection strategy is not 'random', it
252
+ * sends an additional PUT request to update the strategy.
253
+ *
254
+ * @param options - Server installation options
255
+ * @param host - Server host address
256
+ * @param port - Server port number
257
+ * @returns Promise that resolves when installation completes
258
+ * @throws Error if the server already exists or the API request fails
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * await installServer({
263
+ * name: 'github-mcp',
264
+ * command: 'npx github-mcp',
265
+ * transport: 'stdio',
266
+ * env: { API_KEY: 'xxx' },
267
+ * timeout: 60,
268
+ * autoStart: true,
269
+ * instanceSelectionStrategy: 'random'
270
+ * }, 'localhost', 7788);
271
+ * ```
272
+ */
273
+ export async function installServer(options, host, port) {
274
+ // Build request payload
275
+ const payload = {
276
+ name: options.name,
277
+ config: {
278
+ type: options.transport,
279
+ command: options.command,
280
+ url: options.url,
281
+ args: options.args || [],
282
+ env: options.env || {},
283
+ headers: options.headers || {},
284
+ timeout: options.timeout * 1000,
285
+ enabled: options.autoStart,
286
+ description: options.description,
287
+ instanceSelectionStrategy: options.instanceSelectionStrategy !== 'random'
288
+ ? options.instanceSelectionStrategy
289
+ : undefined
290
+ }
291
+ };
292
+ // Call POST /web/servers to install
293
+ const response = await fetch(`http://${host}:${port}/web/servers`, {
294
+ method: 'POST',
295
+ headers: { 'Content-Type': 'application/json' },
296
+ body: JSON.stringify(payload)
297
+ });
298
+ if (!response.ok) {
299
+ const errorData = (await response.json().catch(() => ({ message: response.statusText })));
300
+ const errorMessage = errorData.message || response.statusText;
301
+ if (errorMessage.includes('already exists')) {
302
+ throw new Error(`Server "${options.name}" already exists`);
303
+ }
304
+ throw new Error(`Failed to install server: ${errorMessage}`);
305
+ }
306
+ // If strategy is not random, update via PUT
307
+ if (options.instanceSelectionStrategy !== 'random') {
308
+ const putResponse = await fetch(`http://${host}:${port}/web/servers/${options.name}`, {
309
+ method: 'PUT',
310
+ headers: { 'Content-Type': 'application/json' },
311
+ body: JSON.stringify({ instanceSelectionStrategy: options.instanceSelectionStrategy })
312
+ });
313
+ if (!putResponse.ok) {
314
+ const errorData = (await putResponse
315
+ .json()
316
+ .catch(() => ({ message: putResponse.statusText })));
317
+ throw new Error(`Server installed but failed to set strategy: ${errorData.message || putResponse.statusText}`);
318
+ }
319
+ }
320
+ }
321
+ /**
322
+ * Parses environment variable flags into a key-value object.
323
+ *
324
+ * @param envFlags - Array of environment variables in KEY=VALUE format
325
+ * @returns Record of environment variable key-value pairs
326
+ * @throws Error if the format is invalid
327
+ *
328
+ * @example
329
+ * ```typescript
330
+ * parseEnvVars(['API_KEY=xxx', 'DEBUG=true'])
331
+ * // Returns: { API_KEY: 'xxx', DEBUG: 'true' }
332
+ * ```
333
+ */
334
+ export function parseEnvVars(envFlags) {
335
+ const env = {};
336
+ for (const item of envFlags) {
337
+ const equalIndex = item.indexOf('=');
338
+ if (equalIndex === -1) {
339
+ throw new Error(`Invalid env format: ${item}, expected KEY=VALUE`);
340
+ }
341
+ const key = item.substring(0, equalIndex);
342
+ const value = item.substring(equalIndex + 1);
343
+ if (!key) {
344
+ throw new Error(`Invalid env format: ${item}, KEY cannot be empty`);
345
+ }
346
+ if (value === undefined) {
347
+ throw new Error(`Invalid env format: ${item}, VALUE cannot be empty`);
348
+ }
349
+ env[key] = value;
350
+ }
351
+ return env;
352
+ }
353
+ /**
354
+ * Parses HTTP header flags into a key-value object.
355
+ *
356
+ * @param headerFlags - Array of headers in "Key: Value" format
357
+ * @returns Record of header key-value pairs
358
+ * @throws Error if the format is invalid
359
+ *
360
+ * @example
361
+ * ```typescript
362
+ * parseHeaders(['Authorization: Bearer xxx', 'Content-Type: application/json'])
363
+ * // Returns: { Authorization: 'Bearer xxx', 'Content-Type': 'application/json' }
364
+ * ```
365
+ */
366
+ export function parseHeaders(headerFlags) {
367
+ const headers = {};
368
+ for (const item of headerFlags) {
369
+ const colonIndex = item.indexOf(':');
370
+ if (colonIndex === -1) {
371
+ throw new Error(`Invalid header format: ${item}, expected "Key: Value"`);
372
+ }
373
+ const key = item.substring(0, colonIndex).trim();
374
+ const value = item.substring(colonIndex + 1).trim();
375
+ if (!key) {
376
+ throw new Error(`Invalid header format: ${item}, KEY cannot be empty`);
377
+ }
378
+ if (!value) {
379
+ throw new Error(`Invalid header format: ${item}, VALUE cannot be empty`);
380
+ }
381
+ headers[key] = value;
382
+ }
383
+ return headers;
384
+ }
@@ -0,0 +1,156 @@
1
+ # MCP Hub Lite CLI Use Guide
2
+
3
+ ## Overview
4
+
5
+ MCP Hub Lite CLI provides command-line interface for managing MCP servers. This guide covers CLI-specific usage only.
6
+
7
+ ## Commands
8
+
9
+ ### start
10
+
11
+ Start the MCP Hub Lite server.
12
+
13
+ ```bash
14
+ # Start in daemon mode (default)
15
+ mcp-hub-lite start
16
+
17
+ # Start in foreground mode
18
+ mcp-hub-lite start --foreground
19
+
20
+ # Start with custom port
21
+ mcp-hub-lite start --port 8080
22
+ ```
23
+
24
+ ### stop
25
+
26
+ Stop the running MCP Hub Lite server.
27
+
28
+ ```bash
29
+ mcp-hub-lite stop
30
+ ```
31
+
32
+ ### status
33
+
34
+ Display server status and connected MCP servers.
35
+
36
+ ```bash
37
+ mcp-hub-lite status
38
+ ```
39
+
40
+ ### ui
41
+
42
+ Open the web UI in default browser.
43
+
44
+ ```bash
45
+ mcp-hub-lite ui
46
+ ```
47
+
48
+ ### list
49
+
50
+ List all configured MCP servers.
51
+
52
+ ```bash
53
+ mcp-hub-lite list
54
+ ```
55
+
56
+ ### restart
57
+
58
+ Restart the MCP Hub Lite server.
59
+
60
+ ```bash
61
+ mcp-hub-lite restart
62
+ ```
63
+
64
+ ### install
65
+
66
+ Add a new MCP server to MCP Hub Lite.
67
+
68
+ **Parametric Mode:**
69
+
70
+ ```bash
71
+ # stdio server
72
+ mcp-hub-lite install github-mcp "npx github-mcp" --env API_KEY=xxx
73
+
74
+ # HTTP server
75
+ mcp-hub-lite install api-server https://api.example.com/mcp -t streamable-http -H "Authorization: Bearer xxx"
76
+ ```
77
+
78
+ **JSON Mode:**
79
+
80
+ ```bash
81
+ # stdio server
82
+ mcp-hub-lite install --json '{"name":"github-mcp","type":"stdio","command":"npx github-mcp","env":{"API_KEY":"xxx"}}'
83
+
84
+ # HTTP server
85
+ mcp-hub-lite install --json '{"name":"api-server","type":"streamable-http","url":"https://api.example.com/mcp","headers":{"Authorization":"Bearer xxx"}}'
86
+ ```
87
+
88
+ **Options:**
89
+
90
+ | Option | Description |
91
+ | -------------------------- | ------------------------------------------------------------ |
92
+ | `-t, --transport <type>` | Transport type: stdio, sse, streamable-http (default: stdio) |
93
+ | `-e, --env <env...>` | Environment variables (KEY=VALUE) |
94
+ | `-H, --header <header...>` | HTTP headers (Header-Key: Value) |
95
+ | `--timeout <seconds>` | Timeout in seconds (default: 60) |
96
+ | `--strategy <strategy>` | Instance selection: random, round-robin, tag-match-unique |
97
+ | `-a, --auto-start` | Auto-start server (default: true) |
98
+ | `--no-auto-start` | Disable auto-start |
99
+ | `-d, --description <desc>` | Server description |
100
+
101
+ **JSON Config Fields:**
102
+
103
+ | Field | Required | Description |
104
+ | --------------------------- | ----------- | ------------------------------- |
105
+ | `name` | Yes | Server name |
106
+ | `type` | No | Transport type (default: stdio) |
107
+ | `command` | Yes (stdio) | Command to execute |
108
+ | `url` | Yes (HTTP) | Server URL |
109
+ | `args` | No | Command arguments |
110
+ | `env` | No | Environment variables object |
111
+ | `headers` | No | HTTP headers object |
112
+ | `timeout` | No | Timeout in seconds |
113
+ | `enabled` | No | Auto-start enabled |
114
+ | `description` | No | Server description |
115
+ | `instanceSelectionStrategy` | No | Instance selection strategy |
116
+
117
+ ### tool-use
118
+
119
+ Manage MCP server tools via API.
120
+
121
+ ```bash
122
+ # List all connected servers
123
+ mcp-hub-lite tool-use list-servers
124
+
125
+ # List system tools
126
+ mcp-hub-lite tool-use list-tools
127
+
128
+ # List tools from specific server
129
+ mcp-hub-lite tool-use list-tools --server baidu-search
130
+
131
+ # Get tool schema
132
+ mcp-hub-lite tool-use get-tool --tool list_tools
133
+
134
+ # Call a tool
135
+ mcp-hub-lite tool-use call-tool --tool search --server baidu-search --args '{"query":"天气"}'
136
+ ```
137
+
138
+ **Options:**
139
+
140
+ | Option | Description |
141
+ | ----------------- | ------------------------------------------- |
142
+ | `--server <name>` | Server name (default: mcp-hub-lite) |
143
+ | `--tool <name>` | Tool name (required for get-tool/call-tool) |
144
+ | `--args <json>` | Tool arguments JSON |
145
+ | `--tags <json>` | Instance selection tags |
146
+
147
+ **JSON Merge Form:**
148
+
149
+ ```bash
150
+ # All parameters in one JSON
151
+ mcp-hub-lite tool-use call-tool --args '{"server":"baidu-search","tool":"search","query":"天气"}'
152
+ ```
153
+
154
+ ---
155
+
156
+ _Last updated: 2026-04-20_
@@ -1 +1 @@
1
- {"version":3,"file":"initialize-handler.d.ts","sourceRoot":"","sources":["../../../../../../src/services/gateway/request-handlers/initialize-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+DlE"}
1
+ {"version":3,"file":"initialize-handler.d.ts","sourceRoot":"","sources":["../../../../../../src/services/gateway/request-handlers/initialize-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAYpE;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAqElE"}
@@ -1,4 +1,5 @@
1
1
  import { logger, LOG_MODULES } from '../../../utils/logger/index.js';
2
+ import { getGatewayDebugSetting } from '../../../utils/json-utils.js';
2
3
  import { MCP_HUB_LITE_SERVER } from '../../../models/system-tools.constants.js';
3
4
  import { getAppVersion, getProtocolVersion } from '../../../utils/version.js';
4
5
  import { InitializedNotificationSchema, InitializeRequestSchema, PingRequestSchema } from './initialize.constants.js';
@@ -13,8 +14,10 @@ export function registerInitializeHandlers(server) {
13
14
  const { name, version } = request.params.clientInfo;
14
15
  const protocolVersion = request.params?.protocolVersion || getProtocolVersion();
15
16
  const clientCapabilities = request.params?.capabilities;
16
- logger.debug(`Initialized client: Name=${name}, Version=${version}, ProtocolVersion=${protocolVersion}`, LOG_MODULES.GATEWAY);
17
- if (clientCapabilities?.roots) {
17
+ if (getGatewayDebugSetting()) {
18
+ logger.debug(`Initialized client: Name=${name}, Version=${version}, ProtocolVersion=${protocolVersion}`, LOG_MODULES.GATEWAY);
19
+ }
20
+ if (getGatewayDebugSetting() && clientCapabilities?.roots) {
18
21
  logger.debug(`Client ${name} supports roots capability`, LOG_MODULES.GATEWAY);
19
22
  }
20
23
  }
@@ -41,11 +44,15 @@ export function registerInitializeHandlers(server) {
41
44
  return { pong: true };
42
45
  });
43
46
  server.server.setNotificationHandler(InitializedNotificationSchema, async (notification) => {
44
- logger.debug('Received initialized notification from client', LOG_MODULES.GATEWAY);
45
- logger.debug(`Initialized notification details: ${JSON.stringify(notification)}`, LOG_MODULES.GATEWAY);
47
+ if (getGatewayDebugSetting()) {
48
+ logger.debug('Received initialized notification from client', LOG_MODULES.GATEWAY);
49
+ logger.debug(`Initialized notification details: ${JSON.stringify(notification)}`, LOG_MODULES.GATEWAY);
50
+ }
46
51
  try {
47
52
  // Process the notification
48
- logger.debug('Successfully processed initialized notification', LOG_MODULES.GATEWAY);
53
+ if (getGatewayDebugSetting()) {
54
+ logger.debug('Successfully processed initialized notification', LOG_MODULES.GATEWAY);
55
+ }
49
56
  }
50
57
  catch (error) {
51
58
  const errorMessage = error instanceof Error ? error.message : String(error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loop_ouroboros/mcp-hub-lite",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "A lightweight MCP management platform designed for independent developers",
5
5
  "license": "MIT",
6
6
  "author": "loop_ouroboros",
@@ -38,10 +38,6 @@
38
38
  "start": "node dist/server/src/cli/index.js start",
39
39
  "stop": "node dist/server/src/cli/index.js stop",
40
40
  "restart": "node dist/server/src/cli/index.js restart",
41
- "status": "node dist/server/src/cli/index.js status",
42
- "list": "node dist/server/src/cli/index.js list",
43
- "ui": "node dist/server/src/cli/index.js ui",
44
- "tool-use": "node dist/server/src/cli/index.js tool-use",
45
41
  "dev": "run-p dev:client dev:server",
46
42
  "dev:client": "vite",
47
43
  "dev:server": "tsx src/server/dev-server.ts",