@mcp-shark/mcp-shark 1.5.4 → 1.5.6
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 +32 -96
- package/bin/mcp-shark.js +1 -1
- package/core/configs/codex.js +68 -0
- package/core/configs/environment.js +51 -0
- package/{lib/common → core}/configs/index.js +16 -1
- package/core/constants/Defaults.js +15 -0
- package/core/constants/HttpStatus.js +14 -0
- package/core/constants/Server.js +20 -0
- package/core/constants/StatusCodes.js +25 -0
- package/core/constants/index.js +7 -0
- package/core/container/DependencyContainer.js +179 -0
- package/core/db/init.js +33 -0
- package/core/index.js +10 -0
- package/{mcp-server/lib/common/error.js → core/libraries/ErrorLibrary.js} +4 -0
- package/core/libraries/LoggerLibrary.js +91 -0
- package/core/libraries/SerializationLibrary.js +32 -0
- package/core/libraries/bootstrap-logger.js +19 -0
- package/core/libraries/errors/ApplicationError.js +97 -0
- package/core/libraries/index.js +17 -0
- package/{mcp-server/lib → core/mcp-server}/auditor/audit.js +77 -53
- package/core/mcp-server/index.js +192 -0
- package/{mcp-server/lib → core/mcp-server}/server/external/all.js +1 -1
- package/core/mcp-server/server/external/config.js +75 -0
- package/{mcp-server/lib → core/mcp-server}/server/external/single/client.js +1 -1
- package/{mcp-server/lib → core/mcp-server}/server/external/single/request.js +1 -1
- package/{mcp-server/lib → core/mcp-server}/server/external/single/run.js +20 -11
- package/{mcp-server/lib → core/mcp-server}/server/external/single/transport.js +1 -1
- package/{mcp-server/lib → core/mcp-server}/server/internal/handlers/error.js +1 -1
- package/core/mcp-server/server/internal/handlers/prompts-get.js +28 -0
- package/core/mcp-server/server/internal/handlers/prompts-list.js +21 -0
- package/core/mcp-server/server/internal/handlers/resources-list.js +21 -0
- package/core/mcp-server/server/internal/handlers/resources-read.js +28 -0
- package/core/mcp-server/server/internal/handlers/tools-call.js +44 -0
- package/core/mcp-server/server/internal/handlers/tools-list.js +23 -0
- package/core/mcp-server/server/internal/run.js +53 -0
- package/{mcp-server/lib → core/mcp-server}/server/internal/server.js +11 -1
- package/core/models/ConversationFilters.js +31 -0
- package/core/models/ExportFormat.js +8 -0
- package/core/models/RequestFilters.js +43 -0
- package/core/models/SessionFilters.js +23 -0
- package/core/models/index.js +8 -0
- package/core/repositories/AuditRepository.js +233 -0
- package/core/repositories/ConversationRepository.js +182 -0
- package/core/repositories/PacketRepository.js +237 -0
- package/core/repositories/SchemaRepository.js +107 -0
- package/core/repositories/SessionRepository.js +59 -0
- package/core/repositories/StatisticsRepository.js +54 -0
- package/core/repositories/index.js +10 -0
- package/core/services/AuditService.js +144 -0
- package/core/services/BackupService.js +222 -0
- package/core/services/ConfigDetectionService.js +89 -0
- package/core/services/ConfigFileService.js +210 -0
- package/core/services/ConfigPatchingService.js +137 -0
- package/core/services/ConfigService.js +250 -0
- package/core/services/ConfigTransformService.js +178 -0
- package/core/services/ConversationService.js +19 -0
- package/core/services/ExportService.js +117 -0
- package/core/services/LogService.js +64 -0
- package/core/services/McpClientService.js +235 -0
- package/core/services/McpDiscoveryService.js +107 -0
- package/core/services/RequestService.js +56 -0
- package/core/services/ScanCacheService.js +242 -0
- package/core/services/ScanService.js +167 -0
- package/core/services/ServerManagementService.js +206 -0
- package/core/services/SessionService.js +34 -0
- package/core/services/SettingsService.js +163 -0
- package/core/services/StatisticsService.js +64 -0
- package/core/services/TokenService.js +94 -0
- package/core/services/index.js +25 -0
- package/core/services/parsers/ConfigParserFactory.js +113 -0
- package/core/services/parsers/JsonConfigParser.js +66 -0
- package/core/services/parsers/LegacyJsonConfigParser.js +71 -0
- package/core/services/parsers/TomlConfigParser.js +87 -0
- package/core/services/parsers/index.js +4 -0
- package/{ui/server → core}/utils/scan-cache/directory.js +1 -1
- package/core/utils/validation.js +77 -0
- package/package.json +14 -11
- package/ui/dist/assets/index-CArYxKxS.js +35 -0
- package/ui/dist/index.html +1 -1
- package/ui/server/controllers/BackupController.js +129 -0
- package/ui/server/controllers/ConfigController.js +92 -0
- package/ui/server/controllers/ConversationController.js +41 -0
- package/ui/server/controllers/LogController.js +44 -0
- package/ui/server/controllers/McpClientController.js +60 -0
- package/ui/server/controllers/McpDiscoveryController.js +44 -0
- package/ui/server/controllers/RequestController.js +129 -0
- package/ui/server/controllers/ScanController.js +122 -0
- package/ui/server/controllers/ServerManagementController.js +154 -0
- package/ui/server/controllers/SessionController.js +57 -0
- package/ui/server/controllers/SettingsController.js +24 -0
- package/ui/server/controllers/StatisticsController.js +54 -0
- package/ui/server/controllers/TokenController.js +58 -0
- package/ui/server/controllers/index.js +17 -0
- package/ui/server/routes/backups/index.js +15 -9
- package/ui/server/routes/composite/index.js +63 -32
- package/ui/server/routes/composite/servers.js +20 -15
- package/ui/server/routes/config.js +13 -172
- package/ui/server/routes/conversations.js +9 -19
- package/ui/server/routes/help.js +4 -3
- package/ui/server/routes/logs.js +14 -26
- package/ui/server/routes/playground.js +11 -174
- package/ui/server/routes/requests.js +12 -232
- package/ui/server/routes/sessions.js +10 -21
- package/ui/server/routes/settings.js +10 -192
- package/ui/server/routes/smartscan.js +26 -15
- package/ui/server/routes/statistics.js +8 -79
- package/ui/server/setup.js +163 -0
- package/ui/server/swagger/paths/backups.js +151 -0
- package/ui/server/swagger/paths/components.js +76 -0
- package/ui/server/swagger/paths/config.js +117 -0
- package/ui/server/swagger/paths/conversations.js +29 -0
- package/ui/server/swagger/paths/help.js +82 -0
- package/ui/server/swagger/paths/logs.js +87 -0
- package/ui/server/swagger/paths/playground.js +49 -0
- package/ui/server/swagger/paths/requests.js +178 -0
- package/ui/server/swagger/paths/serverManagement.js +205 -0
- package/ui/server/swagger/paths/sessions.js +61 -0
- package/ui/server/swagger/paths/settings.js +31 -0
- package/ui/server/swagger/paths/smartScan/discovery.js +97 -0
- package/ui/server/swagger/paths/smartScan/index.js +13 -0
- package/ui/server/swagger/paths/smartScan/scans.js +151 -0
- package/ui/server/swagger/paths/smartScan/token.js +71 -0
- package/ui/server/swagger/paths/statistics.js +40 -0
- package/ui/server/swagger/paths.js +38 -0
- package/ui/server/swagger/swagger.js +37 -0
- package/ui/server/utils/cleanup.js +99 -0
- package/ui/server/utils/config.js +18 -96
- package/ui/server/utils/errorHandler.js +43 -0
- package/ui/server/utils/logger.js +2 -2
- package/ui/server/utils/paths.js +27 -30
- package/ui/server/utils/port.js +21 -21
- package/ui/server/utils/process.js +18 -10
- package/ui/server/utils/processState.js +17 -0
- package/ui/server/utils/signals.js +34 -0
- package/ui/server/websocket/broadcast.js +33 -0
- package/ui/server/websocket/handler.js +52 -0
- package/ui/server.js +51 -230
- package/ui/src/App.jsx +2 -0
- package/ui/src/CompositeSetup.jsx +23 -9
- package/ui/src/PacketFilters.jsx +17 -3
- package/ui/src/components/AlertModal.jsx +116 -0
- package/ui/src/components/App/ApiDocsButton.jsx +57 -0
- package/ui/src/components/App/useAppState.js +43 -1
- package/ui/src/components/BackupList.jsx +27 -3
- package/ui/src/utils/requestPairing.js +35 -36
- package/ui/src/utils/requestUtils.js +1 -0
- package/lib/common/db/init.js +0 -132
- package/lib/common/db/logger.js +0 -349
- package/lib/common/db/query.js +0 -403
- package/lib/common/logger.js +0 -90
- package/mcp-server/index.js +0 -138
- package/mcp-server/lib/server/external/config.js +0 -57
- package/mcp-server/lib/server/internal/handlers/prompts-get.js +0 -20
- package/mcp-server/lib/server/internal/handlers/prompts-list.js +0 -13
- package/mcp-server/lib/server/internal/handlers/resources-list.js +0 -13
- package/mcp-server/lib/server/internal/handlers/resources-read.js +0 -20
- package/mcp-server/lib/server/internal/handlers/tools-call.js +0 -35
- package/mcp-server/lib/server/internal/handlers/tools-list.js +0 -15
- package/mcp-server/lib/server/internal/run.js +0 -37
- package/mcp-server/mcp-shark.js +0 -22
- package/ui/dist/assets/index-CFHeMNwd.js +0 -35
- package/ui/server/routes/backups/deleteBackup.js +0 -54
- package/ui/server/routes/backups/listBackups.js +0 -75
- package/ui/server/routes/backups/restoreBackup.js +0 -83
- package/ui/server/routes/backups/viewBackup.js +0 -47
- package/ui/server/routes/composite/setup.js +0 -129
- package/ui/server/routes/composite/status.js +0 -7
- package/ui/server/routes/composite/stop.js +0 -39
- package/ui/server/routes/composite/utils.js +0 -45
- package/ui/server/routes/smartscan/discover.js +0 -118
- package/ui/server/routes/smartscan/scans/clearCache.js +0 -23
- package/ui/server/routes/smartscan/scans/createBatchScans.js +0 -124
- package/ui/server/routes/smartscan/scans/createScan.js +0 -43
- package/ui/server/routes/smartscan/scans/getCachedResults.js +0 -52
- package/ui/server/routes/smartscan/scans/getScan.js +0 -42
- package/ui/server/routes/smartscan/scans/listScans.js +0 -25
- package/ui/server/routes/smartscan/scans.js +0 -13
- package/ui/server/routes/smartscan/token.js +0 -57
- package/ui/server/utils/config-update.js +0 -240
- package/ui/server/utils/scan-cache/all-results.js +0 -197
- package/ui/server/utils/scan-cache/file-operations.js +0 -107
- package/ui/server/utils/scan-cache/hash.js +0 -47
- package/ui/server/utils/scan-cache/server-operations.js +0 -85
- package/ui/server/utils/scan-cache.js +0 -12
- package/ui/server/utils/smartscan-token.js +0 -43
- /package/{mcp-server/lib → core/mcp-server}/server/external/kv.js +0 -0
- /package/{mcp-server/lib → core/mcp-server}/server/internal/handlers/common.js +0 -0
- /package/{mcp-server/lib → core/mcp-server}/server/internal/session.js +0 -0
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import * as path from 'node:path';
|
|
4
|
-
|
|
5
|
-
export function deleteBackup(req, res, mcpSharkLogs, broadcastLogUpdate) {
|
|
6
|
-
try {
|
|
7
|
-
const { backupPath } = req.body;
|
|
8
|
-
|
|
9
|
-
if (!backupPath) {
|
|
10
|
-
return res.status(400).json({ error: 'backupPath is required' });
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const resolvedBackupPath = backupPath.startsWith('~')
|
|
14
|
-
? path.join(homedir(), backupPath.slice(1))
|
|
15
|
-
: backupPath;
|
|
16
|
-
|
|
17
|
-
if (!fs.existsSync(resolvedBackupPath)) {
|
|
18
|
-
return res.status(404).json({ error: 'Backup file not found', path: resolvedBackupPath });
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
fs.unlinkSync(resolvedBackupPath);
|
|
22
|
-
|
|
23
|
-
const timestamp = new Date().toISOString();
|
|
24
|
-
const deleteLog = {
|
|
25
|
-
timestamp,
|
|
26
|
-
type: 'stdout',
|
|
27
|
-
line: `[DELETE] Deleted backup: ${resolvedBackupPath.replace(homedir(), '~')}`,
|
|
28
|
-
};
|
|
29
|
-
mcpSharkLogs.push(deleteLog);
|
|
30
|
-
if (mcpSharkLogs.length > 10000) {
|
|
31
|
-
mcpSharkLogs.shift();
|
|
32
|
-
}
|
|
33
|
-
broadcastLogUpdate(deleteLog);
|
|
34
|
-
|
|
35
|
-
res.json({
|
|
36
|
-
success: true,
|
|
37
|
-
message: 'Backup file deleted successfully',
|
|
38
|
-
backupPath: resolvedBackupPath.replace(homedir(), '~'),
|
|
39
|
-
});
|
|
40
|
-
} catch (error) {
|
|
41
|
-
const timestamp = new Date().toISOString();
|
|
42
|
-
const errorLog = {
|
|
43
|
-
timestamp,
|
|
44
|
-
type: 'error',
|
|
45
|
-
line: `[DELETE ERROR] Failed to delete backup: ${error.message}`,
|
|
46
|
-
};
|
|
47
|
-
mcpSharkLogs.push(errorLog);
|
|
48
|
-
if (mcpSharkLogs.length > 10000) {
|
|
49
|
-
mcpSharkLogs.shift();
|
|
50
|
-
}
|
|
51
|
-
broadcastLogUpdate(errorLog);
|
|
52
|
-
res.status(500).json({ error: 'Failed to delete backup', details: error.message });
|
|
53
|
-
}
|
|
54
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import * as path from 'node:path';
|
|
4
|
-
|
|
5
|
-
export function listBackups(_req, res) {
|
|
6
|
-
try {
|
|
7
|
-
const backups = [];
|
|
8
|
-
const homeDir = homedir();
|
|
9
|
-
|
|
10
|
-
const commonPaths = [
|
|
11
|
-
path.join(homeDir, '.cursor', 'mcp.json'),
|
|
12
|
-
path.join(homeDir, '.codeium', 'windsurf', 'mcp_config.json'),
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
const backupDirs = [path.join(homeDir, '.cursor'), path.join(homeDir, '.codeium', 'windsurf')];
|
|
16
|
-
|
|
17
|
-
// Find backups with new format: .mcp.json-mcpshark.<datetime>.json
|
|
18
|
-
backupDirs.forEach((dir) => {
|
|
19
|
-
if (fs.existsSync(dir)) {
|
|
20
|
-
const files = fs.readdirSync(dir);
|
|
21
|
-
files
|
|
22
|
-
.filter((file) => {
|
|
23
|
-
// Match pattern: .<basename>-mcpshark.<datetime>.json
|
|
24
|
-
return /^\.(.+)-mcpshark\.\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}\.json$/.test(file);
|
|
25
|
-
})
|
|
26
|
-
.forEach((file) => {
|
|
27
|
-
const backupPath = path.join(dir, file);
|
|
28
|
-
// Extract original filename from backup name
|
|
29
|
-
// .mcp.json-mcpshark.<datetime>.json -> mcp.json
|
|
30
|
-
const match = file.match(/^\.(.+)-mcpshark\./);
|
|
31
|
-
if (match) {
|
|
32
|
-
const originalBasename = match[1];
|
|
33
|
-
const originalPath = path.join(dir, originalBasename);
|
|
34
|
-
const stats = fs.statSync(backupPath);
|
|
35
|
-
backups.push({
|
|
36
|
-
originalPath: originalPath,
|
|
37
|
-
backupPath: backupPath,
|
|
38
|
-
createdAt: stats.birthtime.toISOString(),
|
|
39
|
-
modifiedAt: stats.mtime.toISOString(),
|
|
40
|
-
size: stats.size,
|
|
41
|
-
displayPath: originalPath.replace(homeDir, '~'),
|
|
42
|
-
backupFileName: file,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// Also check for old .backup format for backward compatibility
|
|
50
|
-
commonPaths.forEach((configPath) => {
|
|
51
|
-
const backupPath = `${configPath}.backup`;
|
|
52
|
-
if (fs.existsSync(backupPath)) {
|
|
53
|
-
const stats = fs.statSync(backupPath);
|
|
54
|
-
backups.push({
|
|
55
|
-
originalPath: configPath,
|
|
56
|
-
backupPath: backupPath,
|
|
57
|
-
createdAt: stats.birthtime.toISOString(),
|
|
58
|
-
modifiedAt: stats.mtime.toISOString(),
|
|
59
|
-
size: stats.size,
|
|
60
|
-
displayPath: configPath.replace(homeDir, '~'),
|
|
61
|
-
backupFileName: path.basename(backupPath),
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Sort by modifiedAt (latest first)
|
|
67
|
-
res.json({
|
|
68
|
-
backups: backups.sort(
|
|
69
|
-
(a, b) => new Date(b.modifiedAt || b.createdAt) - new Date(a.modifiedAt || a.createdAt)
|
|
70
|
-
),
|
|
71
|
-
});
|
|
72
|
-
} catch (error) {
|
|
73
|
-
res.status(500).json({ error: 'Failed to list backups', details: error.message });
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import * as path from 'node:path';
|
|
4
|
-
|
|
5
|
-
export function restoreBackup(req, res, mcpSharkLogs, broadcastLogUpdate) {
|
|
6
|
-
try {
|
|
7
|
-
const { backupPath, originalPath } = req.body;
|
|
8
|
-
|
|
9
|
-
if (!backupPath) {
|
|
10
|
-
return res.status(400).json({ error: 'backupPath is required' });
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const resolvedBackupPath = backupPath.startsWith('~')
|
|
14
|
-
? path.join(homedir(), backupPath.slice(1))
|
|
15
|
-
: backupPath;
|
|
16
|
-
|
|
17
|
-
if (!fs.existsSync(resolvedBackupPath)) {
|
|
18
|
-
return res.status(404).json({ error: 'Backup file not found', path: resolvedBackupPath });
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Determine original path
|
|
22
|
-
const determineTargetPath = (originalPath, backupPath) => {
|
|
23
|
-
if (originalPath) {
|
|
24
|
-
return originalPath.startsWith('~')
|
|
25
|
-
? path.join(homedir(), originalPath.slice(1))
|
|
26
|
-
: originalPath;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Try to extract from backup filename
|
|
30
|
-
if (backupPath.endsWith('.backup')) {
|
|
31
|
-
return backupPath.replace('.backup', '');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// New format: .mcp.json-mcpshark.<datetime>.json
|
|
35
|
-
const match = path.basename(backupPath).match(/^\.(.+)-mcpshark\./);
|
|
36
|
-
if (match) {
|
|
37
|
-
const originalBasename = match[1];
|
|
38
|
-
return path.join(path.dirname(backupPath), originalBasename);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return null;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const targetPath = determineTargetPath(originalPath, resolvedBackupPath);
|
|
45
|
-
if (!targetPath) {
|
|
46
|
-
return res.status(400).json({ error: 'Could not determine original file path' });
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const backupContent = fs.readFileSync(resolvedBackupPath, 'utf8');
|
|
50
|
-
fs.writeFileSync(targetPath, backupContent);
|
|
51
|
-
|
|
52
|
-
const timestamp = new Date().toISOString();
|
|
53
|
-
const restoreLog = {
|
|
54
|
-
timestamp,
|
|
55
|
-
type: 'stdout',
|
|
56
|
-
line: `[RESTORE] Restored config from backup: ${targetPath.replace(homedir(), '~')}`,
|
|
57
|
-
};
|
|
58
|
-
mcpSharkLogs.push(restoreLog);
|
|
59
|
-
if (mcpSharkLogs.length > 10000) {
|
|
60
|
-
mcpSharkLogs.shift();
|
|
61
|
-
}
|
|
62
|
-
broadcastLogUpdate(restoreLog);
|
|
63
|
-
|
|
64
|
-
res.json({
|
|
65
|
-
success: true,
|
|
66
|
-
message: 'Config file restored from backup',
|
|
67
|
-
originalPath: targetPath.replace(homedir(), '~'),
|
|
68
|
-
});
|
|
69
|
-
} catch (error) {
|
|
70
|
-
const timestamp = new Date().toISOString();
|
|
71
|
-
const errorLog = {
|
|
72
|
-
timestamp,
|
|
73
|
-
type: 'error',
|
|
74
|
-
line: `[RESTORE ERROR] Failed to restore: ${error.message}`,
|
|
75
|
-
};
|
|
76
|
-
mcpSharkLogs.push(errorLog);
|
|
77
|
-
if (mcpSharkLogs.length > 10000) {
|
|
78
|
-
mcpSharkLogs.shift();
|
|
79
|
-
}
|
|
80
|
-
broadcastLogUpdate(errorLog);
|
|
81
|
-
res.status(500).json({ error: 'Failed to restore backup', details: error.message });
|
|
82
|
-
}
|
|
83
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import * as path from 'node:path';
|
|
4
|
-
|
|
5
|
-
function tryParseJson(content) {
|
|
6
|
-
try {
|
|
7
|
-
return JSON.parse(content);
|
|
8
|
-
} catch (_e) {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function viewBackup(req, res) {
|
|
14
|
-
try {
|
|
15
|
-
const { backupPath } = req.query;
|
|
16
|
-
|
|
17
|
-
if (!backupPath) {
|
|
18
|
-
return res.status(400).json({ error: 'backupPath is required' });
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const resolvedBackupPath = backupPath.startsWith('~')
|
|
22
|
-
? path.join(homedir(), backupPath.slice(1))
|
|
23
|
-
: backupPath;
|
|
24
|
-
|
|
25
|
-
if (!fs.existsSync(resolvedBackupPath)) {
|
|
26
|
-
return res.status(404).json({ error: 'Backup file not found', path: resolvedBackupPath });
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const content = fs.readFileSync(resolvedBackupPath, 'utf-8');
|
|
30
|
-
const parsed = tryParseJson(content);
|
|
31
|
-
|
|
32
|
-
const stats = fs.statSync(resolvedBackupPath);
|
|
33
|
-
|
|
34
|
-
res.json({
|
|
35
|
-
success: true,
|
|
36
|
-
backupPath: resolvedBackupPath,
|
|
37
|
-
displayPath: resolvedBackupPath.replace(homedir(), '~'),
|
|
38
|
-
content: content,
|
|
39
|
-
parsed: parsed,
|
|
40
|
-
createdAt: stats.birthtime.toISOString(),
|
|
41
|
-
modifiedAt: stats.mtime.toISOString(),
|
|
42
|
-
size: stats.size,
|
|
43
|
-
});
|
|
44
|
-
} catch (error) {
|
|
45
|
-
res.status(500).json({ error: 'Failed to read backup file', details: error.message });
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import * as path from 'node:path';
|
|
4
|
-
import { startMcpSharkServer } from '@mcp-shark/mcp-shark/mcp-server';
|
|
5
|
-
import { getMcpConfigPath } from '#common/configs';
|
|
6
|
-
import { getSelectedServiceNames, updateConfigFile } from '../../utils/config-update.js';
|
|
7
|
-
import { clearOriginalConfig, convertMcpServersToServers } from '../../utils/config.js';
|
|
8
|
-
import logger from '../../utils/logger.js';
|
|
9
|
-
import { createLogEntry } from '../../utils/process.js';
|
|
10
|
-
import { filterServers, parseJsonConfig, resolveFileData } from './utils.js';
|
|
11
|
-
|
|
12
|
-
const MAX_LOG_LINES = 10000;
|
|
13
|
-
|
|
14
|
-
export async function setup(
|
|
15
|
-
req,
|
|
16
|
-
res,
|
|
17
|
-
getMcpSharkProcess,
|
|
18
|
-
setMcpSharkProcess,
|
|
19
|
-
mcpSharkLogs,
|
|
20
|
-
broadcastLogUpdate
|
|
21
|
-
) {
|
|
22
|
-
mcpSharkLogs.length = 0;
|
|
23
|
-
const logEntry = createLogEntry(mcpSharkLogs, broadcastLogUpdate);
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
const { filePath, fileContent, selectedServices } = req.body;
|
|
27
|
-
|
|
28
|
-
if (!filePath && !fileContent) {
|
|
29
|
-
return res.status(400).json({ error: 'Either filePath or fileContent is required' });
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const fileData = resolveFileData(filePath, fileContent);
|
|
33
|
-
|
|
34
|
-
if (!fileData) {
|
|
35
|
-
const resolvedFilePath = filePath.startsWith('~')
|
|
36
|
-
? path.join(homedir(), filePath.slice(1))
|
|
37
|
-
: filePath;
|
|
38
|
-
return res.status(404).json({ error: 'File not found', path: resolvedFilePath });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const parseResult = parseJsonConfig(fileData.content);
|
|
42
|
-
|
|
43
|
-
if (!parseResult.config) {
|
|
44
|
-
return res.status(400).json({
|
|
45
|
-
error: 'Invalid JSON file',
|
|
46
|
-
details: parseResult.error ? parseResult.error.message : 'Failed to parse JSON',
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const originalConfig = parseResult.config;
|
|
51
|
-
const baseConvertedConfig = convertMcpServersToServers(originalConfig);
|
|
52
|
-
|
|
53
|
-
const convertedConfig =
|
|
54
|
-
selectedServices && Array.isArray(selectedServices) && selectedServices.length > 0
|
|
55
|
-
? filterServers(baseConvertedConfig, selectedServices)
|
|
56
|
-
: baseConvertedConfig;
|
|
57
|
-
|
|
58
|
-
if (Object.keys(convertedConfig.servers).length === 0) {
|
|
59
|
-
return res.status(400).json({ error: 'No servers found in config' });
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const mcpsJsonPath = getMcpConfigPath();
|
|
63
|
-
fs.writeFileSync(mcpsJsonPath, JSON.stringify(convertedConfig, null, 2));
|
|
64
|
-
logger.info({ path: mcpsJsonPath }, 'Wrote converted config');
|
|
65
|
-
|
|
66
|
-
const currentServer = getMcpSharkProcess();
|
|
67
|
-
if (currentServer?.stop) {
|
|
68
|
-
await currentServer.stop();
|
|
69
|
-
setMcpSharkProcess(null);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
logEntry('info', '[UI Server] Starting MCP-Shark server as library...');
|
|
73
|
-
logEntry('info', `[UI Server] Config: ${mcpsJsonPath}`);
|
|
74
|
-
|
|
75
|
-
const serverInstance = await startMcpSharkServer({
|
|
76
|
-
configPath: mcpsJsonPath,
|
|
77
|
-
port: 9851,
|
|
78
|
-
onError: (err) => {
|
|
79
|
-
logEntry('error', `Failed to start mcp-shark server: ${err.message}`);
|
|
80
|
-
setMcpSharkProcess(null);
|
|
81
|
-
throw err;
|
|
82
|
-
},
|
|
83
|
-
onReady: () => {
|
|
84
|
-
logEntry('info', 'MCP Shark server is ready!');
|
|
85
|
-
logger.info('MCP Shark server is ready!');
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
setMcpSharkProcess(serverInstance);
|
|
90
|
-
logger.info('MCP Shark server started successfully');
|
|
91
|
-
|
|
92
|
-
const selectedServiceNames = getSelectedServiceNames(originalConfig, selectedServices);
|
|
93
|
-
const { updatedConfig, backupPath: createdBackupPath } = updateConfigFile(
|
|
94
|
-
originalConfig,
|
|
95
|
-
selectedServiceNames,
|
|
96
|
-
fileData.resolvedFilePath,
|
|
97
|
-
fileData.content,
|
|
98
|
-
mcpSharkLogs,
|
|
99
|
-
broadcastLogUpdate
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
if (!fileData.resolvedFilePath) {
|
|
103
|
-
clearOriginalConfig();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
res.json({
|
|
107
|
-
success: true,
|
|
108
|
-
message: 'MCP Shark server started successfully and config file updated',
|
|
109
|
-
convertedConfig,
|
|
110
|
-
updatedConfig,
|
|
111
|
-
filePath: fileData.resolvedFilePath || null,
|
|
112
|
-
backupPath: createdBackupPath || null,
|
|
113
|
-
});
|
|
114
|
-
} catch (error) {
|
|
115
|
-
logger.error({ error: error.message }, 'Error setting up mcp-shark server');
|
|
116
|
-
const timestamp = new Date().toISOString();
|
|
117
|
-
const errorLog = {
|
|
118
|
-
timestamp,
|
|
119
|
-
type: 'error',
|
|
120
|
-
line: `[ERROR] Failed to setup mcp-shark server: ${error.message}`,
|
|
121
|
-
};
|
|
122
|
-
mcpSharkLogs.push(errorLog);
|
|
123
|
-
if (mcpSharkLogs.length > MAX_LOG_LINES) {
|
|
124
|
-
mcpSharkLogs.shift();
|
|
125
|
-
}
|
|
126
|
-
broadcastLogUpdate(errorLog);
|
|
127
|
-
res.status(500).json({ error: 'Failed to setup mcp-shark server', details: error.message });
|
|
128
|
-
}
|
|
129
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
export async function stop(
|
|
2
|
-
_req,
|
|
3
|
-
res,
|
|
4
|
-
restoreOriginalConfig,
|
|
5
|
-
getMcpSharkProcess,
|
|
6
|
-
setMcpSharkProcess,
|
|
7
|
-
mcpSharkLogs,
|
|
8
|
-
broadcastLogUpdate
|
|
9
|
-
) {
|
|
10
|
-
try {
|
|
11
|
-
const currentServer = getMcpSharkProcess();
|
|
12
|
-
if (currentServer?.stop) {
|
|
13
|
-
await currentServer.stop();
|
|
14
|
-
setMcpSharkProcess(null);
|
|
15
|
-
|
|
16
|
-
const restored = restoreOriginalConfig();
|
|
17
|
-
|
|
18
|
-
if (restored) {
|
|
19
|
-
const timestamp = new Date().toISOString();
|
|
20
|
-
const restoreLog = {
|
|
21
|
-
timestamp,
|
|
22
|
-
type: 'stdout',
|
|
23
|
-
line: '[RESTORE] Restored original config',
|
|
24
|
-
};
|
|
25
|
-
mcpSharkLogs.push(restoreLog);
|
|
26
|
-
if (mcpSharkLogs.length > 10000) {
|
|
27
|
-
mcpSharkLogs.shift();
|
|
28
|
-
}
|
|
29
|
-
broadcastLogUpdate(restoreLog);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
res.json({ success: true, message: 'MCP Shark server stopped and config restored' });
|
|
33
|
-
} else {
|
|
34
|
-
res.json({ success: true, message: 'MCP Shark server was not running' });
|
|
35
|
-
}
|
|
36
|
-
} catch (error) {
|
|
37
|
-
res.status(500).json({ error: 'Failed to stop mcp-shark server', details: error.message });
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import * as path from 'node:path';
|
|
4
|
-
|
|
5
|
-
export function resolveFileData(filePath, fileContent) {
|
|
6
|
-
if (fileContent) {
|
|
7
|
-
const resolvedFilePath = filePath
|
|
8
|
-
? filePath.startsWith('~')
|
|
9
|
-
? path.join(homedir(), filePath.slice(1))
|
|
10
|
-
: filePath
|
|
11
|
-
: null;
|
|
12
|
-
return { content: fileContent, resolvedFilePath };
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const resolvedFilePath = filePath.startsWith('~')
|
|
16
|
-
? path.join(homedir(), filePath.slice(1))
|
|
17
|
-
: filePath;
|
|
18
|
-
|
|
19
|
-
if (!fs.existsSync(resolvedFilePath)) {
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
content: fs.readFileSync(resolvedFilePath, 'utf-8'),
|
|
25
|
-
resolvedFilePath,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function parseJsonConfig(content) {
|
|
30
|
-
try {
|
|
31
|
-
return { config: JSON.parse(content), error: null };
|
|
32
|
-
} catch (e) {
|
|
33
|
-
return { config: null, error: e };
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function filterServers(config, services) {
|
|
38
|
-
const filteredServers = {};
|
|
39
|
-
services.forEach((serviceName) => {
|
|
40
|
-
if (config.servers[serviceName]) {
|
|
41
|
-
filteredServers[serviceName] = config.servers[serviceName];
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
return { servers: filteredServers };
|
|
45
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
-
import { getMcpConfigPath } from '#common/configs';
|
|
4
|
-
import { convertMcpServersToServers } from '../../utils/config.js';
|
|
5
|
-
import logger from '../../utils/logger.js';
|
|
6
|
-
import { createTransport } from './transport.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Discover a single MCP server
|
|
10
|
-
*/
|
|
11
|
-
async function discoverServer(serverName, serverConfig) {
|
|
12
|
-
const transport = createTransport(serverConfig, serverName);
|
|
13
|
-
const client = new Client(
|
|
14
|
-
{ name: 'mcp-shark-smart-scan', version: '1.0.0' },
|
|
15
|
-
{
|
|
16
|
-
capabilities: {
|
|
17
|
-
tools: {},
|
|
18
|
-
resources: {},
|
|
19
|
-
prompts: {},
|
|
20
|
-
},
|
|
21
|
-
}
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
await client.connect(transport);
|
|
26
|
-
|
|
27
|
-
const [toolsResult, resourcesResult, promptsResult] = await Promise.allSettled([
|
|
28
|
-
client.listTools(),
|
|
29
|
-
client.listResources(),
|
|
30
|
-
client.listPrompts(),
|
|
31
|
-
]);
|
|
32
|
-
|
|
33
|
-
const tools = toolsResult.status === 'fulfilled' ? toolsResult.value?.tools || [] : [];
|
|
34
|
-
const resources =
|
|
35
|
-
resourcesResult.status === 'fulfilled' ? resourcesResult.value?.resources || [] : [];
|
|
36
|
-
const prompts = promptsResult.status === 'fulfilled' ? promptsResult.value?.prompts || [] : [];
|
|
37
|
-
|
|
38
|
-
await client.close();
|
|
39
|
-
if (transport.close) {
|
|
40
|
-
await transport.close();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return {
|
|
44
|
-
name: serverName,
|
|
45
|
-
tools,
|
|
46
|
-
resources,
|
|
47
|
-
prompts,
|
|
48
|
-
};
|
|
49
|
-
} catch (error) {
|
|
50
|
-
try {
|
|
51
|
-
await client.close();
|
|
52
|
-
if (transport.close) {
|
|
53
|
-
await transport.close();
|
|
54
|
-
}
|
|
55
|
-
} catch (_closeError) {
|
|
56
|
-
// Ignore close errors
|
|
57
|
-
}
|
|
58
|
-
throw error;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Discover all MCP servers from config
|
|
64
|
-
* GET /api/smartscan/discover
|
|
65
|
-
*/
|
|
66
|
-
export async function discoverServers(_req, res) {
|
|
67
|
-
try {
|
|
68
|
-
const configPath = getMcpConfigPath();
|
|
69
|
-
|
|
70
|
-
if (!existsSync(configPath)) {
|
|
71
|
-
return res.status(404).json({
|
|
72
|
-
error: 'MCP config file not found',
|
|
73
|
-
message: `Config file not found at: ${configPath}`,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const configContent = readFileSync(configPath, 'utf-8');
|
|
78
|
-
const parsedConfig = JSON.parse(configContent);
|
|
79
|
-
|
|
80
|
-
const convertedConfig = convertMcpServersToServers(parsedConfig);
|
|
81
|
-
const servers = convertedConfig.servers || {};
|
|
82
|
-
|
|
83
|
-
if (Object.keys(servers).length === 0) {
|
|
84
|
-
return res.status(400).json({
|
|
85
|
-
error: 'No servers found in config',
|
|
86
|
-
message: 'The config file does not contain any MCP servers',
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const discoveryPromises = Object.entries(servers).map(async ([serverName, serverConfig]) => {
|
|
91
|
-
try {
|
|
92
|
-
return await discoverServer(serverName, serverConfig);
|
|
93
|
-
} catch (error) {
|
|
94
|
-
logger.error({ serverName, error: error.message }, 'Error discovering server');
|
|
95
|
-
return {
|
|
96
|
-
name: serverName,
|
|
97
|
-
tools: [],
|
|
98
|
-
resources: [],
|
|
99
|
-
prompts: [],
|
|
100
|
-
error: error.message,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const discoveredServers = await Promise.all(discoveryPromises);
|
|
106
|
-
|
|
107
|
-
return res.json({
|
|
108
|
-
success: true,
|
|
109
|
-
servers: discoveredServers,
|
|
110
|
-
});
|
|
111
|
-
} catch (error) {
|
|
112
|
-
logger.error({ error: error.message }, 'Error discovering servers');
|
|
113
|
-
return res.status(500).json({
|
|
114
|
-
error: 'Failed to discover servers',
|
|
115
|
-
message: error.message,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import logger from '../../../utils/logger.js';
|
|
2
|
-
import { clearAllScanResults } from '../../../utils/scan-cache.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Clear all cached scan results
|
|
6
|
-
* POST /api/smartscan/cache/clear
|
|
7
|
-
*/
|
|
8
|
-
export function clearCache(_req, res) {
|
|
9
|
-
try {
|
|
10
|
-
const deletedCount = clearAllScanResults();
|
|
11
|
-
return res.json({
|
|
12
|
-
success: true,
|
|
13
|
-
message: `Cleared ${deletedCount} cached scan result${deletedCount !== 1 ? 's' : ''}`,
|
|
14
|
-
deletedCount,
|
|
15
|
-
});
|
|
16
|
-
} catch (error) {
|
|
17
|
-
logger.error({ error: error.message }, 'Error clearing cache');
|
|
18
|
-
return res.status(500).json({
|
|
19
|
-
error: 'Failed to clear cache',
|
|
20
|
-
message: error.message,
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
}
|