imcp 0.0.14 → 0.0.16

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 (136) hide show
  1. package/dist/core/ConfigurationProvider.d.ts +1 -0
  2. package/dist/core/ConfigurationProvider.js +15 -0
  3. package/dist/core/InstallationService.js +2 -7
  4. package/dist/core/MCPManager.d.ts +11 -2
  5. package/dist/core/MCPManager.js +24 -1
  6. package/dist/core/RequirementService.js +2 -8
  7. package/dist/core/installers/clients/BaseClientInstaller.d.ts +51 -0
  8. package/dist/core/installers/clients/BaseClientInstaller.js +160 -0
  9. package/dist/core/installers/clients/ClientInstaller.d.ts +16 -9
  10. package/dist/core/installers/clients/ClientInstaller.js +80 -527
  11. package/dist/core/installers/clients/ClientInstallerFactory.d.ts +20 -0
  12. package/dist/core/installers/clients/ClientInstallerFactory.js +37 -0
  13. package/dist/core/installers/clients/ClineInstaller.d.ts +18 -0
  14. package/dist/core/installers/clients/ClineInstaller.js +124 -0
  15. package/dist/core/installers/clients/GithubCopilotInstaller.d.ts +34 -0
  16. package/dist/core/installers/clients/GithubCopilotInstaller.js +162 -0
  17. package/dist/core/installers/clients/MSRooCodeInstaller.d.ts +15 -0
  18. package/dist/core/installers/clients/MSRooCodeInstaller.js +122 -0
  19. package/dist/core/installers/requirements/BaseInstaller.d.ts +11 -34
  20. package/dist/core/installers/requirements/BaseInstaller.js +5 -116
  21. package/dist/core/installers/requirements/CommandInstaller.d.ts +6 -1
  22. package/dist/core/installers/requirements/CommandInstaller.js +7 -0
  23. package/dist/core/installers/requirements/GeneralInstaller.d.ts +6 -1
  24. package/dist/core/installers/requirements/GeneralInstaller.js +9 -4
  25. package/dist/core/installers/requirements/NpmInstaller.d.ts +46 -7
  26. package/dist/core/installers/requirements/NpmInstaller.js +150 -58
  27. package/dist/core/installers/requirements/PipInstaller.d.ts +9 -0
  28. package/dist/core/installers/requirements/PipInstaller.js +66 -28
  29. package/dist/core/onboard/FeedOnboardService.d.ts +50 -13
  30. package/dist/core/onboard/FeedOnboardService.js +263 -88
  31. package/dist/core/onboard/OnboardProcessor.d.ts +79 -0
  32. package/dist/core/onboard/OnboardProcessor.js +290 -0
  33. package/dist/core/onboard/OnboardStatus.d.ts +49 -0
  34. package/dist/core/onboard/OnboardStatus.js +10 -0
  35. package/dist/core/onboard/OnboardStatusManager.d.ts +57 -0
  36. package/dist/core/onboard/OnboardStatusManager.js +176 -0
  37. package/dist/core/types.d.ts +4 -5
  38. package/dist/core/validators/FeedValidator.d.ts +8 -1
  39. package/dist/core/validators/FeedValidator.js +60 -7
  40. package/dist/core/validators/IServerValidator.d.ts +19 -0
  41. package/dist/core/validators/IServerValidator.js +2 -0
  42. package/dist/core/validators/SSEServerValidator.d.ts +15 -0
  43. package/dist/core/validators/SSEServerValidator.js +39 -0
  44. package/dist/core/validators/ServerValidatorFactory.d.ts +24 -0
  45. package/dist/core/validators/ServerValidatorFactory.js +45 -0
  46. package/dist/core/validators/StdioServerValidator.d.ts +46 -0
  47. package/dist/core/validators/StdioServerValidator.js +229 -0
  48. package/dist/services/InstallRequestValidator.d.ts +1 -1
  49. package/dist/services/ServerService.d.ts +9 -6
  50. package/dist/services/ServerService.js +18 -7
  51. package/dist/utils/adoUtils.d.ts +29 -0
  52. package/dist/utils/adoUtils.js +252 -0
  53. package/dist/utils/clientUtils.d.ts +0 -7
  54. package/dist/utils/clientUtils.js +0 -42
  55. package/dist/utils/githubUtils.d.ts +10 -0
  56. package/dist/utils/githubUtils.js +22 -0
  57. package/dist/utils/macroExpressionUtils.d.ts +38 -0
  58. package/dist/utils/macroExpressionUtils.js +116 -0
  59. package/dist/utils/osUtils.d.ts +4 -20
  60. package/dist/utils/osUtils.js +78 -23
  61. package/dist/web/contract/serverContract.d.ts +3 -1
  62. package/dist/web/public/css/notifications.css +48 -17
  63. package/dist/web/public/css/onboard.css +66 -3
  64. package/dist/web/public/index.html +84 -16
  65. package/dist/web/public/js/api.js +3 -6
  66. package/dist/web/public/js/flights/flights.js +127 -0
  67. package/dist/web/public/js/modal/installation.js +5 -5
  68. package/dist/web/public/js/modal/modalSetup.js +3 -2
  69. package/dist/web/public/js/notifications.js +66 -27
  70. package/dist/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +338 -0
  71. package/dist/web/public/js/onboard/formProcessor.js +810 -255
  72. package/dist/web/public/js/onboard/index.js +328 -85
  73. package/dist/web/public/js/onboard/publishHandler.js +132 -0
  74. package/dist/web/public/js/onboard/state.js +61 -17
  75. package/dist/web/public/js/onboard/templates.js +217 -249
  76. package/dist/web/public/js/onboard/uiHandlers.js +679 -117
  77. package/dist/web/public/js/onboard/validationHandlers.js +378 -0
  78. package/dist/web/public/js/serverCategoryList.js +15 -2
  79. package/dist/web/public/onboard.html +191 -45
  80. package/dist/web/public/styles.css +91 -1
  81. package/dist/web/server.d.ts +0 -10
  82. package/dist/web/server.js +131 -22
  83. package/package.json +2 -2
  84. package/src/core/ConfigurationProvider.ts +15 -0
  85. package/src/core/InstallationService.ts +2 -7
  86. package/src/core/MCPManager.ts +26 -1
  87. package/src/core/RequirementService.ts +2 -9
  88. package/src/core/installers/clients/BaseClientInstaller.ts +196 -0
  89. package/src/core/installers/clients/ClientInstaller.ts +97 -608
  90. package/src/core/installers/clients/ClientInstallerFactory.ts +43 -0
  91. package/src/core/installers/clients/ClineInstaller.ts +135 -0
  92. package/src/core/installers/clients/GithubCopilotInstaller.ts +179 -0
  93. package/src/core/installers/clients/MSRooCodeInstaller.ts +133 -0
  94. package/src/core/installers/requirements/BaseInstaller.ts +13 -136
  95. package/src/core/installers/requirements/CommandInstaller.ts +9 -1
  96. package/src/core/installers/requirements/GeneralInstaller.ts +11 -4
  97. package/src/core/installers/requirements/NpmInstaller.ts +178 -61
  98. package/src/core/installers/requirements/PipInstaller.ts +68 -29
  99. package/src/core/onboard/FeedOnboardService.ts +346 -0
  100. package/src/core/onboard/OnboardProcessor.ts +305 -0
  101. package/src/core/onboard/OnboardStatus.ts +55 -0
  102. package/src/core/onboard/OnboardStatusManager.ts +188 -0
  103. package/src/core/types.ts +4 -5
  104. package/src/core/validators/FeedValidator.ts +79 -0
  105. package/src/core/validators/IServerValidator.ts +21 -0
  106. package/src/core/validators/SSEServerValidator.ts +43 -0
  107. package/src/core/validators/ServerValidatorFactory.ts +51 -0
  108. package/src/core/validators/StdioServerValidator.ts +259 -0
  109. package/src/services/InstallRequestValidator.ts +1 -1
  110. package/src/services/ServerService.ts +22 -7
  111. package/src/utils/adoUtils.ts +291 -0
  112. package/src/utils/clientUtils.ts +0 -44
  113. package/src/utils/githubUtils.ts +24 -0
  114. package/src/utils/macroExpressionUtils.ts +121 -0
  115. package/src/utils/osUtils.ts +89 -24
  116. package/src/web/contract/serverContract.ts +74 -0
  117. package/src/web/public/css/notifications.css +48 -17
  118. package/src/web/public/css/onboard.css +107 -0
  119. package/src/web/public/index.html +84 -16
  120. package/src/web/public/js/api.js +3 -6
  121. package/src/web/public/js/flights/flights.js +127 -0
  122. package/src/web/public/js/modal/installation.js +5 -5
  123. package/src/web/public/js/modal/modalSetup.js +3 -2
  124. package/src/web/public/js/notifications.js +66 -27
  125. package/src/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +338 -0
  126. package/src/web/public/js/onboard/formProcessor.js +864 -0
  127. package/src/web/public/js/onboard/index.js +374 -0
  128. package/src/web/public/js/onboard/publishHandler.js +132 -0
  129. package/src/web/public/js/onboard/state.js +76 -0
  130. package/src/web/public/js/onboard/templates.js +343 -0
  131. package/src/web/public/js/onboard/uiHandlers.js +758 -0
  132. package/src/web/public/js/onboard/validationHandlers.js +378 -0
  133. package/src/web/public/js/serverCategoryList.js +15 -2
  134. package/src/web/public/onboard.html +296 -0
  135. package/src/web/public/styles.css +91 -1
  136. package/src/web/server.ts +167 -58
