@mcp-shark/mcp-shark 1.4.2 → 1.5.0

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 (203) hide show
  1. package/README.md +84 -645
  2. package/bin/mcp-shark.js +30 -36
  3. package/mcp-server/index.js +115 -0
  4. package/mcp-server/lib/auditor/audit.js +22 -38
  5. package/mcp-server/lib/common/error.js +1 -1
  6. package/mcp-server/lib/server/external/all.js +5 -6
  7. package/mcp-server/lib/server/external/config.js +1 -3
  8. package/mcp-server/lib/server/external/kv.js +4 -12
  9. package/mcp-server/lib/server/external/single/request.js +3 -6
  10. package/mcp-server/lib/server/external/single/run.js +8 -19
  11. package/mcp-server/lib/server/internal/handlers/prompts-get.js +3 -13
  12. package/mcp-server/lib/server/internal/handlers/prompts-list.js +2 -6
  13. package/mcp-server/lib/server/internal/handlers/resources-list.js +2 -6
  14. package/mcp-server/lib/server/internal/handlers/resources-read.js +3 -12
  15. package/mcp-server/lib/server/internal/handlers/tools-call.js +3 -9
  16. package/mcp-server/lib/server/internal/handlers/tools-list.js +2 -2
  17. package/mcp-server/lib/server/internal/run.js +4 -16
  18. package/mcp-server/lib/server/internal/server.js +6 -7
  19. package/mcp-server/lib/server/internal/session.js +2 -15
  20. package/mcp-server/mcp-shark.js +16 -66
  21. package/package.json +23 -38
  22. package/ui/dist/assets/index-Cc-IUa83.css +1 -0
  23. package/ui/dist/assets/index-srLDlk97.js +35 -0
  24. package/ui/dist/index.html +17 -0
  25. package/ui/dist/og-image.png +0 -0
  26. package/ui/server/routes/backups/deleteBackup.js +54 -0
  27. package/ui/server/routes/backups/index.js +15 -0
  28. package/ui/server/routes/backups/listBackups.js +75 -0
  29. package/ui/server/routes/backups/restoreBackup.js +83 -0
  30. package/ui/server/routes/backups/viewBackup.js +47 -0
  31. package/ui/server/routes/composite/index.js +46 -0
  32. package/ui/server/routes/composite/servers.js +18 -0
  33. package/ui/server/routes/composite/setup.js +129 -0
  34. package/ui/server/routes/composite/status.js +7 -0
  35. package/ui/server/routes/composite/stop.js +39 -0
  36. package/ui/server/routes/composite/utils.js +45 -0
  37. package/ui/server/routes/config.js +34 -30
  38. package/ui/server/routes/conversations.js +3 -3
  39. package/ui/server/routes/help.js +2 -2
  40. package/ui/server/routes/logs.js +5 -5
  41. package/ui/server/routes/playground.js +45 -47
  42. package/ui/server/routes/requests.js +112 -108
  43. package/ui/server/routes/sessions.js +4 -4
  44. package/ui/server/routes/settings.js +199 -0
  45. package/ui/server/routes/smartscan/discover.js +7 -6
  46. package/ui/server/routes/smartscan/scans/clearCache.js +3 -2
  47. package/ui/server/routes/smartscan/scans/createBatchScans.js +4 -3
  48. package/ui/server/routes/smartscan/scans/createScan.js +2 -1
  49. package/ui/server/routes/smartscan/scans/getCachedResults.js +2 -1
  50. package/ui/server/routes/smartscan/scans/getScan.js +2 -1
  51. package/ui/server/routes/smartscan/scans/listScans.js +5 -4
  52. package/ui/server/routes/smartscan/scans.js +3 -3
  53. package/ui/server/routes/smartscan/token.js +4 -3
  54. package/ui/server/routes/smartscan/transport.js +1 -1
  55. package/ui/server/routes/smartscan.js +1 -1
  56. package/ui/server/routes/statistics.js +13 -10
  57. package/ui/server/utils/config-update.js +7 -6
  58. package/ui/server/utils/config.js +4 -4
  59. package/ui/server/utils/logger.js +2 -0
  60. package/ui/server/utils/paths.js +210 -2
  61. package/ui/server/utils/port.js +2 -2
  62. package/ui/server/utils/process.js +0 -67
  63. package/ui/server/utils/scan-cache/all-results.js +76 -59
  64. package/ui/server/utils/scan-cache/directory.js +1 -1
  65. package/ui/server/utils/scan-cache/file-operations.js +19 -16
  66. package/ui/server/utils/scan-cache/server-operations.js +14 -9
  67. package/ui/server/utils/serialization.js +9 -3
  68. package/ui/server/utils/smartscan-token.js +4 -3
  69. package/ui/server.js +86 -41
  70. package/ui/src/App.jsx +5 -5
  71. package/ui/src/CompositeLogs.jsx +20 -20
  72. package/ui/src/CompositeSetup.jsx +9 -9
  73. package/ui/src/HelpGuide/HelpGuideFooter.jsx +1 -0
  74. package/ui/src/HelpGuide/HelpGuideHeader.jsx +2 -1
  75. package/ui/src/HelpGuide.jsx +17 -4
  76. package/ui/src/IntroTour.jsx +19 -5
  77. package/ui/src/LogDetail.jsx +1 -0
  78. package/ui/src/LogTable.jsx +24 -6
  79. package/ui/src/PacketDetail.jsx +21 -16
  80. package/ui/src/PacketFilters.jsx +29 -14
  81. package/ui/src/PacketList.jsx +4 -5
  82. package/ui/src/SmartScan.jsx +5 -5
  83. package/ui/src/TabNavigation.jsx +5 -5
  84. package/ui/src/components/App/HelpButton.jsx +4 -0
  85. package/ui/src/components/App/TrafficTab.jsx +4 -4
  86. package/ui/src/components/App/useAppState.js +118 -24
  87. package/ui/src/components/BackupList.jsx +6 -2
  88. package/ui/src/components/CollapsibleSection.jsx +16 -2
  89. package/ui/src/components/ConfigViewerModal.jsx +17 -3
  90. package/ui/src/components/ConfirmationModal.jsx +20 -3
  91. package/ui/src/components/DetailsTab/BodySection.jsx +3 -1
  92. package/ui/src/components/DetailsTab/CollapsibleRequestResponse.jsx +14 -3
  93. package/ui/src/components/DetailsTab/InfoSection.jsx +4 -2
  94. package/ui/src/components/DetailsTab/RequestDetailsSection.jsx +7 -5
  95. package/ui/src/components/DetailsTab/ResponseDetailsSection.jsx +7 -5
  96. package/ui/src/components/DetectedPathsList.jsx +5 -2
  97. package/ui/src/components/FileInput.jsx +3 -1
  98. package/ui/src/components/GroupHeader.jsx +14 -0
  99. package/ui/src/components/GroupedByMcpView.jsx +3 -4
  100. package/ui/src/components/GroupedByServerView.jsx +1 -1
  101. package/ui/src/components/GroupedBySessionView.jsx +1 -1
  102. package/ui/src/components/HexTab.jsx +17 -4
  103. package/ui/src/components/LogsToolbar.jsx +3 -1
  104. package/ui/src/components/McpPlayground/LoadingModal.jsx +7 -3
  105. package/ui/src/components/McpPlayground/PromptsSection/PromptCallPanel.jsx +5 -0
  106. package/ui/src/components/McpPlayground/PromptsSection/PromptItem.jsx +6 -2
  107. package/ui/src/components/McpPlayground/PromptsSection/PromptsList.jsx +4 -4
  108. package/ui/src/components/McpPlayground/PromptsSection.jsx +2 -1
  109. package/ui/src/components/McpPlayground/ResourcesSection/ResourceCallPanel.jsx +3 -0
  110. package/ui/src/components/McpPlayground/ResourcesSection/ResourceItem.jsx +6 -2
  111. package/ui/src/components/McpPlayground/ResourcesSection/ResourcesList.jsx +4 -4
  112. package/ui/src/components/McpPlayground/ResourcesSection.jsx +2 -1
  113. package/ui/src/components/McpPlayground/ToolsSection/ToolCallPanel.jsx +5 -0
  114. package/ui/src/components/McpPlayground/ToolsSection/ToolItem.jsx +6 -2
  115. package/ui/src/components/McpPlayground/ToolsSection/ToolsList.jsx +4 -4
  116. package/ui/src/components/McpPlayground/ToolsSection.jsx +2 -1
  117. package/ui/src/components/McpPlayground/hooks/useMcpDataLoader.js +9 -9
  118. package/ui/src/components/McpPlayground/hooks/useMcpRequest.js +10 -5
  119. package/ui/src/components/McpPlayground/hooks/useMcpServerStatus.js +43 -23
  120. package/ui/src/components/McpPlayground/useMcpPlayground.js +72 -44
  121. package/ui/src/components/McpPlayground.jsx +5 -2
  122. package/ui/src/components/PacketDetailHeader.jsx +8 -3
  123. package/ui/src/components/PacketFilters/ExportControls.jsx +2 -1
  124. package/ui/src/components/PacketFilters/FilterInput.jsx +1 -1
  125. package/ui/src/components/RawTab.jsx +15 -2
  126. package/ui/src/components/RequestRow/OrphanedResponseRow.jsx +10 -2
  127. package/ui/src/components/RequestRow/RequestRowMain.jsx +12 -3
  128. package/ui/src/components/RequestRow/ResponseRow.jsx +11 -3
  129. package/ui/src/components/RequestRow.jsx +17 -9
  130. package/ui/src/components/ServerControl.jsx +3 -1
  131. package/ui/src/components/ServiceSelector.jsx +2 -0
  132. package/ui/src/components/SmartScan/AnalysisResult.jsx +2 -2
  133. package/ui/src/components/SmartScan/BatchResultsDisplay/BatchResultItem.jsx +2 -1
  134. package/ui/src/components/SmartScan/BatchResultsDisplay/BatchResultsHeader.jsx +1 -1
  135. package/ui/src/components/SmartScan/BatchResultsDisplay.jsx +9 -3
  136. package/ui/src/components/SmartScan/EmptyState.jsx +3 -0
  137. package/ui/src/components/SmartScan/ErrorDisplay.jsx +4 -2
  138. package/ui/src/components/SmartScan/ExpandableSection.jsx +4 -0
  139. package/ui/src/components/SmartScan/FindingsTable.jsx +46 -42
  140. package/ui/src/components/SmartScan/ListViewContent.jsx +2 -2
  141. package/ui/src/components/SmartScan/NotablePatternsSection.jsx +13 -8
  142. package/ui/src/components/SmartScan/OverallSummarySection.jsx +36 -29
  143. package/ui/src/components/SmartScan/RecommendationsSection.jsx +10 -8
  144. package/ui/src/components/SmartScan/ScanDetailHeader.jsx +2 -1
  145. package/ui/src/components/SmartScan/ScanDetailView.jsx +4 -4
  146. package/ui/src/components/SmartScan/ScanListView/ScanListHeader.jsx +2 -1
  147. package/ui/src/components/SmartScan/ScanListView/ScanListItem.jsx +15 -1
  148. package/ui/src/components/SmartScan/ScanOverviewSection.jsx +3 -1
  149. package/ui/src/components/SmartScan/ScanResultsDisplay.jsx +1 -1
  150. package/ui/src/components/SmartScan/ScanViewContent.jsx +2 -2
  151. package/ui/src/components/SmartScan/ScanningProgress.jsx +4 -2
  152. package/ui/src/components/SmartScan/ServerInfoSection.jsx +3 -1
  153. package/ui/src/components/SmartScan/ServerSelectionRow.jsx +4 -2
  154. package/ui/src/components/SmartScan/SingleResultDisplay.jsx +5 -3
  155. package/ui/src/components/SmartScan/SmartScanControls.jsx +11 -7
  156. package/ui/src/components/SmartScan/SmartScanHeader.jsx +1 -1
  157. package/ui/src/components/SmartScan/ViewModeTabs.jsx +2 -0
  158. package/ui/src/components/SmartScan/hooks/useCacheManagement.js +1 -2
  159. package/ui/src/components/SmartScan/hooks/useMcpDiscovery.js +22 -26
  160. package/ui/src/components/SmartScan/hooks/useScanList.js +10 -9
  161. package/ui/src/components/SmartScan/hooks/useScanOperations.js +23 -14
  162. package/ui/src/components/SmartScan/hooks/useServerStatus.js +2 -2
  163. package/ui/src/components/SmartScan/hooks/useTokenManagement.js +2 -2
  164. package/ui/src/components/SmartScan/scanDataUtils.js +22 -17
  165. package/ui/src/components/SmartScan/useSmartScan.js +4 -4
  166. package/ui/src/components/SmartScan/utils.js +3 -1
  167. package/ui/src/components/SmartScanIcons.jsx +6 -3
  168. package/ui/src/components/TabNavigation/DesktopTabs.jsx +8 -3
  169. package/ui/src/components/TabNavigation/MobileDropdown.jsx +3 -1
  170. package/ui/src/components/TabNavigation.jsx +8 -3
  171. package/ui/src/components/TabNavigationIcons.jsx +4 -4
  172. package/ui/src/components/TourOverlay.jsx +1 -1
  173. package/ui/src/components/TourTooltip/TourTooltipButtons.jsx +3 -0
  174. package/ui/src/components/TourTooltip/TourTooltipHeader.jsx +1 -0
  175. package/ui/src/components/TourTooltip/TourTooltipIcons.jsx +9 -0
  176. package/ui/src/components/TourTooltip/useTooltipPosition.js +63 -36
  177. package/ui/src/components/TourTooltip.jsx +11 -3
  178. package/ui/src/components/ViewModeTabs.jsx +3 -1
  179. package/ui/src/config/tourSteps.jsx +0 -2
  180. package/ui/src/hooks/useAnimation.js +15 -12
  181. package/ui/src/hooks/useConfigManagement.js +8 -8
  182. package/ui/src/hooks/useServiceExtraction.js +1 -1
  183. package/ui/src/index.css +3 -8
  184. package/ui/src/theme.js +3 -3
  185. package/ui/src/utils/hexUtils.js +11 -5
  186. package/ui/src/utils/mcpGroupingUtils.js +18 -10
  187. package/ui/src/utils/requestPairing.js +89 -0
  188. package/ui/src/utils/requestUtils.js +32 -101
  189. package/ui/vite.config.js +1 -1
  190. package/mcp-server/.editorconfig +0 -15
  191. package/mcp-server/.prettierignore +0 -11
  192. package/mcp-server/.prettierrc +0 -12
  193. package/mcp-server/README.md +0 -280
  194. package/mcp-server/commitlint.config.cjs +0 -42
  195. package/mcp-server/eslint.config.js +0 -131
  196. package/mcp-server/package-lock.json +0 -4784
  197. package/mcp-server/package.json +0 -30
  198. package/ui/README.md +0 -212
  199. package/ui/package-lock.json +0 -3574
  200. package/ui/package.json +0 -12
  201. package/ui/paths.js +0 -282
  202. package/ui/server/routes/backups.js +0 -251
  203. package/ui/server/routes/composite.js +0 -260
