@mcp-shark/mcp-shark 1.5.4 → 1.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/README.md +32 -96
  2. package/bin/mcp-shark.js +1 -1
  3. package/core/configs/codex.js +68 -0
  4. package/core/configs/environment.js +51 -0
  5. package/{lib/common → core}/configs/index.js +16 -1
  6. package/core/constants/Defaults.js +15 -0
  7. package/core/constants/HttpStatus.js +14 -0
  8. package/core/constants/Server.js +20 -0
  9. package/core/constants/StatusCodes.js +25 -0
  10. package/core/constants/index.js +7 -0
  11. package/core/container/DependencyContainer.js +179 -0
  12. package/core/db/init.js +33 -0
  13. package/core/index.js +10 -0
  14. package/{mcp-server/lib/common/error.js → core/libraries/ErrorLibrary.js} +4 -0
  15. package/core/libraries/LoggerLibrary.js +91 -0
  16. package/core/libraries/SerializationLibrary.js +32 -0
  17. package/core/libraries/bootstrap-logger.js +19 -0
  18. package/core/libraries/errors/ApplicationError.js +97 -0
  19. package/core/libraries/index.js +17 -0
  20. package/{mcp-server/lib → core/mcp-server}/auditor/audit.js +77 -53
  21. package/core/mcp-server/index.js +192 -0
  22. package/{mcp-server/lib → core/mcp-server}/server/external/all.js +1 -1
  23. package/core/mcp-server/server/external/config.js +75 -0
  24. package/{mcp-server/lib → core/mcp-server}/server/external/single/client.js +1 -1
  25. package/{mcp-server/lib → core/mcp-server}/server/external/single/request.js +1 -1
  26. package/{mcp-server/lib → core/mcp-server}/server/external/single/run.js +20 -11
  27. package/{mcp-server/lib → core/mcp-server}/server/external/single/transport.js +1 -1
  28. package/{mcp-server/lib → core/mcp-server}/server/internal/handlers/error.js +1 -1
  29. package/core/mcp-server/server/internal/handlers/prompts-get.js +28 -0
  30. package/core/mcp-server/server/internal/handlers/prompts-list.js +21 -0
  31. package/core/mcp-server/server/internal/handlers/resources-list.js +21 -0
  32. package/core/mcp-server/server/internal/handlers/resources-read.js +28 -0
  33. package/core/mcp-server/server/internal/handlers/tools-call.js +44 -0
  34. package/core/mcp-server/server/internal/handlers/tools-list.js +23 -0
  35. package/core/mcp-server/server/internal/run.js +53 -0
  36. package/{mcp-server/lib → core/mcp-server}/server/internal/server.js +11 -1
  37. package/core/models/ConversationFilters.js +31 -0
  38. package/core/models/ExportFormat.js +8 -0
  39. package/core/models/RequestFilters.js +43 -0
  40. package/core/models/SessionFilters.js +23 -0
  41. package/core/models/index.js +8 -0
  42. package/core/repositories/AuditRepository.js +233 -0
  43. package/core/repositories/ConversationRepository.js +182 -0
  44. package/core/repositories/PacketRepository.js +237 -0
  45. package/core/repositories/SchemaRepository.js +107 -0
  46. package/core/repositories/SessionRepository.js +59 -0
  47. package/core/repositories/StatisticsRepository.js +54 -0
  48. package/core/repositories/index.js +10 -0
  49. package/core/services/AuditService.js +144 -0
  50. package/core/services/BackupService.js +222 -0
  51. package/core/services/ConfigDetectionService.js +89 -0
  52. package/core/services/ConfigFileService.js +210 -0
  53. package/core/services/ConfigPatchingService.js +137 -0
  54. package/core/services/ConfigService.js +250 -0
  55. package/core/services/ConfigTransformService.js +178 -0
  56. package/core/services/ConversationService.js +19 -0
  57. package/core/services/ExportService.js +117 -0
  58. package/core/services/LogService.js +64 -0
  59. package/core/services/McpClientService.js +235 -0
  60. package/core/services/McpDiscoveryService.js +107 -0
  61. package/core/services/RequestService.js +56 -0
  62. package/core/services/ScanCacheService.js +242 -0
  63. package/core/services/ScanService.js +167 -0
  64. package/core/services/ServerManagementService.js +206 -0
  65. package/core/services/SessionService.js +34 -0
  66. package/core/services/SettingsService.js +163 -0
  67. package/core/services/StatisticsService.js +64 -0
  68. package/core/services/TokenService.js +94 -0
  69. package/core/services/index.js +25 -0
  70. package/core/services/parsers/ConfigParserFactory.js +113 -0
  71. package/core/services/parsers/JsonConfigParser.js +66 -0
  72. package/core/services/parsers/LegacyJsonConfigParser.js +71 -0
  73. package/core/services/parsers/TomlConfigParser.js +87 -0
  74. package/core/services/parsers/index.js +4 -0
  75. package/{ui/server → core}/utils/scan-cache/directory.js +1 -1
  76. package/core/utils/validation.js +77 -0
  77. package/package.json +14 -11
  78. package/ui/dist/assets/index-CArYxKxS.js +35 -0
  79. package/ui/dist/index.html +1 -1
  80. package/ui/server/controllers/BackupController.js +129 -0
  81. package/ui/server/controllers/ConfigController.js +92 -0
  82. package/ui/server/controllers/ConversationController.js +41 -0
  83. package/ui/server/controllers/LogController.js +44 -0
  84. package/ui/server/controllers/McpClientController.js +60 -0
  85. package/ui/server/controllers/McpDiscoveryController.js +44 -0
  86. package/ui/server/controllers/RequestController.js +129 -0
  87. package/ui/server/controllers/ScanController.js +122 -0
  88. package/ui/server/controllers/ServerManagementController.js +134 -0
  89. package/ui/server/controllers/SessionController.js +57 -0
  90. package/ui/server/controllers/SettingsController.js +24 -0
  91. package/ui/server/controllers/StatisticsController.js +54 -0
  92. package/ui/server/controllers/TokenController.js +58 -0
  93. package/ui/server/controllers/index.js +17 -0
  94. package/ui/server/routes/backups/index.js +15 -9
  95. package/ui/server/routes/composite/index.js +62 -32
  96. package/ui/server/routes/composite/servers.js +20 -15
  97. package/ui/server/routes/config.js +13 -172
  98. package/ui/server/routes/conversations.js +9 -19
  99. package/ui/server/routes/help.js +4 -3
  100. package/ui/server/routes/logs.js +14 -26
  101. package/ui/server/routes/playground.js +11 -174
  102. package/ui/server/routes/requests.js +12 -232
  103. package/ui/server/routes/sessions.js +10 -21
  104. package/ui/server/routes/settings.js +10 -192
  105. package/ui/server/routes/smartscan.js +26 -15
  106. package/ui/server/routes/statistics.js +8 -79
  107. package/ui/server/setup.js +162 -0
  108. package/ui/server/swagger/paths/backups.js +151 -0
  109. package/ui/server/swagger/paths/components.js +76 -0
  110. package/ui/server/swagger/paths/config.js +117 -0
  111. package/ui/server/swagger/paths/conversations.js +29 -0
  112. package/ui/server/swagger/paths/help.js +82 -0
  113. package/ui/server/swagger/paths/logs.js +87 -0
  114. package/ui/server/swagger/paths/playground.js +49 -0
  115. package/ui/server/swagger/paths/requests.js +178 -0
  116. package/ui/server/swagger/paths/serverManagement.js +169 -0
  117. package/ui/server/swagger/paths/sessions.js +61 -0
  118. package/ui/server/swagger/paths/settings.js +31 -0
  119. package/ui/server/swagger/paths/smartScan/discovery.js +97 -0
  120. package/ui/server/swagger/paths/smartScan/index.js +13 -0
  121. package/ui/server/swagger/paths/smartScan/scans.js +151 -0
  122. package/ui/server/swagger/paths/smartScan/token.js +71 -0
  123. package/ui/server/swagger/paths/statistics.js +40 -0
  124. package/ui/server/swagger/paths.js +38 -0
  125. package/ui/server/swagger/swagger.js +37 -0
  126. package/ui/server/utils/cleanup.js +99 -0
  127. package/ui/server/utils/config.js +18 -96
  128. package/ui/server/utils/errorHandler.js +43 -0
  129. package/ui/server/utils/logger.js +2 -2
  130. package/ui/server/utils/paths.js +27 -30
  131. package/ui/server/utils/port.js +21 -21
  132. package/ui/server/utils/process.js +18 -10
  133. package/ui/server/utils/processState.js +17 -0
  134. package/ui/server/utils/signals.js +34 -0
  135. package/ui/server/websocket/broadcast.js +33 -0
  136. package/ui/server/websocket/handler.js +52 -0
  137. package/ui/server.js +51 -230
  138. package/ui/src/App.jsx +2 -0
  139. package/ui/src/CompositeSetup.jsx +23 -9
  140. package/ui/src/PacketFilters.jsx +17 -3
  141. package/ui/src/components/AlertModal.jsx +116 -0
  142. package/ui/src/components/App/ApiDocsButton.jsx +57 -0
  143. package/ui/src/components/App/useAppState.js +43 -1
  144. package/ui/src/components/BackupList.jsx +27 -3
  145. package/ui/src/utils/requestPairing.js +35 -36
  146. package/ui/src/utils/requestUtils.js +1 -0
  147. package/lib/common/db/init.js +0 -132
  148. package/lib/common/db/logger.js +0 -349
  149. package/lib/common/db/query.js +0 -403
  150. package/lib/common/logger.js +0 -90
  151. package/mcp-server/index.js +0 -138
  152. package/mcp-server/lib/server/external/config.js +0 -57
  153. package/mcp-server/lib/server/internal/handlers/prompts-get.js +0 -20
  154. package/mcp-server/lib/server/internal/handlers/prompts-list.js +0 -13
  155. package/mcp-server/lib/server/internal/handlers/resources-list.js +0 -13
  156. package/mcp-server/lib/server/internal/handlers/resources-read.js +0 -20
  157. package/mcp-server/lib/server/internal/handlers/tools-call.js +0 -35
  158. package/mcp-server/lib/server/internal/handlers/tools-list.js +0 -15
  159. package/mcp-server/lib/server/internal/run.js +0 -37
  160. package/mcp-server/mcp-shark.js +0 -22
  161. package/ui/dist/assets/index-CFHeMNwd.js +0 -35
  162. package/ui/server/routes/backups/deleteBackup.js +0 -54
  163. package/ui/server/routes/backups/listBackups.js +0 -75
  164. package/ui/server/routes/backups/restoreBackup.js +0 -83
  165. package/ui/server/routes/backups/viewBackup.js +0 -47
  166. package/ui/server/routes/composite/setup.js +0 -129
  167. package/ui/server/routes/composite/status.js +0 -7
  168. package/ui/server/routes/composite/stop.js +0 -39
  169. package/ui/server/routes/composite/utils.js +0 -45
  170. package/ui/server/routes/smartscan/discover.js +0 -118
  171. package/ui/server/routes/smartscan/scans/clearCache.js +0 -23
  172. package/ui/server/routes/smartscan/scans/createBatchScans.js +0 -124
  173. package/ui/server/routes/smartscan/scans/createScan.js +0 -43
  174. package/ui/server/routes/smartscan/scans/getCachedResults.js +0 -52
  175. package/ui/server/routes/smartscan/scans/getScan.js +0 -42
  176. package/ui/server/routes/smartscan/scans/listScans.js +0 -25
  177. package/ui/server/routes/smartscan/scans.js +0 -13
  178. package/ui/server/routes/smartscan/token.js +0 -57
  179. package/ui/server/utils/config-update.js +0 -240
  180. package/ui/server/utils/scan-cache/all-results.js +0 -197
  181. package/ui/server/utils/scan-cache/file-operations.js +0 -107
  182. package/ui/server/utils/scan-cache/hash.js +0 -47
  183. package/ui/server/utils/scan-cache/server-operations.js +0 -85
  184. package/ui/server/utils/scan-cache.js +0 -12
  185. package/ui/server/utils/smartscan-token.js +0 -43
  186. /package/{mcp-server/lib → core/mcp-server}/server/external/kv.js +0 -0
  187. /package/{mcp-server/lib → core/mcp-server}/server/internal/handlers/common.js +0 -0
  188. /package/{mcp-server/lib → core/mcp-server}/server/internal/session.js +0 -0