@@ -273,6 +273,21 @@ export class ConfigurationProvider {
273
273
  });
274
274
  }
275
275
 
276
+ async GetServerRequirementStatus(categoryName: string, serverName: string): Promise<RequirementStatus[]> {
277
+ return await this.withLock(async () => {
278
+ // Inline getServerCategory logic
279
+ const category = this.configuration.localServerCategories.find(s => s.name === categoryName);
280
+ if (!category?.feedConfiguration) return [];
281
+ const serverConfig = category.feedConfiguration.mcpServers.find(s => s.name === serverName);
282
+ if (!serverConfig?.dependencies?.requirements) return [];
283
+ const requirementNames = serverConfig.dependencies.requirements.map(r => r.name);
284
+
285
+ return requirementNames
286
+ .map(name => category?.installationStatus?.requirementsStatus[name])
287
+ .filter(x => x !== undefined) as RequirementStatus[];
288
+ });
289
+ }
290
+
276
291
  async isServerReady(categoryName: string, serverName: string, clients: string[]): Promise<boolean> {
277
292
  return await this.withLock(async () => {
278
293
  // Inline the logic from getServerStatus and getInstallationStatus to avoid nested lock
@@ -149,14 +149,9 @@ export class InstallationService {
149
149
  }
150
150
  });
151
151
 
152
- // Create updated requirement config with new version
153
- const updatedReqConfig: RequirementConfig = {
154
- ...reqConfig,
155
- version: reqToUpdate.version
156
- };
157
152
 
158
153
  // For pip requirements, check if we have a stored pythonEnv
159
- if (updatedReqConfig.type === 'pip' && currentStatus.pythonEnv && !options?.settings?.pythonEnv) {
154
+ if (reqConfig.type === 'pip' && currentStatus.pythonEnv && !options?.settings?.pythonEnv) {
160
155
  options = {
161
156
  ...options,
162
157
  settings: { ...options?.settings, pythonEnv: currentStatus.pythonEnv }
@@ -164,7 +159,7 @@ export class InstallationService {
164
159
  }
165
160
 
166
161
  // Update the requirement with options for pip environment
167
- const updatedStatus = await requirementService.updateRequirement(updatedReqConfig, reqToUpdate.version, options);
162
+ const updatedStatus = await requirementService.updateRequirement(reqConfig, reqToUpdate.version, options);
168
163
 
169
164
  // Update requirement status
170
165
  await configProvider.updateRequirementStatus(categoryName, reqToUpdate.name, {
@@ -9,18 +9,24 @@ import {
9
9
  ServerCategoryListOptions,
10
10
  ServerOperationResult,
11
11
  ServerUninstallOptions,
12
- InstallationStatus
12
+ InstallationStatus,
13
+ FeedConfiguration,
13
14
  } from './types.js';
15
+ import { OperationStatus } from './onboard/OnboardStatus.js';
16
+ import { Logger } from '../utils/logger.js';
17
+ import { FeedOnboardService } from './onboard/FeedOnboardService.js';
14
18
  import path from 'path';
15
19
 
16
20
  export class MCPManager extends EventEmitter {
17
21
  private installationService: InstallationService;
18
22
  private configProvider: ConfigurationProvider;
23
+ private feedOnboardService: FeedOnboardService;
19
24
 
20
25
  constructor() {
21
26
  super();
22
27
  this.configProvider = ConfigurationProvider.getInstance();
23
28
  this.installationService = new InstallationService();
29
+ this.feedOnboardService = new FeedOnboardService();
24
30
  }
25
31
 
26
32
  async syncFeeds(): Promise<void> {
@@ -204,6 +210,25 @@ export class MCPManager extends EventEmitter {
204
210
  }
205
211
  }
206
212
 
213
+ /**
214
+ * Onboards a new feed configuration
215
+ * @param config The feed configuration to onboard
216
+ */
217
+ async onboardFeed(config: FeedConfiguration): Promise<OperationStatus & { feedConfiguration?: FeedConfiguration }> {
218
+ try {
219
+ const result = await this.feedOnboardService.onboardFeed(config);
220
+ // After successful onboarding initiation, sync feeds to get the latest changes
221
+ // Syncing should ideally happen after the PR is merged, but for now,
222
+ // syncing here makes the new (pending) category available locally if needed.
223
+ // Consider if syncFeeds should be conditional based on operation status or handled differently.
224
+ await this.syncFeeds();
225
+ return result;
226
+ } catch (error) {
227
+ Logger.error('Failed to onboard feed in MCPManager:', error);
228
+ throw error; // Rethrow or handle by returning a failed OperationStatus
229
+ }
230
+ }
231
+
207
232
  // Type-safe event emitter methods
208
233
  emit<E extends MCPEvent>(event: E, data: MCPEventData[E]): boolean {
209
234
  return super.emit(event, data);
@@ -87,7 +87,7 @@ export class RequirementService {
87
87
  // Create an updated requirement with the new version
88
88
  const updatedRequirement: RequirementConfig = {
89
89
  ...requirement,
90
- version: updateVersion
90
+ version: requirement.version.includes('latest') ? requirement.version : updateVersion,
91
91
  };
92
92
 
93
93
  // Install the updated version
@@ -132,7 +132,7 @@ export class RequirementService {
132
132
 
133
133
  // Validate registry configuration if provided
134
134
  if (requirement.registry) {
135
- const { githubRelease, artifacts, local } = requirement.registry;
135
+ const { githubRelease, artifacts } = requirement.registry;
136
136
 
137
137
  // Validate GitHub release configuration
138
138
  if (githubRelease) {
@@ -151,13 +151,6 @@ export class RequirementService {
151
151
  throw new Error('Registry URL is required for artifacts registry');
152
152
  }
153
153
  }
154
-
155
- // Validate local registry configuration
156
- if (local) {
157
- if (!local.localPath) {
158
- throw new Error('Local path is required for local registry');
159
- }
160
- }
161
154
  }
162
155
  }
163
156
  }
@@ -0,0 +1,196 @@
1
+ import { Logger } from '../../../utils/logger.js';
2
+ import { exec } from 'child_process';
3
+ import { promisify } from 'util';
4
+ import {
5
+ OperationStatus,
6
+ McpConfig,
7
+ ServerInstallOptions,
8
+ } from '../../types.js';
9
+ import {
10
+ MACRO_EXPRESSIONS,
11
+ MacroResolverFunctions
12
+ } from '../../../utils/macroExpressionUtils.js';
13
+
14
+ const execAsync = promisify(exec);
15
+
16
+ /**
17
+ * Base class for client installers with shared functionality
18
+ */
19
+ export abstract class BaseClientInstaller {
20
+ /**
21
+ * Generate a unique operation ID for tracking installations
22
+ */
23
+ protected generateOperationId(): string {
24
+ return `install-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
25
+ }
26
+
27
+ /**
28
+ * Set up installation configuration with environment variables and arguments
29
+ * Handles Python environment configuration if specified
30
+ */
31
+ protected async setupInstallConfig(
32
+ serverConfig: McpConfig,
33
+ options: ServerInstallOptions
34
+ ): Promise<any> {
35
+ const finalConfig: any = { ...serverConfig.installation };
36
+ finalConfig.mode = serverConfig.mode;
37
+
38
+ // Handle command line arguments
39
+ if (options.args && options.args.length > 0) {
40
+ Logger.debug(`Using args from ServerInstallOptions: ${options.args.join(' ')}`);
41
+ finalConfig.args = options.args;
42
+ }
43
+
44
+ // Handle environment variables
45
+ const baseEnv = finalConfig.env || {};
46
+ const defaultEnv: Record<string, string> = {};
47
+ for (const [key, config] of Object.entries(baseEnv)) {
48
+ const envConfig = config as any;
49
+ if (envConfig.Default) {
50
+ defaultEnv[key] = envConfig.Default;
51
+ }
52
+ }
53
+ finalConfig.env = { ...defaultEnv, ...(options.env || {}) };
54
+
55
+ // Handle macro expressions
56
+ await this._resolveConfigMacros(finalConfig, options);
57
+
58
+ Logger.debug(`Final installation config: ${JSON.stringify(finalConfig)}`);
59
+ return finalConfig;
60
+ }
61
+
62
+ /**
63
+ * Resolves and replaces known macro expressions (e.g., ${PYTHON_PACKAGE}, ${NPMPATH}, ${BROWSER_PATH})
64
+ * in the provided configuration object's 'args' and 'env' properties.
65
+ * This method directly mutates the finalConfig object.
66
+ * @param finalConfig The configuration object to modify.
67
+ * @param options Server installation options which may contain settings like pythonEnv or npmPath.
68
+ */
69
+ private async _resolveConfigMacros(
70
+ finalConfig: any,
71
+ options: ServerInstallOptions
72
+ ): Promise<void> {
73
+ for (const macro of Object.values(MACRO_EXPRESSIONS)) {
74
+ const isMacroInArgs = finalConfig.args?.some((arg: string) => typeof arg === 'string' && arg.includes(macro));
75
+ const isMacroInEnv = Object.values(finalConfig.env || {}).some(value => typeof value === 'string' && value.includes(macro));
76
+
77
+ if (!isMacroInArgs && !isMacroInEnv) {
78
+ Logger.debug(`Macro ${macro} not found in args or env, skipping resolution.`);
79
+ continue;
80
+ }
81
+
82
+ const resolver = MacroResolverFunctions[macro];
83
+ if (resolver) {
84
+ const resolvedValue = await resolver(finalConfig, options);
85
+ if (resolvedValue !== undefined) {
86
+ // Replace in args
87
+ if (finalConfig.args) {
88
+ const originalArgsString = finalConfig.args.join(' ');
89
+ finalConfig.args = finalConfig.args.map((arg: string) =>
90
+ typeof arg === 'string' && arg.includes(macro)
91
+ ? arg.replace(new RegExp(macro.replace(/[${}]/g, '\\$&'), 'g'), resolvedValue)
92
+ : arg
93
+ );
94
+ if (finalConfig.args.join(' ') !== originalArgsString) {
95
+ Logger.debug(`Args after ${macro} ('${resolvedValue}') replacement: ${finalConfig.args.join(' ')}`);
96
+ }
97
+ }
98
+ // Replace in env
99
+ if (finalConfig.env) {
100
+ const originalEnvJson = JSON.stringify(finalConfig.env);
101
+ for (const key in finalConfig.env) {
102
+ if (typeof finalConfig.env[key] === 'string' && (finalConfig.env[key] as string).includes(macro)) {
103
+ finalConfig.env[key] = (finalConfig.env[key] as string).replace(new RegExp(macro.replace(/[${}]/g, '\\$&'), 'g'), resolvedValue);
104
+ }
105
+ }
106
+ if (JSON.stringify(finalConfig.env) !== originalEnvJson) {
107
+ Logger.debug(`Env after ${macro} ('${resolvedValue}') replacement: ${JSON.stringify(finalConfig.env)}`);
108
+ }
109
+ }
110
+ } else {
111
+ Logger.debug(`Could not resolve value for macro: ${macro}. It will not be replaced.`);
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Handle NPX commands for Windows platform
119
+ */
120
+ protected async handleWindowsNpx(config: any): Promise<any> {
121
+ if (process.platform === 'win32' && config.command === 'npx') {
122
+ const npmPath = await this.getNpmPath();
123
+ return {
124
+ ...config,
125
+ command: 'cmd',
126
+ args: ['/c', 'npx', ...config.args],
127
+ env: {
128
+ ...config.env,
129
+ 'APPDATA': npmPath
130
+ }
131
+ };
132
+ }
133
+ return config;
134
+ }
135
+
136
+ /**
137
+ * Initialize settings object with client-specific structure
138
+ * Override in child classes to provide custom initialization
139
+ */
140
+ protected initializeSettings(settings: any): void {
141
+ if (!settings.mcpServers) {
142
+ settings.mcpServers = {};
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Handle stdio mode configuration
148
+ * Override in child classes to provide custom stdio configuration
149
+ */
150
+ protected async handleStdioMode(settings: any, serverName: string, finalConfig: any): Promise<void> {
151
+ // Convert backslashes to forward slashes in args
152
+ if (finalConfig.args) {
153
+ finalConfig.args = finalConfig.args.map((arg: string) =>
154
+ typeof arg === 'string' ? arg.replace(/\\/g, '/') : arg
155
+ );
156
+ }
157
+ settings.mcpServers[serverName] = {
158
+ command: finalConfig.command,
159
+ args: finalConfig.args,
160
+ env: finalConfig.env,
161
+ autoApprove: [],
162
+ disabled: false,
163
+ alwaysAllow: []
164
+ };
165
+ }
166
+
167
+ /**
168
+ * Handle SSE mode configuration
169
+ * Override in child classes to provide custom SSE configuration
170
+ */
171
+ protected handleSseMode(settings: any, serverName: string, installConfig: any): void {
172
+ settings.mcpServers[serverName] = {
173
+ type: 'sse',
174
+ url: installConfig.url
175
+ };
176
+ }
177
+
178
+ /**
179
+ * Get the NPM path on Windows
180
+ */
181
+ private async getNpmPath(): Promise<string> {
182
+ try {
183
+ const { stdout } = await execAsync('powershell -Command "get-command npm | Select-Object -ExpandProperty Source"');
184
+ return stdout.trim().replace(/\\npm\.cmd$/, '');
185
+ } catch (error) {
186
+ Logger.error('Error getting npm path:', error);
187
+ return 'C:\\Program Files\\nodejs';
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Abstract methods that must be implemented by client-specific installers
193
+ */
194
+ abstract install(serverConfig: McpConfig, options: ServerInstallOptions): Promise<OperationStatus>;
195
+ abstract setupClientSettings(settingPath: string, serverName: string, installConfig: any): Promise<void>;
196
+ }