imcp 0.0.16 → 0.0.17

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 (135) hide show
  1. package/dist/cli/commands/install.js +2 -2
  2. package/dist/cli/commands/list.js +2 -2
  3. package/dist/cli/commands/serve.js +1 -1
  4. package/dist/core/RequirementService.d.ts +0 -12
  5. package/dist/core/RequirementService.js +0 -24
  6. package/dist/core/installers/clients/BaseClientInstaller.d.ts +1 -1
  7. package/dist/core/installers/clients/ClientInstaller.d.ts +1 -1
  8. package/dist/core/installers/clients/ClientInstaller.js +1 -1
  9. package/dist/core/installers/clients/ClientInstallerFactory.js +1 -1
  10. package/dist/core/installers/clients/ClineInstaller.d.ts +1 -1
  11. package/dist/core/installers/clients/ClineInstaller.js +1 -1
  12. package/dist/core/installers/clients/ExtensionInstaller.js +1 -1
  13. package/dist/core/installers/clients/GithubCopilotInstaller.d.ts +1 -1
  14. package/dist/core/installers/clients/GithubCopilotInstaller.js +1 -1
  15. package/dist/core/installers/clients/MSRooCodeInstaller.d.ts +1 -1
  16. package/dist/core/installers/clients/MSRooCodeInstaller.js +1 -1
  17. package/dist/core/installers/requirements/BaseInstaller.d.ts +1 -1
  18. package/dist/core/installers/requirements/BaseInstaller.js +1 -1
  19. package/dist/core/installers/requirements/CommandInstaller.d.ts +1 -1
  20. package/dist/core/installers/requirements/CommandInstaller.js +1 -1
  21. package/dist/core/installers/requirements/GeneralInstaller.d.ts +1 -1
  22. package/dist/core/installers/requirements/InstallerFactory.d.ts +1 -1
  23. package/dist/core/installers/requirements/NpmInstaller.d.ts +1 -1
  24. package/dist/core/installers/requirements/NpmInstaller.js +1 -1
  25. package/dist/core/installers/requirements/PipInstaller.d.ts +1 -1
  26. package/dist/core/installers/requirements/RequirementInstaller.d.ts +1 -1
  27. package/dist/core/loaders/ConfigurationLoader.d.ts +32 -0
  28. package/dist/core/loaders/ConfigurationLoader.js +236 -0
  29. package/dist/core/loaders/ConfigurationProvider.d.ts +35 -0
  30. package/dist/core/loaders/ConfigurationProvider.js +375 -0
  31. package/dist/core/loaders/ServerSchemaLoader.d.ts +11 -0
  32. package/{src/core/ServerSchemaLoader.ts → dist/core/loaders/ServerSchemaLoader.js} +43 -48
  33. package/dist/core/loaders/ServerSchemaProvider.d.ts +17 -0
  34. package/{src/core/ServerSchemaProvider.ts → dist/core/loaders/ServerSchemaProvider.js} +120 -137
  35. package/dist/core/metadatas/constants.d.ts +47 -0
  36. package/dist/core/metadatas/constants.js +94 -0
  37. package/dist/core/metadatas/types.d.ts +166 -0
  38. package/dist/core/metadatas/types.js +16 -0
  39. package/dist/core/onboard/FeedOnboardService.d.ts +1 -1
  40. package/dist/core/onboard/FeedOnboardService.js +1 -1
  41. package/dist/core/onboard/OnboardProcessor.d.ts +1 -1
  42. package/dist/core/onboard/OnboardProcessor.js +1 -1
  43. package/dist/core/onboard/OnboardStatus.d.ts +1 -1
  44. package/dist/core/onboard/OnboardStatusManager.d.ts +1 -1
  45. package/dist/core/onboard/OnboardStatusManager.js +1 -1
  46. package/dist/core/validators/FeedValidator.d.ts +1 -1
  47. package/dist/core/validators/IServerValidator.d.ts +1 -1
  48. package/dist/core/validators/SSEServerValidator.d.ts +1 -1
  49. package/dist/core/validators/ServerValidatorFactory.d.ts +1 -1
  50. package/dist/core/validators/StdioServerValidator.d.ts +1 -1
  51. package/dist/core/validators/StdioServerValidator.js +1 -1
  52. package/dist/index.d.ts +3 -3
  53. package/dist/index.js +3 -3
  54. package/dist/services/InstallationService.d.ts +50 -0
  55. package/dist/services/InstallationService.js +350 -0
  56. package/dist/services/MCPManager.d.ts +28 -0
  57. package/dist/services/MCPManager.js +188 -0
  58. package/dist/services/RequirementService.d.ts +40 -0
  59. package/dist/services/RequirementService.js +110 -0
  60. package/dist/services/ServerService.d.ts +2 -2
  61. package/dist/services/ServerService.js +5 -5
  62. package/dist/utils/adoUtils.d.ts +2 -2
  63. package/dist/utils/adoUtils.js +1 -1
  64. package/dist/utils/feedUtils.js +1 -1
  65. package/dist/utils/githubUtils.d.ts +1 -1
  66. package/dist/utils/githubUtils.js +1 -1
  67. package/dist/utils/logger.js +1 -1
  68. package/dist/utils/macroExpressionUtils.d.ts +1 -1
  69. package/dist/utils/osUtils.d.ts +1 -1
  70. package/dist/utils/osUtils.js +1 -1
  71. package/dist/web/contract/serverContract.d.ts +1 -1
  72. package/dist/web/public/index.html +1 -3
  73. package/dist/web/public/js/api.js +2 -80
  74. package/dist/web/server.js +2 -2
  75. package/package.json +1 -1
  76. package/src/cli/commands/install.ts +3 -3
  77. package/src/cli/commands/list.ts +2 -2
  78. package/src/cli/commands/serve.ts +3 -2
  79. package/src/cli/index.ts +1 -1
  80. package/src/core/installers/clients/BaseClientInstaller.ts +134 -3
  81. package/src/core/installers/clients/ClientInstaller.ts +3 -3
  82. package/src/core/installers/clients/ClientInstallerFactory.ts +1 -1
  83. package/src/core/installers/clients/ClineInstaller.ts +1 -101
  84. package/src/core/installers/clients/ExtensionInstaller.ts +1 -1
  85. package/src/core/installers/clients/GithubCopilotInstaller.ts +1 -101
  86. package/src/core/installers/clients/MSRooCodeInstaller.ts +1 -102
  87. package/src/core/installers/requirements/BaseInstaller.ts +2 -2
  88. package/src/core/installers/requirements/CommandInstaller.ts +1 -1
  89. package/src/core/installers/requirements/GeneralInstaller.ts +1 -1
  90. package/src/core/installers/requirements/InstallerFactory.ts +1 -1
  91. package/src/core/installers/requirements/NpmInstaller.ts +12 -12
  92. package/src/core/installers/requirements/PipInstaller.ts +1 -1
  93. package/src/core/installers/requirements/RequirementInstaller.ts +1 -1
  94. package/src/core/{ConfigurationLoader.ts → loaders/ConfigurationLoader.ts} +31 -7
  95. package/src/core/{ConfigurationProvider.ts → loaders/ConfigurationProvider.ts} +18 -10
  96. package/src/core/loaders/ServerSchemaLoader.ts +117 -0
  97. package/src/core/loaders/ServerSchemaProvider.ts +99 -0
  98. package/src/core/{types.ts → metadatas/types.ts} +3 -2
  99. package/src/core/onboard/FeedOnboardService.ts +270 -146
  100. package/src/core/onboard/OnboardProcessor.ts +60 -11
  101. package/src/core/onboard/OnboardStatus.ts +7 -2
  102. package/src/core/onboard/OnboardStatusManager.ts +270 -43
  103. package/src/core/validators/FeedValidator.ts +65 -9
  104. package/src/core/validators/IServerValidator.ts +1 -1
  105. package/src/core/validators/SSEServerValidator.ts +2 -2
  106. package/src/core/validators/ServerValidatorFactory.ts +1 -1
  107. package/src/core/validators/StdioServerValidator.ts +86 -34
  108. package/src/index.ts +3 -3
  109. package/src/{core → services}/InstallationService.ts +5 -5
  110. package/src/{core → services}/MCPManager.ts +10 -5
  111. package/src/{core → services}/RequirementService.ts +2 -31
  112. package/src/services/ServerService.ts +7 -7
  113. package/src/utils/adoUtils.ts +3 -3
  114. package/src/utils/feedUtils.ts +2 -2
  115. package/src/utils/githubUtils.ts +2 -2
  116. package/src/utils/logger.ts +13 -1
  117. package/src/utils/macroExpressionUtils.ts +1 -1
  118. package/src/utils/osUtils.ts +4 -4
  119. package/src/web/contract/serverContract.ts +2 -2
  120. package/src/web/public/index.html +1 -3
  121. package/src/web/public/js/api.js +2 -80
  122. package/src/web/public/js/modal/installation.js +1 -1
  123. package/src/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +41 -9
  124. package/src/web/public/js/onboard/formProcessor.js +200 -34
  125. package/src/web/public/js/onboard/index.js +2 -2
  126. package/src/web/public/js/onboard/publishHandler.js +30 -22
  127. package/src/web/public/js/onboard/templates.js +34 -40
  128. package/src/web/public/js/onboard/uiHandlers.js +175 -84
  129. package/src/web/public/js/onboard/validationHandlers.js +147 -64
  130. package/src/web/public/js/serverCategoryDetails.js +19 -4
  131. package/src/web/public/js/serverCategoryList.js +13 -1
  132. package/src/web/public/onboard.html +1 -1
  133. package/src/web/server.ts +30 -14
  134. package/src/services/InstallRequestValidator.ts +0 -112
  135. /package/src/core/{constants.ts → metadatas/constants.ts} +0 -0
