@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.
- package/CHANGELOG.md +535 -380
- package/dist/server/src/cli/commands/install.d.ts +25 -0
- package/dist/server/src/cli/commands/install.d.ts.map +1 -0
- package/dist/server/src/cli/commands/install.js +274 -0
- package/dist/server/src/cli/commands/use-guide.d.ts +11 -0
- package/dist/server/src/cli/commands/use-guide.d.ts.map +1 -0
- package/dist/server/src/cli/commands/use-guide.js +175 -0
- package/dist/server/src/cli/index.d.ts.map +1 -1
- package/dist/server/src/cli/index.js +4 -0
- package/dist/server/src/cli/server.d.ts +71 -0
- package/dist/server/src/cli/server.d.ts.map +1 -1
- package/dist/server/src/cli/server.js +138 -0
- package/dist/server/src/cli/use-guide.md +156 -0
- package/dist/server/src/services/gateway/request-handlers/initialize-handler.d.ts.map +1 -1
- package/dist/server/src/services/gateway/request-handlers/initialize-handler.js +12 -5
- package/package.json +1 -5
|
@@ -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;
|
|
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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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.
|
|
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",
|