mcp-config-manager 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.
- package/README.md +235 -0
- package/docs/images/kanban-view.png +0 -0
- package/docs/images/list-view.png +0 -0
- package/docs/images/remote-mcp-modal.png +0 -0
- package/docs/images/server-view.png +0 -0
- package/package.json +52 -0
- package/public/index.html +325 -0
- package/public/js/api.js +108 -0
- package/public/js/clientView.js +211 -0
- package/public/js/kanbanView.js +224 -0
- package/public/js/main.js +126 -0
- package/public/js/modals.js +822 -0
- package/public/js/serverView.js +299 -0
- package/public/js/utils.js +185 -0
- package/public/style.css +640 -0
- package/src/cli.js +394 -0
- package/src/clients.js +113 -0
- package/src/config-manager.js +520 -0
- package/src/server.js +214 -0
package/src/server.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import cors from 'cors';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { MCPConfigManager } from './config-manager.js';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
const manager = new MCPConfigManager();
|
|
11
|
+
|
|
12
|
+
export function startServer(port = 3456) {
|
|
13
|
+
const app = express();
|
|
14
|
+
|
|
15
|
+
app.use(cors());
|
|
16
|
+
app.use(express.json());
|
|
17
|
+
app.use(express.static(path.join(__dirname, '..', 'public')));
|
|
18
|
+
|
|
19
|
+
// API Routes
|
|
20
|
+
app.get('/api/clients/detect', async (req, res) => {
|
|
21
|
+
try {
|
|
22
|
+
const clients = await manager.detectClients();
|
|
23
|
+
res.json(Object.keys(clients));
|
|
24
|
+
} catch (error) {
|
|
25
|
+
res.status(500).json({ error: error.message });
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
app.get('/api/clients', async (req, res) => {
|
|
30
|
+
try {
|
|
31
|
+
const clients = await manager.listClients();
|
|
32
|
+
res.json(clients);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
res.status(500).json({ error: error.message });
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
app.get('/api/servers', async (req, res) => {
|
|
39
|
+
try {
|
|
40
|
+
const servers = await manager.getServersInClients();
|
|
41
|
+
res.json(servers);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
res.status(500).json({ error: error.message });
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
app.get('/api/clients/:client', async (req, res) => {
|
|
48
|
+
try {
|
|
49
|
+
const config = await manager.readConfig(req.params.client);
|
|
50
|
+
res.json(config);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
res.status(500).json({ error: error.message });
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
app.post('/api/clients/:client/servers/:server', async (req, res) => {
|
|
57
|
+
try {
|
|
58
|
+
await manager.addServer(req.params.client, req.params.server, req.body);
|
|
59
|
+
res.json({ success: true });
|
|
60
|
+
} catch (error) {
|
|
61
|
+
res.status(500).json({ error: error.message });
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
app.post('/api/servers/add-to-clients', async (req, res) => {
|
|
66
|
+
try {
|
|
67
|
+
const { serverName, serverConfig, clientIds } = req.body;
|
|
68
|
+
if (!serverName || !serverConfig || !clientIds || !Array.isArray(clientIds)) {
|
|
69
|
+
return res.status(400).json({ error: 'Missing serverName, serverConfig, or clientIds' });
|
|
70
|
+
}
|
|
71
|
+
const results = await manager.addServerToMultipleClients(serverName, serverConfig, clientIds);
|
|
72
|
+
res.json({ success: true, results });
|
|
73
|
+
} catch (error) {
|
|
74
|
+
res.status(500).json({ error: error.message });
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
app.delete('/api/clients/:client/servers/:server', async (req, res) => {
|
|
79
|
+
try {
|
|
80
|
+
await manager.removeServer(req.params.client, req.params.server);
|
|
81
|
+
res.json({ success: true });
|
|
82
|
+
} catch (error) {
|
|
83
|
+
res.status(500).json({ error: error.message });
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
app.put('/api/clients/:client/servers/:server', async (req, res) => {
|
|
88
|
+
try {
|
|
89
|
+
const config = await manager.readConfig(req.params.client);
|
|
90
|
+
config.servers[req.params.server] = req.body;
|
|
91
|
+
await manager.writeConfig(req.params.client, config);
|
|
92
|
+
res.json({ success: true });
|
|
93
|
+
} catch (error) {
|
|
94
|
+
res.status(500).json({ error: error.message });
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
app.put('/api/servers/:serverName/update-in-clients', async (req, res) => {
|
|
99
|
+
try {
|
|
100
|
+
const { serverConfig, clientIds } = req.body;
|
|
101
|
+
const serverName = req.params.serverName;
|
|
102
|
+
|
|
103
|
+
if (!serverConfig || !clientIds || !Array.isArray(clientIds)) {
|
|
104
|
+
return res.status(400).json({ error: 'Missing serverConfig or clientIds' });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const results = await manager.updateServerInMultipleClients(serverName, serverConfig, clientIds);
|
|
108
|
+
res.json({ success: true, results });
|
|
109
|
+
} catch (error) {
|
|
110
|
+
res.status(500).json({ error: error.message });
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
app.put('/api/servers/:serverName/env', async (req, res) => {
|
|
115
|
+
try {
|
|
116
|
+
const { envKey, envValue, clientIds } = req.body;
|
|
117
|
+
const serverName = req.params.serverName;
|
|
118
|
+
|
|
119
|
+
if (!envKey) {
|
|
120
|
+
return res.status(400).json({ error: 'Missing envKey' });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let targetServers = null;
|
|
124
|
+
if (clientIds && Array.isArray(clientIds) && clientIds.length > 0) {
|
|
125
|
+
targetServers = clientIds.map(clientId => ({ client: clientId, server: serverName }));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const results = await manager.updateEnvironmentVariableAcrossConfigs(envKey, envValue, targetServers);
|
|
129
|
+
res.json({ success: true, results });
|
|
130
|
+
} catch (error) {
|
|
131
|
+
res.status(500).json({ error: error.message });
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
app.put('/api/servers/:oldName/rename', async (req, res) => {
|
|
136
|
+
try {
|
|
137
|
+
const { newName } = req.body;
|
|
138
|
+
const oldName = req.params.oldName;
|
|
139
|
+
|
|
140
|
+
if (!newName) {
|
|
141
|
+
return res.status(400).json({ error: 'Missing newName' });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const results = await manager.renameServerAcrossClients(oldName, newName);
|
|
145
|
+
res.json({ success: true, results });
|
|
146
|
+
} catch (error) {
|
|
147
|
+
res.status(500).json({ error: error.message });
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
app.post('/api/copy', async (req, res) => {
|
|
152
|
+
try {
|
|
153
|
+
const { fromClient, fromServer, toClient, toServer } = req.body;
|
|
154
|
+
await manager.copyServer(fromClient, fromServer, toClient, toServer);
|
|
155
|
+
res.json({ success: true });
|
|
156
|
+
} catch (error) {
|
|
157
|
+
res.status(500).json({ error: error.message });
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
app.get('/api/export/:client', async (req, res) => {
|
|
162
|
+
try {
|
|
163
|
+
const serverName = req.query.server;
|
|
164
|
+
let result;
|
|
165
|
+
|
|
166
|
+
if (serverName) {
|
|
167
|
+
result = await manager.exportServer(req.params.client, serverName);
|
|
168
|
+
} else {
|
|
169
|
+
result = await manager.exportConfig(req.params.client);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
res.json(result);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
res.status(500).json({ error: error.message });
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
app.post('/api/import/:client', async (req, res) => {
|
|
179
|
+
try {
|
|
180
|
+
const { servers, config, serverName } = req.body;
|
|
181
|
+
|
|
182
|
+
if (servers) {
|
|
183
|
+
await manager.writeConfig(req.params.client, { servers });
|
|
184
|
+
} else if (config && serverName) {
|
|
185
|
+
await manager.addServer(req.params.client, serverName, config);
|
|
186
|
+
} else {
|
|
187
|
+
throw new Error('Invalid import data');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
res.json({ success: true });
|
|
191
|
+
} catch (error) {
|
|
192
|
+
res.status(500).json({ error: error.message });
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
app.listen(port, () => {
|
|
197
|
+
console.log(`MCP Config Manager server running on http://localhost:${port}`);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
process.on('uncaughtException', (err) => {
|
|
201
|
+
console.error('Unhandled Exception:', err);
|
|
202
|
+
process.exit(1);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
206
|
+
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
212
|
+
const port = process.env.PORT || 3456;
|
|
213
|
+
startServer(port);
|
|
214
|
+
}
|