@mcp-shark/mcp-shark 1.5.3 → 1.5.5

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.
Files changed (188) hide show
  1. package/README.md +32 -96
  2. package/bin/mcp-shark.js +1 -1
  3. package/core/configs/codex.js +68 -0
  4. package/core/configs/environment.js +51 -0
  5. package/{lib/common → core}/configs/index.js +16 -1
  6. package/core/constants/Defaults.js +15 -0
  7. package/core/constants/HttpStatus.js +14 -0
  8. package/core/constants/Server.js +20 -0
  9. package/core/constants/StatusCodes.js +25 -0
  10. package/core/constants/index.js +7 -0
  11. package/core/container/DependencyContainer.js +179 -0
  12. package/core/db/init.js +33 -0
  13. package/core/index.js +10 -0
  14. package/{mcp-server/lib/common/error.js → core/libraries/ErrorLibrary.js} +4 -0
  15. package/core/libraries/LoggerLibrary.js +91 -0
  16. package/core/libraries/SerializationLibrary.js +32 -0
  17. package/core/libraries/bootstrap-logger.js +19 -0
  18. package/core/libraries/errors/ApplicationError.js +97 -0
  19. package/core/libraries/index.js +17 -0
  20. package/{mcp-server/lib → core/mcp-server}/auditor/audit.js +77 -53
  21. package/core/mcp-server/index.js +192 -0
  22. package/{mcp-server/lib → core/mcp-server}/server/external/all.js +1 -1
  23. package/core/mcp-server/server/external/config.js +75 -0
  24. package/{mcp-server/lib → core/mcp-server}/server/external/single/client.js +1 -1
  25. package/{mcp-server/lib → core/mcp-server}/server/external/single/request.js +1 -1
  26. package/{mcp-server/lib → core/mcp-server}/server/external/single/run.js +20 -11
  27. package/{mcp-server/lib → core/mcp-server}/server/external/single/transport.js +1 -1
  28. package/{mcp-server/lib → core/mcp-server}/server/internal/handlers/error.js +1 -1
  29. package/core/mcp-server/server/internal/handlers/prompts-get.js +28 -0
  30. package/core/mcp-server/server/internal/handlers/prompts-list.js +21 -0
  31. package/core/mcp-server/server/internal/handlers/resources-list.js +21 -0
  32. package/core/mcp-server/server/internal/handlers/resources-read.js +28 -0
  33. package/core/mcp-server/server/internal/handlers/tools-call.js +44 -0
  34. package/core/mcp-server/server/internal/handlers/tools-list.js +23 -0
  35. package/core/mcp-server/server/internal/run.js +53 -0
  36. package/{mcp-server/lib → core/mcp-server}/server/internal/server.js +11 -1
  37. package/core/models/ConversationFilters.js +31 -0
  38. package/core/models/ExportFormat.js +8 -0
  39. package/core/models/RequestFilters.js +43 -0
  40. package/core/models/SessionFilters.js +23 -0
  41. package/core/models/index.js +8 -0
  42. package/core/repositories/AuditRepository.js +233 -0
  43. package/core/repositories/ConversationRepository.js +182 -0
  44. package/core/repositories/PacketRepository.js +237 -0
  45. package/core/repositories/SchemaRepository.js +107 -0
  46. package/core/repositories/SessionRepository.js +59 -0
  47. package/core/repositories/StatisticsRepository.js +54 -0
  48. package/core/repositories/index.js +10 -0
  49. package/core/services/AuditService.js +144 -0
  50. package/core/services/BackupService.js +222 -0
  51. package/core/services/ConfigDetectionService.js +89 -0
  52. package/core/services/ConfigFileService.js +210 -0
  53. package/core/services/ConfigPatchingService.js +137 -0
  54. package/core/services/ConfigService.js +250 -0
  55. package/core/services/ConfigTransformService.js +178 -0
  56. package/core/services/ConversationService.js +19 -0
  57. package/core/services/ExportService.js +117 -0
  58. package/core/services/LogService.js +64 -0
  59. package/core/services/McpClientService.js +235 -0
  60. package/core/services/McpDiscoveryService.js +107 -0
  61. package/core/services/RequestService.js +56 -0
  62. package/core/services/ScanCacheService.js +242 -0
  63. package/core/services/ScanService.js +167 -0
  64. package/core/services/ServerManagementService.js +206 -0
  65. package/core/services/SessionService.js +34 -0
  66. package/core/services/SettingsService.js +163 -0
  67. package/core/services/StatisticsService.js +64 -0
  68. package/core/services/TokenService.js +94 -0
  69. package/core/services/index.js +25 -0
  70. package/core/services/parsers/ConfigParserFactory.js +113 -0
  71. package/core/services/parsers/JsonConfigParser.js +66 -0
  72. package/core/services/parsers/LegacyJsonConfigParser.js +71 -0
  73. package/core/services/parsers/TomlConfigParser.js +87 -0
  74. package/core/services/parsers/index.js +4 -0
  75. package/{ui/server → core}/utils/scan-cache/directory.js +1 -1
  76. package/core/utils/validation.js +77 -0
  77. package/package.json +14 -11
  78. package/ui/dist/assets/index-CArYxKxS.js +35 -0
  79. package/ui/dist/index.html +1 -1
  80. package/ui/server/controllers/BackupController.js +129 -0
  81. package/ui/server/controllers/ConfigController.js +92 -0
  82. package/ui/server/controllers/ConversationController.js +41 -0
  83. package/ui/server/controllers/LogController.js +44 -0
  84. package/ui/server/controllers/McpClientController.js +60 -0
  85. package/ui/server/controllers/McpDiscoveryController.js +44 -0
  86. package/ui/server/controllers/RequestController.js +129 -0
  87. package/ui/server/controllers/ScanController.js +122 -0
  88. package/ui/server/controllers/ServerManagementController.js +134 -0
  89. package/ui/server/controllers/SessionController.js +57 -0
  90. package/ui/server/controllers/SettingsController.js +24 -0
  91. package/ui/server/controllers/StatisticsController.js +54 -0
  92. package/ui/server/controllers/TokenController.js +58 -0
  93. package/ui/server/controllers/index.js +17 -0
  94. package/ui/server/routes/backups/index.js +15 -9
  95. package/ui/server/routes/composite/index.js +62 -32
  96. package/ui/server/routes/composite/servers.js +20 -15
  97. package/ui/server/routes/config.js +13 -172
  98. package/ui/server/routes/conversations.js +9 -19
  99. package/ui/server/routes/help.js +4 -3
  100. package/ui/server/routes/logs.js +14 -26
  101. package/ui/server/routes/playground.js +11 -174
  102. package/ui/server/routes/requests.js +12 -232
  103. package/ui/server/routes/sessions.js +10 -21
  104. package/ui/server/routes/settings.js +10 -192
  105. package/ui/server/routes/smartscan.js +26 -15
  106. package/ui/server/routes/statistics.js +8 -79
  107. package/ui/server/setup.js +162 -0
  108. package/ui/server/swagger/paths/backups.js +151 -0
  109. package/ui/server/swagger/paths/components.js +76 -0
  110. package/ui/server/swagger/paths/config.js +117 -0
  111. package/ui/server/swagger/paths/conversations.js +29 -0
  112. package/ui/server/swagger/paths/help.js +82 -0
  113. package/ui/server/swagger/paths/logs.js +87 -0
  114. package/ui/server/swagger/paths/playground.js +49 -0
  115. package/ui/server/swagger/paths/requests.js +178 -0
  116. package/ui/server/swagger/paths/serverManagement.js +169 -0
  117. package/ui/server/swagger/paths/sessions.js +61 -0
  118. package/ui/server/swagger/paths/settings.js +31 -0
  119. package/ui/server/swagger/paths/smartScan/discovery.js +97 -0
  120. package/ui/server/swagger/paths/smartScan/index.js +13 -0
  121. package/ui/server/swagger/paths/smartScan/scans.js +151 -0
  122. package/ui/server/swagger/paths/smartScan/token.js +71 -0
  123. package/ui/server/swagger/paths/statistics.js +40 -0
  124. package/ui/server/swagger/paths.js +38 -0
  125. package/ui/server/swagger/swagger.js +37 -0
  126. package/ui/server/utils/cleanup.js +99 -0
  127. package/ui/server/utils/config.js +18 -96
  128. package/ui/server/utils/errorHandler.js +43 -0
  129. package/ui/server/utils/logger.js +2 -2
  130. package/ui/server/utils/paths.js +27 -30
  131. package/ui/server/utils/port.js +21 -21
  132. package/ui/server/utils/process.js +18 -10
  133. package/ui/server/utils/processState.js +17 -0
  134. package/ui/server/utils/signals.js +34 -0
  135. package/ui/server/websocket/broadcast.js +33 -0
  136. package/ui/server/websocket/handler.js +52 -0
  137. package/ui/server.js +51 -230
  138. package/ui/src/App.jsx +2 -0
  139. package/ui/src/CompositeSetup.jsx +23 -9
  140. package/ui/src/PacketFilters.jsx +17 -3
  141. package/ui/src/components/AlertModal.jsx +116 -0
  142. package/ui/src/components/App/ApiDocsButton.jsx +57 -0
  143. package/ui/src/components/App/useAppState.js +43 -1
  144. package/ui/src/components/BackupList.jsx +27 -3
  145. package/ui/src/utils/requestPairing.js +35 -36
  146. package/ui/src/utils/requestUtils.js +1 -0
  147. package/lib/common/db/init.js +0 -132
  148. package/lib/common/db/logger.js +0 -349
  149. package/lib/common/db/query.js +0 -403
  150. package/lib/common/logger.js +0 -90
  151. package/mcp-server/index.js +0 -111
  152. package/mcp-server/lib/server/external/config.js +0 -57
  153. package/mcp-server/lib/server/internal/handlers/prompts-get.js +0 -20
  154. package/mcp-server/lib/server/internal/handlers/prompts-list.js +0 -13
  155. package/mcp-server/lib/server/internal/handlers/resources-list.js +0 -13
  156. package/mcp-server/lib/server/internal/handlers/resources-read.js +0 -20
  157. package/mcp-server/lib/server/internal/handlers/tools-call.js +0 -35
  158. package/mcp-server/lib/server/internal/handlers/tools-list.js +0 -15
  159. package/mcp-server/lib/server/internal/run.js +0 -37
  160. package/mcp-server/mcp-shark.js +0 -22
  161. package/ui/dist/assets/index-CFHeMNwd.js +0 -35
  162. package/ui/server/routes/backups/deleteBackup.js +0 -54
  163. package/ui/server/routes/backups/listBackups.js +0 -75
  164. package/ui/server/routes/backups/restoreBackup.js +0 -83
  165. package/ui/server/routes/backups/viewBackup.js +0 -47
  166. package/ui/server/routes/composite/setup.js +0 -129
  167. package/ui/server/routes/composite/status.js +0 -7
  168. package/ui/server/routes/composite/stop.js +0 -39
  169. package/ui/server/routes/composite/utils.js +0 -45
  170. package/ui/server/routes/smartscan/discover.js +0 -118
  171. package/ui/server/routes/smartscan/scans/clearCache.js +0 -23
  172. package/ui/server/routes/smartscan/scans/createBatchScans.js +0 -124
  173. package/ui/server/routes/smartscan/scans/createScan.js +0 -43
  174. package/ui/server/routes/smartscan/scans/getCachedResults.js +0 -52
  175. package/ui/server/routes/smartscan/scans/getScan.js +0 -42
  176. package/ui/server/routes/smartscan/scans/listScans.js +0 -25
  177. package/ui/server/routes/smartscan/scans.js +0 -13
  178. package/ui/server/routes/smartscan/token.js +0 -57
  179. package/ui/server/utils/config-update.js +0 -240
  180. package/ui/server/utils/scan-cache/all-results.js +0 -197
  181. package/ui/server/utils/scan-cache/file-operations.js +0 -107
  182. package/ui/server/utils/scan-cache/hash.js +0 -47
  183. package/ui/server/utils/scan-cache/server-operations.js +0 -85
  184. package/ui/server/utils/scan-cache.js +0 -12
  185. package/ui/server/utils/smartscan-token.js +0 -43
  186. /package/{mcp-server/lib → core/mcp-server}/server/external/kv.js +0 -0
  187. /package/{mcp-server/lib → core/mcp-server}/server/internal/handlers/common.js +0 -0
  188. /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,7 +0,0 @@
1
- export function getStatus(_req, res, getMcpSharkProcess) {
2
- const currentServer = getMcpSharkProcess();
3
- res.json({
4
- running: currentServer !== null,
5
- pid: null, // No process PID when using library
6
- });
7
- }
@@ -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
- }