@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.
- 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 +134 -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 +62 -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 +162 -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 +169 -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 -111
- 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,197 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import logger from '../logger.js';
|
|
4
|
-
import { getScanResultsDirectory } from './directory.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Extract server name from cached scan data
|
|
8
|
-
* @param {Object} data - Cached file data
|
|
9
|
-
* @param {Object} scanData - Scan data from API
|
|
10
|
-
* @returns {string} Server name
|
|
11
|
-
*/
|
|
12
|
-
function extractServerName(data, scanData) {
|
|
13
|
-
const cachedServerName = data.serverName; // From cache file metadata (most reliable)
|
|
14
|
-
|
|
15
|
-
// If not found at top level, try to extract from scan data (API response)
|
|
16
|
-
if (!cachedServerName || cachedServerName === 'Unknown Server') {
|
|
17
|
-
const actualScanData = scanData.data || scanData;
|
|
18
|
-
|
|
19
|
-
const serverName =
|
|
20
|
-
actualScanData.serverName ||
|
|
21
|
-
actualScanData.server_name ||
|
|
22
|
-
actualScanData.server?.name ||
|
|
23
|
-
actualScanData.mcp_server_data?.server?.name ||
|
|
24
|
-
scanData.serverName ||
|
|
25
|
-
scanData.server_name ||
|
|
26
|
-
scanData.server?.name ||
|
|
27
|
-
scanData.mcp_server_data?.server?.name ||
|
|
28
|
-
'Unknown Server';
|
|
29
|
-
|
|
30
|
-
return serverName;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return cachedServerName;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Process a single cached scan file
|
|
38
|
-
* @param {string} file - File name
|
|
39
|
-
* @param {string} scanResultsDir - Directory path
|
|
40
|
-
* @returns {Object|null} Processed scan result or null if error
|
|
41
|
-
*/
|
|
42
|
-
function processScanFile(file, scanResultsDir) {
|
|
43
|
-
try {
|
|
44
|
-
const filePath = join(scanResultsDir, file);
|
|
45
|
-
logger.debug({ file }, 'Reading cached scan result file');
|
|
46
|
-
|
|
47
|
-
const fileContent = readFileSync(filePath, 'utf8');
|
|
48
|
-
const data = JSON.parse(fileContent);
|
|
49
|
-
|
|
50
|
-
// Validate that this is a scan result file
|
|
51
|
-
if (!data || typeof data !== 'object') {
|
|
52
|
-
logger.warn({ file }, 'Invalid data in file: not an object');
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Debug: Log the structure to understand what we're working with
|
|
57
|
-
logger.debug(
|
|
58
|
-
{
|
|
59
|
-
file,
|
|
60
|
-
hasServerName: !!data.serverName,
|
|
61
|
-
serverName: data.serverName,
|
|
62
|
-
hasScanData: !!data.scanData,
|
|
63
|
-
scanDataKeys: data.scanData ? Object.keys(data.scanData) : [],
|
|
64
|
-
topLevelKeys: Object.keys(data),
|
|
65
|
-
},
|
|
66
|
-
'File structure'
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
// Create a scan-like object with id, server name, and scan data
|
|
70
|
-
const scanData = data.scanData || data;
|
|
71
|
-
const scanId = scanData.id || scanData.scan_id || data.hash || file.replace('.json', '');
|
|
72
|
-
const serverName = extractServerName(data, scanData);
|
|
73
|
-
|
|
74
|
-
// Log if we couldn't find server name
|
|
75
|
-
if (serverName === 'Unknown Server') {
|
|
76
|
-
logger.warn(
|
|
77
|
-
{
|
|
78
|
-
file,
|
|
79
|
-
dataServerName: data.serverName,
|
|
80
|
-
dataKeys: Object.keys(data || {}).join(', '),
|
|
81
|
-
scanDataKeys: Object.keys(scanData || {}).join(', '),
|
|
82
|
-
scanDataDataKeys: scanData?.data ? Object.keys(scanData.data || {}).join(', ') : null,
|
|
83
|
-
},
|
|
84
|
-
'Could not find server name in file'
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const scanResult = {
|
|
89
|
-
id: scanId,
|
|
90
|
-
scan_id: scanId,
|
|
91
|
-
server: {
|
|
92
|
-
name: serverName,
|
|
93
|
-
},
|
|
94
|
-
server_name: serverName,
|
|
95
|
-
serverName: serverName,
|
|
96
|
-
status: 'completed',
|
|
97
|
-
risk_level: scanData.overall_risk_level || scanData.risk_level || 'unknown',
|
|
98
|
-
overall_risk_level: scanData.overall_risk_level || scanData.risk_level || 'unknown',
|
|
99
|
-
created_at: data.createdAt || data.created_at || scanData.created_at,
|
|
100
|
-
updated_at: data.updatedAt || data.updated_at || scanData.updated_at,
|
|
101
|
-
cached: true,
|
|
102
|
-
hash: data.hash || file.replace('.json', ''),
|
|
103
|
-
data: scanData,
|
|
104
|
-
result: scanData,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
logger.debug({ serverName, scanId }, 'Successfully loaded scan');
|
|
108
|
-
return scanResult;
|
|
109
|
-
} catch (error) {
|
|
110
|
-
logger.warn(
|
|
111
|
-
{
|
|
112
|
-
file,
|
|
113
|
-
filePath: join(scanResultsDir, file),
|
|
114
|
-
error: error.message,
|
|
115
|
-
stack: error.stack,
|
|
116
|
-
},
|
|
117
|
-
'Error reading scan result file'
|
|
118
|
-
);
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Get all cached scan results (across all servers)
|
|
125
|
-
* @returns {Array} Array of cached scan results
|
|
126
|
-
*/
|
|
127
|
-
export function getAllCachedScanResults() {
|
|
128
|
-
try {
|
|
129
|
-
const scanResultsDir = getScanResultsDirectory();
|
|
130
|
-
logger.debug({ scanResultsDir }, 'Reading cached scans from directory');
|
|
131
|
-
|
|
132
|
-
// Check if directory exists (don't create it, just check)
|
|
133
|
-
if (!existsSync(scanResultsDir)) {
|
|
134
|
-
logger.debug({ scanResultsDir }, 'Scan results directory does not exist');
|
|
135
|
-
return [];
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Read all files in the directory
|
|
139
|
-
const allFiles = readdirSync(scanResultsDir);
|
|
140
|
-
logger.debug({ count: allFiles.length }, 'Total files in directory');
|
|
141
|
-
|
|
142
|
-
// Filter for JSON files only
|
|
143
|
-
const jsonFiles = allFiles.filter((f) => f.endsWith('.json'));
|
|
144
|
-
logger.debug({ count: jsonFiles.length, scanResultsDir }, 'Found JSON files');
|
|
145
|
-
|
|
146
|
-
if (jsonFiles.length === 0) {
|
|
147
|
-
logger.debug('No cached scan JSON files found');
|
|
148
|
-
return [];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Read each file
|
|
152
|
-
const { results, successCount, errorCount } = jsonFiles.reduce(
|
|
153
|
-
(acc, file) => {
|
|
154
|
-
const result = processScanFile(file, scanResultsDir);
|
|
155
|
-
if (result) {
|
|
156
|
-
return {
|
|
157
|
-
results: [...acc.results, result],
|
|
158
|
-
successCount: acc.successCount + 1,
|
|
159
|
-
errorCount: acc.errorCount,
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
return {
|
|
163
|
-
results: acc.results,
|
|
164
|
-
successCount: acc.successCount,
|
|
165
|
-
errorCount: acc.errorCount + 1,
|
|
166
|
-
};
|
|
167
|
-
},
|
|
168
|
-
{ results: [], successCount: 0, errorCount: 0 }
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
// Sort by updatedAt descending (most recent first)
|
|
172
|
-
results.sort((a, b) => {
|
|
173
|
-
const aTime = a.updated_at || a.created_at || 0;
|
|
174
|
-
const bTime = b.updated_at || b.created_at || 0;
|
|
175
|
-
return bTime - aTime;
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
logger.info(
|
|
179
|
-
{
|
|
180
|
-
successCount,
|
|
181
|
-
errorCount,
|
|
182
|
-
total: results.length,
|
|
183
|
-
},
|
|
184
|
-
'Summary: cached scans loaded'
|
|
185
|
-
);
|
|
186
|
-
return results;
|
|
187
|
-
} catch (error) {
|
|
188
|
-
logger.error(
|
|
189
|
-
{
|
|
190
|
-
error: error.message,
|
|
191
|
-
stack: error.stack,
|
|
192
|
-
},
|
|
193
|
-
'Fatal error getting all cached scan results'
|
|
194
|
-
);
|
|
195
|
-
return [];
|
|
196
|
-
}
|
|
197
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import logger from '../logger.js';
|
|
4
|
-
import { getScanResultFilePath, getScanResultsDirectory } from './directory.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Get cached scan result by hash
|
|
8
|
-
* @param {string} hash - SHA-256 hash of MCP server data
|
|
9
|
-
* @returns {Object|null} Cached scan result or null if not found
|
|
10
|
-
*/
|
|
11
|
-
export function getCachedScanResult(hash) {
|
|
12
|
-
try {
|
|
13
|
-
const filePath = getScanResultFilePath(hash);
|
|
14
|
-
|
|
15
|
-
if (!existsSync(filePath)) {
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const fileContent = readFileSync(filePath, 'utf8');
|
|
20
|
-
const data = JSON.parse(fileContent);
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
...data.scanData,
|
|
24
|
-
cached: true,
|
|
25
|
-
cachedAt: data.createdAt,
|
|
26
|
-
updatedAt: data.updatedAt,
|
|
27
|
-
serverName: data.serverName,
|
|
28
|
-
};
|
|
29
|
-
} catch (error) {
|
|
30
|
-
logger.error({ hash, error: error.message }, 'Error getting cached scan result');
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Store scan result in cache
|
|
37
|
-
* @param {string} serverName - Name of the MCP server
|
|
38
|
-
* @param {string} hash - SHA-256 hash of MCP server data
|
|
39
|
-
* @param {Object} scanData - Scan result data to store
|
|
40
|
-
* @returns {boolean} Success status
|
|
41
|
-
*/
|
|
42
|
-
export function storeScanResult(serverName, hash, scanData) {
|
|
43
|
-
try {
|
|
44
|
-
const filePath = getScanResultFilePath(hash);
|
|
45
|
-
const now = Date.now();
|
|
46
|
-
|
|
47
|
-
// Check if file exists to preserve original creation time
|
|
48
|
-
const getCreatedAt = (filePath, defaultTime) => {
|
|
49
|
-
if (!existsSync(filePath)) {
|
|
50
|
-
return defaultTime;
|
|
51
|
-
}
|
|
52
|
-
try {
|
|
53
|
-
const existingContent = readFileSync(filePath, 'utf8');
|
|
54
|
-
const existingData = JSON.parse(existingContent);
|
|
55
|
-
return existingData.createdAt || defaultTime;
|
|
56
|
-
} catch (_e) {
|
|
57
|
-
return defaultTime;
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
const createdAt = getCreatedAt(filePath, now);
|
|
61
|
-
|
|
62
|
-
const dataToStore = {
|
|
63
|
-
serverName,
|
|
64
|
-
hash,
|
|
65
|
-
scanData,
|
|
66
|
-
createdAt,
|
|
67
|
-
updatedAt: now,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
writeFileSync(filePath, JSON.stringify(dataToStore, null, 2), 'utf8');
|
|
71
|
-
return true;
|
|
72
|
-
} catch (error) {
|
|
73
|
-
logger.error({ serverName, hash, error: error.message }, 'Error storing scan result');
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Clear all cached scan results
|
|
80
|
-
* @returns {number} Number of files deleted
|
|
81
|
-
*/
|
|
82
|
-
export function clearAllScanResults() {
|
|
83
|
-
try {
|
|
84
|
-
const scanResultsDir = getScanResultsDirectory();
|
|
85
|
-
if (!existsSync(scanResultsDir)) {
|
|
86
|
-
return 0;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const files = readdirSync(scanResultsDir).filter((f) => f.endsWith('.json'));
|
|
90
|
-
|
|
91
|
-
const deletedCount = files.reduce((count, file) => {
|
|
92
|
-
try {
|
|
93
|
-
const filePath = join(scanResultsDir, file);
|
|
94
|
-
unlinkSync(filePath);
|
|
95
|
-
return count + 1;
|
|
96
|
-
} catch (error) {
|
|
97
|
-
logger.warn({ file, error: error.message }, 'Error deleting scan result file');
|
|
98
|
-
return count;
|
|
99
|
-
}
|
|
100
|
-
}, 0);
|
|
101
|
-
|
|
102
|
-
return deletedCount;
|
|
103
|
-
} catch (error) {
|
|
104
|
-
logger.error({ error: error.message }, 'Error clearing all scan results');
|
|
105
|
-
return 0;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Compute SHA-256 hash of MCP server data for change detection
|
|
5
|
-
* @param {Object} serverData - MCP server data (name, tools, resources, prompts)
|
|
6
|
-
* @returns {string} SHA-256 hash in hex format
|
|
7
|
-
*/
|
|
8
|
-
export function computeMcpHash(serverData) {
|
|
9
|
-
// Normalize the data to ensure consistent hashing
|
|
10
|
-
// Sort arrays to ensure order doesn't matter
|
|
11
|
-
const normalized = {
|
|
12
|
-
name: serverData.name || '',
|
|
13
|
-
tools: (serverData.tools || [])
|
|
14
|
-
.map((tool) => ({
|
|
15
|
-
name: tool.name || '',
|
|
16
|
-
description: tool.description || '',
|
|
17
|
-
inputSchema: tool.inputSchema || tool.input_schema || null,
|
|
18
|
-
outputSchema: tool.outputSchema || tool.output_schema || null,
|
|
19
|
-
}))
|
|
20
|
-
.sort((a, b) => (a.name || '').localeCompare(b.name || '')),
|
|
21
|
-
resources: (serverData.resources || [])
|
|
22
|
-
.map((resource) => ({
|
|
23
|
-
uri: resource.uri || '',
|
|
24
|
-
name: resource.name || '',
|
|
25
|
-
description: resource.description || '',
|
|
26
|
-
mimeType: resource.mimeType || resource.mime_type || null,
|
|
27
|
-
}))
|
|
28
|
-
.sort((a, b) => (a.uri || '').localeCompare(b.uri || '')),
|
|
29
|
-
prompts: (serverData.prompts || [])
|
|
30
|
-
.map((prompt) => ({
|
|
31
|
-
name: prompt.name || '',
|
|
32
|
-
description: prompt.description || '',
|
|
33
|
-
arguments: (prompt.arguments || []).sort((a, b) => {
|
|
34
|
-
const aName = (a.name || '').toString();
|
|
35
|
-
const bName = (b.name || '').toString();
|
|
36
|
-
return aName.localeCompare(bName);
|
|
37
|
-
}),
|
|
38
|
-
}))
|
|
39
|
-
.sort((a, b) => (a.name || '').localeCompare(b.name || '')),
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
// Create deterministic JSON string (sorted keys)
|
|
43
|
-
const jsonString = JSON.stringify(normalized);
|
|
44
|
-
|
|
45
|
-
// Compute SHA-256 hash
|
|
46
|
-
return createHash('sha256').update(jsonString).digest('hex');
|
|
47
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { readFileSync, readdirSync, unlinkSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import logger from '../logger.js';
|
|
4
|
-
import { ensureScanResultsDirectory } from './directory.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Get all cached scan results for a server
|
|
8
|
-
* @param {string} serverName - Name of the MCP server
|
|
9
|
-
* @returns {Array} Array of cached scan results
|
|
10
|
-
*/
|
|
11
|
-
export function getCachedScanResultsForServer(serverName) {
|
|
12
|
-
try {
|
|
13
|
-
const scanResultsDir = ensureScanResultsDirectory();
|
|
14
|
-
const files = readdirSync(scanResultsDir).filter((f) => f.endsWith('.json'));
|
|
15
|
-
const results = [];
|
|
16
|
-
|
|
17
|
-
for (const file of files) {
|
|
18
|
-
try {
|
|
19
|
-
const filePath = join(scanResultsDir, file);
|
|
20
|
-
const fileContent = readFileSync(filePath, 'utf8');
|
|
21
|
-
const data = JSON.parse(fileContent);
|
|
22
|
-
|
|
23
|
-
if (data.serverName === serverName) {
|
|
24
|
-
results.push({
|
|
25
|
-
...data.scanData,
|
|
26
|
-
cached: true,
|
|
27
|
-
cachedAt: data.createdAt,
|
|
28
|
-
updatedAt: data.updatedAt,
|
|
29
|
-
hash: data.hash,
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
} catch (error) {
|
|
33
|
-
// Skip files that can't be parsed
|
|
34
|
-
logger.warn({ file, error: error.message }, 'Error reading scan result file');
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Sort by updatedAt descending
|
|
39
|
-
results.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
|
|
40
|
-
|
|
41
|
-
return results;
|
|
42
|
-
} catch (error) {
|
|
43
|
-
logger.error({ error: error.message }, 'Error getting cached scan results for server');
|
|
44
|
-
return [];
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Clear old scan results (optional cleanup function)
|
|
50
|
-
* @param {number} maxAgeMs - Maximum age in milliseconds (default: 30 days)
|
|
51
|
-
* @returns {number} Number of files deleted
|
|
52
|
-
*/
|
|
53
|
-
export function clearOldScanResults(maxAgeMs = 30 * 24 * 60 * 60 * 1000) {
|
|
54
|
-
try {
|
|
55
|
-
const scanResultsDir = ensureScanResultsDirectory();
|
|
56
|
-
const files = readdirSync(scanResultsDir).filter((f) => f.endsWith('.json'));
|
|
57
|
-
const cutoffTime = Date.now() - maxAgeMs;
|
|
58
|
-
|
|
59
|
-
const deletedCount = files.reduce((count, file) => {
|
|
60
|
-
try {
|
|
61
|
-
const filePath = join(scanResultsDir, file);
|
|
62
|
-
const fileContent = readFileSync(filePath, 'utf8');
|
|
63
|
-
const data = JSON.parse(fileContent);
|
|
64
|
-
|
|
65
|
-
if (data.updatedAt && data.updatedAt < cutoffTime) {
|
|
66
|
-
unlinkSync(filePath);
|
|
67
|
-
return count + 1;
|
|
68
|
-
}
|
|
69
|
-
return count;
|
|
70
|
-
} catch (error) {
|
|
71
|
-
// Skip files that can't be parsed
|
|
72
|
-
logger.warn(
|
|
73
|
-
{ file, error: error.message },
|
|
74
|
-
'Error processing scan result file for cleanup'
|
|
75
|
-
);
|
|
76
|
-
return count;
|
|
77
|
-
}
|
|
78
|
-
}, 0);
|
|
79
|
-
|
|
80
|
-
return deletedCount;
|
|
81
|
-
} catch (error) {
|
|
82
|
-
logger.error({ error: error.message }, 'Error clearing old scan results');
|
|
83
|
-
return 0;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Main entry point - re-export all functions
|
|
2
|
-
export { computeMcpHash } from './scan-cache/hash.js';
|
|
3
|
-
export {
|
|
4
|
-
getCachedScanResult,
|
|
5
|
-
storeScanResult,
|
|
6
|
-
clearAllScanResults,
|
|
7
|
-
} from './scan-cache/file-operations.js';
|
|
8
|
-
export {
|
|
9
|
-
getCachedScanResultsForServer,
|
|
10
|
-
clearOldScanResults,
|
|
11
|
-
} from './scan-cache/server-operations.js';
|
|
12
|
-
export { getAllCachedScanResults } from './scan-cache/all-results.js';
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { getWorkingDirectory, prepareAppDataSpaces } from '#common/configs';
|
|
4
|
-
import logger from './logger.js';
|
|
5
|
-
|
|
6
|
-
const SMART_SCAN_TOKEN_NAME = 'smart-scan-token.json';
|
|
7
|
-
|
|
8
|
-
function getSmartScanTokenPath() {
|
|
9
|
-
return join(getWorkingDirectory(), SMART_SCAN_TOKEN_NAME);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function readSmartScanToken() {
|
|
13
|
-
try {
|
|
14
|
-
const tokenPath = getSmartScanTokenPath();
|
|
15
|
-
if (existsSync(tokenPath)) {
|
|
16
|
-
const content = readFileSync(tokenPath, 'utf8');
|
|
17
|
-
const data = JSON.parse(content);
|
|
18
|
-
return data.token || null;
|
|
19
|
-
}
|
|
20
|
-
return null;
|
|
21
|
-
} catch (error) {
|
|
22
|
-
logger.error({ error: error.message }, 'Error reading Smart Scan token');
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function writeSmartScanToken(token) {
|
|
28
|
-
try {
|
|
29
|
-
const tokenPath = getSmartScanTokenPath();
|
|
30
|
-
prepareAppDataSpaces(); // Ensure directory exists
|
|
31
|
-
|
|
32
|
-
const data = {
|
|
33
|
-
token: token || null,
|
|
34
|
-
updatedAt: new Date().toISOString(),
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
writeFileSync(tokenPath, JSON.stringify(data, null, 2), { mode: 0o600 }); // Read/write for owner only
|
|
38
|
-
return true;
|
|
39
|
-
} catch (error) {
|
|
40
|
-
logger.error({ error: error.message }, 'Error writing Smart Scan token');
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|