imcp 0.0.3 → 0.0.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 (93) hide show
  1. package/README.md +5 -6
  2. package/dist/cli/commands/install.js +2 -0
  3. package/dist/cli/commands/list.js +1 -0
  4. package/dist/cli/index.js +1 -2
  5. package/dist/core/ConfigurationLoader.d.ts +32 -0
  6. package/dist/core/ConfigurationLoader.js +213 -0
  7. package/dist/core/ConfigurationProvider.d.ts +2 -3
  8. package/dist/core/ConfigurationProvider.js +13 -182
  9. package/dist/core/InstallationService.d.ts +8 -0
  10. package/dist/core/InstallationService.js +124 -96
  11. package/dist/core/RequirementService.d.ts +1 -1
  12. package/dist/core/RequirementService.js +5 -9
  13. package/dist/core/constants.js +14 -1
  14. package/dist/core/installers/BaseInstaller.d.ts +5 -4
  15. package/dist/core/installers/BaseInstaller.js +17 -28
  16. package/dist/core/installers/ClientInstaller.js +159 -39
  17. package/dist/core/installers/CommandInstaller.d.ts +1 -0
  18. package/dist/core/installers/CommandInstaller.js +3 -0
  19. package/dist/core/installers/GeneralInstaller.d.ts +1 -0
  20. package/dist/core/installers/GeneralInstaller.js +3 -0
  21. package/dist/core/installers/InstallerFactory.d.ts +9 -7
  22. package/dist/core/installers/InstallerFactory.js +10 -8
  23. package/dist/core/installers/NpmInstaller.d.ts +1 -0
  24. package/dist/core/installers/NpmInstaller.js +3 -0
  25. package/dist/core/installers/PipInstaller.d.ts +6 -3
  26. package/dist/core/installers/PipInstaller.js +21 -8
  27. package/dist/core/installers/RequirementInstaller.d.ts +4 -3
  28. package/dist/core/installers/clients/ClientInstaller.d.ts +23 -0
  29. package/dist/core/installers/clients/ClientInstaller.js +573 -0
  30. package/dist/core/installers/clients/ExtensionInstaller.d.ts +26 -0
  31. package/dist/core/installers/clients/ExtensionInstaller.js +149 -0
  32. package/dist/core/installers/index.d.ts +8 -6
  33. package/dist/core/installers/index.js +8 -6
  34. package/dist/core/installers/requirements/BaseInstaller.d.ts +59 -0
  35. package/dist/core/installers/requirements/BaseInstaller.js +168 -0
  36. package/dist/core/installers/requirements/CommandInstaller.d.ts +37 -0
  37. package/dist/core/installers/requirements/CommandInstaller.js +173 -0
  38. package/dist/core/installers/requirements/GeneralInstaller.d.ts +33 -0
  39. package/dist/core/installers/requirements/GeneralInstaller.js +86 -0
  40. package/dist/core/installers/requirements/InstallerFactory.d.ts +54 -0
  41. package/dist/core/installers/requirements/InstallerFactory.js +97 -0
  42. package/dist/core/installers/requirements/NpmInstaller.d.ts +26 -0
  43. package/dist/core/installers/requirements/NpmInstaller.js +128 -0
  44. package/dist/core/installers/requirements/PipInstaller.d.ts +28 -0
  45. package/dist/core/installers/requirements/PipInstaller.js +128 -0
  46. package/{src/core/installers/RequirementInstaller.ts → dist/core/installers/requirements/RequirementInstaller.d.ts} +33 -38
  47. package/dist/core/installers/requirements/RequirementInstaller.js +3 -0
  48. package/dist/core/types.d.ts +4 -1
  49. package/dist/services/ServerService.js +1 -1
  50. package/dist/utils/clientUtils.d.ts +0 -6
  51. package/dist/utils/clientUtils.js +3 -2
  52. package/dist/utils/githubUtils.d.ts +11 -0
  53. package/dist/utils/githubUtils.js +88 -0
  54. package/dist/utils/osUtils.d.ts +17 -0
  55. package/dist/utils/osUtils.js +184 -0
  56. package/dist/web/public/css/modal.css +97 -3
  57. package/dist/web/public/index.html +21 -2
  58. package/dist/web/public/js/modal.js +177 -28
  59. package/dist/web/public/js/serverCategoryDetails.js +12 -10
  60. package/dist/web/public/js/serverCategoryList.js +20 -5
  61. package/dist/web/public/modal.html +27 -13
  62. package/dist/web/server.js +1 -1
  63. package/package.json +2 -1
  64. package/src/cli/commands/install.ts +4 -2
  65. package/src/cli/commands/list.ts +1 -0
  66. package/src/cli/index.ts +1 -1
  67. package/src/core/ConfigurationLoader.ts +251 -0
  68. package/src/core/ConfigurationProvider.ts +13 -195
  69. package/src/core/InstallationService.ts +140 -106
  70. package/src/core/RequirementService.ts +5 -10
  71. package/src/core/constants.ts +15 -1
  72. package/src/core/installers/{ClientInstaller.ts → clients/ClientInstaller.ts} +185 -46
  73. package/src/core/installers/clients/ExtensionInstaller.ts +162 -0
  74. package/src/core/installers/index.ts +9 -7
  75. package/src/core/installers/{BaseInstaller.ts → requirements/BaseInstaller.ts} +10 -118
  76. package/src/core/installers/{CommandInstaller.ts → requirements/CommandInstaller.ts} +7 -3
  77. package/src/core/installers/{GeneralInstaller.ts → requirements/GeneralInstaller.ts} +6 -2
  78. package/src/core/installers/{InstallerFactory.ts → requirements/InstallerFactory.ts} +11 -9
  79. package/src/core/installers/{NpmInstaller.ts → requirements/NpmInstaller.ts} +7 -4
  80. package/src/core/installers/{PipInstaller.ts → requirements/PipInstaller.ts} +26 -10
  81. package/src/core/installers/requirements/RequirementInstaller.ts +41 -0
  82. package/src/core/types.ts +4 -1
  83. package/src/services/ServerService.ts +1 -1
  84. package/src/utils/clientUtils.ts +4 -2
  85. package/src/utils/githubUtils.ts +103 -0
  86. package/src/utils/osUtils.ts +206 -15
  87. package/src/web/public/css/modal.css +97 -3
  88. package/src/web/public/index.html +21 -2
  89. package/src/web/public/js/modal.js +177 -28
  90. package/src/web/public/js/serverCategoryDetails.js +12 -10
  91. package/src/web/public/js/serverCategoryList.js +20 -5
  92. package/src/web/public/modal.html +27 -13
  93. package/src/web/server.ts +1 -1