@@ -0,0 +1,40 @@
1
+ import { RequirementConfig, RequirementStatus, ServerInstallOptions } from '../core/metadatas/types.js';
2
+ /**
3
+ * Service responsible for managing requirements installation and status
4
+ */
5
+ export declare class RequirementService {
6
+ private static instance;
7
+ private installerFactory;
8
+ private constructor();
9
+ /**
10
+ * Get the singleton instance of RequirementService
11
+ * @returns The RequirementService instance
12
+ */
13
+ static getInstance(): RequirementService;
14
+ /**
15
+ * Check the installation status of a requirement
16
+ * @param requirement The requirement to check
17
+ * @returns The installation status
18
+ */
19
+ checkRequirementStatus(requirement: RequirementConfig, options?: ServerInstallOptions): Promise<RequirementStatus>;
20
+ /**
21
+ * Check if updates are available for a requirement
22
+ * @param requirement The requirement to check for updates
23
+ * @returns Updated status with available updates information
24
+ */
25
+ checkRequirementForUpdates(requirement: RequirementConfig, currentStatus: RequirementStatus): Promise<RequirementStatus>;
26
+ /**
27
+ * Update a requirement to a new version
28
+ * @param requirement The requirement configuration
29
+ * @param updateVersion The version to update to
30
+ * @returns The updated requirement status
31
+ */
32
+ updateRequirement(requirement: RequirementConfig, updateVersion: string, options?: ServerInstallOptions): Promise<RequirementStatus>;
33
+ /**
34
+ * Validate a requirement configuration
35
+ * @param requirement The requirement to validate
36
+ * @throws Error if the requirement is invalid
37
+ */
38
+ private validateRequirement;
39
+ }
40
+ export declare const requirementService: RequirementService;
@@ -0,0 +1,110 @@
1
+ import { createInstallerFactory } from '../core/installers/index.js';
2
+ import { exec } from 'child_process';
3
+ import util from 'util';
4
+ /**
5
+ * Service responsible for managing requirements installation and status
6
+ */
7
+ export class RequirementService {
8
+ static instance;
9
+ installerFactory = createInstallerFactory(util.promisify(exec));
10
+ constructor() { }
11
+ /**
12
+ * Get the singleton instance of RequirementService
13
+ * @returns The RequirementService instance
14
+ */
15
+ static getInstance() {
16
+ if (!RequirementService.instance) {
17
+ RequirementService.instance = new RequirementService();
18
+ }
19
+ return RequirementService.instance;
20
+ }
21
+ /**
22
+ * Check the installation status of a requirement
23
+ * @param requirement The requirement to check
24
+ * @returns The installation status
25
+ */
26
+ async checkRequirementStatus(requirement, options) {
27
+ // Validate requirement
28
+ this.validateRequirement(requirement);
29
+ // Check the installation status
30
+ return await this.installerFactory.checkInstallation(requirement, options);
31
+ }
32
+ /**
33
+ * Check if updates are available for a requirement
34
+ * @param requirement The requirement to check for updates
35
+ * @returns Updated status with available updates information
36
+ */
37
+ async checkRequirementForUpdates(requirement, currentStatus) {
38
+ // Validate requirement
39
+ this.validateRequirement(requirement);
40
+ // Get current status
41
+ // Check for updates using the appropriate installer
42
+ const installer = this.installerFactory.getInstaller(requirement);
43
+ if (!installer || !installer.supportCheckUpdates()) {
44
+ return currentStatus;
45
+ }
46
+ // Pass pythonEnv from currentStatus if it exists for pip packages
47
+ const options = requirement.type === 'pip' && currentStatus.pythonEnv
48
+ ? { settings: { pythonEnv: currentStatus.pythonEnv } }
49
+ : undefined;
50
+ const status = await this.checkRequirementStatus(requirement, options);
51
+ return await installer.checkForUpdates(requirement, status);
52
+ }
53
+ /**
54
+ * Update a requirement to a new version
55
+ * @param requirement The requirement configuration
56
+ * @param updateVersion The version to update to
57
+ * @returns The updated requirement status
58
+ */
59
+ async updateRequirement(requirement, updateVersion, options) {
60
+ // Validate requirement
61
+ this.validateRequirement(requirement);
62
+ // Create an updated requirement with the new version
63
+ const updatedRequirement = {
64
+ ...requirement,
65
+ version: requirement.version.includes('latest') ? requirement.version : updateVersion,
66
+ };
67
+ // Install the updated version
68
+ return await this.installerFactory.install(updatedRequirement, options);
69
+ }
70
+ /**
71
+ * Validate a requirement configuration
72
+ * @param requirement The requirement to validate
73
+ * @throws Error if the requirement is invalid
74
+ */
75
+ validateRequirement(requirement) {
76
+ // Ensure requirement has required fields
77
+ if (!requirement.name) {
78
+ throw new Error('Requirement name is required');
79
+ }
80
+ if (!requirement.type) {
81
+ throw new Error('Requirement type is required');
82
+ }
83
+ // For type 'other', registry must be specified
84
+ if (requirement.type === 'other' && !requirement.registry) {
85
+ throw new Error('Registry must be specified for requirement type "other"');
86
+ }
87
+ // Validate registry configuration if provided
88
+ if (requirement.registry) {
89
+ const { githubRelease, artifacts } = requirement.registry;
90
+ // Validate GitHub release configuration
91
+ if (githubRelease) {
92
+ if (!githubRelease.repository) {
93
+ throw new Error('Repository is required for GitHub release registry');
94
+ }
95
+ if (!githubRelease.assetName) {
96
+ throw new Error('Asset name is required for GitHub release registry');
97
+ }
98
+ }
99
+ // Validate artifacts registry configuration
100
+ if (artifacts) {
101
+ if (!artifacts.registryUrl) {
102
+ throw new Error('Registry URL is required for artifacts registry');
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+ // Export a singleton instance
109
+ export const requirementService = RequirementService.getInstance();
110
+ //# sourceMappingURL=RequirementService.js.map
@@ -1,5 +1,5 @@
1
- import { ServerSchema } from '../core/ServerSchemaProvider.js';
2
- import { MCPServerCategory, ServerInstallOptions, ServerCategoryListOptions, ServerOperationResult, ServerUninstallOptions, FeedConfiguration } from '../core/types.js';
1
+ import { ServerSchema } from '../core/loaders/ServerSchemaProvider.js';
2
+ import { MCPServerCategory, ServerInstallOptions, ServerCategoryListOptions, ServerOperationResult, ServerUninstallOptions, FeedConfiguration } from '../core/metadatas/types.js';
3
3
  import { OperationStatus } from '../core/onboard/OnboardStatus.js';
4
4
  /**
5
5
  * ServerService provides a unified interface for server management operations.
@@ -1,9 +1,9 @@
1
1
  import path from 'path';
2
2
  import { fileURLToPath } from 'url';
3
3
  import { Logger } from '../utils/logger.js';
4
- import { getServerSchemaProvider } from '../core/ServerSchemaProvider.js';
5
- import { mcpManager } from '../core/MCPManager.js';
6
- import { UPDATE_CHECK_INTERVAL_MS } from '../core/constants.js';
4
+ import { getServerSchemaProvider } from '../core/loaders/ServerSchemaProvider.js';
5
+ import { mcpManager } from './MCPManager.js';
6
+ import { UPDATE_CHECK_INTERVAL_MS } from '../core/metadatas/constants.js';
7
7
  import { updateCheckTracker } from '../utils/UpdateCheckTracker.js';
8
8
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
9
  /**
@@ -53,8 +53,8 @@ export class ServerService {
53
53
  return;
54
54
  }
55
55
  try {
56
- const { requirementService } = await import('../core/RequirementService.js');
57
- const { configProvider } = await import('../core/ConfigurationProvider.js');
56
+ const { requirementService } = await import('./RequirementService.js');
57
+ const { configProvider } = await import('../core/loaders/ConfigurationProvider.js');
58
58
  for (const requirement of serverCategory.feedConfiguration.requirements) {
59
59
  if (requirement.version.includes('latest')) {
60
60
  // Get current status if available
@@ -1,4 +1,4 @@
1
- import { RequirementConfig, RegistryConfig } from '../core/types.js';
1
+ import { RequirementConfig, RegistryConfig } from '../core/metadatas/types.js';
2
2
  export interface AdoArtifactResult {
3
3
  type: 'npm' | 'pip';
4
4
  package: string;
@@ -25,5 +25,5 @@ targetDir?: string): Promise<AdoArtifactResult>;
25
25
  * @param options Optional server install options (e.g., for pythonCommand).
26
26
  * @returns The latest version string, or undefined if not found or an error occurs.
27
27
  */
28
- export declare function getArtifactLatestVersion(requirement: RequirementConfig, registry: RegistryConfig['artifacts'], options?: import('../core/types.js').ServerInstallOptions, // Added import for ServerInstallOptions
28
+ export declare function getArtifactLatestVersion(requirement: RequirementConfig, registry: RegistryConfig['artifacts'], options?: import('../core/metadatas/types.js').ServerInstallOptions, // Added import for ServerInstallOptions
29
29
  targetDir?: string): Promise<string | undefined>;
@@ -1,4 +1,4 @@
1
- import { SETTINGS_DIR } from '../core/constants.js';
1
+ import { SETTINGS_DIR } from '../core/metadatas/constants.js';
2
2
  import { Logger } from './logger.js';
3
3
  import { exec } from 'child_process';
4
4
  import util from 'util';
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs/promises';
2
2
  import { Logger } from './logger.js';
3
- import { LOCAL_FEEDS_DIR } from '../core/constants.js';
3
+ import { LOCAL_FEEDS_DIR } from '../core/metadatas/constants.js';
4
4
  /**
5
5
  * Checks if local feeds exist in the LOCAL_FEEDS_DIR
6
6
  * Returns true if the directory exists and contains at least one .json file
@@ -1,4 +1,4 @@
1
- import { RegistryConfig, RequirementConfig } from '../core/types.js';
1
+ import { RegistryConfig, RequirementConfig } from '../core/metadatas/types.js';
2
2
  /**
3
3
  * Get the latest version available for a GitHub repository
4
4
  * @param execPromise The promise-based exec function
@@ -3,7 +3,7 @@ import util from 'util';
3
3
  import fs from 'fs/promises';
4
4
  import path from 'path';
5
5
  import { extractZipFile } from './clientUtils.js';
6
- import { SETTINGS_DIR } from '../core/constants.js';
6
+ import { SETTINGS_DIR } from '../core/metadatas/constants.js';
7
7
  const execAsync = util.promisify(exec);
8
8
  /**
9
9
  * Get the latest version available for a GitHub repository
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { SETTINGS_DIR } from '../core/constants.js';
3
+ import { SETTINGS_DIR } from '../core/metadatas/constants.js';
4
4
  export class Logger {
5
5
  static verbose = false;
6
6
  static fileLoggingEnabled = true;
@@ -1,4 +1,4 @@
1
- import { ServerInstallOptions } from '../core/types.js';
1
+ import { ServerInstallOptions } from '../core/metadatas/types.js';
2
2
  export declare const MACRO_EXPRESSIONS: {
3
3
  readonly PYTHON_PACKAGE: "${PYTHON_PACKAGE}";
4
4
  readonly NPMPATH: "${NPMPATH}";
@@ -1,4 +1,4 @@
1
- import { OSType } from '../core/types.js';
1
+ import { OSType } from '../core/metadatas/types.js';
2
2
  export declare function getOSType(): OSType;
3
3
  export declare function installCLI(tool: 'gh' | 'git'): Promise<void>;
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { OSType } from '../core/types.js';
1
+ import { OSType } from '../core/metadatas/types.js';
2
2
  import os from 'os';
3
3
  import { exec } from 'child_process';
4
4
  import util from 'util';
@@ -1,4 +1,4 @@
1
- import { DependencyConfig, RegistryConfig, ServerInstallOptions } from '../../core/types.js';
1
+ import { DependencyConfig, RegistryConfig, ServerInstallOptions } from '../../core/metadatas/types.js';
2
2
  export interface OnboardServerConfig {
3
3
  name: string;
4
4
  description: string;
@@ -167,7 +167,7 @@
167
167
 
168
168
  <!-- Module scripts -->
169
169
  <script type="module">
170
- import { fetchServerCategories, handleInstallServer, installRequirement, upgradeRequirement, uninstallTool } from './js/api.js';
170
+ import { fetchServerCategories, handleInstallServer, uninstallTool } from './js/api.js';
171
171
  import { setupSearch } from './js/serverCategoryList.js';
172
172
  import { showServerDetails } from './js/serverCategoryDetails.js';
173
173
  import { showInstallModal, closeModal, setupModalOutsideClick } from './js/modal.js';
@@ -182,8 +182,6 @@
182
182
  // If other parts of the app call window.showOnboardModal, they'll need updating too.
183
183
  window.closeModal = closeModal;
184
184
  window.handleInstallServer = handleInstallServer;
185
- window.installRequirement = installRequirement;
186
- window.upgradeRequirement = upgradeRequirement;
187
185
  window.uninstallTool = uninstallTool;
188
186
 
189
187
  // Initialize
@@ -42,7 +42,7 @@ async function fetchServerCategories() {
42
42
  async function handleInstallServer(event, categoryName, serverName, callback, options = {}) {
43
43
  event.preventDefault(); // Prevent page reload
44
44
  console.log("Handling install for:", categoryName, serverName);
45
-
45
+
46
46
  // Get selected targets from the form if not provided in options
47
47
  const selectedTargets = options.targets || [...document.querySelectorAll('input[name="targets"]:checked')]
48
48
  .map(cb => cb.value);
@@ -71,7 +71,7 @@ async function handleInstallServer(event, categoryName, serverName, callback, op
71
71
  const response = await fetch(`/api/categories/${categoryName}/install`, {
72
72
  method: 'POST',
73
73
  headers: { 'Content-Type': 'application/json' },
74
- body: JSON.stringify({serverList: serverList})
74
+ body: JSON.stringify({ serverList: serverList })
75
75
  });
76
76
 
77
77
  if (!response.ok) {
@@ -90,82 +90,6 @@ async function handleInstallServer(event, categoryName, serverName, callback, op
90
90
  }
91
91
  }
92
92
 
93
- // Install requirement handler
94
- async function installRequirement(reqName) {
95
- const detailsDiv = document.getElementById('serverCategoryDetails');
96
- const serverTitle = detailsDiv.querySelector('h3');
97
- if (!serverTitle) {
98
- showToast('No server selected.', 'error');
99
- return;
100
- }
101
- let serverName = serverTitle.textContent;
102
- if (serverName.includes(' for ')) {
103
- serverName = serverName.split(' for ')[0];
104
- }
105
- const confirmed = await showConfirm(`Do you want to install requirement '${reqName}' for ${serverName}?`);
106
- if (!confirmed) {
107
- return;
108
- }
109
-
110
- const btn = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Install' && b.onclick?.toString().includes(reqName));
111
- if (btn) btn.disabled = true;
112
-
113
- try {
114
- const response = await fetch(`/api/categories/${serverName}/install-requirement`, {
115
- method: 'POST',
116
- headers: { 'Content-Type': 'application/json' },
117
- body: JSON.stringify({ requirementName: reqName })
118
- });
119
- if (!response.ok) {
120
- const errorData = await response.text();
121
- throw new Error(`Installation failed: ${errorData || response.statusText}`);
122
- }
123
- showToast(`Requirement '${reqName}' installation initiated successfully!`, 'success');
124
- setTimeout(() => {
125
- fetchServerCategories();
126
- window.showServerDetails(serverName);
127
- }, 1000);
128
- } catch (error) {
129
- console.error('Error installing requirement:', error);
130
- showToast(`Error installing requirement: ${error.message}. Please check console.`, 'error');
131
- } finally {
132
- if (btn) btn.disabled = false;
133
- }
134
- }
135
-
136
- // Handle upgrade/uninstall actions
137
- async function upgradeRequirement(name) {
138
- const serverTitle = document.querySelector('#serverCategoryDetails h3')?.textContent;
139
- if (!serverTitle) {
140
- showToast('No server selected.', 'error');
141
- return;
142
- }
143
-
144
- const upgradeConfirmed = await showConfirm(`Do you want to upgrade requirement '${name}' for ${serverTitle}?`);
145
- if (!upgradeConfirmed) {
146
- return;
147
- }
148
-
149
- try {
150
- const response = await fetch(`/api/categories/${serverTitle}/upgrade-requirement`, {
151
- method: 'POST',
152
- headers: { 'Content-Type': 'application/json' },
153
- body: JSON.stringify({ requirementName: name })
154
- });
155
-
156
- if (!response.ok) {
157
- const errorData = await response.text();
158
- throw new Error(`Upgrade failed: ${errorData || response.statusText}`);
159
- }
160
-
161
- showToast(`Requirement '${name}' upgrade initiated successfully!`, 'success');
162
- fetchServerCategories();
163
- window.showServerDetails(serverTitle);
164
- } catch (error) {
165
- console.error('Error upgrading requirement:', error);
166
- showToast(`Error upgrading requirement: ${error.message}`, 'error');
167
- }
168
- }
169
93
 
170
94
  async function uninstallTool(name) {
171
95
  const serverTitle = document.querySelector('#serverCategoryDetails h3')?.textContent;
@@ -204,7 +128,5 @@ export {
204
128
  allServerCategoriesData,
205
129
  fetchServerCategories,
206
130
  handleInstallServer,
207
- installRequirement,
208
- upgradeRequirement,
209
131
  uninstallTool
210
132
  };
@@ -2,12 +2,12 @@ import express from 'express';
2
2
  import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { OnboardingProcessStatus } from '../core/onboard/OnboardStatus.js';
5
- import { SUPPORTED_CLIENT_NAMES } from '../core/constants.js';
5
+ import { SUPPORTED_CLIENT_NAMES } from '../core/metadatas/constants.js';
6
6
  import { serverService } from '../services/ServerService.js';
7
7
  import { feedOnboardService } from '../core/onboard/FeedOnboardService.js';
8
8
  import { openBrowser } from '../utils/osUtils.js';
9
9
  import { Logger } from '../utils/logger.js';
10
- import { configProvider } from '../core/ConfigurationProvider.js';
10
+ import { configProvider } from '../core/loaders/ConfigurationProvider.js';
11
11
  import { onboardStatusManager } from '../core/onboard/OnboardStatusManager.js';
12
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
13
  const app = express();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imcp",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "description": "Node.js SDK for Model Context Protocol (MCP)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -2,9 +2,9 @@ import { Command } from 'commander';
2
2
  import { serverService } from '../../services/ServerService.js';
3
3
  import { Logger } from '../../utils/logger.js';
4
4
  import { hasLocalFeeds } from '../../utils/feedUtils.js';
5
- import { ServerInstallOptions } from '../../core/types.js';
6
- import { SUPPORTED_CLIENT_NAMES } from '../../core/constants.js';
7
- import { mcpManager } from '../../core/MCPManager.js';
5
+ import { ServerInstallOptions } from '../../core/metadatas/types.js';
6
+ import { SUPPORTED_CLIENT_NAMES } from '../../core/metadatas/constants.js';
7
+ import { mcpManager } from '../../services/MCPManager.js';
8
8
 
9
9
  export function createInstallCommand(): Command {
10
10
  return new Command('install')
@@ -1,8 +1,8 @@
1
1
  import { Command } from 'commander';
2
2
  import fs from 'fs/promises';
3
3
  import path from 'path';
4
- import { LOCAL_FEEDS_DIR } from '../../core/constants.js';
5
- import { mcpManager } from '../../core/MCPManager.js';
4
+ import { LOCAL_FEEDS_DIR } from '../../core/metadatas/constants.js';
5
+ import { mcpManager } from '../../services/MCPManager.js';
6
6
  import { Logger } from '../../utils/logger.js';
7
7
 
8
8
  interface SimplifiedServer {
@@ -1,6 +1,6 @@
1
1
  import { Command } from 'commander';
2
2
  import { startWebServer } from '../../web/server.js';
3
- import { mcpManager } from '../../core/MCPManager.js';
3
+ import { mcpManager } from '../../services/MCPManager.js';
4
4
  import { checkGithubAuth } from '../../utils/githubAuth.js';
5
5
  import { Logger } from '../../utils/logger.js';
6
6
 
@@ -9,13 +9,14 @@ export function createServeCommand(): Command {
9
9
  .description('Serve local web interface')
10
10
  .option('-p, --port <port>', 'Port to run the server on', '3000')
11
11
  .option('-f, --feed-file <filepath>', 'Path to a custom feed configuration file')
12
+ .option('-s, --schemas-directory <path>', 'Path to a directory containing adhoc schema files')
12
13
  .action(async (options) => {
13
14
  try {
14
15
  // Sync feeds before start the local UI
15
16
  await mcpManager.syncFeeds();
16
17
 
17
18
  // Ensure MCP manager is initialized before starting the web server
18
- await mcpManager.initialize(options.feedFile);
19
+ await mcpManager.initialize(options.feedFile, options.schemasDirectory);
19
20
 
20
21
  const port = parseInt(options.port, 10);
21
22
  if (isNaN(port) || port < 1 || port > 65535) {
package/src/cli/index.ts CHANGED
@@ -6,7 +6,7 @@ import { createListCommand } from './commands/list.js';
6
6
  import { createInstallCommand } from './commands/install.js';
7
7
  import { createUninstallCommand } from './commands/uninstall.js';
8
8
  import { createPullCommand } from './commands/pull.js';
9
- import { mcpManager } from '../core/MCPManager.js';
9
+ import { mcpManager } from '../services/MCPManager.js';
10
10
  import { Logger } from '../utils/logger.js';
11
11
  import axios from 'axios';
12
12
  import path from 'path';
@@ -1,11 +1,14 @@
1
1
  import { Logger } from '../../../utils/logger.js';
2
2
  import { exec } from 'child_process';
3
3
  import { promisify } from 'util';
4
+ import { isCommandAvailable } from '../../../utils/osUtils.js';
5
+ import { ExtensionInstaller } from './ExtensionInstaller.js';
6
+ import { SUPPORTED_CLIENTS } from '../../metadatas/constants.js';
4
7
  import {
5
8
  OperationStatus,
6
9
  McpConfig,
7
10
  ServerInstallOptions,
8
- } from '../../types.js';
11
+ } from '../../metadatas/types.js';
9
12
  import {
10
13
  MACRO_EXPRESSIONS,
11
14
  MacroResolverFunctions
@@ -17,6 +20,7 @@ const execAsync = promisify(exec);
17
20
  * Base class for client installers with shared functionality
18
21
  */
19
22
  export abstract class BaseClientInstaller {
23
+ protected abstract readonly clientName: string;
20
24
  /**
21
25
  * Generate a unique operation ID for tracking installations
22
26
  */
@@ -189,8 +193,135 @@ export abstract class BaseClientInstaller {
189
193
  }
190
194
 
191
195
  /**
192
- * Abstract methods that must be implemented by client-specific installers
196
+ * Checks if VS Code or VS Code Insiders is installed and installs the client extension.
197
+ * @param operationId The operation ID for tracking.
198
+ * @returns An OperationStatus object if checks fail or installation fails, otherwise undefined.
199
+ */
200
+ protected async checkVSCodeAndInstallExtension(operationId: string): Promise<OperationStatus | undefined> {
201
+ // Check if VS Code or VS Code Insiders is installed
202
+ const isVSCodeInstalled = await isCommandAvailable('code');
203
+ const isVSCodeInsidersInstalled = await isCommandAvailable('code-insiders');
204
+
205
+ if (!isVSCodeInstalled && !isVSCodeInsidersInstalled) {
206
+ return {
207
+ status: 'failed',
208
+ type: 'install',
209
+ target: 'server',
210
+ message: 'Failed to install as neither VS Code nor VS Code Insiders are installed on this system. Please run `code` or `code-insiders` to make sure they are installed. Relaunch imcp after installation.',
211
+ operationId
212
+ };
213
+ }
214
+
215
+ // Install extension
216
+ const extensionResult = await ExtensionInstaller.installExtension(this.clientName);
217
+ if (!extensionResult) {
218
+ Logger.debug(`Failed to install ${this.clientName} extension`);
219
+ return {
220
+ status: 'failed',
221
+ type: 'install',
222
+ target: 'server',
223
+ message: `Failed to install ${this.clientName} extension`,
224
+ operationId
225
+ };
226
+ }
227
+ return undefined;
228
+ }
229
+
230
+ /**
231
+ * Update VS Code settings for both VS Code and VS Code Insiders if installed
232
+ * @param serverName The name of the server to configure
233
+ * @param installConfig The installation configuration
234
+ * @returns Array of results indicating success/failure for each VS Code variant
235
+ */
236
+ protected async updateVSCodeSettings(serverName: string, installConfig: any): Promise<Array<{ success: boolean; path: string; error?: string }>> {
237
+ const results: Array<{ success: boolean; path: string; error?: string }> = [];
238
+ const isVSCodeInstalled = await isCommandAvailable('code');
239
+ const isVSCodeInsidersInstalled = await isCommandAvailable('code-insiders');
240
+
241
+ // Update settings for VS Code if installed
242
+ if (isVSCodeInstalled) {
243
+ try {
244
+ const settingPath = SUPPORTED_CLIENTS[this.clientName].codeSettingPath;
245
+ await this.setupClientSettings(settingPath, serverName, installConfig);
246
+ results.push({ success: true, path: settingPath });
247
+ } catch (error) {
248
+ results.push({
249
+ success: false,
250
+ path: SUPPORTED_CLIENTS[this.clientName].codeSettingPath,
251
+ error: error instanceof Error ? error.message : String(error)
252
+ });
253
+ }
254
+ }
255
+
256
+ // Update settings for VS Code Insiders if installed
257
+ if (isVSCodeInsidersInstalled) {
258
+ try {
259
+ const settingPath = SUPPORTED_CLIENTS[this.clientName].codeInsiderSettingPath;
260
+ await this.setupClientSettings(settingPath, serverName, installConfig);
261
+ results.push({ success: true, path: settingPath });
262
+ } catch (error) {
263
+ results.push({
264
+ success: false,
265
+ path: SUPPORTED_CLIENTS[this.clientName].codeInsiderSettingPath,
266
+ error: error instanceof Error ? error.message : String(error)
267
+ });
268
+ }
269
+ }
270
+
271
+ return results;
272
+ }
273
+
274
+ /**
275
+ * Install the client
276
+ * @param serverConfig Server configuration
277
+ * @param options Installation options including environment variables and arguments
278
+ */
279
+ async install(serverConfig: McpConfig, options: ServerInstallOptions): Promise<OperationStatus> {
280
+ const operationId = this.generateOperationId();
281
+
282
+ try {
283
+ const vsCodeCheckResult = await this.checkVSCodeAndInstallExtension(operationId);
284
+ if (vsCodeCheckResult) {
285
+ return vsCodeCheckResult;
286
+ }
287
+
288
+ const installConfig = await this.setupInstallConfig(serverConfig, options);
289
+ if (serverConfig.mode) {
290
+ installConfig.mode = serverConfig.mode;
291
+ }
292
+
293
+ // Update VS Code settings
294
+ const results = await this.updateVSCodeSettings(serverConfig.name, installConfig);
295
+
296
+ // Determine overall success
297
+ const anySuccess = results.some(r => r.success);
298
+ const successPaths = results.filter(r => r.success).map(r => r.path);
299
+ const errors = results.filter(r => !r.success).map(r => r.error);
300
+
301
+ return {
302
+ status: anySuccess ? 'completed' : 'failed',
303
+ type: 'install',
304
+ target: 'server',
305
+ message: anySuccess
306
+ ? `Successfully installed ${this.clientName} client. Updated settings in: ${successPaths.join(', ')}`
307
+ : `Failed to install ${this.clientName} client. Errors: ${errors.join('; ')}`,
308
+ operationId,
309
+ error: anySuccess ? undefined : errors.join('; ')
310
+ };
311
+ } catch (error) {
312
+ return {
313
+ status: 'failed',
314
+ type: 'install',
315
+ target: 'server',
316
+ message: `Unexpected error installing ${this.clientName} client: ${error instanceof Error ? error.message : String(error)}`,
317
+ operationId,
318
+ error: error instanceof Error ? error.message : String(error)
319
+ };
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Abstract method that must be implemented by client-specific installers
193
325
  */
194
- abstract install(serverConfig: McpConfig, options: ServerInstallOptions): Promise<OperationStatus>;
195
326
  abstract setupClientSettings(settingPath: string, serverName: string, installConfig: any): Promise<void>;
196
327
  }