@@ -0,0 +1,199 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { getDatabaseFile, getWorkingDirectory } from 'mcp-shark-common/configs/index.js';
5
+ import logger from '../utils/logger.js';
6
+ import { getScanResultsDirectory } from '../utils/scan-cache/directory.js';
7
+
8
+ const SMART_SCAN_TOKEN_NAME = 'smart-scan-token.json';
9
+
10
+ function getSmartScanTokenPath() {
11
+ return join(getWorkingDirectory(), SMART_SCAN_TOKEN_NAME);
12
+ }
13
+
14
+ function getTokenMetadata() {
15
+ try {
16
+ const tokenPath = getSmartScanTokenPath();
17
+ if (existsSync(tokenPath)) {
18
+ const content = readFileSync(tokenPath, 'utf8');
19
+ const data = JSON.parse(content);
20
+ const stats = statSync(tokenPath);
21
+ return {
22
+ token: data.token || null,
23
+ updatedAt: data.updatedAt || stats.mtime.toISOString(),
24
+ path: tokenPath,
25
+ exists: true,
26
+ };
27
+ }
28
+ return {
29
+ token: null,
30
+ updatedAt: null,
31
+ path: tokenPath,
32
+ exists: false,
33
+ };
34
+ } catch (error) {
35
+ logger.error({ error: error.message }, 'Error reading Smart Scan token metadata');
36
+ return {
37
+ token: null,
38
+ updatedAt: null,
39
+ path: getSmartScanTokenPath(),
40
+ exists: false,
41
+ };
42
+ }
43
+ }
44
+
45
+ function getBackupCount() {
46
+ try {
47
+ const homeDir = homedir();
48
+ const backupDirs = [join(homeDir, '.cursor'), join(homeDir, '.codeium', 'windsurf')];
49
+
50
+ const newFormatCount = backupDirs.reduce((count, dir) => {
51
+ if (existsSync(dir)) {
52
+ const files = readdirSync(dir);
53
+ const matchingFiles = files.filter((file) => {
54
+ return /^\.(.+)-mcpshark\.\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}\.json$/.test(file);
55
+ });
56
+ return count + matchingFiles.length;
57
+ }
58
+ return count;
59
+ }, 0);
60
+
61
+ // Also count old .backup format
62
+ const commonPaths = [
63
+ join(homeDir, '.cursor', 'mcp.json'),
64
+ join(homeDir, '.codeium', 'windsurf', 'mcp_config.json'),
65
+ ];
66
+ const oldFormatCount = commonPaths.reduce((count, configPath) => {
67
+ if (existsSync(`${configPath}.backup`)) {
68
+ return count + 1;
69
+ }
70
+ return count;
71
+ }, 0);
72
+
73
+ return newFormatCount + oldFormatCount;
74
+ } catch (error) {
75
+ logger.error({ error: error.message }, 'Error counting backups');
76
+ return 0;
77
+ }
78
+ }
79
+
80
+ function toDisplayPath(absolutePath) {
81
+ const homeDir = homedir();
82
+ return absolutePath.replace(homeDir, '~');
83
+ }
84
+
85
+ export function createSettingsRoutes() {
86
+ const router = {};
87
+
88
+ router.getSettings = (_req, res) => {
89
+ try {
90
+ const homeDir = homedir();
91
+ const workingDir = getWorkingDirectory();
92
+ const databasePath = getDatabaseFile();
93
+ const scanResultsDir = getScanResultsDirectory();
94
+ const tokenPath = getSmartScanTokenPath();
95
+ const tokenMetadata = getTokenMetadata();
96
+
97
+ const cursorConfigPath = join(homeDir, '.cursor', 'mcp.json');
98
+ const windsurfConfigPath = join(homeDir, '.codeium', 'windsurf', 'mcp_config.json');
99
+
100
+ const cursorBackupDir = join(homeDir, '.cursor');
101
+ const windsurfBackupDir = join(homeDir, '.codeium', 'windsurf');
102
+
103
+ const settings = {
104
+ paths: {
105
+ workingDirectory: {
106
+ absolute: workingDir,
107
+ display: toDisplayPath(workingDir),
108
+ exists: existsSync(workingDir),
109
+ },
110
+ database: {
111
+ absolute: databasePath,
112
+ display: toDisplayPath(databasePath),
113
+ exists: existsSync(databasePath),
114
+ },
115
+ smartScanResults: {
116
+ absolute: scanResultsDir,
117
+ display: toDisplayPath(scanResultsDir),
118
+ exists: existsSync(scanResultsDir),
119
+ },
120
+ smartScanToken: {
121
+ absolute: tokenPath,
122
+ display: toDisplayPath(tokenPath),
123
+ exists: tokenMetadata.exists,
124
+ },
125
+ backupDirectories: {
126
+ cursor: {
127
+ absolute: cursorBackupDir,
128
+ display: toDisplayPath(cursorBackupDir),
129
+ exists: existsSync(cursorBackupDir),
130
+ },
131
+ windsurf: {
132
+ absolute: windsurfBackupDir,
133
+ display: toDisplayPath(windsurfBackupDir),
134
+ exists: existsSync(windsurfBackupDir),
135
+ },
136
+ },
137
+ configFiles: {
138
+ cursor: {
139
+ absolute: cursorConfigPath,
140
+ display: toDisplayPath(cursorConfigPath),
141
+ exists: existsSync(cursorConfigPath),
142
+ },
143
+ windsurf: {
144
+ absolute: windsurfConfigPath,
145
+ display: toDisplayPath(windsurfConfigPath),
146
+ exists: existsSync(windsurfConfigPath),
147
+ },
148
+ },
149
+ },
150
+ smartScan: {
151
+ token: tokenMetadata.token,
152
+ tokenPath: {
153
+ absolute: tokenMetadata.path,
154
+ display: toDisplayPath(tokenMetadata.path),
155
+ },
156
+ tokenUpdatedAt: tokenMetadata.updatedAt,
157
+ tokenExists: tokenMetadata.exists,
158
+ },
159
+ database: {
160
+ path: {
161
+ absolute: databasePath,
162
+ display: toDisplayPath(databasePath),
163
+ },
164
+ exists: existsSync(databasePath),
165
+ },
166
+ system: {
167
+ platform: process.platform,
168
+ homeDirectory: {
169
+ absolute: homeDir,
170
+ display: '~',
171
+ },
172
+ },
173
+ backups: {
174
+ directories: [
175
+ {
176
+ absolute: cursorBackupDir,
177
+ display: toDisplayPath(cursorBackupDir),
178
+ },
179
+ {
180
+ absolute: windsurfBackupDir,
181
+ display: toDisplayPath(windsurfBackupDir),
182
+ },
183
+ ],
184
+ count: getBackupCount(),
185
+ },
186
+ };
187
+
188
+ res.json(settings);
189
+ } catch (error) {
190
+ logger.error({ error: error.message }, 'Error getting settings');
191
+ res.status(500).json({
192
+ error: 'Failed to get settings',
193
+ details: error.message,
194
+ });
195
+ }
196
+ };
197
+
198
+ return router;
199
+ }
@@ -1,7 +1,8 @@
1
- import { getMcpConfigPath } from 'mcp-shark-common/configs/index.js';
2
- import { readFileSync, existsSync } from 'node:fs';
1
+ import { existsSync, readFileSync } from 'node:fs';
3
2
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
3
+ import { getMcpConfigPath } from 'mcp-shark-common/configs/index.js';
4
4
  import { convertMcpServersToServers } from '../../utils/config.js';