@@ -0,0 +1,251 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { LOCAL_FEEDS_DIR, SUPPORTED_CLIENTS } from './constants.js';
4
+ import { Logger } from '../utils/logger.js';
5
+ import { readJsonFile } from '../utils/clientUtils.js';
6
+ import {
7
+ MCPConfiguration,
8
+ MCPServerCategory,
9
+ MCPServerStatus,
10
+ OperationStatus,
11
+ FeedConfiguration,
12
+ RequirementStatus,
13
+ InstallationStatus
14
+ } from './types.js';
15
+
16
+ export class ConfigurationLoader {
17
+ /**
18
+ * Updates the installed status for a server and client combination
19
+ */
20
+ private static updateServerInstalledStatus(
21
+ serverStatus: MCPServerStatus,
22
+ clientName: string,
23
+ operationStatus: OperationStatus
24
+ ): void {
25
+ if (!serverStatus.installedStatus) {
26
+ serverStatus.installedStatus = {};
27
+ }
28
+ serverStatus.installedStatus[clientName] = operationStatus;
29
+ }
30
+
31
+ /**
32
+ * Removes a client's status from a server
33
+ */
34
+ private static removeClientStatus(
35
+ serverStatus: MCPServerStatus,
36
+ clientName: string
37
+ ): void {
38
+ if (serverStatus.installedStatus && serverStatus.installedStatus[clientName]) {
39
+ delete serverStatus.installedStatus[clientName];
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Synchronizes server categories with client MCP settings.
45
+ * Uses clientMCPSettings as source of truth for installation status.
46
+ */
47
+ static syncServerCategoriesWithClientSettings(configuration: MCPConfiguration): MCPConfiguration {
48
+ if (!configuration.clientMCPSettings) {
49
+ return configuration;
50
+ }
51
+
52
+ configuration.localServerCategories = configuration.localServerCategories.map(category => {
53
+ if (!category.installationStatus?.serversStatus) {
54
+ return category;
55
+ }
56
+
57
+ const updatedServerStatus = { ...category.installationStatus.serversStatus };
58
+ const clientSettings = configuration.clientMCPSettings as Record<string, Record<string, any>>;
59
+
60
+ for (const [clientName, settings] of Object.entries(clientSettings)) {
61
+ const clientServers = clientName === 'GithubCopilot'
62
+ ? settings.servers || {}
63
+ : settings.mcpServers || {};
64
+
65
+ Object.keys(updatedServerStatus).forEach(serverName => {
66
+ if (clientServers[serverName]) {
67
+ if (!updatedServerStatus[serverName].installedStatus[clientName]) {
68
+ const operationStatus: OperationStatus = {
69
+ status: 'completed',
70
+ type: 'install',
71
+ target: 'server',
72
+ message: `Server ${serverName} is configured for client ${clientName}`
73
+ };
74
+ ConfigurationLoader.updateServerInstalledStatus(updatedServerStatus[serverName], clientName, operationStatus);
75
+ }
76
+ } else {
77
+ ConfigurationLoader.removeClientStatus(updatedServerStatus[serverName], clientName);
78
+ }
79
+ });
80
+ }
81
+
82
+ return {
83
+ ...category,
84
+ installationStatus: {
85
+ ...category.installationStatus,
86
+ serversStatus: updatedServerStatus,
87
+ lastUpdated: new Date().toISOString()
88
+ }
89
+ };
90
+ });
91
+
92
+ return configuration;
93
+ }
94
+
95
+ /**
96
+ * Initializes installation status for a feed configuration
97
+ */
98
+ private static initializeInstallationStatus(feedConfig?: FeedConfiguration): InstallationStatus {
99
+ const requirementsStatus: Record<string, RequirementStatus> = {};
100
+ const serversStatus: Record<string, MCPServerStatus> = {};
101
+
102
+ if (feedConfig) {
103
+ if (feedConfig.requirements) {
104
+ for (const req of feedConfig.requirements) {
105
+ requirementsStatus[req.name] = {
106
+ name: req.name,
107
+ type: req.type,
108
+ installed: false,
109
+ version: req.version,
110
+ error: undefined
111
+ };
112
+ }
113
+ }
114
+ if (feedConfig.mcpServers) {
115
+ for (const mcp of feedConfig.mcpServers) {
116
+ serversStatus[mcp.name] = {
117
+ name: mcp.name,
118
+ error: undefined,
119
+ installedStatus: {}
120
+ };
121
+ }
122
+ }
123
+ }
124
+
125
+ return {
126
+ requirementsStatus,
127
+ serversStatus,
128
+ lastUpdated: new Date().toISOString()
129
+ };
130
+ }
131
+
132
+ /**
133
+ * Synchronizes server categories with feeds
134
+ */
135
+ private static async syncServerCategoriesWithFeeds(configuration: MCPConfiguration): Promise<MCPConfiguration> {
136
+ configuration.localServerCategories = configuration.localServerCategories.map(server => {
137
+ if (configuration.feeds[server.name]) {
138
+ server.feedConfiguration = configuration.feeds[server.name];
139
+ }
140
+
141
+ if (
142
+ !server.installationStatus ||
143
+ !server.installationStatus.requirementsStatus ||
144
+ Object.keys(server.installationStatus.requirementsStatus).length === 0 ||
145
+ !server.installationStatus.serversStatus ||
146
+ Object.keys(server.installationStatus.serversStatus).length === 0
147
+ ) {
148
+ server.installationStatus = ConfigurationLoader.initializeInstallationStatus(server.feedConfiguration);
149
+ }
150
+
151
+ return server;
152
+ });
153
+
154
+ const existingServerNames = new Set(configuration.localServerCategories.map(category => category.name));
155
+
156
+ for (const [feedName, feedConfig] of Object.entries(configuration.feeds)) {
157
+ if (!existingServerNames.has(feedName)) {
158
+ const newServerCategory: MCPServerCategory = {
159
+ name: feedName,
160
+ displayName: feedConfig.displayName || feedName,
161
+ type: 'local',
162
+ description: feedConfig.description || `Local MCP server category: ${feedName}`,
163
+ installationStatus: ConfigurationLoader.initializeInstallationStatus(feedConfig),
164
+ feedConfiguration: feedConfig
165
+ };
166
+
167
+ configuration.localServerCategories.push(newServerCategory);
168
+ console.log(`Created new local server entry for feed: ${feedName}`);
169
+ }
170
+ }
171
+
172
+ return configuration;
173
+ }
174
+
175
+ /**
176
+ * Loads feed configurations into the MCP configuration
177
+ */
178
+ static async loadFeedsIntoConfiguration(configuration: MCPConfiguration): Promise<MCPConfiguration> {
179
+ try {
180
+ await fs.mkdir(LOCAL_FEEDS_DIR, { recursive: true });
181
+ const files = await fs.readdir(LOCAL_FEEDS_DIR);
182
+ const jsonFiles = files.filter(file => file.endsWith('.json'));
183
+
184
+ if (jsonFiles.length === 0) {
185
+ console.log(`No feed configuration files found in ${LOCAL_FEEDS_DIR}`);
186
+ return configuration;
187
+ }
188
+
189
+ const feeds: Record<string, FeedConfiguration> = {};
190
+ for (const file of jsonFiles) {
191
+ try {
192
+ const filePath = path.join(LOCAL_FEEDS_DIR, file);
193
+ const content = await fs.readFile(filePath, 'utf8');
194
+ const config = JSON.parse(content) as FeedConfiguration;
195
+ if (config && config.name) {
196
+ feeds[config.name] = config;
197
+ }
198
+ } catch (error) {
199
+ console.warn(`Error loading feed configuration from ${file}:`, error);
200
+ }
201
+ }
202
+
203
+ configuration.feeds = feeds;
204
+ return await ConfigurationLoader.syncServerCategoriesWithFeeds(configuration);
205
+ } catch (error) {
206
+ console.error("Error loading feed configurations:", error);
207
+ throw error;
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Loads MCP client settings into the configuration
213
+ */
214
+ static async loadClientMCPSettings(configuration: MCPConfiguration): Promise<MCPConfiguration> {
215
+ try {
216
+ Logger.debug('Starting to load MCP client settings...');
217
+ const settings: Record<string, Record<string, any>> = {};
218
+
219
+ for (const [clientName, clientSettings] of Object.entries(SUPPORTED_CLIENTS)) {
220
+ const settingPath = process.env.CODE_INSIDERS
221
+ ? clientSettings.codeInsiderSettingPath
222
+ : clientSettings.codeSettingPath;
223
+ try {
224
+ let content = await readJsonFile(settingPath, true);
225
+
226
+ if (clientName === 'GithubCopilot') {
227
+ if (!content.mcp) {
228
+ content = {
229
+ servers: {},
230
+ inputs: []
231
+ };
232
+ } else {
233
+ content = content.mcp;
234
+ }
235
+ }
236
+ settings[clientName] = content;
237
+ Logger.debug(`Successfully loaded MCP settings for ${clientName}`);
238
+ } catch (error) {
239
+ Logger.debug(`Warning: Could not load MCP settings for client ${clientName}: ${error instanceof Error ? error.message : String(error)}`);
240
+ settings[clientName] = {};
241
+ }
242
+ }
243
+
244
+ configuration.clientMCPSettings = settings;
245
+ return ConfigurationLoader.syncServerCategoriesWithClientSettings(configuration);
246
+ } catch (error) {
247
+ Logger.error('Error loading client MCP settings:', error);
248
+ throw error;
249
+ }
250
+ }
251
+ }
@@ -1,10 +1,9 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
- import os from 'os';
4
3
  import { exec } from 'child_process';
5
4
  import { promisify } from 'util';
6
5
  import { fileURLToPath } from 'url';
7
- import { GITHUB_REPO, LOCAL_FEEDS_DIR, SETTINGS_DIR, SUPPORTED_CLIENTS } from './constants.js';
6
+ import { GITHUB_REPO, LOCAL_FEEDS_DIR, SETTINGS_DIR } from './constants.js';
8
7
  import { Logger } from '../utils/logger.js';
9
8
  import { checkGithubAuth } from '../utils/githubAuth.js';
10
9
  import {
@@ -16,7 +15,7 @@ import {
16
15
  MCPServerStatus,
17
16
  OperationStatus
18
17
  } from './types.js';
19
- import { readJsonFile } from '../utils/clientUtils.js';
18
+ import { ConfigurationLoader } from './ConfigurationLoader.js';
20
19
 
21
20
  const execAsync = promisify(exec);
22
21
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -78,46 +77,6 @@ export class ConfigurationProvider {
78
77
  });
79
78
  }
80
79
 
81
- private async loadClientMCPSettings(): Promise<void> {
82
- try {
83
- Logger.debug('Starting to load MCP client settings...');
84
- const settings: Record<string, Record<string, any>> = {};
85
-
86
- for (const [clientName, clientSettings] of Object.entries(SUPPORTED_CLIENTS)) {
87
- const settingPath = process.env.CODE_INSIDERS
88
- ? clientSettings.codeInsiderSettingPath
89
- : clientSettings.codeSettingPath;
90
- try {
91
- let content = await readJsonFile(settingPath, true);
92
-
93
- if (clientName === 'GithubCopilot') {
94
- // Initialize the mcp section if it doesn't exist
95
- if (!content.mcp) {
96
- content = {
97
- servers: {},
98
- inputs: []
99
- };
100
- } else {
101
- content = content.mcp;
102
- }
103
- }
104
- settings[clientName] = content;
105
- Logger.debug(`Successfully loaded MCP settings for ${clientName}`);
106
- } catch (error) {
107
- Logger.debug(`Warning: Could not load MCP settings for client ${clientName}: ${error instanceof Error ? error.message : String(error)}`);
108
- settings[clientName] = {};
109
- }
110
- }
111
-
112
- this.configuration.clientMCPSettings = settings;
113
- await this.saveConfiguration();
114
- Logger.debug('Saved MCP client settings to configuration');
115
- } catch (error) {
116
- Logger.error('Error loading client MCP settings:', error);
117
- throw error;
118
- }
119
- }
120
-
121
80
  private async saveConfiguration(): Promise<void> {
122
81
  const configDir = path.dirname(this.configPath);
123
82
  await fs.mkdir(configDir, { recursive: true });
@@ -355,7 +314,7 @@ export class ConfigurationProvider {
355
314
  }
356
315
 
357
316
  Logger.debug('Updating local feeds...');
358
- await fs.rm(LOCAL_FEEDS_DIR, { recursive: true, force: true });
317
+ // await fs.rm(LOCAL_FEEDS_DIR, { recursive: true, force: true });
359
318
  const sourceFeedsDir = path.join(this.tempDir, GITHUB_REPO.feedsPath);
360
319
 
361
320
  try {
@@ -364,11 +323,9 @@ export class ConfigurationProvider {
364
323
  throw new Error(`Could not find feeds directory in cloned repository: ${sourceFeedsDir}`);
365
324
  }
366
325
 
367
- await fs.cp(sourceFeedsDir, LOCAL_FEEDS_DIR, { recursive: true });
326
+ await fs.cp(sourceFeedsDir, LOCAL_FEEDS_DIR, { recursive: true, force: true });
368
327
  Logger.log('Successfully updated local feeds');
369
328
 
370
- // Update configuration with new feeds
371
- await this.loadFeedsIntoConfiguration();
372
329
  } catch (error) {
373
330
  Logger.error('Error during feed synchronization', error);
374
331
  throw new Error('Failed to sync feeds. Use --verbose for detailed error information.');
@@ -377,158 +334,19 @@ export class ConfigurationProvider {
377
334
  }
378
335
 
379
336
  private async loadFeedsIntoConfiguration(): Promise<void> {
380
- try {
381
- await fs.mkdir(LOCAL_FEEDS_DIR, { recursive: true });
382
- const files = await fs.readdir(LOCAL_FEEDS_DIR);
383
- const jsonFiles = files.filter(file => file.endsWith('.json'));
384
-
385
- if (jsonFiles.length === 0) {
386
- console.log(`No feed configuration files found in ${LOCAL_FEEDS_DIR}`);
387
- return;
388
- }
389
-
390
- const feeds: Record<string, FeedConfiguration> = {};
391
- for (const file of jsonFiles) {
392
- try {
393
- const filePath = path.join(LOCAL_FEEDS_DIR, file);
394
- const content = await fs.readFile(filePath, 'utf8');
395
- const config = JSON.parse(content) as FeedConfiguration;
396
- if (config && config.name) {
397
- feeds[config.name] = config;
398
- }
399
- } catch (error) {
400
- console.warn(`Error loading feed configuration from ${file}:`, error);
401
- }
402
- }
403
-
404
- this.configuration.feeds = feeds;
405
- await this.syncServerCategoriesWithFeeds(); // Sync categories after loading feeds
406
- await this.saveConfiguration();
407
- } catch (error) {
408
- console.error("Error loading feed configurations:", error);
409
- throw error;
410
- }
337
+ this.configuration = await ConfigurationLoader.loadFeedsIntoConfiguration(this.configuration);
338
+ await this.saveConfiguration();
411
339
  }
412
340
 
413
- private async syncServerCategoriesWithFeeds(): Promise<void> {
414
- let configUpdated = false;
415
-
416
- // 1. Process existing local servers - update their feed configurations
417
- for (const server of this.configuration.localServerCategories) {
418
- if (this.configuration.feeds[server.name]) {
419
- server.feedConfiguration = this.configuration.feeds[server.name];
420
- configUpdated = true;
421
- }
422
-
423
- // If server doesn't have installation status, initialize it
424
- const feedConfig = server.feedConfiguration;
425
- // If installationStatus is missing, or requirements/tools are empty, initialize from feed
426
- if (
427
- !server.installationStatus ||
428
- !server.installationStatus.requirementsStatus ||
429
- Object.keys(server.installationStatus.requirementsStatus).length === 0 ||
430
- !server.installationStatus.serversStatus ||
431
- Object.keys(server.installationStatus.serversStatus).length === 0
432
- ) {
433
- const requirementsStatus: Record<string, RequirementStatus> = {};
434
- const serversStatus: Record<string, MCPServerStatus> = {};
435
- if (feedConfig) {
436
- if (feedConfig.requirements) {
437
- for (const req of feedConfig.requirements) {
438
- requirementsStatus[req.name] = {
439
- name: req.name,
440
- type: req.type,
441
- installed: false,
442
- version: req.version,
443
- error: undefined
444
- };
445
- }
446
- }
447
- if (feedConfig.mcpServers) {
448
- for (const mcp of feedConfig.mcpServers) {
449
- serversStatus[mcp.name] = {
450
- name: mcp.name,
451
- error: undefined,
452
- installedStatus: {} // Add missing property
453
- };
454
- }
455
- }
456
- }
457
- server.installationStatus = {
458
- requirementsStatus,
459
- serversStatus,
460
- lastUpdated: new Date().toISOString()
461
- };
462
- configUpdated = true;
463
- }
464
- }
465
-
466
- // 2. Check for feeds that don't have a corresponding local server and create new entries
467
- const existingServerCategoryNames = new Set(this.configuration.localServerCategories.map(catetory => catetory.name));
468
-
469
- for (const feedName in this.configuration.feeds) {
470
- if (!existingServerCategoryNames.has(feedName)) {
471
- // This feed doesn't have a corresponding local server - create one with empty installation status
472
- const feedConfig = this.configuration.feeds[feedName];
473
-
474
- // Create new server with empty installation status
475
- const newServerCategory: MCPServerCategory = {
476
- name: feedName,
477
- displayName: feedConfig.displayName || feedName,
478
- type: 'local',
479
- description: feedConfig.description || `Local MCP server category: ${feedName}`,
480
- installationStatus: (() => {
481
- const requirementsStatus: Record<string, RequirementStatus> = {};
482
- const serversStatus: Record<string, MCPServerStatus> = {};
483
- if (feedConfig) {
484
- if (feedConfig.requirements) {
485
- for (const req of feedConfig.requirements) {
486
- requirementsStatus[req.name] = {
487
- name: req.name,
488
- type: req.type,
489
- installed: false,
490
- version: req.version,
491
- error: undefined
492
- };
493
- }
494
- }
495
- if (feedConfig.mcpServers) {
496
- for (const mcp of feedConfig.mcpServers) {
497
- serversStatus[mcp.name] = {
498
- name: mcp.name,
499
- error: undefined,
500
- installedStatus: {} // Add missing property
501
- };
502
- }
503
- }
504
- }
505
- return {
506
- requirementsStatus,
507
- serversStatus,
508
- lastUpdated: new Date().toISOString()
509
- };
510
- })(),
511
- feedConfiguration: feedConfig
512
- };
513
-
514
- // Add the new server to the configuration
515
- this.configuration.localServerCategories.push(newServerCategory);
516
- console.log(`Created new local server entry for feed: ${feedName}`);
517
- configUpdated = true;
518
- }
519
- }
520
-
521
- if (configUpdated) {
522
- await this.saveConfiguration();
523
- }
341
+ private async loadClientMCPSettings(): Promise<void> {
342
+ this.configuration = await ConfigurationLoader.loadClientMCPSettings(this.configuration);
343
+ await this.saveConfiguration();
524
344
  }
525
345
 
526
-
527
- async syncWithFeed(feedConfiguration: Record<string, FeedConfiguration>): Promise<void> {
528
- await this.withLock(async () => {
529
- this.configuration.feeds = feedConfiguration;
530
- await this.syncServerCategoriesWithFeeds(); // Sync categories after direct update
531
- await this.saveConfiguration();
346
+ // Public method to reload client MCP settings
347
+ async reloadClientMCPSettings(): Promise<void> {
348
+ return await this.withLock(async () => {
349
+ await this.loadClientMCPSettings();
532
350
  });
533
351
  }
534
352
  }