@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
package/lib/common/db/query.js
DELETED
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Query functions for forensic analysis of HTTP packets
|
|
3
|
-
* Can be used independently in other projects
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Query packets with forensic filters
|
|
8
|
-
*/
|
|
9
|
-
export function queryPackets(db, filters = {}) {
|
|
10
|
-
const {
|
|
11
|
-
sessionId = null,
|
|
12
|
-
direction = null,
|
|
13
|
-
method = null,
|
|
14
|
-
jsonrpcMethod = null,
|
|
15
|
-
statusCode = null,
|
|
16
|
-
startTime = null,
|
|
17
|
-
endTime = null,
|
|
18
|
-
jsonrpcId = null,
|
|
19
|
-
limit = 1000,
|
|
20
|
-
offset = 0,
|
|
21
|
-
} = filters;
|
|
22
|
-
|
|
23
|
-
const queryParts = ['SELECT * FROM packets WHERE 1=1'];
|
|
24
|
-
const params = [];
|
|
25
|
-
|
|
26
|
-
if (sessionId) {
|
|
27
|
-
queryParts.push('AND session_id = ?');
|
|
28
|
-
params.push(sessionId);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (direction) {
|
|
32
|
-
queryParts.push('AND direction = ?');
|
|
33
|
-
params.push(direction);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (method) {
|
|
37
|
-
queryParts.push('AND method = ?');
|
|
38
|
-
params.push(method);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (jsonrpcMethod) {
|
|
42
|
-
queryParts.push('AND jsonrpc_method = ?');
|
|
43
|
-
params.push(jsonrpcMethod);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (statusCode !== null && statusCode !== undefined) {
|
|
47
|
-
queryParts.push('AND status_code = ?');
|
|
48
|
-
params.push(statusCode);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (startTime) {
|
|
52
|
-
queryParts.push('AND timestamp_ns >= ?');
|
|
53
|
-
params.push(startTime);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (endTime) {
|
|
57
|
-
queryParts.push('AND timestamp_ns <= ?');
|
|
58
|
-
params.push(endTime);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (jsonrpcId) {
|
|
62
|
-
queryParts.push('AND jsonrpc_id = ?');
|
|
63
|
-
params.push(jsonrpcId);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
queryParts.push('ORDER BY timestamp_ns ASC LIMIT ? OFFSET ?');
|
|
67
|
-
params.push(limit, offset);
|
|
68
|
-
|
|
69
|
-
const query = queryParts.join(' ');
|
|
70
|
-
const stmt = db.prepare(query);
|
|
71
|
-
return stmt.all(...params);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Enhanced query function for requests/responses with search and server name filtering
|
|
76
|
-
* Supports partial matching and general search across multiple fields
|
|
77
|
-
*/
|
|
78
|
-
export function queryRequests(db, filters = {}) {
|
|
79
|
-
const {
|
|
80
|
-
sessionId = null,
|
|
81
|
-
direction = null,
|
|
82
|
-
method = null,
|
|
83
|
-
jsonrpcMethod = null,
|
|
84
|
-
statusCode = null,
|
|
85
|
-
startTime = null,
|
|
86
|
-
endTime = null,
|
|
87
|
-
jsonrpcId = null,
|
|
88
|
-
search = null, // General search across multiple fields
|
|
89
|
-
serverName = null, // MCP server name filter
|
|
90
|
-
limit = 1000,
|
|
91
|
-
offset = 0,
|
|
92
|
-
} = filters;
|
|
93
|
-
|
|
94
|
-
const queryParts = ['SELECT * FROM packets WHERE 1=1'];
|
|
95
|
-
const params = [];
|
|
96
|
-
|
|
97
|
-
// General search - searches across multiple fields with partial matching
|
|
98
|
-
// Also searches for server names in JSON-RPC params (e.g., "params":{"name":"server-name.tool")
|
|
99
|
-
if (search) {
|
|
100
|
-
const searchPattern = `%${search}%`;
|
|
101
|
-
// Also create a pattern to search for server name in params (e.g., "name":"server-name")
|
|
102
|
-
const serverNamePattern = `%"name":"${search}%`;
|
|
103
|
-
queryParts.push(`AND (
|
|
104
|
-
session_id LIKE ? ESCAPE '\\' OR
|
|
105
|
-
method LIKE ? ESCAPE '\\' OR
|
|
106
|
-
url LIKE ? ESCAPE '\\' OR
|
|
107
|
-
jsonrpc_method LIKE ? ESCAPE '\\' OR
|
|
108
|
-
jsonrpc_id LIKE ? ESCAPE '\\' OR
|
|
109
|
-
info LIKE ? ESCAPE '\\' OR
|
|
110
|
-
body_raw LIKE ? ESCAPE '\\' OR
|
|
111
|
-
body_json LIKE ? ESCAPE '\\' OR
|
|
112
|
-
headers_json LIKE ? ESCAPE '\\' OR
|
|
113
|
-
host LIKE ? ESCAPE '\\' OR
|
|
114
|
-
remote_address LIKE ? ESCAPE '\\' OR
|
|
115
|
-
-- Search for server name in JSON-RPC params (e.g., "params":{"name":"server-name.tool")
|
|
116
|
-
body_json LIKE ? ESCAPE '\\' OR
|
|
117
|
-
body_raw LIKE ? ESCAPE '\\'
|
|
118
|
-
)`);
|
|
119
|
-
// Add the pattern for each field (11 regular fields + 2 server name fields = 13 total)
|
|
120
|
-
for (let i = 0; i < 11; i++) {
|
|
121
|
-
params.push(searchPattern);
|
|
122
|
-
}
|
|
123
|
-
// Add server name specific patterns
|
|
124
|
-
params.push(serverNamePattern);
|
|
125
|
-
params.push(serverNamePattern);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Specific field filters with partial matching
|
|
129
|
-
if (sessionId) {
|
|
130
|
-
queryParts.push("AND session_id LIKE ? ESCAPE '\\'");
|
|
131
|
-
params.push(`%${sessionId}%`);
|
|
132
|
-
}
|
|
133
|
-
if (direction) {
|
|
134
|
-
queryParts.push('AND direction = ?');
|
|
135
|
-
params.push(direction);
|
|
136
|
-
}
|
|
137
|
-
if (method) {
|
|
138
|
-
queryParts.push("AND method LIKE ? ESCAPE '\\'");
|
|
139
|
-
params.push(`%${method}%`);
|
|
140
|
-
}
|
|
141
|
-
if (jsonrpcMethod) {
|
|
142
|
-
queryParts.push("AND jsonrpc_method LIKE ? ESCAPE '\\'");
|
|
143
|
-
params.push(`%${jsonrpcMethod}%`);
|
|
144
|
-
}
|
|
145
|
-
if (statusCode !== null && statusCode !== undefined) {
|
|
146
|
-
queryParts.push('AND status_code = ?');
|
|
147
|
-
params.push(statusCode);
|
|
148
|
-
}
|
|
149
|
-
if (startTime) {
|
|
150
|
-
queryParts.push('AND timestamp_ns >= ?');
|
|
151
|
-
params.push(startTime);
|
|
152
|
-
}
|
|
153
|
-
if (endTime) {
|
|
154
|
-
queryParts.push('AND timestamp_ns <= ?');
|
|
155
|
-
params.push(endTime);
|
|
156
|
-
}
|
|
157
|
-
if (jsonrpcId) {
|
|
158
|
-
queryParts.push("AND jsonrpc_id LIKE ? ESCAPE '\\'");
|
|
159
|
-
params.push(`%${jsonrpcId}%`);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Filter by MCP server name - search in JSON-RPC params
|
|
163
|
-
// Server names appear as "params":{"name":"server-name.tool-name" or "name":"server-name.tool-name"
|
|
164
|
-
if (serverName) {
|
|
165
|
-
const serverPattern = `%"name":"${serverName}.%`;
|
|
166
|
-
const serverPattern2 = `%"name":"${serverName}"%`;
|
|
167
|
-
queryParts.push(`AND (
|
|
168
|
-
body_json LIKE ? ESCAPE '\\' OR
|
|
169
|
-
body_raw LIKE ? ESCAPE '\\' OR
|
|
170
|
-
body_json LIKE ? ESCAPE '\\' OR
|
|
171
|
-
body_raw LIKE ? ESCAPE '\\'
|
|
172
|
-
)`);
|
|
173
|
-
params.push(serverPattern);
|
|
174
|
-
params.push(serverPattern);
|
|
175
|
-
params.push(serverPattern2);
|
|
176
|
-
params.push(serverPattern2);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
queryParts.push('ORDER BY timestamp_ns DESC LIMIT ? OFFSET ?');
|
|
180
|
-
params.push(limit, offset);
|
|
181
|
-
|
|
182
|
-
const query = queryParts.join(' ');
|
|
183
|
-
const stmt = db.prepare(query);
|
|
184
|
-
return stmt.all(...params);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Get conversation flow (request/response pairs)
|
|
189
|
-
*/
|
|
190
|
-
export function queryConversations(db, filters = {}) {
|
|
191
|
-
const {
|
|
192
|
-
sessionId = null,
|
|
193
|
-
method = null,
|
|
194
|
-
status = null,
|
|
195
|
-
startTime = null,
|
|
196
|
-
endTime = null,
|
|
197
|
-
jsonrpcId = null,
|
|
198
|
-
limit = 1000,
|
|
199
|
-
offset = 0,
|
|
200
|
-
} = filters;
|
|
201
|
-
|
|
202
|
-
const queryParts = [
|
|
203
|
-
'SELECT',
|
|
204
|
-
' c.*,',
|
|
205
|
-
' req.frame_number as req_frame,',
|
|
206
|
-
' req.timestamp_iso as req_timestamp_iso,',
|
|
207
|
-
' req.method as req_method,',
|
|
208
|
-
' req.url as req_url,',
|
|
209
|
-
' req.jsonrpc_method as req_jsonrpc_method,',
|
|
210
|
-
' req.body_json as req_body_json,',
|
|
211
|
-
' req.headers_json as req_headers_json,',
|
|
212
|
-
' resp.frame_number as resp_frame,',
|
|
213
|
-
' resp.timestamp_iso as resp_timestamp_iso,',
|
|
214
|
-
' resp.status_code as resp_status_code,',
|
|
215
|
-
' resp.jsonrpc_method as resp_jsonrpc_method,',
|
|
216
|
-
' resp.body_json as resp_body_json,',
|
|
217
|
-
' resp.headers_json as resp_headers_json,',
|
|
218
|
-
' resp.jsonrpc_result as resp_jsonrpc_result,',
|
|
219
|
-
' resp.jsonrpc_error as resp_jsonrpc_error',
|
|
220
|
-
'FROM conversations c',
|
|
221
|
-
'LEFT JOIN packets req ON c.request_frame_number = req.frame_number',
|
|
222
|
-
'LEFT JOIN packets resp ON c.response_frame_number = resp.frame_number',
|
|
223
|
-
'WHERE 1=1',
|
|
224
|
-
];
|
|
225
|
-
|
|
226
|
-
const params = [];
|
|
227
|
-
|
|
228
|
-
if (sessionId) {
|
|
229
|
-
queryParts.push('AND c.session_id = ?');
|
|
230
|
-
params.push(sessionId);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (method) {
|
|
234
|
-
queryParts.push('AND c.method = ?');
|
|
235
|
-
params.push(method);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (status) {
|
|
239
|
-
queryParts.push('AND c.status = ?');
|
|
240
|
-
params.push(status);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (startTime) {
|
|
244
|
-
queryParts.push('AND c.request_timestamp_ns >= ?');
|
|
245
|
-
params.push(startTime);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if (endTime) {
|
|
249
|
-
queryParts.push('AND c.request_timestamp_ns <= ?');
|
|
250
|
-
params.push(endTime);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
if (jsonrpcId) {
|
|
254
|
-
queryParts.push('AND c.jsonrpc_id = ?');
|
|
255
|
-
params.push(jsonrpcId);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
queryParts.push('ORDER BY c.request_timestamp_ns ASC LIMIT ? OFFSET ?');
|
|
259
|
-
params.push(limit, offset);
|
|
260
|
-
|
|
261
|
-
const query = queryParts.join(' ');
|
|
262
|
-
const stmt = db.prepare(query);
|
|
263
|
-
return stmt.all(...params);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Get all packets for a specific session (for forensic analysis)
|
|
268
|
-
*/
|
|
269
|
-
export function getSessionPackets(db, sessionId, limit = 10000) {
|
|
270
|
-
const stmt = db.prepare(`
|
|
271
|
-
SELECT * FROM packets
|
|
272
|
-
WHERE session_id = ?
|
|
273
|
-
ORDER BY timestamp_ns ASC
|
|
274
|
-
LIMIT ?
|
|
275
|
-
`);
|
|
276
|
-
return stmt.all(sessionId, limit);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Get all requests for a specific session (ordered by most recent first)
|
|
281
|
-
*/
|
|
282
|
-
export function getSessionRequests(db, sessionId, limit = 10000) {
|
|
283
|
-
const stmt = db.prepare(`
|
|
284
|
-
SELECT * FROM packets
|
|
285
|
-
WHERE session_id = ?
|
|
286
|
-
ORDER BY timestamp_ns DESC
|
|
287
|
-
LIMIT ?
|
|
288
|
-
`);
|
|
289
|
-
return stmt.all(sessionId, limit);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Get session metadata
|
|
294
|
-
*/
|
|
295
|
-
export function getSessions(db, filters = {}) {
|
|
296
|
-
const { startTime = null, endTime = null, limit = 1000, offset = 0 } = filters;
|
|
297
|
-
|
|
298
|
-
const queryParts = ['SELECT * FROM sessions WHERE 1=1'];
|
|
299
|
-
const params = [];
|
|
300
|
-
|
|
301
|
-
if (startTime) {
|
|
302
|
-
queryParts.push('AND first_seen_ns >= ?');
|
|
303
|
-
params.push(startTime);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (endTime) {
|
|
307
|
-
queryParts.push('AND last_seen_ns <= ?');
|
|
308
|
-
params.push(endTime);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
queryParts.push('ORDER BY first_seen_ns DESC LIMIT ? OFFSET ?');
|
|
312
|
-
params.push(limit, offset);
|
|
313
|
-
|
|
314
|
-
const query = queryParts.join(' ');
|
|
315
|
-
const stmt = db.prepare(query);
|
|
316
|
-
return stmt.all(...params);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Get statistics for forensic analysis
|
|
321
|
-
*/
|
|
322
|
-
export function getStatistics(db, filters = {}) {
|
|
323
|
-
const { sessionId = null, startTime = null, endTime = null } = filters;
|
|
324
|
-
|
|
325
|
-
const whereParts = ['WHERE 1=1'];
|
|
326
|
-
const params = [];
|
|
327
|
-
|
|
328
|
-
if (sessionId) {
|
|
329
|
-
whereParts.push('AND session_id = ?');
|
|
330
|
-
params.push(sessionId);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (startTime) {
|
|
334
|
-
whereParts.push('AND timestamp_ns >= ?');
|
|
335
|
-
params.push(startTime);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (endTime) {
|
|
339
|
-
whereParts.push('AND timestamp_ns <= ?');
|
|
340
|
-
params.push(endTime);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const whereClause = whereParts.join(' ');
|
|
344
|
-
const statsQuery = `
|
|
345
|
-
SELECT
|
|
346
|
-
COUNT(*) as total_packets,
|
|
347
|
-
COUNT(CASE WHEN direction = 'request' THEN 1 END) as total_requests,
|
|
348
|
-
COUNT(CASE WHEN direction = 'response' THEN 1 END) as total_responses,
|
|
349
|
-
COUNT(CASE WHEN status_code >= 400 THEN 1 END) as total_errors,
|
|
350
|
-
COUNT(DISTINCT session_id) as unique_sessions,
|
|
351
|
-
AVG(length) as avg_packet_size,
|
|
352
|
-
SUM(length) as total_bytes,
|
|
353
|
-
MIN(timestamp_ns) as first_packet_ns,
|
|
354
|
-
MAX(timestamp_ns) as last_packet_ns
|
|
355
|
-
FROM packets
|
|
356
|
-
${whereClause}
|
|
357
|
-
`;
|
|
358
|
-
|
|
359
|
-
const stmt = db.prepare(statsQuery);
|
|
360
|
-
return stmt.get(...params);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Get conversation statistics
|
|
365
|
-
*/
|
|
366
|
-
export function getConversationStatistics(db, filters = {}) {
|
|
367
|
-
const { sessionId = null, startTime = null, endTime = null } = filters;
|
|
368
|
-
|
|
369
|
-
const whereParts = ['WHERE 1=1'];
|
|
370
|
-
const params = [];
|
|
371
|
-
|
|
372
|
-
if (sessionId) {
|
|
373
|
-
whereParts.push('AND session_id = ?');
|
|
374
|
-
params.push(sessionId);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (startTime) {
|
|
378
|
-
whereParts.push('AND request_timestamp_ns >= ?');
|
|
379
|
-
params.push(startTime);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (endTime) {
|
|
383
|
-
whereParts.push('AND request_timestamp_ns <= ?');
|
|
384
|
-
params.push(endTime);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const whereClause = whereParts.join(' ');
|
|
388
|
-
const statsQuery = `
|
|
389
|
-
SELECT
|
|
390
|
-
COUNT(*) as total_conversations,
|
|
391
|
-
COUNT(CASE WHEN status = 'completed' THEN 1 END) as completed,
|
|
392
|
-
COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending,
|
|
393
|
-
COUNT(CASE WHEN status = 'error' THEN 1 END) as errors,
|
|
394
|
-
AVG(duration_ms) as avg_duration_ms,
|
|
395
|
-
MIN(duration_ms) as min_duration_ms,
|
|
396
|
-
MAX(duration_ms) as max_duration_ms
|
|
397
|
-
FROM conversations
|
|
398
|
-
${whereClause}
|
|
399
|
-
`;
|
|
400
|
-
|
|
401
|
-
const stmt = db.prepare(statsQuery);
|
|
402
|
-
return stmt.get(...params);
|
|
403
|
-
}
|
package/lib/common/logger.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { consola } from 'consola';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Unified logger for the entire codebase
|
|
5
|
-
* Uses consola (already installed) with a consistent API
|
|
6
|
-
* Supports both Pino-style API (object, message) and consola-style (multiple args)
|
|
7
|
-
*/
|
|
8
|
-
const logger = {
|
|
9
|
-
info: (...args) => {
|
|
10
|
-
if (args.length === 0) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
// If first arg is an object and second is a string, use Pino-style
|
|
14
|
-
if (
|
|
15
|
-
args.length === 2 &&
|
|
16
|
-
typeof args[0] === 'object' &&
|
|
17
|
-
args[0] !== null &&
|
|
18
|
-
typeof args[1] === 'string'
|
|
19
|
-
) {
|
|
20
|
-
consola.info(args[1] || '', args[0]);
|
|
21
|
-
} else {
|
|
22
|
-
// Otherwise, pass all args to consola (supports multiple strings/values)
|
|
23
|
-
consola.info(...args);
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
error: (...args) => {
|
|
27
|
-
if (args.length === 0) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
if (
|
|
31
|
-
args.length === 2 &&
|
|
32
|
-
typeof args[0] === 'object' &&
|
|
33
|
-
args[0] !== null &&
|
|
34
|
-
typeof args[1] === 'string'
|
|
35
|
-
) {
|
|
36
|
-
consola.error(args[1] || '', args[0]);
|
|
37
|
-
} else {
|
|
38
|
-
consola.error(...args);
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
warn: (...args) => {
|
|
42
|
-
if (args.length === 0) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (
|
|
46
|
-
args.length === 2 &&
|
|
47
|
-
typeof args[0] === 'object' &&
|
|
48
|
-
args[0] !== null &&
|
|
49
|
-
typeof args[1] === 'string'
|
|
50
|
-
) {
|
|
51
|
-
consola.warn(args[1] || '', args[0]);
|
|
52
|
-
} else {
|
|
53
|
-
consola.warn(...args);
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
debug: (...args) => {
|
|
57
|
-
if (args.length === 0) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
if (
|
|
61
|
-
args.length === 2 &&
|
|
62
|
-
typeof args[0] === 'object' &&
|
|
63
|
-
args[0] !== null &&
|
|
64
|
-
typeof args[1] === 'string'
|
|
65
|
-
) {
|
|
66
|
-
consola.debug(args[1] || '', args[0]);
|
|
67
|
-
} else {
|
|
68
|
-
consola.debug(...args);
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
log: (...args) => {
|
|
72
|
-
if (args.length === 0) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
if (
|
|
76
|
-
args.length === 2 &&
|
|
77
|
-
typeof args[0] === 'object' &&
|
|
78
|
-
args[0] !== null &&
|
|
79
|
-
typeof args[1] === 'string'
|
|
80
|
-
) {
|
|
81
|
-
consola.log(args[1] || '', args[0]);
|
|
82
|
-
} else {
|
|
83
|
-
consola.log(...args);
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
// Expose consola directly for advanced usage
|
|
87
|
-
consola,
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export default logger;
|
package/mcp-server/index.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { createServer } from 'node:http';
|
|
2
|
-
|
|
3
|
-
import serverLogger from '#common/logger';
|
|
4
|
-
import { isError } from './lib/common/error.js';
|
|
5
|
-
import { runAllExternalServers } from './lib/server/external/all.js';
|
|
6
|
-
|
|
7
|
-
import { getDatabaseFile, getMcpConfigPath, prepareAppDataSpaces } from '#common/configs';
|
|
8
|
-
import { initDb } from '#common/db/init';
|
|
9
|
-
import { getLogger } from '#common/db/logger';
|
|
10
|
-
import { withAuditRequestResponseHandler } from './lib/auditor/audit.js';
|
|
11
|
-
import { getInternalServer } from './lib/server/internal/run.js';
|
|
12
|
-
import { createInternalServerFactory } from './lib/server/internal/server.js';
|
|
13
|
-
|
|
14
|
-
function initAuditLogger(serverLogger) {
|
|
15
|
-
serverLogger.info({ path: getDatabaseFile() }, 'Initializing audit logger at');
|
|
16
|
-
return getLogger(initDb(getDatabaseFile()));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Start the MCP Shark server
|
|
21
|
-
* @param {Object} options - Configuration options
|
|
22
|
-
* @param {string} [options.configPath] - Path to MCP config file (defaults to getMcpConfigPath())
|
|
23
|
-
* @param {number} [options.port=9851] - Port to listen on
|
|
24
|
-
* @param {Function} [options.onError] - Error callback
|
|
25
|
-
* @param {Function} [options.onReady] - Ready callback
|
|
26
|
-
* @returns {Promise<{app: Express, server: http.Server, stop: Function}>} Server instance
|
|
27
|
-
*/
|
|
28
|
-
export async function startMcpSharkServer(options = {}) {
|
|
29
|
-
const { configPath = getMcpConfigPath(), port = 9851, onError, onReady } = options;
|
|
30
|
-
|
|
31
|
-
prepareAppDataSpaces();
|
|
32
|
-
|
|
33
|
-
serverLogger.info('[MCP-Shark] Starting MCP server...');
|
|
34
|
-
serverLogger.info(`[MCP-Shark] Config path: ${configPath}`);
|
|
35
|
-
serverLogger.info(`[MCP-Shark] Database path: ${getDatabaseFile()}`);
|
|
36
|
-
serverLogger.info(`[MCP-Shark] Working directory: ${process.cwd()}`);
|
|
37
|
-
serverLogger.info(`[MCP-Shark] PATH: ${process.env.PATH}`);
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
const auditLogger = initAuditLogger(serverLogger);
|
|
41
|
-
const externalServersResult = await runAllExternalServers(serverLogger, configPath);
|
|
42
|
-
|
|
43
|
-
if (isError(externalServersResult)) {
|
|
44
|
-
const error = new Error(JSON.stringify(externalServersResult));
|
|
45
|
-
if (onError) onError(error);
|
|
46
|
-
throw error;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const { kv, servers: externalServers } = externalServersResult;
|
|
50
|
-
|
|
51
|
-
const internalServerFactory = createInternalServerFactory(serverLogger, kv);
|
|
52
|
-
const app = getInternalServer(
|
|
53
|
-
internalServerFactory,
|
|
54
|
-
auditLogger,
|
|
55
|
-
withAuditRequestResponseHandler
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const httpServer = createServer(app);
|
|
59
|
-
|
|
60
|
-
const server = await new Promise((resolve, reject) => {
|
|
61
|
-
httpServer.on('error', (err) => {
|
|
62
|
-
if (onError) onError(err);
|
|
63
|
-
reject(err);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
httpServer.listen(port, '0.0.0.0', () => {
|
|
67
|
-
serverLogger.info(`MCP proxy HTTP server listening on http://localhost:${port}/mcp`);
|
|
68
|
-
if (onReady) onReady();
|
|
69
|
-
resolve(httpServer);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const stop = async () => {
|
|
74
|
-
// Close all external server clients
|
|
75
|
-
for (const serverInfo of externalServers) {
|
|
76
|
-
if (serverInfo?.client && !isError(serverInfo)) {
|
|
77
|
-
try {
|
|
78
|
-
await serverInfo.client.close();
|
|
79
|
-
} catch (err) {
|
|
80
|
-
serverLogger.warn({ error: err.message }, 'Error closing external server client');
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Close all connections forcefully
|
|
86
|
-
if (server.closeAllConnections) {
|
|
87
|
-
server.closeAllConnections();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Close the server
|
|
91
|
-
return new Promise((resolve) => {
|
|
92
|
-
server.close(() => {
|
|
93
|
-
serverLogger.info('MCP Shark server stopped');
|
|
94
|
-
resolve();
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
return {
|
|
100
|
-
app,
|
|
101
|
-
server,
|
|
102
|
-
stop,
|
|
103
|
-
auditLogger,
|
|
104
|
-
};
|
|
105
|
-
} catch (error) {
|
|
106
|
-
const errorMsg = 'Error starting MCP server';
|
|
107
|
-
serverLogger.error({ error: error.message, stack: error.stack }, `[MCP-Shark] ${errorMsg}`);
|
|
108
|
-
if (onError) onError(error);
|
|
109
|
-
throw error;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { CompositeError, isError } from '../../common/error.js';
|
|
3
|
-
|
|
4
|
-
const DEFAULT_TYPE = 'stdio';
|
|
5
|
-
export class ConfigError extends CompositeError {
|
|
6
|
-
constructor(message, error) {
|
|
7
|
-
super('ConfigError', message, error);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function parseConfig(configPath) {
|
|
12
|
-
try {
|
|
13
|
-
const conf = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
14
|
-
if (conf && typeof conf === 'object') {
|
|
15
|
-
return conf;
|
|
16
|
-
}
|
|
17
|
-
return new ConfigError(
|
|
18
|
-
'Invalid config file',
|
|
19
|
-
new Error(`Invalid config file: ${configPath} - ${JSON.stringify(conf, null, 2)}`)
|
|
20
|
-
);
|
|
21
|
-
} catch (error) {
|
|
22
|
-
return new ConfigError(
|
|
23
|
-
'Error parsing config',
|
|
24
|
-
new Error(`Error parsing config: ${configPath} - ${error.message}`)
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function normalizeConfig(configPath) {
|
|
30
|
-
const parsedConfigResult = parseConfig(configPath);
|
|
31
|
-
if (isError(parsedConfigResult)) {
|
|
32
|
-
return parsedConfigResult;
|
|
33
|
-
}
|
|
34
|
-
const out = new Map();
|
|
35
|
-
const { servers, mcpServers } = parsedConfigResult;
|
|
36
|
-
// Servers are the old format
|
|
37
|
-
if (servers) {
|
|
38
|
-
Object.entries(servers).forEach(([name, cfg]) => {
|
|
39
|
-
const type = cfg.type ?? DEFAULT_TYPE;
|
|
40
|
-
out.set(name, { type, ...cfg });
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
// MCP Servers are the new format
|
|
44
|
-
if (mcpServers) {
|
|
45
|
-
Object.entries(mcpServers).forEach(([name, cfg]) => {
|
|
46
|
-
// Cursor/Claude usually omit type; assume stdio if command is given
|
|
47
|
-
const type = cfg.type ?? DEFAULT_TYPE;
|
|
48
|
-
out.set(name, { type, ...cfg });
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (out.size === 0) {
|
|
53
|
-
return new ConfigError('No servers found in config');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return Object.fromEntries(out);
|
|
57
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { getBy } from '../../external/kv.js';
|
|
2
|
-
import { InternalServerError } from './error.js';
|
|
3
|
-
|
|
4
|
-
export function createPromptsGetHandler(logger, mcpServers, requestedMcpServer) {
|
|
5
|
-
return async (req) => {
|
|
6
|
-
const name = req.params.name;
|
|
7
|
-
const promptArgs = req?.params?.arguments || {};
|
|
8
|
-
logger.debug('Prompt get', name, promptArgs);
|
|
9
|
-
|
|
10
|
-
const getPrompt = getBy(mcpServers, requestedMcpServer, name, 'getPrompt', promptArgs);
|
|
11
|
-
if (!getPrompt) {
|
|
12
|
-
throw new InternalServerError(`Prompt not found: ${name}`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const result = await getPrompt(name, promptArgs);
|
|
16
|
-
logger.debug('Prompt get result', result);
|
|
17
|
-
|
|
18
|
-
return result;
|
|
19
|
-
};
|
|
20
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { listAll } from '../../external/kv.js';
|
|
2
|
-
|
|
3
|
-
export function createPromptsListHandler(logger, mcpServers, requestedMcpServer) {
|
|
4
|
-
return async (req) => {
|
|
5
|
-
const path = req.path;
|
|
6
|
-
logger.debug('Prompts list', path);
|
|
7
|
-
|
|
8
|
-
const res = await listAll(mcpServers, requestedMcpServer, 'prompts');
|
|
9
|
-
const result = Array.isArray(res) ? { prompts: res } : res;
|
|
10
|
-
|
|
11
|
-
return result;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { listAll } from '../../external/kv.js';
|
|
2
|
-
|
|
3
|
-
export function createResourcesListHandler(logger, mcpServers, requestedMcpServer) {
|
|
4
|
-
return async (req) => {
|
|
5
|
-
const path = req.path;
|
|
6
|
-
logger.debug('Resources list', path);
|
|
7
|
-
|
|
8
|
-
const res = await listAll(mcpServers, requestedMcpServer, 'resources');
|
|
9
|
-
const result = Array.isArray(res) ? { resources: res } : res;
|
|
10
|
-
|
|
11
|
-
return result;
|
|
12
|
-
};
|
|
13
|
-
}
|