5
+ import logger from '../../utils/logger.js';
5
6
  import { createTransport } from './transport.js';
6
7
 
7
8
  /**
@@ -51,7 +52,7 @@ async function discoverServer(serverName, serverConfig) {
51
52
  if (transport.close) {
52
53
  await transport.close();
53
54
  }
54
- } catch (closeError) {
55
+ } catch (_closeError) {
55
56
  // Ignore close errors
56
57
  }
57
58
  throw error;
@@ -62,7 +63,7 @@ async function discoverServer(serverName, serverConfig) {
62
63
  * Discover all MCP servers from config
63
64
  * GET /api/smartscan/discover
64
65
  */
65
- export async function discoverServers(req, res) {
66
+ export async function discoverServers(_req, res) {
66
67
  try {
67
68
  const configPath = getMcpConfigPath();
68
69
 
@@ -90,7 +91,7 @@ export async function discoverServers(req, res) {
90
91
  try {
91
92
  return await discoverServer(serverName, serverConfig);
92
93
  } catch (error) {
93
- console.error(`Error discovering server ${serverName}:`, error);
94
+ logger.error({ serverName, error: error.message }, 'Error discovering server');
94
95
  return {
95
96
  name: serverName,
96
97
  tools: [],
@@ -108,7 +109,7 @@ export async function discoverServers(req, res) {
108
109
  servers: discoveredServers,
109
110
  });
110
111
  } catch (error) {
111
- console.error('Error discovering servers:', error);
112
+ logger.error({ error: error.message }, 'Error discovering servers');
112
113
  return res.status(500).json({
113
114
  error: 'Failed to discover servers',
114
115
  message: error.message,
@@ -1,10 +1,11 @@
1
+ import logger from '../../../utils/logger.js';
1
2
  import { clearAllScanResults } from '../../../utils/scan-cache.js';
2
3
 
3
4
  /**
4
5
  * Clear all cached scan results
5
6
  * POST /api/smartscan/cache/clear
6
7
  */
7
- export function clearCache(req, res) {
8
+ export function clearCache(_req, res) {
8
9
  try {
9
10
  const deletedCount = clearAllScanResults();
10
11
  return res.json({
@@ -13,7 +14,7 @@ export function clearCache(req, res) {
13
14
  deletedCount,
14
15
  });
15
16
  } catch (error) {
16
- console.error('Error clearing cache:', error);
17
+ logger.error({ error: error.message }, 'Error clearing cache');
17
18
  return res.status(500).json({
18
19
  error: 'Failed to clear cache',
19
20
  message: error.message,
@@ -1,4 +1,5 @@
1
1
  const API_BASE_URL = 'https://smart.mcpshark.sh';
2
+ import logger from '../../../utils/logger.js';
2
3
  import { computeMcpHash, getCachedScanResult, storeScanResult } from '../../../utils/scan-cache.js';
3
4
 
4
5
  /**
@@ -25,7 +26,7 @@ export async function createBatchScans(req, res) {
25
26
  const hash = computeMcpHash(serverData);
26
27
  const cachedResult = getCachedScanResult(hash);
27
28
  if (cachedResult) {
28
- console.log(`Using cached scan result for server: ${serverData.name}`);
29
+ logger.info({ serverName: serverData.name }, 'Using cached scan result for server');
29
30
  return {
30
31
  serverName: serverData.name,
31
32
  success: true,
@@ -91,7 +92,7 @@ export async function createBatchScans(req, res) {
91
92
 
92
93
  if (response.ok && data) {
93
94
  storeScanResult(serverData.name, hash, data);
94
- console.log(`Stored scan result in cache for server: ${serverData.name}`);
95
+ logger.info({ serverName: serverData.name }, 'Stored scan result in cache for server');
95
96
  }
96
97
 
97
98
  return result;
@@ -114,7 +115,7 @@ export async function createBatchScans(req, res) {
114
115
  results,
115
116
  });
116
117
  } catch (error) {
117
- console.error('Smart Scan batch API error:', error);
118
+ logger.error({ error: error.message }, 'Smart Scan batch API error');
118
119
  return res.status(500).json({
119
120
  error: 'Failed to create batch scans',
120
121
  message: error.message,
@@ -1,4 +1,5 @@
1
1
  const API_BASE_URL = 'https://smart.mcpshark.sh';
2
+ import logger from '../../../utils/logger.js';
2
3
 
3
4
  /**
4
5
  * Proxy POST request to create a scan
@@ -33,7 +34,7 @@ export async function createScan(req, res) {
33
34
  const data = await response.json();
34
35
  return res.status(response.status).json(data);
35
36
  } catch (error) {
36
- console.error('Smart Scan API error:', error);
37
+ logger.error({ error: error.message }, 'Smart Scan API error');
37
38
  return res.status(500).json({
38
39
  error: 'Failed to create scan',
39
40
  message: error.message,
@@ -1,3 +1,4 @@
1
+ import logger from '../../../utils/logger.js';
1
2
  import { computeMcpHash, getCachedScanResult } from '../../../utils/scan-cache.js';
2
3
 
3
4
  /**
@@ -42,7 +43,7 @@ export function getCachedResults(req, res) {
42
43
  results: cachedResults,
43
44
  });
44
45
  } catch (error) {
45
- console.error('Error getting cached results:', error);
46
+ logger.error({ error: error.message }, 'Error getting cached results');
46
47
  return res.status(500).json({
47
48
  error: 'Failed to get cached results',
48
49
  message: error.message,
@@ -1,4 +1,5 @@
1
1
  const API_BASE_URL = 'https://smart.mcpshark.sh';
2
+ import logger from '../../../utils/logger.js';
2
3
 
3
4
  /**
4
5
  * Proxy GET request to get a scan by ID
@@ -32,7 +33,7 @@ export async function getScan(req, res) {
32
33
  const data = await response.json();
33
34
  return res.status(response.status).json(data);
34
35
  } catch (error) {
35
- console.error('Smart Scan API error:', error);
36
+ logger.error({ error: error.message }, 'Smart Scan API error');
36
37
  return res.status(500).json({
37
38
  error: 'Failed to get scan',
38
39
  message: error.message,
@@ -1,21 +1,22 @@
1
+ import logger from '../../../utils/logger.js';
1
2
  import { getAllCachedScanResults } from '../../../utils/scan-cache.js';
2
3
 
3
4
  /**
4
5
  * List all scans from local cache only
5
6
  * GET /api/smartscan/scans?cache=true
6
7
  */
7
- export async function listScans(req, res) {
8
+ export async function listScans(_req, res) {
8
9
  try {
9
- console.log('[listScans] Loading cached scans from local storage...');
10
+ logger.info('Loading cached scans from local storage');
10
11
  const cachedScans = getAllCachedScanResults();
11
- console.log(`[listScans] Returning ${cachedScans.length} cached scans`);
12
+ logger.info({ count: cachedScans.length }, 'Returning cached scans');
12
13
  return res.json({
13
14
  scans: cachedScans,
14
15
  cached: true,
15
16
  count: cachedScans.length,
16
17
  });
17
18
  } catch (error) {
18
- console.error('[listScans] Error loading cached scans:', error);
19
+ logger.error({ error: error.message }, 'Error loading cached scans');
19
20
  return res.status(500).json({
20
21
  error: 'Failed to load cached scans',
21
22
  message: error.message,
@@ -1,9 +1,9 @@
1
+ import * as clearCacheRoute from './scans/clearCache.js';
2
+ import * as createBatchScansRoute from './scans/createBatchScans.js';
1
3
  import * as createScanRoute from './scans/createScan.js';
2
- import * as getScanRoute from './scans/getScan.js';
3
4
  import * as getCachedResultsRoute from './scans/getCachedResults.js';
4
- import * as createBatchScansRoute from './scans/createBatchScans.js';
5
+ import * as getScanRoute from './scans/getScan.js';
5
6
  import * as listScansRoute from './scans/listScans.js';
6
- import * as clearCacheRoute from './scans/clearCache.js';
7
7
 
8
8
  export const createScan = createScanRoute.createScan;
9
9
  export const getScan = getScanRoute.getScan;
@@ -1,10 +1,11 @@
1
+ import logger from '../../utils/logger.js';
1
2
  import { readSmartScanToken, writeSmartScanToken } from '../../utils/smartscan-token.js';
2
3
 
3
4
  /**
4
5
  * Get stored Smart Scan token
5
6
  * GET /api/smartscan/token
6
7
  */
7
- export function getToken(req, res) {
8
+ export function getToken(_req, res) {
8
9
  try {
9
10
  const token = readSmartScanToken();
10
11
  return res.json({
@@ -12,7 +13,7 @@ export function getToken(req, res) {
12
13
  token: token || null,
13
14
  });
14
15
  } catch (error) {
15
- console.error('Error reading Smart Scan token:', error);
16
+ logger.error({ error: error.message }, 'Error reading Smart Scan token');
16
17
  return res.status(500).json({
17
18
  error: 'Failed to read token',
18
19
  message: error.message,
@@ -47,7 +48,7 @@ export function saveToken(req, res) {
47
48
  message: 'Token saved successfully',
48
49
  });
49
50
  } catch (error) {
50
- console.error('Error saving Smart Scan token:', error);
51
+ logger.error({ error: error.message }, 'Error saving Smart Scan token');
51
52
  return res.status(500).json({
52
53
  error: 'Failed to save token',
53
54
  message: error.message,
@@ -1,6 +1,6 @@
1
1
  import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
2
- import { WebSocketClientTransport } from '@modelcontextprotocol/sdk/client/websocket.js';
3
2
  import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
3
+ import { WebSocketClientTransport } from '@modelcontextprotocol/sdk/client/websocket.js';
4
4
 
5
5
  /**
6
6
  * Create transport for MCP server based on config
@@ -3,9 +3,9 @@
3
3
  * Proxies requests to the Smart Scan API to avoid CORS issues
4
4
  */
5
5
 
6
- import * as tokenRoutes from './smartscan/token.js';
7
6
  import * as discoverRoutes from './smartscan/discover.js';
8
7
  import * as scanRoutes from './smartscan/scans.js';
8
+ import * as tokenRoutes from './smartscan/token.js';
9
9
 
10
10
  export function createSmartScanRoutes() {
11
11
  const router = {};
@@ -1,5 +1,14 @@
1
- import { serializeBigInt } from '../utils/serialization.js';
2
1
  import { queryRequests } from 'mcp-shark-common/db/query.js';
2
+ import logger from '../utils/logger.js';
3
+ import { serializeBigInt } from '../utils/serialization.js';
4
+
5
+ const sanitizeSearch = (value) => {
6
+ if (value !== undefined && value !== null) {
7
+ const trimmed = String(value).trim();
8
+ return trimmed.length > 0 ? trimmed : null;
9
+ }
10
+ return null;
11
+ };
3
12
 
4
13
  export function createStatisticsRoutes(db) {
5
14
  const router = {};
@@ -7,13 +16,7 @@ export function createStatisticsRoutes(db) {
7
16
  router.getStatistics = (req, res) => {
8
17
  try {
9
18
  // Sanitize search parameter - convert empty strings to null
10
- let search = req.query.search;
11
- if (search !== undefined && search !== null) {
12
- search = String(search).trim();
13
- search = search.length > 0 ? search : null;
14
- } else {
15
- search = null;
16
- }
19
+ const search = sanitizeSearch(req.query.search);
17
20
 
18
21
  // Build filters object matching the requests route
19
22
  const filters = {
@@ -21,7 +24,7 @@ export function createStatisticsRoutes(db) {
21
24
  direction: (req.query.direction && String(req.query.direction).trim()) || null,
22
25
  method: (req.query.method && String(req.query.method).trim()) || null,
23
26
  jsonrpcMethod: (req.query.jsonrpcMethod && String(req.query.jsonrpcMethod).trim()) || null,
24
- statusCode: req.query.statusCode ? parseInt(req.query.statusCode) : null,
27
+ statusCode: req.query.statusCode ? Number.parseInt(req.query.statusCode) : null,
25
28
  jsonrpcId: (req.query.jsonrpcId && String(req.query.jsonrpcId).trim()) || null,
26
29
  search: search,
27
30
  serverName: (req.query.serverName && String(req.query.serverName).trim()) || null,
@@ -74,7 +77,7 @@ export function createStatisticsRoutes(db) {
74
77
 
75
78
  res.json(serializeBigInt(stats));
76
79
  } catch (error) {
77
- console.error('Error in getStatistics:', error);
80
+ logger.error({ error: error.message }, 'Error in getStatistics');
78
81
  res.status(500).json({ error: 'Failed to get statistics', details: error.message });
79
82
  }
80
83
  };
@@ -1,7 +1,8 @@
1
1
  import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
2
  import { homedir } from 'node:os';
3
+ import * as path from 'node:path';
4
4
  import { storeOriginalConfig } from './config.js';
5
+ import logger from './logger.js';
5
6
 
6
7
  function findLatestBackup(filePath) {
7
8
  const dir = path.dirname(filePath);
@@ -51,7 +52,7 @@ function findLatestBackup(filePath) {
51
52
  backups.sort((a, b) => b.modifiedAt - a.modifiedAt);
52
53
  return backups[0].backupPath;
53
54
  } catch (error) {
54
- console.error('Error finding latest backup:', error);
55
+ logger.error({ error: error.message }, 'Error finding latest backup');
55
56
  return null;
56
57
  }
57
58
  }
@@ -101,7 +102,7 @@ function shouldCreateBackup(
101
102
  }
102
103
  return true;
103
104
  } catch (error) {
104
- console.error('Error comparing with latest backup:', error);
105
+ logger.error({ error: error.message }, 'Error comparing with latest backup');
105
106
  // If comparison fails, create backup to be safe
106
107
  return true;
107
108
  }
@@ -157,7 +158,7 @@ function computeBackupPath(resolvedFilePath, content, mcpSharkLogs, broadcastLog
157
158
 
158
159
  export function updateConfigFile(
159
160
  originalConfig,
160
- selectedServiceNames,
161
+ _selectedServiceNames,
161
162
  resolvedFilePath,
162
163
  content,
163
164
  mcpSharkLogs,
@@ -170,7 +171,7 @@ export function updateConfigFile(
170
171
  const updatedServers = {};
171
172
  // Transform all original servers to HTTP URLs pointing to MCP shark server
172
173
  // Each server gets its own endpoint to avoid tool name prefixing issues
173
- Object.entries(serverObject).forEach(([name, cfg]) => {
174
+ Object.entries(serverObject).forEach(([name, _cfg]) => {
174
175
  updatedServers[name] = {
175
176
  type: 'http',
176
177
  url: `http://localhost:9851/mcp/${encodeURIComponent(name)}`,
@@ -188,7 +189,7 @@ export function updateConfigFile(
188
189
 
189
190
  if (resolvedFilePath && fs.existsSync(resolvedFilePath)) {
190
191
  fs.writeFileSync(resolvedFilePath, JSON.stringify(updatedConfig, null, 2));
191
- console.log(`Updated config file: ${resolvedFilePath}`);
192
+ logger.info({ path: resolvedFilePath }, 'Updated config file');
192
193
  }
193
194
 
194
195
  return { updatedConfig, backupPath: createdBackupPath };
@@ -1,5 +1,5 @@
1
1
  import * as fs from 'node:fs';
2
- import { homedir } from 'node:os';
2
+ import logger from './logger.js';
3
3
 
4
4
  const state = { originalConfigData: null };
5
5
 
@@ -8,21 +8,21 @@ export function storeOriginalConfig(filePath, originalContent, backupPath) {
8
8
  }
9
9
 
10
10
  export function restoreOriginalConfig(mcpSharkLogs, broadcastLogUpdate) {
11
- if (state.originalConfigData && state.originalConfigData.filePath) {
11
+ if (state.originalConfigData?.filePath) {
12
12
  try {
13
13
  if (fs.existsSync(state.originalConfigData.filePath)) {
14
14
  fs.writeFileSync(
15
15
  state.originalConfigData.filePath,
16
16
  state.originalConfigData.originalContent
17
17
  );
18
- console.log(`Restored original config to: ${state.originalConfigData.filePath}`);
18
+ logger.info({ path: state.originalConfigData.filePath }, 'Restored original config');
19
19
  state.originalConfigData = null;
20
20
  return true;
21
21
  }
22
22
  state.originalConfigData = null;
23
23
  return false;
24
24
  } catch (error) {
25
- console.error('Failed to restore original config:', error);
25
+ logger.error({ error: error.message }, 'Failed to restore original config');
26
26
  const timestamp = new Date().toISOString();
27
27
  const errorLog = {
28
28
  timestamp,
@@ -0,0 +1,2 @@
1
+ // Re-export shared logger
2
+ export { default } from '../../../shared/logger.js';