@@ -0,0 +1,210 @@
1
+ import * as fs from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { getMcpConfigPath } from '#core/configs/index.js';
5
+
6
+ /**
7
+ * Service for configuration file operations
8
+ * Handles file I/O, path resolution, and backup/restore
9
+ */
10
+ export class ConfigFileService {
11
+ constructor(logger, configDetectionService, configParserFactory) {
12
+ this.logger = logger;
13
+ this.originalConfigData = null;
14
+ this.detectionService = configDetectionService;
15
+ this.parserFactory = configParserFactory;
16
+ }
17
+
18
+ /**
19
+ * Resolve file path (expand ~ to home directory)
20
+ */
21
+ resolveFilePath(filePath) {
22
+ if (!filePath) {
23
+ return null;
24
+ }
25
+ return filePath.startsWith('~') ? path.join(homedir(), filePath.slice(1)) : filePath;
26
+ }
27
+
28
+ /**
29
+ * Read file content from path or use provided content
30
+ */
31
+ resolveFileData(filePath, fileContent) {
32
+ if (fileContent) {
33
+ const resolvedFilePath = filePath ? this.resolveFilePath(filePath) : null;
34
+ return { content: fileContent, resolvedFilePath };
35
+ }
36
+
37
+ if (!filePath) {
38
+ return null;
39
+ }
40
+
41
+ const resolvedFilePath = this.resolveFilePath(filePath);
42
+
43
+ if (!fs.existsSync(resolvedFilePath)) {
44
+ return null;
45
+ }
46
+
47
+ return {
48
+ content: fs.readFileSync(resolvedFilePath, 'utf-8'),
49
+ resolvedFilePath,
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Parse JSON or TOML content safely using appropriate parser
55
+ */
56
+ parseJsonConfig(content, filePath = null) {
57
+ try {
58
+ const config = this.parserFactory.parse(content, filePath);
59
+ return { config, error: null };
60
+ } catch (error) {
61
+ return { config: null, error };
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Try to parse JSON or TOML, return null on error
67
+ */
68
+ tryParseJson(content, filePath = null) {
69
+ return this.parserFactory.parse(content, filePath);
70
+ }
71
+
72
+ /**
73
+ * Read config file content
74
+ */
75
+ readConfigFile(filePath) {
76
+ const resolvedPath = this.resolveFilePath(filePath);
77
+
78
+ if (!fs.existsSync(resolvedPath)) {
79
+ return null;
80
+ }
81
+
82
+ return fs.readFileSync(resolvedPath, 'utf-8');
83
+ }
84
+
85
+ /**
86
+ * Write config file
87
+ */
88
+ writeConfigFile(filePath, content) {
89
+ const resolvedPath = this.resolveFilePath(filePath);
90
+ fs.writeFileSync(resolvedPath, content);
91
+ this.logger?.info({ path: resolvedPath }, 'Wrote config file');
92
+ }
93
+
94
+ /**
95
+ * Check if file exists
96
+ */
97
+ fileExists(filePath) {
98
+ const resolvedPath = this.resolveFilePath(filePath);
99
+ return fs.existsSync(resolvedPath);
100
+ }
101
+
102
+ /**
103
+ * Get file type from path
104
+ */
105
+ getFileType(filePath) {
106
+ if (!filePath) {
107
+ return 'JSON';
108
+ }
109
+ const ext = path.extname(filePath).toLowerCase();
110
+ return ext === '.toml' ? 'TOML' : 'JSON';
111
+ }
112
+
113
+ /**
114
+ * Get display path (replace home directory with ~)
115
+ */
116
+ getDisplayPath(filePath) {
117
+ if (!filePath) {
118
+ return filePath;
119
+ }
120
+ const homeDir = homedir();
121
+ return filePath.replace(homeDir, '~');
122
+ }
123
+
124
+ /**
125
+ * Get home directory
126
+ */
127
+ getHomeDir() {
128
+ return homedir();
129
+ }
130
+
131
+ /**
132
+ * Detect config files on the system
133
+ */
134
+ detectConfigFiles() {
135
+ return this.detectionService.detectConfigFiles();
136
+ }
137
+
138
+ /**
139
+ * Get MCP config path
140
+ */
141
+ getMcpConfigPath() {
142
+ return getMcpConfigPath();
143
+ }
144
+
145
+ /**
146
+ * Read MCP config file (supports both JSON and TOML)
147
+ * Uses appropriate parser based on file extension
148
+ */
149
+ readMcpConfig() {
150
+ const configPath = this.getMcpConfigPath();
151
+ if (!fs.existsSync(configPath)) {
152
+ return null;
153
+ }
154
+
155
+ const content = fs.readFileSync(configPath, 'utf-8');
156
+ return this.parserFactory.parse(content, configPath);
157
+ }
158
+
159
+ /**
160
+ * Get servers from MCP config
161
+ */
162
+ getServersFromConfig() {
163
+ const config = this.readMcpConfig();
164
+ if (!config) {
165
+ return [];
166
+ }
167
+
168
+ return config.servers ? Object.keys(config.servers) : [];
169
+ }
170
+
171
+ /**
172
+ * Store original config for restoration
173
+ */
174
+ storeOriginalConfig(filePath, originalContent, backupPath) {
175
+ this.originalConfigData = { filePath, originalContent, backupPath };
176
+ }
177
+
178
+ /**
179
+ * Restore original config
180
+ */
181
+ restoreOriginalConfig() {
182
+ if (this.originalConfigData?.filePath) {
183
+ try {
184
+ if (fs.existsSync(this.originalConfigData.filePath)) {
185
+ fs.writeFileSync(
186
+ this.originalConfigData.filePath,
187
+ this.originalConfigData.originalContent
188
+ );
189
+ this.logger?.info({ path: this.originalConfigData.filePath }, 'Restored original config');
190
+ this.originalConfigData = null;
191
+ return true;
192
+ }
193
+ this.originalConfigData = null;
194
+ return false;
195
+ } catch (error) {
196
+ this.logger?.error({ error: error.message }, 'Failed to restore original config');
197
+ this.originalConfigData = null;
198
+ return false;
199
+ }
200
+ }
201
+ return false;
202
+ }
203
+
204
+ /**
205
+ * Clear original config reference
206
+ */
207
+ clearOriginalConfig() {
208
+ this.originalConfigData = null;
209
+ }
210
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Service for handling config patching operations
3
+ * Handles checking if config is patched, restoring original, and repatching
4
+ */
5
+ export class ConfigPatchingService {
6
+ /**
7
+ * @param {ConfigService} configService - Config service instance
8
+ * @param {BackupService} backupService - Backup service instance
9
+ * @param {object} logger - Logger instance
10
+ */
11
+ constructor(configService, backupService, logger) {
12
+ this.configService = configService;
13
+ this.backupService = backupService;
14
+ this.logger = logger;
15
+ }
16
+
17
+ /**
18
+ * Restore original config if file is already patched
19
+ * Should be called before processing setup to ensure original config is read
20
+ * @param {string} filePath - Path to config file
21
+ * @returns {{wasPatched: boolean, restored: boolean, warning?: string}}
22
+ */
23
+ restoreIfPatched(filePath) {
24
+ const resolvedPath = this.configService.fileService.resolveFilePath(filePath);
25
+ const isPatched = this.configService.isFilePatched(resolvedPath);
26
+
27
+ if (!isPatched) {
28
+ return { wasPatched: false, restored: false };
29
+ }
30
+
31
+ // Config is already patched - restore original first
32
+ this.logger?.warn(
33
+ { filePath: resolvedPath },
34
+ 'Config file is already patched, restoring original before processing'
35
+ );
36
+
37
+ // Try to restore from in-memory backup first
38
+ const inMemoryRestored = this.configService.restoreOriginalConfig();
39
+
40
+ // If that didn't work, use BackupService to find and restore from backup file
41
+ const restoreResult = inMemoryRestored
42
+ ? { success: true }
43
+ : this._restoreFromBackupFile(resolvedPath);
44
+
45
+ const restored = restoreResult.success;
46
+ const warning = restored
47
+ ? 'Config was already patched. Restored original before processing.'
48
+ : 'Config was patched but could not restore original. Proceeding anyway.';
49
+
50
+ if (!restored) {
51
+ this.logger?.warn(
52
+ { filePath: resolvedPath },
53
+ 'Could not restore original config - may cause issues'
54
+ );
55
+ } else {
56
+ this.logger?.info({ filePath: resolvedPath }, 'Restored original config successfully');
57
+ }
58
+
59
+ return { wasPatched: true, restored, warning };
60
+ }
61
+
62
+ /**
63
+ * Patch config file, restoring original first if already patched
64
+ * @param {string} filePath - Path to config file
65
+ * @param {object} patchedConfig - Config object to write (already patched)
66
+ * @returns {{wasPatched: boolean, restored: boolean, warning?: string}}
67
+ */
68
+ patchConfigFile(filePath, patchedConfig) {
69
+ const resolvedPath = this.configService.fileService.resolveFilePath(filePath);
70
+ const isPatched = this.configService.isFilePatched(resolvedPath);
71
+
72
+ if (!isPatched) {
73
+ // Not patched, just write the patched config
74
+ this.configService.writeConfigAsJson(resolvedPath, patchedConfig);
75
+ return { wasPatched: false, restored: false };
76
+ }
77
+
78
+ // Config is already patched - restore original first
79
+ this.logger?.warn(
80
+ { filePath: resolvedPath },
81
+ 'Config file is already patched, restoring original before repatching'
82
+ );
83
+
84
+ // Try to restore from in-memory backup first
85
+ const inMemoryRestored = this.configService.restoreOriginalConfig();
86
+
87
+ // If that didn't work, use BackupService to find and restore from backup file
88
+ const restoreResult = inMemoryRestored
89
+ ? { success: true }
90
+ : this._restoreFromBackupFile(resolvedPath);
91
+
92
+ const restored = restoreResult.success;
93
+ const warning = restored
94
+ ? 'Config was already patched. Restored original and repatched.'
95
+ : 'Config was patched but could not restore original. Proceeding anyway.';
96
+
97
+ if (!restored) {
98
+ this.logger?.warn(
99
+ { filePath: resolvedPath },
100
+ 'Could not restore original config - may cause issues'
101
+ );
102
+ }
103
+
104
+ // Now write the patched config
105
+ this.configService.writeConfigAsJson(resolvedPath, patchedConfig);
106
+
107
+ return { wasPatched: true, restored, warning };
108
+ }
109
+
110
+ /**
111
+ * Restore config from backup file using BackupService
112
+ * @private
113
+ * @param {string} filePath - Path to config file to restore
114
+ * @returns {{success: boolean}}
115
+ */
116
+ _restoreFromBackupFile(filePath) {
117
+ const backups = this.backupService.listBackups();
118
+ const matchingBackup = backups.find((backup) => backup.originalPath === filePath);
119
+
120
+ if (!matchingBackup) {
121
+ return { success: false };
122
+ }
123
+
124
+ this.logger?.info(
125
+ { backupPath: matchingBackup.backupPath },
126
+ 'Found backup file, restoring from backup'
127
+ );
128
+
129
+ const restoreResult = this.backupService.restoreBackup(
130
+ matchingBackup.backupPath,
131
+ filePath,
132
+ false
133
+ );
134
+
135
+ return { success: restoreResult.success };
136
+ }
137
+ }
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Service for configuration file operations
3
+ * Composes ConfigFileService and ConfigTransformService
4
+ * Uses dependency injection for all dependencies
5
+ */
6
+ export class ConfigService {
7
+ /**
8
+ * @param {Object} logger - Logger instance
9
+ * @param {ConfigFileService} configFileService - File service instance
10
+ * @param {ConfigTransformService} configTransformService - Transform service instance
11
+ * @param {ConfigDetectionService} configDetectionService - Detection service instance
12
+ */
13
+ constructor(logger, configFileService, configTransformService, configDetectionService) {
14
+ this.fileService = configFileService;
15
+ this.transformService = configTransformService;
16
+ this.detectionService = configDetectionService;
17
+ this.logger = logger;
18
+ }
19
+
20
+ resolveFilePath(filePath) {
21
+ return this.fileService.resolveFilePath(filePath);
22
+ }
23
+
24
+ resolveFileData(filePath, fileContent) {
25
+ return this.fileService.resolveFileData(filePath, fileContent);
26
+ }
27
+
28
+ parseJsonConfig(content) {
29
+ return this.fileService.parseJsonConfig(content);
30
+ }
31
+
32
+ tryParseJson(content) {
33
+ return this.fileService.tryParseJson(content);
34
+ }
35
+
36
+ readConfigFile(filePath) {
37
+ return this.fileService.readConfigFile(filePath);
38
+ }
39
+
40
+ writeConfigFile(filePath, content) {
41
+ return this.fileService.writeConfigFile(filePath, content);
42
+ }
43
+
44
+ fileExists(filePath) {
45
+ return this.fileService.fileExists(filePath);
46
+ }
47
+
48
+ convertMcpServersToServers(config) {
49
+ return this.transformService.convertMcpServersToServers(config);
50
+ }
51
+
52
+ extractServices(config) {
53
+ return this.transformService.extractServices(config);
54
+ }
55
+
56
+ filterServers(config, selectedServices) {
57
+ return this.transformService.filterServers(config, selectedServices);
58
+ }
59
+
60
+ detectConfigFiles() {
61
+ return this.fileService.detectConfigFiles();
62
+ }
63
+
64
+ getMcpConfigPath() {
65
+ return this.fileService.getMcpConfigPath();
66
+ }
67
+
68
+ readMcpConfig() {
69
+ return this.fileService.readMcpConfig();
70
+ }
71
+
72
+ getServersFromConfig() {
73
+ return this.fileService.getServersFromConfig();
74
+ }
75
+
76
+ updateConfigForMcpShark(originalConfig) {
77
+ return this.transformService.updateConfigForMcpShark(originalConfig);
78
+ }
79
+
80
+ getSelectedServiceNames(originalConfig, selectedServices) {
81
+ return this.transformService.getSelectedServiceNames(originalConfig, selectedServices);
82
+ }
83
+
84
+ storeOriginalConfig(filePath, originalContent, backupPath) {
85
+ return this.fileService.storeOriginalConfig(filePath, originalContent, backupPath);
86
+ }
87
+
88
+ restoreOriginalConfig() {
89
+ return this.fileService.restoreOriginalConfig();
90
+ }
91
+
92
+ clearOriginalConfig() {
93
+ return this.fileService.clearOriginalConfig();
94
+ }
95
+
96
+ getFileType(filePath) {
97
+ return this.fileService.getFileType(filePath);
98
+ }
99
+
100
+ getDisplayPath(filePath) {
101
+ return this.fileService.getDisplayPath(filePath);
102
+ }
103
+
104
+ getHomeDir() {
105
+ return this.fileService.getHomeDir();
106
+ }
107
+
108
+ /**
109
+ * Extract services from file (handles full flow)
110
+ */
111
+ extractServicesFromFile(filePath, fileContent) {
112
+ const fileData = this.fileService.resolveFileData(filePath, fileContent);
113
+ if (!fileData) {
114
+ const resolvedFilePath = filePath ? this.fileService.resolveFilePath(filePath) : null;
115
+ return {
116
+ success: false,
117
+ error: 'File not found',
118
+ path: resolvedFilePath,
119
+ };
120
+ }
121
+
122
+ const parseResult = this.fileService.parseJsonConfig(
123
+ fileData.content,
124
+ fileData.resolvedFilePath
125
+ );
126
+ if (!parseResult.config) {
127
+ const fileType = this.fileService.getFileType(fileData.resolvedFilePath);
128
+ return {
129
+ success: false,
130
+ error: `Invalid ${fileType} file`,
131
+ details: parseResult.error ? parseResult.error.message : `Failed to parse ${fileType}`,
132
+ };
133
+ }
134
+
135
+ const services = this.transformService.extractServices(parseResult.config);
136
+ return {
137
+ success: true,
138
+ services,
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Read config file with metadata
144
+ */
145
+ readConfigFileWithMetadata(filePath) {
146
+ const resolvedPath = this.fileService.resolveFilePath(filePath);
147
+
148
+ if (!this.fileService.fileExists(resolvedPath)) {
149
+ return {
150
+ success: false,
151
+ error: 'File not found',
152
+ path: resolvedPath,
153
+ };
154
+ }
155
+
156
+ const content = this.fileService.readConfigFile(resolvedPath);
157
+ const parsed = this.fileService.tryParseJson(content, resolvedPath);
158
+
159
+ return {
160
+ success: true,
161
+ filePath: resolvedPath,
162
+ displayPath: this.fileService.getDisplayPath(resolvedPath),
163
+ content,
164
+ parsed,
165
+ exists: true,
166
+ };
167
+ }
168
+
169
+ /**
170
+ * Process setup: parse, convert, filter, and prepare config
171
+ */
172
+ processSetup(filePath, fileContent, selectedServices) {
173
+ const fileData = this.fileService.resolveFileData(filePath, fileContent);
174
+ if (!fileData) {
175
+ const resolvedFilePath = filePath ? this.fileService.resolveFilePath(filePath) : null;
176
+ return {
177
+ success: false,
178
+ error: 'File not found',
179
+ path: resolvedFilePath,
180
+ };
181
+ }
182
+
183
+ const parseResult = this.fileService.parseJsonConfig(
184
+ fileData.content,
185
+ fileData.resolvedFilePath
186
+ );
187
+ if (!parseResult.config) {
188
+ const fileType = this.fileService.getFileType(fileData.resolvedFilePath);
189
+ return {
190
+ success: false,
191
+ error: `Invalid ${fileType} file`,
192
+ details: parseResult.error ? parseResult.error.message : `Failed to parse ${fileType}`,
193
+ };
194
+ }
195
+
196
+ const originalConfig = parseResult.config;
197
+ const baseConvertedConfig = this.transformService.convertMcpServersToServers(originalConfig);
198
+
199
+ const convertedConfig =
200
+ selectedServices && Array.isArray(selectedServices) && selectedServices.length > 0
201
+ ? this.transformService.filterServers(baseConvertedConfig, selectedServices)
202
+ : baseConvertedConfig;
203
+
204
+ if (Object.keys(convertedConfig.servers || {}).length === 0) {
205
+ return {
206
+ success: false,
207
+ error: 'No servers found in config',
208
+ };
209
+ }
210
+
211
+ const updatedConfig = this.transformService.updateConfigForMcpShark(originalConfig);
212
+
213
+ return {
214
+ success: true,
215
+ fileData,
216
+ originalConfig,
217
+ convertedConfig,
218
+ updatedConfig,
219
+ };
220
+ }
221
+
222
+ /**
223
+ * Write config as JSON string
224
+ * @param {string} filePath - Path to config file
225
+ * @param {object} config - Config object to write
226
+ */
227
+ writeConfigAsJson(filePath, config) {
228
+ const jsonContent = JSON.stringify(config, null, 2);
229
+ this.fileService.writeConfigFile(filePath, jsonContent);
230
+ }
231
+
232
+ /**
233
+ * Check if config file is patched by mcp-shark
234
+ */
235
+ isConfigPatched(config) {
236
+ return this.transformService.isConfigPatched(config);
237
+ }
238
+
239
+ /**
240
+ * Check if a file path contains a patched config
241
+ */
242
+ isFilePatched(filePath) {
243
+ if (!this.fileService.fileExists(filePath)) {
244
+ return false;
245
+ }
246
+ const content = this.fileService.readConfigFile(filePath);
247
+ const parseResult = this.fileService.parseJsonConfig(content, filePath);
248
+ return parseResult.config ? this.isConfigPatched(parseResult.config) : false;
249
+ }
250
+ }