@maplezzk/mcps 1.0.14 → 1.0.18
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 +30 -15
- package/dist/commands/daemon.js +179 -101
- package/dist/commands/server.js +88 -32
- package/dist/core/constants.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,11 +25,7 @@ mcps 支持守护进程模式,可以保持与 MCP 服务的长连接,显著
|
|
|
25
25
|
|
|
26
26
|
**启动守护进程:**
|
|
27
27
|
```bash
|
|
28
|
-
mcps
|
|
29
|
-
```
|
|
30
|
-
或者
|
|
31
|
-
```bash
|
|
32
|
-
mcps daemon start
|
|
28
|
+
mcps start
|
|
33
29
|
```
|
|
34
30
|
|
|
35
31
|
**重启连接:**
|
|
@@ -37,49 +33,68 @@ mcps daemon start
|
|
|
37
33
|
|
|
38
34
|
```bash
|
|
39
35
|
# 重置所有连接
|
|
40
|
-
mcps
|
|
36
|
+
mcps restart
|
|
41
37
|
|
|
42
38
|
# 仅重置特定服务的连接
|
|
43
|
-
mcps
|
|
39
|
+
mcps restart my-server
|
|
44
40
|
```
|
|
45
41
|
|
|
46
42
|
**停止守护进程:**
|
|
47
43
|
```bash
|
|
48
|
-
mcps
|
|
44
|
+
mcps stop
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**查看守护进程状态:**
|
|
48
|
+
```bash
|
|
49
|
+
mcps status
|
|
49
50
|
```
|
|
50
51
|
|
|
52
|
+
> **注意**:旧的三词命令(如 `mcps daemon start`)仍然可用,保持向后兼容。
|
|
53
|
+
|
|
51
54
|
### 2. 服务管理 (Server Management)
|
|
52
55
|
|
|
53
56
|
**查看所有服务:**
|
|
54
57
|
```bash
|
|
55
|
-
mcps
|
|
58
|
+
mcps ls
|
|
56
59
|
```
|
|
57
60
|
|
|
58
61
|
**添加 Stdio 服务:**
|
|
59
62
|
```bash
|
|
60
63
|
# 添加本地 Node.js 服务
|
|
61
|
-
mcps
|
|
64
|
+
mcps add my-server --command node --args ./build/index.js
|
|
62
65
|
|
|
63
66
|
# 使用 npx/uvx 添加服务
|
|
64
|
-
mcps
|
|
67
|
+
mcps add fetch --command uvx --args mcp-server-fetch
|
|
65
68
|
```
|
|
66
69
|
|
|
67
70
|
**添加 SSE 服务:**
|
|
68
71
|
```bash
|
|
69
|
-
mcps
|
|
72
|
+
mcps add remote-server --type sse --url http://localhost:8000/sse
|
|
70
73
|
```
|
|
71
74
|
|
|
72
75
|
**添加 Streamable HTTP 服务:**
|
|
73
76
|
```bash
|
|
74
|
-
mcps
|
|
77
|
+
mcps add my-http-server --type http --url http://localhost:8000/mcp
|
|
75
78
|
```
|
|
76
79
|
|
|
77
80
|
**移除服务:**
|
|
78
81
|
```bash
|
|
79
|
-
mcps
|
|
82
|
+
mcps rm my-server
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**更新服务:**
|
|
86
|
+
```bash
|
|
87
|
+
# 刷新所有服务连接
|
|
88
|
+
mcps update
|
|
89
|
+
|
|
90
|
+
# 更新特定服务的命令
|
|
91
|
+
mcps update my-server --command new-command
|
|
92
|
+
|
|
93
|
+
# 更新特定服务的参数
|
|
94
|
+
mcps update my-server --args arg1 arg2
|
|
80
95
|
```
|
|
81
96
|
|
|
82
|
-
###
|
|
97
|
+
### 3. 工具交互 (Tool Interaction)
|
|
83
98
|
|
|
84
99
|
**查看服务下的可用工具:**
|
|
85
100
|
```bash
|
package/dist/commands/daemon.js
CHANGED
|
@@ -1,128 +1,196 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
import http from 'http';
|
|
3
|
+
import net from 'net';
|
|
3
4
|
import chalk from 'chalk';
|
|
4
5
|
import { connectionPool } from '../core/pool.js';
|
|
5
6
|
import { createRequire } from 'module';
|
|
6
7
|
import { DAEMON_PORT } from '../core/constants.js';
|
|
7
8
|
const require = createRequire(import.meta.url);
|
|
8
9
|
const pkg = require('../../package.json');
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
.
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
// Check if a port is in use
|
|
11
|
+
function isPortInUse(port) {
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
const server = net.createServer();
|
|
14
|
+
server.once('error', () => {
|
|
15
|
+
resolve(true); // Port is in use
|
|
16
|
+
});
|
|
17
|
+
server.once('listening', () => {
|
|
18
|
+
server.once('close', () => {
|
|
19
|
+
resolve(false); // Port is available
|
|
20
|
+
});
|
|
21
|
+
server.close();
|
|
22
|
+
});
|
|
23
|
+
server.listen(port, '127.0.0.1');
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
// Action functions for daemon commands
|
|
27
|
+
const startAction = async (options, parentCmd) => {
|
|
28
|
+
const port = parseInt(options.port || DAEMON_PORT);
|
|
29
|
+
// Check if port is in use (more reliable than HTTP check)
|
|
30
|
+
const portInUse = await isPortInUse(port);
|
|
31
|
+
if (portInUse) {
|
|
32
|
+
// Try to check if it's our daemon via HTTP
|
|
19
33
|
try {
|
|
20
34
|
const res = await fetch(`http://localhost:${port}/status`);
|
|
21
35
|
if (res.ok) {
|
|
22
36
|
console.log(chalk.yellow(`Daemon is already running on port ${port}.`));
|
|
37
|
+
process.exit(0);
|
|
23
38
|
return;
|
|
24
39
|
}
|
|
25
40
|
}
|
|
26
41
|
catch {
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
// Port is in use but not our daemon
|
|
43
|
+
console.error(chalk.red(`Port ${port} is already in use by another process.`));
|
|
44
|
+
process.exit(1);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// If we are already detached (indicated by env var), run the server
|
|
49
|
+
if (process.env.MCPS_DAEMON_DETACHED === 'true') {
|
|
50
|
+
startDaemon(port);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// Otherwise, spawn a detached process
|
|
54
|
+
console.log(chalk.gray('Starting daemon in background...'));
|
|
55
|
+
let childFailed = false;
|
|
56
|
+
const subprocess = spawn(process.execPath, [process.argv[1], 'daemon', 'start'], {
|
|
57
|
+
detached: true,
|
|
58
|
+
// Pipe stdout/stderr so we can see initialization logs
|
|
59
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
60
|
+
env: {
|
|
61
|
+
...process.env,
|
|
62
|
+
MCPS_DAEMON_DETACHED: 'true'
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
// Stream logs to current console while waiting for ready
|
|
66
|
+
if (subprocess.stdout) {
|
|
67
|
+
subprocess.stdout.on('data', (data) => {
|
|
68
|
+
process.stdout.write(chalk.gray(`[Daemon] ${data}`));
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (subprocess.stderr) {
|
|
72
|
+
subprocess.stderr.on('data', (data) => {
|
|
73
|
+
const msg = data.toString();
|
|
74
|
+
process.stderr.write(chalk.red(`[Daemon] ${msg}`));
|
|
75
|
+
// Detect port conflict in child process
|
|
76
|
+
if (msg.includes('Port') && msg.includes('is already in use')) {
|
|
77
|
+
childFailed = true;
|
|
49
78
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
subprocess.unref();
|
|
82
|
+
// Wait briefly to ensure it started (optional but good UX)
|
|
83
|
+
// We can poll status for a second
|
|
84
|
+
const start = Date.now();
|
|
85
|
+
// Increased timeout to allow for connection initialization
|
|
86
|
+
while (Date.now() - start < 10000) {
|
|
87
|
+
// If child reported port conflict, check if daemon is actually running
|
|
88
|
+
if (childFailed) {
|
|
89
|
+
const stillRunning = await isPortInUse(port);
|
|
90
|
+
if (stillRunning) {
|
|
91
|
+
// Another daemon is running
|
|
92
|
+
console.log(chalk.yellow(`\nDaemon is already running on port ${port}.`));
|
|
93
|
+
process.exit(0);
|
|
94
|
+
return;
|
|
54
95
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (res.ok) {
|
|
64
|
-
const data = await res.json();
|
|
65
|
-
if (data.initialized) {
|
|
66
|
-
console.log(chalk.green(`Daemon started successfully on port ${port}.`));
|
|
67
|
-
process.exit(0);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const res = await fetch(`http://localhost:${port}/status`);
|
|
99
|
+
if (res.ok) {
|
|
100
|
+
const data = await res.json();
|
|
101
|
+
if (data.initialized) {
|
|
102
|
+
console.log(chalk.green(`Daemon started successfully on port ${port}.`));
|
|
103
|
+
process.exit(0);
|
|
70
104
|
}
|
|
71
|
-
catch { }
|
|
72
|
-
await new Promise(r => setTimeout(r, 200));
|
|
73
105
|
}
|
|
74
|
-
console.log(chalk.yellow('Daemon started (async check timeout, but likely running).'));
|
|
75
106
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
107
|
+
catch { }
|
|
108
|
+
await new Promise(r => setTimeout(r, 200));
|
|
109
|
+
}
|
|
110
|
+
console.log(chalk.yellow('Daemon started (async check timeout, but likely running).'));
|
|
111
|
+
process.exit(0);
|
|
112
|
+
};
|
|
113
|
+
const stopAction = async (parentCmd) => {
|
|
114
|
+
try {
|
|
115
|
+
const port = parseInt(parentCmd.opts().port || DAEMON_PORT);
|
|
116
|
+
await fetch(`http://localhost:${port}/stop`, { method: 'POST' });
|
|
117
|
+
console.log(chalk.green('Daemon stopped successfully.'));
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
console.error(chalk.red('Failed to stop daemon. Is it running?'));
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const statusAction = async (parentCmd) => {
|
|
124
|
+
try {
|
|
125
|
+
const port = parseInt(parentCmd.opts().port || DAEMON_PORT);
|
|
126
|
+
const res = await fetch(`http://localhost:${port}/status`);
|
|
127
|
+
const data = await res.json();
|
|
128
|
+
console.log(chalk.green(`Daemon is running (v${data.version})`));
|
|
129
|
+
if (data.connections && data.connections.length > 0) {
|
|
130
|
+
console.log(chalk.bold('\nActive Connections:'));
|
|
131
|
+
data.connections.forEach((conn) => {
|
|
132
|
+
const count = conn.toolsCount !== null ? `(${conn.toolsCount} tools)` : (data.initializing ? '(initializing)' : '(error listing tools)');
|
|
133
|
+
const status = conn.status === 'error' ? chalk.red('[Error]') : '';
|
|
134
|
+
console.log(chalk.cyan(`- ${conn.name} ${chalk.gray(count)} ${status}`));
|
|
135
|
+
});
|
|
83
136
|
}
|
|
84
|
-
|
|
85
|
-
console.
|
|
137
|
+
else {
|
|
138
|
+
console.log(chalk.gray('No active connections.'));
|
|
86
139
|
}
|
|
87
|
-
}
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
console.error(chalk.red('Daemon is not running.'));
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const restartAction = async (serverName, parentCmd) => {
|
|
146
|
+
try {
|
|
147
|
+
const port = parseInt(parentCmd.opts().port || DAEMON_PORT);
|
|
148
|
+
const res = await fetch(`http://localhost:${port}/restart`, {
|
|
149
|
+
method: 'POST',
|
|
150
|
+
body: JSON.stringify({ server: serverName })
|
|
151
|
+
});
|
|
152
|
+
const data = await res.json();
|
|
153
|
+
console.log(chalk.green(data.message));
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
console.error(chalk.red('Failed to restart. Is the daemon running?'));
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
export const registerDaemonCommand = (program) => {
|
|
160
|
+
// ===== Top-level commands (new, simplified) =====
|
|
161
|
+
program.command('start')
|
|
162
|
+
.description('Start the daemon')
|
|
163
|
+
.option('-p, --port <number>', 'Daemon port', String(DAEMON_PORT))
|
|
164
|
+
.action((options) => startAction(options, program));
|
|
165
|
+
program.command('stop')
|
|
166
|
+
.description('Stop the daemon')
|
|
167
|
+
.option('-p, --port <number>', 'Daemon port', String(DAEMON_PORT))
|
|
168
|
+
.action(() => stopAction(program));
|
|
169
|
+
program.command('status')
|
|
170
|
+
.description('Check daemon status')
|
|
171
|
+
.option('-p, --port <number>', 'Daemon port', String(DAEMON_PORT))
|
|
172
|
+
.action(() => statusAction(program));
|
|
173
|
+
program.command('restart [server]')
|
|
174
|
+
.description('Restart the daemon or a specific server connection')
|
|
175
|
+
.option('-p, --port <number>', 'Daemon port', String(DAEMON_PORT))
|
|
176
|
+
.action((serverName) => restartAction(serverName, program));
|
|
177
|
+
// ===== Legacy daemon subcommands (for backward compatibility) =====
|
|
178
|
+
const daemonCmd = program.command('daemon')
|
|
179
|
+
.description('Manage the mcps daemon (legacy, use top-level commands)')
|
|
180
|
+
.usage('start|stop|restart|status')
|
|
181
|
+
.option('-p, --port <number>', 'Daemon port', String(DAEMON_PORT));
|
|
182
|
+
daemonCmd.command('start', { isDefault: true, hidden: true })
|
|
183
|
+
.description('Start the daemon (default)')
|
|
184
|
+
.action((options) => startAction(options, daemonCmd));
|
|
185
|
+
daemonCmd.command('stop')
|
|
186
|
+
.description('Stop the running daemon')
|
|
187
|
+
.action(() => stopAction(daemonCmd));
|
|
88
188
|
daemonCmd.command('status')
|
|
89
189
|
.description('Check daemon status')
|
|
90
|
-
.action(
|
|
91
|
-
try {
|
|
92
|
-
const res = await fetch(`http://localhost:${DAEMON_PORT}/status`);
|
|
93
|
-
const data = await res.json();
|
|
94
|
-
console.log(chalk.green(`Daemon is running (v${data.version})`));
|
|
95
|
-
if (data.connections && data.connections.length > 0) {
|
|
96
|
-
console.log(chalk.bold('\nActive Connections:'));
|
|
97
|
-
data.connections.forEach((conn) => {
|
|
98
|
-
const count = conn.toolsCount !== null ? `(${conn.toolsCount} tools)` : (data.initializing ? '(initializing)' : '(error listing tools)');
|
|
99
|
-
const status = conn.status === 'error' ? chalk.red('[Error]') : '';
|
|
100
|
-
console.log(chalk.cyan(`- ${conn.name} ${chalk.gray(count)} ${status}`));
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
console.log(chalk.gray('No active connections.'));
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
catch (e) {
|
|
108
|
-
console.error(chalk.red('Daemon is not running.'));
|
|
109
|
-
}
|
|
110
|
-
});
|
|
190
|
+
.action(() => statusAction(daemonCmd));
|
|
111
191
|
daemonCmd.command('restart [server]')
|
|
112
192
|
.description('Restart the daemon or a specific server connection')
|
|
113
|
-
.action(
|
|
114
|
-
try {
|
|
115
|
-
const res = await fetch(`http://localhost:${DAEMON_PORT}/restart`, {
|
|
116
|
-
method: 'POST',
|
|
117
|
-
body: JSON.stringify({ server: serverName })
|
|
118
|
-
});
|
|
119
|
-
const data = await res.json();
|
|
120
|
-
console.log(chalk.green(data.message));
|
|
121
|
-
}
|
|
122
|
-
catch (e) {
|
|
123
|
-
console.error(chalk.red('Failed to restart. Is the daemon running?'));
|
|
124
|
-
}
|
|
125
|
-
});
|
|
193
|
+
.action((serverName) => restartAction(serverName, daemonCmd));
|
|
126
194
|
};
|
|
127
195
|
const startDaemon = (port) => {
|
|
128
196
|
const server = http.createServer(async (req, res) => {
|
|
@@ -238,12 +306,18 @@ const startDaemon = (port) => {
|
|
|
238
306
|
});
|
|
239
307
|
server.listen(port, async () => {
|
|
240
308
|
// Initialize all connections eagerly
|
|
241
|
-
|
|
309
|
+
try {
|
|
310
|
+
await connectionPool.initializeAll();
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
console.error('[Daemon] Error during initialization:', error.message);
|
|
314
|
+
// Don't exit, continue running with partial connections
|
|
315
|
+
}
|
|
242
316
|
});
|
|
243
317
|
server.on('error', (e) => {
|
|
244
318
|
if (e.code === 'EADDRINUSE') {
|
|
245
|
-
console.
|
|
246
|
-
process.exit(
|
|
319
|
+
console.error(chalk.red(`Port ${port} is already in use by another daemon.`));
|
|
320
|
+
process.exit(1); // Exit with error if port is in use
|
|
247
321
|
}
|
|
248
322
|
else {
|
|
249
323
|
console.error('[Daemon] Server error:', e);
|
|
@@ -258,4 +332,8 @@ const startDaemon = (port) => {
|
|
|
258
332
|
};
|
|
259
333
|
process.on('SIGINT', shutdown);
|
|
260
334
|
process.on('SIGTERM', shutdown);
|
|
335
|
+
// Prevent unhandled rejections from crashing the daemon
|
|
336
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
337
|
+
console.error('[Daemon] Unhandled Rejection at:', promise, 'reason:', reason);
|
|
338
|
+
});
|
|
261
339
|
};
|
package/dist/commands/server.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { configManager } from '../core/config.js';
|
|
3
|
+
import { DaemonClient } from '../core/daemon-client.js';
|
|
3
4
|
export const registerServerCommands = (program) => {
|
|
4
5
|
const listServersAction = () => {
|
|
5
6
|
const servers = configManager.listServers();
|
|
@@ -21,25 +22,7 @@ export const registerServerCommands = (program) => {
|
|
|
21
22
|
console.log('');
|
|
22
23
|
});
|
|
23
24
|
};
|
|
24
|
-
|
|
25
|
-
program.command('list')
|
|
26
|
-
.alias('ls')
|
|
27
|
-
.description('List all configured servers')
|
|
28
|
-
.action(listServersAction);
|
|
29
|
-
const serverCmd = program.command('server')
|
|
30
|
-
.description('Manage MCP servers');
|
|
31
|
-
serverCmd.command('list')
|
|
32
|
-
.alias('ls')
|
|
33
|
-
.description('List all configured servers')
|
|
34
|
-
.action(listServersAction);
|
|
35
|
-
serverCmd.command('add <name>')
|
|
36
|
-
.description('Add a new MCP server')
|
|
37
|
-
.option('--type <type>', 'Server type (stdio, sse, or http)', 'stdio')
|
|
38
|
-
.option('--command <command>', 'Command to execute (for stdio)')
|
|
39
|
-
.option('--args [args...]', 'Arguments for the command', [])
|
|
40
|
-
.option('--url <url>', 'URL for SSE/HTTP connection')
|
|
41
|
-
.option('--env <env...>', 'Environment variables (KEY=VALUE)', [])
|
|
42
|
-
.action((name, options) => {
|
|
25
|
+
const addServerAction = (name, options) => {
|
|
43
26
|
try {
|
|
44
27
|
if (options.type === 'sse' || options.type === 'http') {
|
|
45
28
|
if (!options.url)
|
|
@@ -76,11 +59,8 @@ export const registerServerCommands = (program) => {
|
|
|
76
59
|
catch (error) {
|
|
77
60
|
console.error(chalk.red(`Error adding server: ${error.message}`));
|
|
78
61
|
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.alias('rm')
|
|
82
|
-
.description('Remove a server')
|
|
83
|
-
.action((name) => {
|
|
62
|
+
};
|
|
63
|
+
const removeServerAction = (name) => {
|
|
84
64
|
try {
|
|
85
65
|
configManager.removeServer(name);
|
|
86
66
|
console.log(chalk.green(`Server "${name}" removed.`));
|
|
@@ -88,13 +68,35 @@ export const registerServerCommands = (program) => {
|
|
|
88
68
|
catch (error) {
|
|
89
69
|
console.error(chalk.red(error.message));
|
|
90
70
|
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
71
|
+
};
|
|
72
|
+
const updateServerAction = async (name, options) => {
|
|
73
|
+
// If no server name provided, refresh all connections
|
|
74
|
+
if (!name) {
|
|
75
|
+
try {
|
|
76
|
+
await DaemonClient.ensureDaemon();
|
|
77
|
+
// Call daemon restart API to refresh all connections
|
|
78
|
+
const port = parseInt(process.env.MCPS_PORT || '4100');
|
|
79
|
+
const res = await fetch(`http://localhost:${port}/restart`, {
|
|
80
|
+
method: 'POST',
|
|
81
|
+
headers: { 'Content-Type': 'application/json' },
|
|
82
|
+
body: JSON.stringify({})
|
|
83
|
+
});
|
|
84
|
+
if (res.ok) {
|
|
85
|
+
const data = await res.json();
|
|
86
|
+
console.log(chalk.green(data.message));
|
|
87
|
+
console.log(chalk.gray('All servers will be reconnected on next use.'));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
throw new Error('Failed to refresh connections');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error(chalk.red(`Failed to refresh all servers: ${error.message}`));
|
|
95
|
+
console.error(chalk.yellow('Make sure the daemon is running (use: mcps start)'));
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Update specific server configuration
|
|
98
100
|
try {
|
|
99
101
|
const updates = {};
|
|
100
102
|
if (options.command)
|
|
@@ -105,13 +107,67 @@ export const registerServerCommands = (program) => {
|
|
|
105
107
|
updates.url = options.url;
|
|
106
108
|
if (Object.keys(updates).length === 0) {
|
|
107
109
|
console.log(chalk.yellow('No updates provided.'));
|
|
110
|
+
console.log(chalk.gray('Use: mcps update <server> --command <cmd> --args <args>'));
|
|
108
111
|
return;
|
|
109
112
|
}
|
|
110
113
|
configManager.updateServer(name, updates);
|
|
111
114
|
console.log(chalk.green(`Server "${name}" updated.`));
|
|
115
|
+
console.log(chalk.gray('Note: Restart the daemon to apply changes: mcps restart'));
|
|
112
116
|
}
|
|
113
117
|
catch (error) {
|
|
114
118
|
console.error(chalk.red(`Error updating server: ${error.message}`));
|
|
115
119
|
}
|
|
116
|
-
}
|
|
120
|
+
};
|
|
121
|
+
// ===== Top-level commands (new, simplified) =====
|
|
122
|
+
// List command (already exists, keeping as-is)
|
|
123
|
+
program.command('list')
|
|
124
|
+
.alias('ls')
|
|
125
|
+
.description('List all configured servers')
|
|
126
|
+
.action(listServersAction);
|
|
127
|
+
// Add server command
|
|
128
|
+
program.command('add <name>')
|
|
129
|
+
.description('Add a new MCP server')
|
|
130
|
+
.option('--type <type>', 'Server type (stdio, sse, or http)', 'stdio')
|
|
131
|
+
.option('--command <command>', 'Command to execute (for stdio)')
|
|
132
|
+
.option('--args [args...]', 'Arguments for the command', [])
|
|
133
|
+
.option('--url <url>', 'URL for SSE/HTTP connection')
|
|
134
|
+
.option('--env <env...>', 'Environment variables (KEY=VALUE)', [])
|
|
135
|
+
.action(addServerAction);
|
|
136
|
+
// Remove server command
|
|
137
|
+
program.command('remove <name>')
|
|
138
|
+
.alias('rm')
|
|
139
|
+
.description('Remove a server')
|
|
140
|
+
.action(removeServerAction);
|
|
141
|
+
// Update server command
|
|
142
|
+
program.command('update [name]')
|
|
143
|
+
.description('Update a server configuration or refresh all servers')
|
|
144
|
+
.option('--command <command>', 'New command')
|
|
145
|
+
.option('--args [args...]', 'New arguments for the command')
|
|
146
|
+
.option('--url <url>', 'New URL')
|
|
147
|
+
.action(updateServerAction);
|
|
148
|
+
// ===== Legacy server subcommands (for backward compatibility) =====
|
|
149
|
+
const serverCmd = program.command('server')
|
|
150
|
+
.description('Manage MCP servers (legacy, use top-level commands)');
|
|
151
|
+
serverCmd.command('list')
|
|
152
|
+
.alias('ls')
|
|
153
|
+
.description('List all configured servers')
|
|
154
|
+
.action(listServersAction);
|
|
155
|
+
serverCmd.command('add <name>')
|
|
156
|
+
.description('Add a new MCP server')
|
|
157
|
+
.option('--type <type>', 'Server type (stdio, sse, or http)', 'stdio')
|
|
158
|
+
.option('--command <command>', 'Command to execute (for stdio)')
|
|
159
|
+
.option('--args [args...]', 'Arguments for the command', [])
|
|
160
|
+
.option('--url <url>', 'URL for SSE/HTTP connection')
|
|
161
|
+
.option('--env <env...>', 'Environment variables (KEY=VALUE)', [])
|
|
162
|
+
.action(addServerAction);
|
|
163
|
+
serverCmd.command('remove <name>')
|
|
164
|
+
.alias('rm')
|
|
165
|
+
.description('Remove a server')
|
|
166
|
+
.action(removeServerAction);
|
|
167
|
+
serverCmd.command('update [name]')
|
|
168
|
+
.description('Update a server configuration or refresh all servers')
|
|
169
|
+
.option('--command <command>', 'New command')
|
|
170
|
+
.option('--args [args...]', 'New arguments for the command')
|
|
171
|
+
.option('--url <url>', 'New URL')
|
|
172
|
+
.action(updateServerAction);
|
|
117
173
|
};
|
package/dist/core/constants.js
CHANGED