@mcp-shark/mcp-shark 1.5.4 → 1.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -96
- package/bin/mcp-shark.js +1 -1
- package/core/configs/codex.js +68 -0
- package/core/configs/environment.js +51 -0
- package/{lib/common → core}/configs/index.js +16 -1
- package/core/constants/Defaults.js +15 -0
- package/core/constants/HttpStatus.js +14 -0
- package/core/constants/Server.js +20 -0
- package/core/constants/StatusCodes.js +25 -0
- package/core/constants/index.js +7 -0
- package/core/container/DependencyContainer.js +179 -0
- package/core/db/init.js +33 -0
- package/core/index.js +10 -0
- package/{mcp-server/lib/common/error.js → core/libraries/ErrorLibrary.js} +4 -0
- package/core/libraries/LoggerLibrary.js +91 -0
- package/core/libraries/SerializationLibrary.js +32 -0
- package/core/libraries/bootstrap-logger.js +19 -0
- package/core/libraries/errors/ApplicationError.js +97 -0
- package/core/libraries/index.js +17 -0
- package/{mcp-server/lib → core/mcp-server}/auditor/audit.js +77 -53
- package/core/mcp-server/index.js +192 -0
- package/{mcp-server/lib → core/mcp-server}/server/external/all.js +1 -1
- package/core/mcp-server/server/external/config.js +75 -0
- package/{mcp-server/lib → core/mcp-server}/server/external/single/client.js +1 -1
- package/{mcp-server/lib → core/mcp-server}/server/external/single/request.js +1 -1
- package/{mcp-server/lib → core/mcp-server}/server/external/single/run.js +20 -11
- package/{mcp-server/lib → core/mcp-server}/server/external/single/transport.js +1 -1
- package/{mcp-server/lib → core/mcp-server}/server/internal/handlers/error.js +1 -1
- package/core/mcp-server/server/internal/handlers/prompts-get.js +28 -0
- package/core/mcp-server/server/internal/handlers/prompts-list.js +21 -0
- package/core/mcp-server/server/internal/handlers/resources-list.js +21 -0
- package/core/mcp-server/server/internal/handlers/resources-read.js +28 -0
- package/core/mcp-server/server/internal/handlers/tools-call.js +44 -0
- package/core/mcp-server/server/internal/handlers/tools-list.js +23 -0
- package/core/mcp-server/server/internal/run.js +53 -0
- package/{mcp-server/lib → core/mcp-server}/server/internal/server.js +11 -1
- package/core/models/ConversationFilters.js +31 -0
- package/core/models/ExportFormat.js +8 -0
- package/core/models/RequestFilters.js +43 -0
- package/core/models/SessionFilters.js +23 -0
- package/core/models/index.js +8 -0
- package/core/repositories/AuditRepository.js +233 -0
- package/core/repositories/ConversationRepository.js +182 -0
- package/core/repositories/PacketRepository.js +237 -0
- package/core/repositories/SchemaRepository.js +107 -0
- package/core/repositories/SessionRepository.js +59 -0
- package/core/repositories/StatisticsRepository.js +54 -0
- package/core/repositories/index.js +10 -0
- package/core/services/AuditService.js +144 -0
- package/core/services/BackupService.js +222 -0
- package/core/services/ConfigDetectionService.js +89 -0
- package/core/services/ConfigFileService.js +210 -0
- package/core/services/ConfigPatchingService.js +137 -0
- package/core/services/ConfigService.js +250 -0
- package/core/services/ConfigTransformService.js +178 -0
- package/core/services/ConversationService.js +19 -0
- package/core/services/ExportService.js +117 -0
- package/core/services/LogService.js +64 -0
- package/core/services/McpClientService.js +235 -0
- package/core/services/McpDiscoveryService.js +107 -0
- package/core/services/RequestService.js +56 -0
- package/core/services/ScanCacheService.js +242 -0
- package/core/services/ScanService.js +167 -0
- package/core/services/ServerManagementService.js +206 -0
- package/core/services/SessionService.js +34 -0
- package/core/services/SettingsService.js +163 -0
- package/core/services/StatisticsService.js +64 -0
- package/core/services/TokenService.js +94 -0
- package/core/services/index.js +25 -0
- package/core/services/parsers/ConfigParserFactory.js +113 -0
- package/core/services/parsers/JsonConfigParser.js +66 -0
- package/core/services/parsers/LegacyJsonConfigParser.js +71 -0
- package/core/services/parsers/TomlConfigParser.js +87 -0
- package/core/services/parsers/index.js +4 -0
- package/{ui/server → core}/utils/scan-cache/directory.js +1 -1
- package/core/utils/validation.js +77 -0
- package/package.json +14 -11
- package/ui/dist/assets/index-CArYxKxS.js +35 -0
- package/ui/dist/index.html +1 -1
- package/ui/server/controllers/BackupController.js +129 -0
- package/ui/server/controllers/ConfigController.js +92 -0
- package/ui/server/controllers/ConversationController.js +41 -0
- package/ui/server/controllers/LogController.js +44 -0
- package/ui/server/controllers/McpClientController.js +60 -0
- package/ui/server/controllers/McpDiscoveryController.js +44 -0
- package/ui/server/controllers/RequestController.js +129 -0
- package/ui/server/controllers/ScanController.js +122 -0
- package/ui/server/controllers/ServerManagementController.js +154 -0
- package/ui/server/controllers/SessionController.js +57 -0
- package/ui/server/controllers/SettingsController.js +24 -0
- package/ui/server/controllers/StatisticsController.js +54 -0
- package/ui/server/controllers/TokenController.js +58 -0
- package/ui/server/controllers/index.js +17 -0
- package/ui/server/routes/backups/index.js +15 -9
- package/ui/server/routes/composite/index.js +63 -32
- package/ui/server/routes/composite/servers.js +20 -15
- package/ui/server/routes/config.js +13 -172
- package/ui/server/routes/conversations.js +9 -19
- package/ui/server/routes/help.js +4 -3
- package/ui/server/routes/logs.js +14 -26
- package/ui/server/routes/playground.js +11 -174
- package/ui/server/routes/requests.js +12 -232
- package/ui/server/routes/sessions.js +10 -21
- package/ui/server/routes/settings.js +10 -192
- package/ui/server/routes/smartscan.js +26 -15
- package/ui/server/routes/statistics.js +8 -79
- package/ui/server/setup.js +163 -0
- package/ui/server/swagger/paths/backups.js +151 -0
- package/ui/server/swagger/paths/components.js +76 -0
- package/ui/server/swagger/paths/config.js +117 -0
- package/ui/server/swagger/paths/conversations.js +29 -0
- package/ui/server/swagger/paths/help.js +82 -0
- package/ui/server/swagger/paths/logs.js +87 -0
- package/ui/server/swagger/paths/playground.js +49 -0
- package/ui/server/swagger/paths/requests.js +178 -0
- package/ui/server/swagger/paths/serverManagement.js +205 -0
- package/ui/server/swagger/paths/sessions.js +61 -0
- package/ui/server/swagger/paths/settings.js +31 -0
- package/ui/server/swagger/paths/smartScan/discovery.js +97 -0
- package/ui/server/swagger/paths/smartScan/index.js +13 -0
- package/ui/server/swagger/paths/smartScan/scans.js +151 -0
- package/ui/server/swagger/paths/smartScan/token.js +71 -0
- package/ui/server/swagger/paths/statistics.js +40 -0
- package/ui/server/swagger/paths.js +38 -0
- package/ui/server/swagger/swagger.js +37 -0
- package/ui/server/utils/cleanup.js +99 -0
- package/ui/server/utils/config.js +18 -96
- package/ui/server/utils/errorHandler.js +43 -0
- package/ui/server/utils/logger.js +2 -2
- package/ui/server/utils/paths.js +27 -30
- package/ui/server/utils/port.js +21 -21
- package/ui/server/utils/process.js +18 -10
- package/ui/server/utils/processState.js +17 -0
- package/ui/server/utils/signals.js +34 -0
- package/ui/server/websocket/broadcast.js +33 -0
- package/ui/server/websocket/handler.js +52 -0
- package/ui/server.js +51 -230
- package/ui/src/App.jsx +2 -0
- package/ui/src/CompositeSetup.jsx +23 -9
- package/ui/src/PacketFilters.jsx +17 -3
- package/ui/src/components/AlertModal.jsx +116 -0
- package/ui/src/components/App/ApiDocsButton.jsx +57 -0
- package/ui/src/components/App/useAppState.js +43 -1
- package/ui/src/components/BackupList.jsx +27 -3
- package/ui/src/utils/requestPairing.js +35 -36
- package/ui/src/utils/requestUtils.js +1 -0
- package/lib/common/db/init.js +0 -132
- package/lib/common/db/logger.js +0 -349
- package/lib/common/db/query.js +0 -403
- package/lib/common/logger.js +0 -90
- package/mcp-server/index.js +0 -138
- package/mcp-server/lib/server/external/config.js +0 -57
- package/mcp-server/lib/server/internal/handlers/prompts-get.js +0 -20
- package/mcp-server/lib/server/internal/handlers/prompts-list.js +0 -13
- package/mcp-server/lib/server/internal/handlers/resources-list.js +0 -13
- package/mcp-server/lib/server/internal/handlers/resources-read.js +0 -20
- package/mcp-server/lib/server/internal/handlers/tools-call.js +0 -35
- package/mcp-server/lib/server/internal/handlers/tools-list.js +0 -15
- package/mcp-server/lib/server/internal/run.js +0 -37
- package/mcp-server/mcp-shark.js +0 -22
- package/ui/dist/assets/index-CFHeMNwd.js +0 -35
- package/ui/server/routes/backups/deleteBackup.js +0 -54
- package/ui/server/routes/backups/listBackups.js +0 -75
- package/ui/server/routes/backups/restoreBackup.js +0 -83
- package/ui/server/routes/backups/viewBackup.js +0 -47
- package/ui/server/routes/composite/setup.js +0 -129
- package/ui/server/routes/composite/status.js +0 -7
- package/ui/server/routes/composite/stop.js +0 -39
- package/ui/server/routes/composite/utils.js +0 -45
- package/ui/server/routes/smartscan/discover.js +0 -118
- package/ui/server/routes/smartscan/scans/clearCache.js +0 -23
- package/ui/server/routes/smartscan/scans/createBatchScans.js +0 -124
- package/ui/server/routes/smartscan/scans/createScan.js +0 -43
- package/ui/server/routes/smartscan/scans/getCachedResults.js +0 -52
- package/ui/server/routes/smartscan/scans/getScan.js +0 -42
- package/ui/server/routes/smartscan/scans/listScans.js +0 -25
- package/ui/server/routes/smartscan/scans.js +0 -13
- package/ui/server/routes/smartscan/token.js +0 -57
- package/ui/server/utils/config-update.js +0 -240
- package/ui/server/utils/scan-cache/all-results.js +0 -197
- package/ui/server/utils/scan-cache/file-operations.js +0 -107
- package/ui/server/utils/scan-cache/hash.js +0 -47
- package/ui/server/utils/scan-cache/server-operations.js +0 -85
- package/ui/server/utils/scan-cache.js +0 -12
- package/ui/server/utils/smartscan-token.js +0 -43
- /package/{mcp-server/lib → core/mcp-server}/server/external/kv.js +0 -0
- /package/{mcp-server/lib → core/mcp-server}/server/internal/handlers/common.js +0 -0
- /package/{mcp-server/lib → core/mcp-server}/server/internal/session.js +0 -0
|
@@ -1,179 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import * as path from 'node:path';
|
|
4
|
-
import { extractServices } from '../utils/config.js';
|
|
5
|
-
import { createBackupRoutes } from './backups/index.js';
|
|
1
|
+
import { ConfigController } from '#ui/server/controllers/index.js';
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Create config routes
|
|
5
|
+
* Routes delegate to ConfigController which calls ConfigService
|
|
6
|
+
*/
|
|
7
|
+
export function createConfigRoutes(container) {
|
|
8
|
+
const configService = container.getService('config');
|
|
9
|
+
const logger = container.getLibrary('logger');
|
|
10
|
+
const configController = new ConfigController(configService, logger);
|
|
11
11
|
|
|
12
|
-
if (!fs.existsSync(resolvedFilePath)) {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
return fs.readFileSync(resolvedFilePath, 'utf-8');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function parseJsonSafely(content) {
|
|
19
|
-
try {
|
|
20
|
-
return { config: JSON.parse(content), error: null };
|
|
21
|
-
} catch (e) {
|
|
22
|
-
return { config: null, error: e };
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function tryParseJson(content) {
|
|
27
|
-
try {
|
|
28
|
-
return JSON.parse(content);
|
|
29
|
-
} catch (_e) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function createConfigRoutes() {
|
|
35
12
|
const router = {};
|
|
36
13
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (!filePath && !fileContent) {
|
|
42
|
-
return res.status(400).json({ error: 'Either filePath or fileContent is required' });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const content = fileContent ? fileContent : readFileContent(filePath);
|
|
46
|
-
|
|
47
|
-
if (!content) {
|
|
48
|
-
const resolvedFilePath = filePath.startsWith('~')
|
|
49
|
-
? path.join(homedir(), filePath.slice(1))
|
|
50
|
-
: filePath;
|
|
51
|
-
return res.status(404).json({ error: 'File not found', path: resolvedFilePath });
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const parseResult = parseJsonSafely(content);
|
|
55
|
-
|
|
56
|
-
if (!parseResult.config) {
|
|
57
|
-
return res.status(400).json({
|
|
58
|
-
error: 'Invalid JSON file',
|
|
59
|
-
details: parseResult.error ? parseResult.error.message : 'Failed to parse JSON',
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const config = parseResult.config;
|
|
64
|
-
|
|
65
|
-
const services = extractServices(config);
|
|
66
|
-
res.json({ success: true, services });
|
|
67
|
-
} catch (error) {
|
|
68
|
-
res.status(500).json({ error: 'Failed to extract services', details: error.message });
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
router.readConfig = (req, res) => {
|
|
73
|
-
try {
|
|
74
|
-
const { filePath } = req.query;
|
|
75
|
-
|
|
76
|
-
if (!filePath) {
|
|
77
|
-
return res.status(400).json({ error: 'filePath is required' });
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const resolvedPath = filePath.startsWith('~')
|
|
81
|
-
? path.join(homedir(), filePath.slice(1))
|
|
82
|
-
: filePath;
|
|
83
|
-
|
|
84
|
-
if (!fs.existsSync(resolvedPath)) {
|
|
85
|
-
return res.status(404).json({ error: 'File not found', path: resolvedPath });
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const content = fs.readFileSync(resolvedPath, 'utf-8');
|
|
89
|
-
const parsed = tryParseJson(content);
|
|
90
|
-
|
|
91
|
-
res.json({
|
|
92
|
-
success: true,
|
|
93
|
-
filePath: resolvedPath,
|
|
94
|
-
displayPath: resolvedPath.replace(homedir(), '~'),
|
|
95
|
-
content: content,
|
|
96
|
-
parsed: parsed,
|
|
97
|
-
exists: true,
|
|
98
|
-
});
|
|
99
|
-
} catch (error) {
|
|
100
|
-
res.status(500).json({ error: 'Failed to read file', details: error.message });
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
router.detectConfig = (_req, res) => {
|
|
105
|
-
const detected = [];
|
|
106
|
-
const platform = process.platform;
|
|
107
|
-
const homeDir = homedir();
|
|
108
|
-
|
|
109
|
-
const cursorPaths = [
|
|
110
|
-
path.join(homeDir, '.cursor', 'mcp.json'),
|
|
111
|
-
...(platform === 'win32'
|
|
112
|
-
? [path.join(process.env.USERPROFILE || '', '.cursor', 'mcp.json')]
|
|
113
|
-
: []),
|
|
114
|
-
];
|
|
115
|
-
|
|
116
|
-
const windsurfPaths = [
|
|
117
|
-
path.join(homeDir, '.codeium', 'windsurf', 'mcp_config.json'),
|
|
118
|
-
...(platform === 'win32'
|
|
119
|
-
? [path.join(process.env.USERPROFILE || '', '.codeium', 'windsurf', 'mcp_config.json')]
|
|
120
|
-
: []),
|
|
121
|
-
];
|
|
122
|
-
|
|
123
|
-
for (const cursorPath of cursorPaths) {
|
|
124
|
-
if (fs.existsSync(cursorPath)) {
|
|
125
|
-
detected.push({
|
|
126
|
-
editor: 'Cursor',
|
|
127
|
-
path: cursorPath,
|
|
128
|
-
displayPath: cursorPath.replace(homeDir, '~'),
|
|
129
|
-
exists: true,
|
|
130
|
-
});
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
for (const windsurfPath of windsurfPaths) {
|
|
136
|
-
if (fs.existsSync(windsurfPath)) {
|
|
137
|
-
detected.push({
|
|
138
|
-
editor: 'Windsurf',
|
|
139
|
-
path: windsurfPath,
|
|
140
|
-
displayPath: windsurfPath.replace(homeDir, '~'),
|
|
141
|
-
exists: true,
|
|
142
|
-
});
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const defaultPaths = [
|
|
148
|
-
{
|
|
149
|
-
editor: 'Cursor',
|
|
150
|
-
path: path.join(homeDir, '.cursor', 'mcp.json'),
|
|
151
|
-
displayPath: '~/.cursor/mcp.json',
|
|
152
|
-
exists: fs.existsSync(path.join(homeDir, '.cursor', 'mcp.json')),
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
editor: 'Windsurf',
|
|
156
|
-
path: path.join(homeDir, '.codeium', 'windsurf', 'mcp_config.json'),
|
|
157
|
-
displayPath: '~/.codeium/windsurf/mcp_config.json',
|
|
158
|
-
exists: fs.existsSync(path.join(homeDir, '.codeium', 'windsurf', 'mcp_config.json')),
|
|
159
|
-
},
|
|
160
|
-
];
|
|
161
|
-
|
|
162
|
-
const result = detected.length > 0 ? detected : defaultPaths;
|
|
163
|
-
|
|
164
|
-
res.json({
|
|
165
|
-
detected: result,
|
|
166
|
-
platform,
|
|
167
|
-
homeDir,
|
|
168
|
-
});
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
// Delegate backup routes to separate module
|
|
172
|
-
const backupRoutes = createBackupRoutes();
|
|
173
|
-
router.listBackups = backupRoutes.listBackups;
|
|
174
|
-
router.restoreBackup = backupRoutes.restoreBackup;
|
|
175
|
-
router.viewBackup = backupRoutes.viewBackup;
|
|
176
|
-
router.deleteBackup = backupRoutes.deleteBackup;
|
|
14
|
+
// Delegate to controller
|
|
15
|
+
router.extractServices = configController.extractServices;
|
|
16
|
+
router.readConfig = configController.readConfig;
|
|
17
|
+
router.detectConfig = configController.detectConfig;
|
|
177
18
|
|
|
178
19
|
return router;
|
|
179
20
|
}
|
|
@@ -1,25 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { ConversationController } from '../controllers/ConversationController.js';
|
|
2
|
+
|
|
3
|
+
export function createConversationsRoutes(container) {
|
|
4
|
+
const conversationService = container.getService('conversation');
|
|
5
|
+
const serializationLib = container.getLibrary('serialization');
|
|
6
|
+
const logger = container.getLibrary('logger');
|
|
7
|
+
|
|
8
|
+
const controller = new ConversationController(conversationService, serializationLib, logger);
|
|
3
9
|
|
|
4
|
-
export function createConversationsRoutes(db) {
|
|
5
10
|
const router = {};
|
|
6
11
|
|
|
7
|
-
router.getConversations = (req, res) =>
|
|
8
|
-
const limit = Number.parseInt(req.query.limit) || 1000;
|
|
9
|
-
const offset = Number.parseInt(req.query.offset) || 0;
|
|
10
|
-
const filters = {
|
|
11
|
-
sessionId: req.query.sessionId || null,
|
|
12
|
-
method: req.query.method || null,
|
|
13
|
-
status: req.query.status || null,
|
|
14
|
-
jsonrpcId: req.query.jsonrpcId || null,
|
|
15
|
-
startTime: req.query.startTime ? BigInt(req.query.startTime) : null,
|
|
16
|
-
endTime: req.query.endTime ? BigInt(req.query.endTime) : null,
|
|
17
|
-
limit,
|
|
18
|
-
offset,
|
|
19
|
-
};
|
|
20
|
-
const conversations = queryConversations(db, filters);
|
|
21
|
-
res.json(serializeBigInt(conversations));
|
|
22
|
-
};
|
|
12
|
+
router.getConversations = (req, res) => controller.getConversations(req, res);
|
|
23
13
|
|
|
24
14
|
return router;
|
|
25
15
|
}
|
package/ui/server/routes/help.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { readHelpState, writeHelpState } from '#
|
|
1
|
+
import { readHelpState, writeHelpState } from '#core/configs/index.js';
|
|
2
|
+
import { StatusCodes } from '#core/constants/index.js';
|
|
2
3
|
|
|
3
4
|
export function createHelpRoutes() {
|
|
4
5
|
const router = {};
|
|
@@ -21,7 +22,7 @@ export function createHelpRoutes() {
|
|
|
21
22
|
if (success) {
|
|
22
23
|
res.json({ success: true });
|
|
23
24
|
} else {
|
|
24
|
-
res.status(
|
|
25
|
+
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: 'Failed to save help state' });
|
|
25
26
|
}
|
|
26
27
|
};
|
|
27
28
|
|
|
@@ -35,7 +36,7 @@ export function createHelpRoutes() {
|
|
|
35
36
|
if (success) {
|
|
36
37
|
res.json({ success: true });
|
|
37
38
|
} else {
|
|
38
|
-
res.status(
|
|
39
|
+
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: 'Failed to reset help state' });
|
|
39
40
|
}
|
|
40
41
|
};
|
|
41
42
|
|
package/ui/server/routes/logs.js
CHANGED
|
@@ -1,32 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
const router = {};
|
|
3
|
-
|
|
4
|
-
router.getLogs = (req, res) => {
|
|
5
|
-
const limit = Number.parseInt(req.query.limit) || 1000;
|
|
6
|
-
const offset = Number.parseInt(req.query.offset) || 0;
|
|
7
|
-
const logs = [...mcpSharkLogs].reverse().slice(offset, offset + limit);
|
|
8
|
-
res.json(logs);
|
|
9
|
-
};
|
|
1
|
+
import { LogController } from '#ui/server/controllers/index.js';
|
|
10
2
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Create logs routes
|
|
5
|
+
* Routes delegate to LogController which calls LogService
|
|
6
|
+
*/
|
|
7
|
+
export function createLogsRoutes(container, mcpSharkLogs) {
|
|
8
|
+
const logService = container.getService('log');
|
|
9
|
+
const logger = container.getLibrary('logger');
|
|
10
|
+
logService.initialize(mcpSharkLogs);
|
|
11
|
+
const logController = new LogController(logService, logger);
|
|
15
12
|
|
|
16
|
-
router
|
|
17
|
-
try {
|
|
18
|
-
const logsText = mcpSharkLogs
|
|
19
|
-
.map((log) => `[${log.timestamp}] [${log.type.toUpperCase()}] ${log.line}`)
|
|
20
|
-
.join('\n');
|
|
13
|
+
const router = {};
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
res.send(logsText);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
res.status(500).json({ error: 'Failed to export logs', details: error.message });
|
|
28
|
-
}
|
|
29
|
-
};
|
|
15
|
+
router.getLogs = logController.getLogs;
|
|
16
|
+
router.clearLogs = logController.clearLogs;
|
|
17
|
+
router.exportLogs = logController.exportLogs;
|
|
30
18
|
|
|
31
19
|
return router;
|
|
32
20
|
}
|
|
@@ -1,181 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
3
|
-
import logger from '../utils/logger.js';
|
|
1
|
+
import { McpClientController } from '#ui/server/controllers/index.js';
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Create playground routes
|
|
5
|
+
* Routes delegate to McpClientController which calls McpClientService
|
|
6
|
+
*/
|
|
7
|
+
export function createPlaygroundRoutes(container) {
|
|
8
|
+
const mcpClientService = container.getService('mcpClient');
|
|
9
|
+
const logger = container.getLibrary('logger');
|
|
10
|
+
const mcpClientController = new McpClientController(mcpClientService, logger);
|
|
6
11
|
|
|
7
|
-
// Store client connections per server and session
|
|
8
|
-
const clientSessions = new Map();
|
|
9
|
-
|
|
10
|
-
function getSessionKey(serverName, sessionId) {
|
|
11
|
-
return `${serverName}:${sessionId}`;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function createPlaygroundRoutes() {
|
|
15
12
|
const router = {};
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const sessionKey = getSessionKey(serverName, sessionId);
|
|
20
|
-
if (clientSessions.has(sessionKey)) {
|
|
21
|
-
return clientSessions.get(sessionKey);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (!serverName) {
|
|
25
|
-
throw new Error('Server name is required');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const mcpServerUrl = `${MCP_SERVER_BASE_URL}/${encodeURIComponent(serverName)}`;
|
|
29
|
-
|
|
30
|
-
const client = new Client(
|
|
31
|
-
{ name: 'mcp-shark-playground', version: '1.0.0' },
|
|
32
|
-
{
|
|
33
|
-
capabilities: {
|
|
34
|
-
tools: {},
|
|
35
|
-
resources: {},
|
|
36
|
-
prompts: {},
|
|
37
|
-
},
|
|
38
|
-
}
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
const transport = new StreamableHTTPClientTransport(new URL(mcpServerUrl));
|
|
42
|
-
await client.connect(transport);
|
|
43
|
-
|
|
44
|
-
const clientWrapper = {
|
|
45
|
-
client,
|
|
46
|
-
transport,
|
|
47
|
-
close: async () => {
|
|
48
|
-
await client.close();
|
|
49
|
-
transport.close?.();
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
clientSessions.set(sessionKey, clientWrapper);
|
|
54
|
-
return clientWrapper;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
router.proxyRequest = async (req, res) => {
|
|
58
|
-
try {
|
|
59
|
-
const { method, params, serverName } = req.body;
|
|
60
|
-
|
|
61
|
-
if (!method) {
|
|
62
|
-
return res.status(400).json({
|
|
63
|
-
error: 'Invalid request',
|
|
64
|
-
message: 'method field is required',
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!serverName) {
|
|
69
|
-
return res.status(400).json({
|
|
70
|
-
error: 'Invalid request',
|
|
71
|
-
message: 'serverName field is required',
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Get or create session ID
|
|
76
|
-
const sessionId =
|
|
77
|
-
req.headers['mcp-session-id'] ||
|
|
78
|
-
req.headers['x-mcp-session-id'] ||
|
|
79
|
-
`playground-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
80
|
-
|
|
81
|
-
const { client } = await getClient(serverName, sessionId);
|
|
82
|
-
|
|
83
|
-
const executeMethod = async () => {
|
|
84
|
-
switch (method) {
|
|
85
|
-
case 'tools/list':
|
|
86
|
-
return await client.listTools();
|
|
87
|
-
case 'tools/call':
|
|
88
|
-
if (!params?.name) {
|
|
89
|
-
return res.status(400).json({
|
|
90
|
-
error: 'Invalid request',
|
|
91
|
-
message: 'Tool name is required',
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
return await client.callTool({
|
|
95
|
-
name: params.name,
|
|
96
|
-
arguments: params.arguments || {},
|
|
97
|
-
});
|
|
98
|
-
case 'prompts/list':
|
|
99
|
-
return await client.listPrompts();
|
|
100
|
-
case 'prompts/get':
|
|
101
|
-
if (!params?.name) {
|
|
102
|
-
return res.status(400).json({
|
|
103
|
-
error: 'Invalid request',
|
|
104
|
-
message: 'Prompt name is required',
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
return await client.getPrompt({
|
|
108
|
-
name: params.name,
|
|
109
|
-
arguments: params.arguments || {},
|
|
110
|
-
});
|
|
111
|
-
case 'resources/list':
|
|
112
|
-
return await client.listResources();
|
|
113
|
-
case 'resources/read':
|
|
114
|
-
if (!params?.uri) {
|
|
115
|
-
return res.status(400).json({
|
|
116
|
-
error: 'Invalid request',
|
|
117
|
-
message: 'Resource URI is required',
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
return await client.readResource({ uri: params.uri });
|
|
121
|
-
default:
|
|
122
|
-
return res.status(400).json({
|
|
123
|
-
error: 'Unsupported method',
|
|
124
|
-
message: `Method ${method} is not supported`,
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const result = await executeMethod();
|
|
130
|
-
|
|
131
|
-
// Return session ID in response
|
|
132
|
-
res.setHeader('Mcp-Session-Id', sessionId);
|
|
133
|
-
res.json({
|
|
134
|
-
result,
|
|
135
|
-
_sessionId: sessionId,
|
|
136
|
-
});
|
|
137
|
-
} catch (error) {
|
|
138
|
-
logger.error({ error: error.message }, 'Error in playground proxy');
|
|
139
|
-
|
|
140
|
-
// Check if it's a connection error
|
|
141
|
-
if (error.message?.includes('ECONNREFUSED') || error.message?.includes('connect')) {
|
|
142
|
-
return res.status(503).json({
|
|
143
|
-
error: 'MCP server unavailable',
|
|
144
|
-
message: error.message,
|
|
145
|
-
details: 'Make sure the MCP Shark server is running on port 9851',
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
res.status(500).json({
|
|
150
|
-
error: 'Internal server error',
|
|
151
|
-
message: error.message || 'Unknown error',
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
// Cleanup endpoint to close client connections
|
|
157
|
-
router.cleanup = async (req, res) => {
|
|
158
|
-
const sessionId = req.headers['mcp-session-id'] || req.headers['x-mcp-session-id'];
|
|
159
|
-
const { serverName } = req.body || {};
|
|
160
|
-
|
|
161
|
-
if (serverName && sessionId) {
|
|
162
|
-
const sessionKey = getSessionKey(serverName, sessionId);
|
|
163
|
-
if (clientSessions.has(sessionKey)) {
|
|
164
|
-
const clientWrapper = clientSessions.get(sessionKey);
|
|
165
|
-
await clientWrapper.close();
|
|
166
|
-
clientSessions.delete(sessionKey);
|
|
167
|
-
}
|
|
168
|
-
} else if (sessionId) {
|
|
169
|
-
// Cleanup all sessions for this sessionId across all servers
|
|
170
|
-
for (const [key, clientWrapper] of clientSessions.entries()) {
|
|
171
|
-
if (key.endsWith(`:${sessionId}`)) {
|
|
172
|
-
await clientWrapper.close();
|
|
173
|
-
clientSessions.delete(key);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
res.json({ success: true });
|
|
178
|
-
};
|
|
14
|
+
router.proxyRequest = mcpClientController.proxyRequest;
|
|
15
|
+
router.cleanup = mcpClientController.cleanup;
|
|
179
16
|
|
|
180
17
|
return router;
|
|
181
18
|
}
|