@samanhappy/mcphub 0.0.6 → 0.0.8
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/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +7 -1
- package/.env.example +0 -2
- package/.eslintrc.json +0 -25
- package/.github/workflows/build.yml +0 -51
- package/.github/workflows/release.yml +0 -19
- package/.prettierrc +0 -7
- package/Dockerfile +0 -51
- package/assets/amap-edit.png +0 -0
- package/assets/amap-result.png +0 -0
- package/assets/cherry-mcp.png +0 -0
- package/assets/cursor-mcp.png +0 -0
- package/assets/cursor-query.png +0 -0
- package/assets/cursor-tools.png +0 -0
- package/assets/dashboard.png +0 -0
- package/assets/dashboard.zh.png +0 -0
- package/assets/group.png +0 -0
- package/assets/group.zh.png +0 -0
- package/assets/market.zh.png +0 -0
- package/assets/wegroup.jpg +0 -0
- package/assets/wegroup.png +0 -0
- package/assets/wexin.png +0 -0
- package/doc/intro.md +0 -73
- package/doc/intro2.md +0 -232
- package/entrypoint.sh +0 -10
- package/frontend/favicon.ico +0 -0
- package/frontend/index.html +0 -13
- package/frontend/postcss.config.js +0 -6
- package/frontend/src/App.tsx +0 -44
- package/frontend/src/components/AddGroupForm.tsx +0 -132
- package/frontend/src/components/AddServerForm.tsx +0 -90
- package/frontend/src/components/ChangePasswordForm.tsx +0 -158
- package/frontend/src/components/EditGroupForm.tsx +0 -149
- package/frontend/src/components/EditServerForm.tsx +0 -76
- package/frontend/src/components/GroupCard.tsx +0 -143
- package/frontend/src/components/MarketServerCard.tsx +0 -153
- package/frontend/src/components/MarketServerDetail.tsx +0 -297
- package/frontend/src/components/ProtectedRoute.tsx +0 -27
- package/frontend/src/components/ServerCard.tsx +0 -230
- package/frontend/src/components/ServerForm.tsx +0 -276
- package/frontend/src/components/icons/LucideIcons.tsx +0 -14
- package/frontend/src/components/layout/Content.tsx +0 -17
- package/frontend/src/components/layout/Header.tsx +0 -61
- package/frontend/src/components/layout/Sidebar.tsx +0 -98
- package/frontend/src/components/ui/Badge.tsx +0 -33
- package/frontend/src/components/ui/Button.tsx +0 -0
- package/frontend/src/components/ui/DeleteDialog.tsx +0 -48
- package/frontend/src/components/ui/Pagination.tsx +0 -128
- package/frontend/src/components/ui/Toast.tsx +0 -96
- package/frontend/src/components/ui/ToggleGroup.tsx +0 -134
- package/frontend/src/components/ui/ToolCard.tsx +0 -38
- package/frontend/src/contexts/AuthContext.tsx +0 -159
- package/frontend/src/contexts/ToastContext.tsx +0 -60
- package/frontend/src/hooks/useGroupData.ts +0 -232
- package/frontend/src/hooks/useMarketData.ts +0 -410
- package/frontend/src/hooks/useServerData.ts +0 -306
- package/frontend/src/hooks/useSettingsData.ts +0 -131
- package/frontend/src/i18n.ts +0 -42
- package/frontend/src/index.css +0 -20
- package/frontend/src/layouts/MainLayout.tsx +0 -33
- package/frontend/src/locales/en.json +0 -214
- package/frontend/src/locales/zh.json +0 -214
- package/frontend/src/main.tsx +0 -12
- package/frontend/src/pages/Dashboard.tsx +0 -206
- package/frontend/src/pages/GroupsPage.tsx +0 -116
- package/frontend/src/pages/LoginPage.tsx +0 -104
- package/frontend/src/pages/MarketPage.tsx +0 -356
- package/frontend/src/pages/ServersPage.tsx +0 -144
- package/frontend/src/pages/SettingsPage.tsx +0 -149
- package/frontend/src/services/authService.ts +0 -141
- package/frontend/src/types/index.ts +0 -160
- package/frontend/src/utils/cn.ts +0 -10
- package/frontend/tsconfig.json +0 -31
- package/frontend/tsconfig.node.json +0 -10
- package/frontend/vite.config.ts +0 -26
- package/googled76ca578b6543fbc.html +0 -1
- package/jest.config.js +0 -10
- package/mcp_settings.json +0 -45
- package/servers.json +0 -74722
- package/src/config/index.ts +0 -46
- package/src/controllers/authController.ts +0 -179
- package/src/controllers/groupController.ts +0 -341
- package/src/controllers/marketController.ts +0 -154
- package/src/controllers/serverController.ts +0 -303
- package/src/index.ts +0 -17
- package/src/middlewares/auth.ts +0 -28
- package/src/middlewares/index.ts +0 -43
- package/src/models/User.ts +0 -103
- package/src/routes/index.ts +0 -96
- package/src/server.ts +0 -72
- package/src/services/groupService.ts +0 -232
- package/src/services/marketService.ts +0 -116
- package/src/services/mcpService.ts +0 -385
- package/src/services/sseService.ts +0 -119
- package/src/types/index.ts +0 -129
- package/src/utils/migration.ts +0 -52
- package/tsconfig.json +0 -17
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
import { Request, Response } from 'express';
|
|
2
|
-
import { ApiResponse, AddServerRequest } from '../types/index.js';
|
|
3
|
-
import {
|
|
4
|
-
getServersInfo,
|
|
5
|
-
addServer,
|
|
6
|
-
removeServer,
|
|
7
|
-
updateMcpServer,
|
|
8
|
-
notifyToolChanged,
|
|
9
|
-
toggleServerStatus,
|
|
10
|
-
} from '../services/mcpService.js';
|
|
11
|
-
import { loadSettings, saveSettings } from '../config/index.js';
|
|
12
|
-
|
|
13
|
-
export const getAllServers = (_: Request, res: Response): void => {
|
|
14
|
-
try {
|
|
15
|
-
const serversInfo = getServersInfo();
|
|
16
|
-
const response: ApiResponse = {
|
|
17
|
-
success: true,
|
|
18
|
-
data: serversInfo,
|
|
19
|
-
};
|
|
20
|
-
res.json(response);
|
|
21
|
-
} catch (error) {
|
|
22
|
-
res.status(500).json({
|
|
23
|
-
success: false,
|
|
24
|
-
message: 'Failed to get servers information',
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const getAllSettings = (_: Request, res: Response): void => {
|
|
30
|
-
try {
|
|
31
|
-
const settings = loadSettings();
|
|
32
|
-
const response: ApiResponse = {
|
|
33
|
-
success: true,
|
|
34
|
-
data: settings,
|
|
35
|
-
};
|
|
36
|
-
res.json(response);
|
|
37
|
-
} catch (error) {
|
|
38
|
-
res.status(500).json({
|
|
39
|
-
success: false,
|
|
40
|
-
message: 'Failed to get server settings',
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export const createServer = async (req: Request, res: Response): Promise<void> => {
|
|
46
|
-
try {
|
|
47
|
-
const { name, config } = req.body as AddServerRequest;
|
|
48
|
-
if (!name || typeof name !== 'string') {
|
|
49
|
-
res.status(400).json({
|
|
50
|
-
success: false,
|
|
51
|
-
message: 'Server name is required',
|
|
52
|
-
});
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (!config || typeof config !== 'object') {
|
|
57
|
-
res.status(400).json({
|
|
58
|
-
success: false,
|
|
59
|
-
message: 'Server configuration is required',
|
|
60
|
-
});
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (!config.url && (!config.command || !config.args)) {
|
|
65
|
-
res.status(400).json({
|
|
66
|
-
success: false,
|
|
67
|
-
message: 'Server configuration must include either a URL or command with arguments',
|
|
68
|
-
});
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const result = await addServer(name, config);
|
|
73
|
-
if (result.success) {
|
|
74
|
-
notifyToolChanged();
|
|
75
|
-
res.json({
|
|
76
|
-
success: true,
|
|
77
|
-
message: 'Server added successfully',
|
|
78
|
-
});
|
|
79
|
-
} else {
|
|
80
|
-
res.status(400).json({
|
|
81
|
-
success: false,
|
|
82
|
-
message: result.message || 'Failed to add server',
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
} catch (error) {
|
|
86
|
-
res.status(500).json({
|
|
87
|
-
success: false,
|
|
88
|
-
message: 'Internal server error',
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
export const deleteServer = async (req: Request, res: Response): Promise<void> => {
|
|
94
|
-
try {
|
|
95
|
-
const { name } = req.params;
|
|
96
|
-
if (!name) {
|
|
97
|
-
res.status(400).json({
|
|
98
|
-
success: false,
|
|
99
|
-
message: 'Server name is required',
|
|
100
|
-
});
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const result = removeServer(name);
|
|
105
|
-
if (result.success) {
|
|
106
|
-
notifyToolChanged();
|
|
107
|
-
res.json({
|
|
108
|
-
success: true,
|
|
109
|
-
message: 'Server removed successfully',
|
|
110
|
-
});
|
|
111
|
-
} else {
|
|
112
|
-
res.status(404).json({
|
|
113
|
-
success: false,
|
|
114
|
-
message: result.message || 'Server not found or failed to remove',
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
} catch (error) {
|
|
118
|
-
res.status(500).json({
|
|
119
|
-
success: false,
|
|
120
|
-
message: 'Internal server error',
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
export const updateServer = async (req: Request, res: Response): Promise<void> => {
|
|
126
|
-
try {
|
|
127
|
-
const { name } = req.params;
|
|
128
|
-
const { config } = req.body;
|
|
129
|
-
if (!name) {
|
|
130
|
-
res.status(400).json({
|
|
131
|
-
success: false,
|
|
132
|
-
message: 'Server name is required',
|
|
133
|
-
});
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (!config || typeof config !== 'object') {
|
|
138
|
-
res.status(400).json({
|
|
139
|
-
success: false,
|
|
140
|
-
message: 'Server configuration is required',
|
|
141
|
-
});
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (!config.url && (!config.command || !config.args)) {
|
|
146
|
-
res.status(400).json({
|
|
147
|
-
success: false,
|
|
148
|
-
message: 'Server configuration must include either a URL or command with arguments',
|
|
149
|
-
});
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const result = await updateMcpServer(name, config);
|
|
154
|
-
if (result.success) {
|
|
155
|
-
notifyToolChanged();
|
|
156
|
-
res.json({
|
|
157
|
-
success: true,
|
|
158
|
-
message: 'Server updated successfully',
|
|
159
|
-
});
|
|
160
|
-
} else {
|
|
161
|
-
res.status(404).json({
|
|
162
|
-
success: false,
|
|
163
|
-
message: result.message || 'Server not found or failed to update',
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
} catch (error) {
|
|
167
|
-
res.status(500).json({
|
|
168
|
-
success: false,
|
|
169
|
-
message: 'Internal server error',
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
export const getServerConfig = (req: Request, res: Response): void => {
|
|
175
|
-
try {
|
|
176
|
-
const { name } = req.params;
|
|
177
|
-
const settings = loadSettings();
|
|
178
|
-
if (!settings.mcpServers || !settings.mcpServers[name]) {
|
|
179
|
-
res.status(404).json({
|
|
180
|
-
success: false,
|
|
181
|
-
message: 'Server not found',
|
|
182
|
-
});
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const serverInfo = getServersInfo().find((s) => s.name === name);
|
|
187
|
-
const serverConfig = settings.mcpServers[name];
|
|
188
|
-
const response: ApiResponse = {
|
|
189
|
-
success: true,
|
|
190
|
-
data: {
|
|
191
|
-
name,
|
|
192
|
-
status: serverInfo ? serverInfo.status : 'disconnected',
|
|
193
|
-
tools: serverInfo ? serverInfo.tools : [],
|
|
194
|
-
config: serverConfig,
|
|
195
|
-
},
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
res.json(response);
|
|
199
|
-
} catch (error) {
|
|
200
|
-
res.status(500).json({
|
|
201
|
-
success: false,
|
|
202
|
-
message: 'Failed to get server configuration',
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
export const toggleServer = async (req: Request, res: Response): Promise<void> => {
|
|
208
|
-
try {
|
|
209
|
-
const { name } = req.params;
|
|
210
|
-
const { enabled } = req.body;
|
|
211
|
-
if (!name) {
|
|
212
|
-
res.status(400).json({
|
|
213
|
-
success: false,
|
|
214
|
-
message: 'Server name is required',
|
|
215
|
-
});
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (typeof enabled !== 'boolean') {
|
|
220
|
-
res.status(400).json({
|
|
221
|
-
success: false,
|
|
222
|
-
message: 'Enabled status must be a boolean',
|
|
223
|
-
});
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const result = await toggleServerStatus(name, enabled);
|
|
228
|
-
if (result.success) {
|
|
229
|
-
notifyToolChanged();
|
|
230
|
-
res.json({
|
|
231
|
-
success: true,
|
|
232
|
-
message: result.message || `Server ${enabled ? 'enabled' : 'disabled'} successfully`,
|
|
233
|
-
});
|
|
234
|
-
} else {
|
|
235
|
-
res.status(404).json({
|
|
236
|
-
success: false,
|
|
237
|
-
message: result.message || 'Server not found or failed to toggle status',
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
} catch (error) {
|
|
241
|
-
res.status(500).json({
|
|
242
|
-
success: false,
|
|
243
|
-
message: 'Internal server error',
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
export const updateSystemConfig = (req: Request, res: Response): void => {
|
|
249
|
-
try {
|
|
250
|
-
const { routing } = req.body;
|
|
251
|
-
|
|
252
|
-
if (!routing || (typeof routing.enableGlobalRoute !== 'boolean' && typeof routing.enableGroupNameRoute !== 'boolean')) {
|
|
253
|
-
res.status(400).json({
|
|
254
|
-
success: false,
|
|
255
|
-
message: 'Invalid system configuration provided',
|
|
256
|
-
});
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const settings = loadSettings();
|
|
261
|
-
if (!settings.systemConfig) {
|
|
262
|
-
settings.systemConfig = {
|
|
263
|
-
routing: {
|
|
264
|
-
enableGlobalRoute: true,
|
|
265
|
-
enableGroupNameRoute: true
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (!settings.systemConfig.routing) {
|
|
271
|
-
settings.systemConfig.routing = {
|
|
272
|
-
enableGlobalRoute: true,
|
|
273
|
-
enableGroupNameRoute: true
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (typeof routing.enableGlobalRoute === 'boolean') {
|
|
278
|
-
settings.systemConfig.routing.enableGlobalRoute = routing.enableGlobalRoute;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (typeof routing.enableGroupNameRoute === 'boolean') {
|
|
282
|
-
settings.systemConfig.routing.enableGroupNameRoute = routing.enableGroupNameRoute;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (saveSettings(settings)) {
|
|
286
|
-
res.json({
|
|
287
|
-
success: true,
|
|
288
|
-
data: settings.systemConfig,
|
|
289
|
-
message: 'System configuration updated successfully',
|
|
290
|
-
});
|
|
291
|
-
} else {
|
|
292
|
-
res.status(500).json({
|
|
293
|
-
success: false,
|
|
294
|
-
message: 'Failed to save system configuration',
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
} catch (error) {
|
|
298
|
-
res.status(500).json({
|
|
299
|
-
success: false,
|
|
300
|
-
message: 'Internal server error',
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
};
|
package/src/index.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import AppServer from './server.js';
|
|
2
|
-
|
|
3
|
-
const appServer = new AppServer();
|
|
4
|
-
|
|
5
|
-
async function boot() {
|
|
6
|
-
try {
|
|
7
|
-
await appServer.initialize();
|
|
8
|
-
appServer.start();
|
|
9
|
-
} catch (error) {
|
|
10
|
-
console.error('Failed to start application:', error);
|
|
11
|
-
process.exit(1);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
boot();
|
|
16
|
-
|
|
17
|
-
export default appServer.getApp();
|
package/src/middlewares/auth.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from 'express';
|
|
2
|
-
import jwt from 'jsonwebtoken';
|
|
3
|
-
|
|
4
|
-
// Default secret key - in production, use an environment variable
|
|
5
|
-
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-this';
|
|
6
|
-
|
|
7
|
-
// Middleware to authenticate JWT token
|
|
8
|
-
export const auth = (req: Request, res: Response, next: NextFunction): void => {
|
|
9
|
-
// Get token from header
|
|
10
|
-
const token = req.header('x-auth-token');
|
|
11
|
-
|
|
12
|
-
// Check if no token
|
|
13
|
-
if (!token) {
|
|
14
|
-
res.status(401).json({ success: false, message: 'No token, authorization denied' });
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Verify token
|
|
19
|
-
try {
|
|
20
|
-
const decoded = jwt.verify(token, JWT_SECRET);
|
|
21
|
-
|
|
22
|
-
// Add user from payload to request
|
|
23
|
-
(req as any).user = (decoded as any).user;
|
|
24
|
-
next();
|
|
25
|
-
} catch (error) {
|
|
26
|
-
res.status(401).json({ success: false, message: 'Token is not valid' });
|
|
27
|
-
}
|
|
28
|
-
};
|
package/src/middlewares/index.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import express, { Request, Response, NextFunction } from 'express';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { auth } from './auth.js';
|
|
4
|
-
import { initializeDefaultUser } from '../models/User.js';
|
|
5
|
-
|
|
6
|
-
export const errorHandler = (
|
|
7
|
-
err: Error,
|
|
8
|
-
_req: Request,
|
|
9
|
-
res: Response,
|
|
10
|
-
_next: NextFunction
|
|
11
|
-
): void => {
|
|
12
|
-
console.error('Unhandled error:', err);
|
|
13
|
-
res.status(500).json({
|
|
14
|
-
success: false,
|
|
15
|
-
message: 'Internal server error',
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const initMiddlewares = (app: express.Application): void => {
|
|
20
|
-
app.use(express.static('frontend/dist'));
|
|
21
|
-
|
|
22
|
-
app.use((req, res, next) => {
|
|
23
|
-
if (req.path !== '/sse' && req.path !== '/messages') {
|
|
24
|
-
express.json()(req, res, next);
|
|
25
|
-
} else {
|
|
26
|
-
next();
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// Initialize default admin user if no users exist
|
|
31
|
-
initializeDefaultUser().catch(err => {
|
|
32
|
-
console.error('Error initializing default user:', err);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Protect all API routes with authentication middleware
|
|
36
|
-
app.use('/api', auth);
|
|
37
|
-
|
|
38
|
-
app.get('/', (_req: Request, res: Response) => {
|
|
39
|
-
res.sendFile(path.join(process.cwd(), 'frontend', 'dist', 'index.html'));
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
app.use(errorHandler);
|
|
43
|
-
};
|
package/src/models/User.ts
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import bcrypt from 'bcryptjs';
|
|
4
|
-
import { IUser, McpSettings } from '../types/index.js';
|
|
5
|
-
import { loadSettings, saveSettings } from '../config/index.js';
|
|
6
|
-
|
|
7
|
-
// Get all users
|
|
8
|
-
export const getUsers = (): IUser[] => {
|
|
9
|
-
try {
|
|
10
|
-
const settings = loadSettings();
|
|
11
|
-
return settings.users || [];
|
|
12
|
-
} catch (error) {
|
|
13
|
-
console.error('Error reading users from settings:', error);
|
|
14
|
-
return [];
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// Save users to settings
|
|
19
|
-
const saveUsers = (users: IUser[]): void => {
|
|
20
|
-
try {
|
|
21
|
-
const settings = loadSettings();
|
|
22
|
-
settings.users = users;
|
|
23
|
-
saveSettings(settings);
|
|
24
|
-
} catch (error) {
|
|
25
|
-
console.error('Error saving users to settings:', error);
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
// Create a new user
|
|
30
|
-
export const createUser = async (userData: IUser): Promise<IUser | null> => {
|
|
31
|
-
const users = getUsers();
|
|
32
|
-
|
|
33
|
-
// Check if username already exists
|
|
34
|
-
if (users.some(user => user.username === userData.username)) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Hash the password
|
|
39
|
-
const salt = await bcrypt.genSalt(10);
|
|
40
|
-
const hashedPassword = await bcrypt.hash(userData.password, salt);
|
|
41
|
-
|
|
42
|
-
const newUser = {
|
|
43
|
-
username: userData.username,
|
|
44
|
-
password: hashedPassword,
|
|
45
|
-
isAdmin: userData.isAdmin || false
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
users.push(newUser);
|
|
49
|
-
saveUsers(users);
|
|
50
|
-
|
|
51
|
-
return newUser;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
// Find user by username
|
|
55
|
-
export const findUserByUsername = (username: string): IUser | undefined => {
|
|
56
|
-
const users = getUsers();
|
|
57
|
-
return users.find(user => user.username === username);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
// Verify user password
|
|
61
|
-
export const verifyPassword = async (
|
|
62
|
-
plainPassword: string,
|
|
63
|
-
hashedPassword: string
|
|
64
|
-
): Promise<boolean> => {
|
|
65
|
-
return await bcrypt.compare(plainPassword, hashedPassword);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// Update user password
|
|
69
|
-
export const updateUserPassword = async (
|
|
70
|
-
username: string,
|
|
71
|
-
newPassword: string
|
|
72
|
-
): Promise<boolean> => {
|
|
73
|
-
const users = getUsers();
|
|
74
|
-
const userIndex = users.findIndex(user => user.username === username);
|
|
75
|
-
|
|
76
|
-
if (userIndex === -1) {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Hash the new password
|
|
81
|
-
const salt = await bcrypt.genSalt(10);
|
|
82
|
-
const hashedPassword = await bcrypt.hash(newPassword, salt);
|
|
83
|
-
|
|
84
|
-
// Update the user's password
|
|
85
|
-
users[userIndex].password = hashedPassword;
|
|
86
|
-
saveUsers(users);
|
|
87
|
-
|
|
88
|
-
return true;
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// Initialize with default admin user if no users exist
|
|
92
|
-
export const initializeDefaultUser = async (): Promise<void> => {
|
|
93
|
-
const users = getUsers();
|
|
94
|
-
|
|
95
|
-
if (users.length === 0) {
|
|
96
|
-
await createUser({
|
|
97
|
-
username: 'admin',
|
|
98
|
-
password: 'admin123',
|
|
99
|
-
isAdmin: true
|
|
100
|
-
});
|
|
101
|
-
console.log('Default admin user created');
|
|
102
|
-
}
|
|
103
|
-
};
|
package/src/routes/index.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import express from 'express';
|
|
2
|
-
import { check } from 'express-validator';
|
|
3
|
-
import {
|
|
4
|
-
getAllServers,
|
|
5
|
-
getAllSettings,
|
|
6
|
-
createServer,
|
|
7
|
-
updateServer,
|
|
8
|
-
deleteServer,
|
|
9
|
-
toggleServer,
|
|
10
|
-
updateSystemConfig
|
|
11
|
-
} from '../controllers/serverController.js';
|
|
12
|
-
import {
|
|
13
|
-
getGroups,
|
|
14
|
-
getGroup,
|
|
15
|
-
createNewGroup,
|
|
16
|
-
updateExistingGroup,
|
|
17
|
-
deleteExistingGroup,
|
|
18
|
-
addServerToExistingGroup,
|
|
19
|
-
removeServerFromExistingGroup,
|
|
20
|
-
getGroupServers,
|
|
21
|
-
updateGroupServersBatch
|
|
22
|
-
} from '../controllers/groupController.js';
|
|
23
|
-
import {
|
|
24
|
-
getAllMarketServers,
|
|
25
|
-
getMarketServer,
|
|
26
|
-
getAllMarketCategories,
|
|
27
|
-
getAllMarketTags,
|
|
28
|
-
searchMarketServersByQuery,
|
|
29
|
-
getMarketServersByCategory,
|
|
30
|
-
getMarketServersByTag
|
|
31
|
-
} from '../controllers/marketController.js';
|
|
32
|
-
import {
|
|
33
|
-
login,
|
|
34
|
-
register,
|
|
35
|
-
getCurrentUser,
|
|
36
|
-
changePassword
|
|
37
|
-
} from '../controllers/authController.js';
|
|
38
|
-
import { auth } from '../middlewares/auth.js';
|
|
39
|
-
|
|
40
|
-
const router = express.Router();
|
|
41
|
-
|
|
42
|
-
export const initRoutes = (app: express.Application): void => {
|
|
43
|
-
// API routes protected by auth middleware in middlewares/index.ts
|
|
44
|
-
router.get('/servers', getAllServers);
|
|
45
|
-
router.get('/settings', getAllSettings);
|
|
46
|
-
router.post('/servers', createServer);
|
|
47
|
-
router.put('/servers/:name', updateServer);
|
|
48
|
-
router.delete('/servers/:name', deleteServer);
|
|
49
|
-
router.post('/servers/:name/toggle', toggleServer);
|
|
50
|
-
router.put('/system-config', updateSystemConfig);
|
|
51
|
-
|
|
52
|
-
// Group management routes
|
|
53
|
-
router.get('/groups', getGroups);
|
|
54
|
-
router.get('/groups/:id', getGroup);
|
|
55
|
-
router.post('/groups', createNewGroup);
|
|
56
|
-
router.put('/groups/:id', updateExistingGroup);
|
|
57
|
-
router.delete('/groups/:id', deleteExistingGroup);
|
|
58
|
-
router.post('/groups/:id/servers', addServerToExistingGroup);
|
|
59
|
-
router.delete('/groups/:id/servers/:serverName', removeServerFromExistingGroup);
|
|
60
|
-
router.get('/groups/:id/servers', getGroupServers);
|
|
61
|
-
// New route for batch updating servers in a group
|
|
62
|
-
router.put('/groups/:id/servers/batch', updateGroupServersBatch);
|
|
63
|
-
|
|
64
|
-
// Market routes
|
|
65
|
-
router.get('/market/servers', getAllMarketServers);
|
|
66
|
-
router.get('/market/servers/search', searchMarketServersByQuery);
|
|
67
|
-
router.get('/market/servers/:name', getMarketServer);
|
|
68
|
-
router.get('/market/categories', getAllMarketCategories);
|
|
69
|
-
router.get('/market/categories/:category', getMarketServersByCategory);
|
|
70
|
-
router.get('/market/tags', getAllMarketTags);
|
|
71
|
-
router.get('/market/tags/:tag', getMarketServersByTag);
|
|
72
|
-
|
|
73
|
-
// Auth routes (these will NOT be protected by auth middleware)
|
|
74
|
-
app.post('/auth/login', [
|
|
75
|
-
check('username', 'Username is required').not().isEmpty(),
|
|
76
|
-
check('password', 'Password is required').not().isEmpty(),
|
|
77
|
-
], login);
|
|
78
|
-
|
|
79
|
-
app.post('/auth/register', [
|
|
80
|
-
check('username', 'Username is required').not().isEmpty(),
|
|
81
|
-
check('password', 'Password must be at least 6 characters').isLength({ min: 6 }),
|
|
82
|
-
], register);
|
|
83
|
-
|
|
84
|
-
app.get('/auth/user', auth, getCurrentUser);
|
|
85
|
-
|
|
86
|
-
// Add change password route
|
|
87
|
-
app.post('/auth/change-password', [
|
|
88
|
-
auth,
|
|
89
|
-
check('currentPassword', 'Current password is required').not().isEmpty(),
|
|
90
|
-
check('newPassword', 'New password must be at least 6 characters').isLength({ min: 6 }),
|
|
91
|
-
], changePassword);
|
|
92
|
-
|
|
93
|
-
app.use('/api', router);
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
export default router;
|
package/src/server.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import express from 'express';
|
|
2
|
-
import config from './config/index.js';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { initMcpServer } from './services/mcpService.js';
|
|
5
|
-
import { initMiddlewares } from './middlewares/index.js';
|
|
6
|
-
import { initRoutes } from './routes/index.js';
|
|
7
|
-
import {
|
|
8
|
-
handleSseConnection,
|
|
9
|
-
handleSseMessage,
|
|
10
|
-
handleMcpPostRequest,
|
|
11
|
-
handleMcpOtherRequest,
|
|
12
|
-
} from './services/sseService.js';
|
|
13
|
-
import { migrateUserData } from './utils/migration.js';
|
|
14
|
-
import { initializeDefaultUser } from './models/User.js';
|
|
15
|
-
|
|
16
|
-
export class AppServer {
|
|
17
|
-
private app: express.Application;
|
|
18
|
-
private port: number | string;
|
|
19
|
-
|
|
20
|
-
constructor() {
|
|
21
|
-
this.app = express();
|
|
22
|
-
this.port = config.port;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async initialize(): Promise<void> {
|
|
26
|
-
try {
|
|
27
|
-
// Migrate user data from users.json to mcp_settings.json if needed
|
|
28
|
-
migrateUserData();
|
|
29
|
-
|
|
30
|
-
// Initialize default admin user if no users exist
|
|
31
|
-
await initializeDefaultUser();
|
|
32
|
-
|
|
33
|
-
initMiddlewares(this.app);
|
|
34
|
-
initRoutes(this.app);
|
|
35
|
-
console.log('Server initialized successfully');
|
|
36
|
-
|
|
37
|
-
initMcpServer(config.mcpHubName, config.mcpHubVersion)
|
|
38
|
-
.then(() => {
|
|
39
|
-
console.log('MCP server initialized successfully');
|
|
40
|
-
this.app.get('/sse/:group?', (req, res) => handleSseConnection(req, res));
|
|
41
|
-
this.app.post('/messages', handleSseMessage);
|
|
42
|
-
this.app.post('/mcp/:group?', handleMcpPostRequest);
|
|
43
|
-
this.app.get('/mcp/:group?', handleMcpOtherRequest);
|
|
44
|
-
this.app.delete('/mcp/:group?', handleMcpOtherRequest);
|
|
45
|
-
})
|
|
46
|
-
.catch((error) => {
|
|
47
|
-
console.error('Error initializing MCP server:', error);
|
|
48
|
-
throw error;
|
|
49
|
-
})
|
|
50
|
-
.finally(() => {
|
|
51
|
-
this.app.get('*', (_req, res) => {
|
|
52
|
-
res.sendFile(path.join(process.cwd(), 'frontend', 'dist', 'index.html'));
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
} catch (error) {
|
|
56
|
-
console.error('Error initializing server:', error);
|
|
57
|
-
throw error;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
start(): void {
|
|
62
|
-
this.app.listen(this.port, () => {
|
|
63
|
-
console.log(`Server is running on port ${this.port}`);
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
getApp(): express.Application {
|
|
68
|
-
return this.app;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export default AppServer;
|