imcp 0.0.12 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/ConfigurationProvider.d.ts +2 -1
- package/dist/core/ConfigurationProvider.js +20 -24
- package/dist/core/InstallationService.d.ts +17 -0
- package/dist/core/InstallationService.js +127 -61
- package/dist/core/MCPManager.d.ts +1 -0
- package/dist/core/MCPManager.js +3 -0
- package/dist/core/RequirementService.d.ts +4 -4
- package/dist/core/RequirementService.js +11 -7
- package/dist/core/ServerSchemaProvider.d.ts +1 -1
- package/dist/core/ServerSchemaProvider.js +15 -10
- package/dist/core/constants.d.ts +3 -0
- package/dist/core/constants.js +4 -1
- package/dist/core/installers/clients/ClientInstaller.js +58 -40
- package/dist/core/installers/requirements/PipInstaller.js +10 -5
- package/dist/core/onboard/FeedOnboardService.d.ts +35 -0
- package/dist/core/onboard/FeedOnboardService.js +137 -0
- package/dist/core/types.d.ts +6 -1
- package/dist/core/validators/FeedValidator.d.ts +13 -0
- package/dist/core/validators/FeedValidator.js +27 -0
- package/dist/services/ServerService.d.ts +5 -0
- package/dist/services/ServerService.js +15 -0
- package/dist/utils/githubAuth.js +0 -10
- package/dist/utils/githubUtils.d.ts +16 -0
- package/dist/utils/githubUtils.js +55 -39
- package/dist/web/contract/serverContract.d.ts +64 -0
- package/dist/web/contract/serverContract.js +2 -0
- package/dist/web/public/css/detailsWidget.css +157 -32
- package/dist/web/public/css/onboard.css +44 -0
- package/dist/web/public/css/serverDetails.css +35 -19
- package/dist/web/public/index.html +16 -10
- package/dist/web/public/js/detailsWidget.js +43 -40
- package/dist/web/public/js/modal/index.js +58 -0
- package/dist/web/public/js/modal/installHandler.js +227 -0
- package/dist/web/public/js/modal/installModal.js +163 -0
- package/dist/web/public/js/modal/installation.js +281 -0
- package/dist/web/public/js/modal/loadingModal.js +52 -0
- package/dist/web/public/js/modal/loadingUI.js +74 -0
- package/dist/web/public/js/modal/messageQueue.js +112 -0
- package/dist/web/public/js/modal/modalSetup.js +512 -0
- package/dist/web/public/js/modal/modalUI.js +214 -0
- package/dist/web/public/js/modal/modalUtils.js +49 -0
- package/dist/web/public/js/modal/version.js +20 -0
- package/dist/web/public/js/modal/versionUtils.js +20 -0
- package/dist/web/public/js/modal.js +25 -1041
- package/dist/web/public/js/onboard/formProcessor.js +309 -0
- package/dist/web/public/js/onboard/index.js +131 -0
- package/dist/web/public/js/onboard/state.js +32 -0
- package/dist/web/public/js/onboard/templates.js +375 -0
- package/dist/web/public/js/onboard/uiHandlers.js +196 -0
- package/dist/web/public/js/serverCategoryDetails.js +211 -123
- package/dist/web/public/onboard.html +150 -0
- package/dist/web/server.js +25 -0
- package/package.json +3 -4
- package/src/core/ConfigurationProvider.ts +37 -29
- package/src/core/InstallationService.ts +176 -62
- package/src/core/MCPManager.ts +4 -0
- package/src/core/RequirementService.ts +12 -8
- package/src/core/ServerSchemaLoader.ts +48 -0
- package/src/core/ServerSchemaProvider.ts +137 -0
- package/src/core/constants.ts +4 -1
- package/src/core/installers/clients/ClientInstaller.ts +66 -49
- package/src/core/installers/requirements/PipInstaller.ts +10 -5
- package/src/core/types.ts +6 -1
- package/src/services/ServerService.ts +15 -0
- package/src/utils/githubAuth.ts +14 -27
- package/src/utils/githubUtils.ts +84 -47
- package/src/web/public/css/detailsWidget.css +235 -0
- package/src/web/public/css/serverDetails.css +126 -0
- package/src/web/public/index.html +16 -10
- package/src/web/public/js/detailsWidget.js +264 -0
- package/src/web/public/js/modal/index.js +58 -0
- package/src/web/public/js/modal/installModal.js +163 -0
- package/src/web/public/js/modal/installation.js +281 -0
- package/src/web/public/js/modal/loadingModal.js +52 -0
- package/src/web/public/js/modal/messageQueue.js +112 -0
- package/src/web/public/js/modal/modalSetup.js +512 -0
- package/src/web/public/js/modal/modalUtils.js +49 -0
- package/src/web/public/js/modal/versionUtils.js +20 -0
- package/src/web/public/js/modal.js +25 -1041
- package/src/web/public/js/serverCategoryDetails.js +211 -123
- package/src/web/server.ts +31 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MCPServerCategory, FeedConfiguration, InstallationStatus, RequirementStatus, MCPServerStatus, OperationStatus } from './types.js';
|
|
1
|
+
import { MCPServerCategory, FeedConfiguration, InstallationStatus, RequirementStatus, MCPServerStatus, OperationStatus, McpConfig } from './types.js';
|
|
2
2
|
export declare class ConfigurationProvider {
|
|
3
3
|
private static instance;
|
|
4
4
|
private configPath;
|
|
@@ -14,6 +14,7 @@ export declare class ConfigurationProvider {
|
|
|
14
14
|
getServerCategory(categoryName: string): Promise<MCPServerCategory | undefined>;
|
|
15
15
|
getClientMcpSettings(): Promise<Record<string, Record<string, any>> | undefined>;
|
|
16
16
|
getFeedConfiguration(categoryName: string): Promise<FeedConfiguration | undefined>;
|
|
17
|
+
getServerMcpConfig(categoryName: string, serverName: string): Promise<McpConfig | undefined>;
|
|
17
18
|
getInstallationStatus(categoryName: string): Promise<InstallationStatus | undefined>;
|
|
18
19
|
getServerStatus(categoryName: string, serverName: string): Promise<MCPServerStatus | undefined>;
|
|
19
20
|
getRequirementStatus(categoryName: string, requirementName: string): Promise<RequirementStatus | undefined>;
|
|
@@ -94,6 +94,11 @@ export class ConfigurationProvider {
|
|
|
94
94
|
return this.configuration.feeds[categoryName];
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
|
+
async getServerMcpConfig(categoryName, serverName) {
|
|
98
|
+
return await this.withLock(async () => {
|
|
99
|
+
return this.configuration.feeds[categoryName]?.mcpServers.find(s => s.name === serverName);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
97
102
|
async getInstallationStatus(categoryName) {
|
|
98
103
|
return await this.withLock(async () => {
|
|
99
104
|
// Inline getServerCategory logic
|
|
@@ -241,35 +246,26 @@ export class ConfigurationProvider {
|
|
|
241
246
|
});
|
|
242
247
|
await fs.mkdir(LOCAL_FEEDS_DIR, { recursive: true });
|
|
243
248
|
await fs.mkdir(this.tempDir, { recursive: true });
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
await fs.rm(this.tempDir, { recursive: true, force: true });
|
|
257
|
-
const { stdout, stderr } = await execAsync(`git clone ${GITHUB_REPO.url} ${this.tempDir}`);
|
|
258
|
-
Logger.debug({
|
|
259
|
-
action: 'git_clone',
|
|
260
|
-
stderr,
|
|
261
|
-
stdout,
|
|
262
|
-
url: GITHUB_REPO.url
|
|
263
|
-
});
|
|
264
|
-
}
|
|
249
|
+
// Clean up temp directory
|
|
250
|
+
await fs.rm(this.tempDir, { recursive: true, force: true });
|
|
251
|
+
// Download latest release
|
|
252
|
+
Logger.debug('Downloading latest release...');
|
|
253
|
+
const { downloadGithubRelease } = await import('../utils/githubUtils.js');
|
|
254
|
+
const { version, downloadPath } = await downloadGithubRelease(GITHUB_REPO.repoName, 'latest', GITHUB_REPO.feedAssetsName, undefined, true, this.tempDir);
|
|
255
|
+
Logger.debug({
|
|
256
|
+
action: 'download_release',
|
|
257
|
+
downloadPath,
|
|
258
|
+
version,
|
|
259
|
+
repoName: GITHUB_REPO.repoName,
|
|
260
|
+
});
|
|
265
261
|
Logger.debug('Updating local feeds...');
|
|
266
262
|
await fs.rm(LOCAL_FEEDS_DIR, { recursive: true, force: true });
|
|
267
|
-
const sourceFeedsDir =
|
|
263
|
+
const sourceFeedsDir = downloadPath;
|
|
268
264
|
try {
|
|
269
|
-
await fs.access(
|
|
265
|
+
await fs.access(downloadPath);
|
|
270
266
|
}
|
|
271
267
|
catch (err) {
|
|
272
|
-
throw new Error(`Could not find feeds directory in
|
|
268
|
+
throw new Error(`Could not find feeds directory in downloaded path: ${sourceFeedsDir}`);
|
|
273
269
|
}
|
|
274
270
|
await fs.cp(sourceFeedsDir, LOCAL_FEEDS_DIR, { recursive: true, force: true });
|
|
275
271
|
Logger.log('Successfully updated local feeds');
|
|
@@ -30,4 +30,21 @@ export declare class InstallationService {
|
|
|
30
30
|
* @returns A failure result if requirements check fails, null if requirements are satisfied
|
|
31
31
|
*/
|
|
32
32
|
private checkAndInstallRequirements;
|
|
33
|
+
/**
|
|
34
|
+
* Installs requirements in background without blocking the main thread
|
|
35
|
+
* Requirements with the same order are installed in parallel
|
|
36
|
+
*/
|
|
37
|
+
private installRequirementsInBackground;
|
|
38
|
+
/**
|
|
39
|
+
* Helper to update requirement status for failure case
|
|
40
|
+
*/
|
|
41
|
+
private updateRequirementFailureStatus;
|
|
42
|
+
/**
|
|
43
|
+
* Helper to update requirement status for in-progress case
|
|
44
|
+
*/
|
|
45
|
+
private updateRequirementProgressStatus;
|
|
46
|
+
/**
|
|
47
|
+
* Helper to update requirement status for completion case
|
|
48
|
+
*/
|
|
49
|
+
private updateRequirementCompletionStatus;
|
|
33
50
|
}
|
|
@@ -34,7 +34,7 @@ export class InstallationService {
|
|
|
34
34
|
// Fire off requirement updates in the background without awaiting completion
|
|
35
35
|
if (options.requirements && options.requirements.length > 0) {
|
|
36
36
|
// Start the process but don't await it - it will run in the background
|
|
37
|
-
this.processRequirementUpdates(categoryName, serverName, options
|
|
37
|
+
this.processRequirementUpdates(categoryName, serverName, options)
|
|
38
38
|
.catch(error => {
|
|
39
39
|
console.error(`Error in background requirement updates: ${error instanceof Error ? error.message : String(error)}`);
|
|
40
40
|
});
|
|
@@ -70,7 +70,7 @@ export class InstallationService {
|
|
|
70
70
|
* @param serverName The server name
|
|
71
71
|
* @param requirements The requirements to update
|
|
72
72
|
*/
|
|
73
|
-
async processRequirementUpdates(categoryName, serverName,
|
|
73
|
+
async processRequirementUpdates(categoryName, serverName, options) {
|
|
74
74
|
// Use UpdateCheckTracker to prevent concurrent updates
|
|
75
75
|
const updateCheckTracker = await import('../utils/UpdateCheckTracker.js').then(m => m.updateCheckTracker);
|
|
76
76
|
const operationKey = `requirement-updates-${categoryName}-${serverName}`;
|
|
@@ -90,7 +90,7 @@ export class InstallationService {
|
|
|
90
90
|
// Import the RequirementService
|
|
91
91
|
const { requirementService } = await import('./RequirementService.js');
|
|
92
92
|
// Create an array of promises to update all requirements in parallel
|
|
93
|
-
const updatePromises = requirements
|
|
93
|
+
const updatePromises = options.requirements?.map(async (reqToUpdate) => {
|
|
94
94
|
try {
|
|
95
95
|
// Find the full requirement config
|
|
96
96
|
const reqConfig = feedConfig.requirements?.find((r) => r.name === reqToUpdate.name);
|
|
@@ -123,8 +123,15 @@ export class InstallationService {
|
|
|
123
123
|
...reqConfig,
|
|
124
124
|
version: reqToUpdate.version
|
|
125
125
|
};
|
|
126
|
-
//
|
|
127
|
-
|
|
126
|
+
// For pip requirements, check if we have a stored pythonEnv
|
|
127
|
+
if (updatedReqConfig.type === 'pip' && currentStatus.pythonEnv && !options?.settings?.pythonEnv) {
|
|
128
|
+
options = {
|
|
129
|
+
...options,
|
|
130
|
+
settings: { ...options?.settings, pythonEnv: currentStatus.pythonEnv }
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// Update the requirement with options for pip environment
|
|
134
|
+
const updatedStatus = await requirementService.updateRequirement(updatedReqConfig, reqToUpdate.version, options);
|
|
128
135
|
// Update requirement status
|
|
129
136
|
await configProvider.updateRequirementStatus(categoryName, reqToUpdate.name, {
|
|
130
137
|
...updatedStatus,
|
|
@@ -162,8 +169,10 @@ export class InstallationService {
|
|
|
162
169
|
});
|
|
163
170
|
}
|
|
164
171
|
});
|
|
165
|
-
// Wait for all updates to complete in parallel
|
|
166
|
-
|
|
172
|
+
// Wait for all updates to complete in parallel if there are any
|
|
173
|
+
if (updatePromises) {
|
|
174
|
+
await Promise.all(updatePromises);
|
|
175
|
+
}
|
|
167
176
|
}
|
|
168
177
|
finally {
|
|
169
178
|
// Always release the lock when done, even if there was an error
|
|
@@ -226,62 +235,119 @@ export class InstallationService {
|
|
|
226
235
|
const orderB = b.order ?? Infinity;
|
|
227
236
|
return orderA - orderB;
|
|
228
237
|
});
|
|
229
|
-
//
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
238
|
+
// Start requirements installation in background
|
|
239
|
+
this.installRequirementsInBackground(categoryName, sortedRequirements, options)
|
|
240
|
+
.catch(error => {
|
|
241
|
+
Logger.error(`Error in background requirement installations: ${error instanceof Error ? error.message : String(error)}`);
|
|
242
|
+
});
|
|
243
|
+
// Return immediately while installation continues in background
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Installs requirements in background without blocking the main thread
|
|
248
|
+
* Requirements with the same order are installed in parallel
|
|
249
|
+
*/
|
|
250
|
+
async installRequirementsInBackground(categoryName, sortedRequirements, options) {
|
|
251
|
+
const configProvider = ConfigurationProvider.getInstance();
|
|
252
|
+
const requirementGroups = sortedRequirements.reduce((groups, req) => {
|
|
253
|
+
const order = req.order ?? Infinity;
|
|
254
|
+
if (!groups[order]) {
|
|
255
|
+
groups[order] = [];
|
|
256
|
+
}
|
|
257
|
+
groups[order].push(req);
|
|
258
|
+
return groups;
|
|
259
|
+
}, {});
|
|
260
|
+
// Process each group in sequence, but requirements within group in parallel
|
|
261
|
+
const orderKeys = Object.keys(requirementGroups).map(Number).sort((a, b) => a - b);
|
|
262
|
+
for (const order of orderKeys) {
|
|
263
|
+
const group = requirementGroups[order];
|
|
264
|
+
await Promise.all(group.map(async (requirement) => {
|
|
265
|
+
try {
|
|
266
|
+
const feeds = await configProvider.getFeedConfiguration(categoryName);
|
|
267
|
+
const requirementConfig = feeds?.requirements?.find((r) => r.name === requirement.name) || {
|
|
241
268
|
name: requirement.name,
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
error: `No installer found for requirement type: ${requirementConfig.type}`,
|
|
245
|
-
operationStatus: {
|
|
246
|
-
status: 'failed',
|
|
247
|
-
type: 'install',
|
|
248
|
-
target: 'requirement',
|
|
249
|
-
message: `No installer found for requirement type: ${requirementConfig.type}`,
|
|
250
|
-
operationId: this.generateOperationId()
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
const operationStatus = {
|
|
256
|
-
status: 'pending',
|
|
257
|
-
type: 'install',
|
|
258
|
-
target: 'requirement',
|
|
259
|
-
message: `Installing requirement: ${requirement.name}`,
|
|
260
|
-
operationId: this.generateOperationId()
|
|
261
|
-
};
|
|
262
|
-
await configProvider.updateRequirementStatus(categoryName, requirement.name, {
|
|
263
|
-
name: requirement.name,
|
|
264
|
-
type: requirementConfig.type,
|
|
265
|
-
installed: false,
|
|
266
|
-
inProgress: true,
|
|
267
|
-
operationStatus
|
|
268
|
-
});
|
|
269
|
-
return installer.install(requirementConfig, options).then(async (installStatus) => {
|
|
270
|
-
const status = {
|
|
271
|
-
...installStatus,
|
|
272
|
-
operationStatus: {
|
|
273
|
-
status: installStatus.installed ? 'completed' : 'failed',
|
|
274
|
-
type: 'install',
|
|
275
|
-
target: 'requirement',
|
|
276
|
-
message: installStatus.installed ? `Requirement ${requirement.name} installed successfully` : `Failed to install ${requirement.name}`,
|
|
277
|
-
operationId: operationStatus.operationId
|
|
278
|
-
}
|
|
269
|
+
version: requirement.version,
|
|
270
|
+
type: 'npm'
|
|
279
271
|
};
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
272
|
+
// For pip requirements, check if we need to use stored pythonEnv
|
|
273
|
+
const currentStatus = await configProvider.getRequirementStatus(categoryName, requirement.name);
|
|
274
|
+
if (requirementConfig.type === 'pip' && currentStatus?.pythonEnv && !options?.settings?.pythonEnv) {
|
|
275
|
+
options = {
|
|
276
|
+
...options,
|
|
277
|
+
settings: { ...options?.settings, pythonEnv: currentStatus.pythonEnv }
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
const installer = this.installerFactory.getInstaller(requirementConfig);
|
|
281
|
+
if (!installer) {
|
|
282
|
+
await this.updateRequirementFailureStatus(categoryName, requirement.name, requirementConfig.type, `No installer found for requirement type: ${requirementConfig.type}`);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const operationId = this.generateOperationId();
|
|
286
|
+
await this.updateRequirementProgressStatus(categoryName, requirement.name, requirementConfig.type, operationId);
|
|
287
|
+
const installStatus = await installer.install(requirementConfig, options);
|
|
288
|
+
await this.updateRequirementCompletionStatus(categoryName, requirement.name, installStatus, operationId);
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
await this.updateRequirementFailureStatus(categoryName, requirement.name, 'unknown', error instanceof Error ? error.message : String(error));
|
|
292
|
+
}
|
|
293
|
+
}));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Helper to update requirement status for failure case
|
|
298
|
+
*/
|
|
299
|
+
async updateRequirementFailureStatus(categoryName, requirementName, requirementType, errorMessage) {
|
|
300
|
+
const configProvider = ConfigurationProvider.getInstance();
|
|
301
|
+
await configProvider.updateRequirementStatus(categoryName, requirementName, {
|
|
302
|
+
name: requirementName,
|
|
303
|
+
type: requirementType,
|
|
304
|
+
installed: false,
|
|
305
|
+
error: errorMessage,
|
|
306
|
+
operationStatus: {
|
|
307
|
+
status: 'failed',
|
|
308
|
+
type: 'install',
|
|
309
|
+
target: 'requirement',
|
|
310
|
+
message: `Error installing requirement: ${errorMessage}`,
|
|
311
|
+
operationId: this.generateOperationId()
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Helper to update requirement status for in-progress case
|
|
317
|
+
*/
|
|
318
|
+
async updateRequirementProgressStatus(categoryName, requirementName, requirementType, operationId) {
|
|
319
|
+
const configProvider = ConfigurationProvider.getInstance();
|
|
320
|
+
await configProvider.updateRequirementStatus(categoryName, requirementName, {
|
|
321
|
+
name: requirementName,
|
|
322
|
+
type: requirementType,
|
|
323
|
+
installed: false,
|
|
324
|
+
inProgress: true,
|
|
325
|
+
operationStatus: {
|
|
326
|
+
status: 'in-progress',
|
|
327
|
+
type: 'install',
|
|
328
|
+
target: 'requirement',
|
|
329
|
+
message: `Installing requirement: ${requirementName}`,
|
|
330
|
+
operationId
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Helper to update requirement status for completion case
|
|
336
|
+
*/
|
|
337
|
+
async updateRequirementCompletionStatus(categoryName, requirementName, installStatus, operationId) {
|
|
338
|
+
const configProvider = ConfigurationProvider.getInstance();
|
|
339
|
+
await configProvider.updateRequirementStatus(categoryName, requirementName, {
|
|
340
|
+
...installStatus,
|
|
341
|
+
operationStatus: {
|
|
342
|
+
status: installStatus.installed ? 'completed' : 'failed',
|
|
343
|
+
type: 'install',
|
|
344
|
+
target: 'requirement',
|
|
345
|
+
message: installStatus.installed
|
|
346
|
+
? `Requirement ${requirementName} installed successfully`
|
|
347
|
+
: `Failed to install ${requirementName}`,
|
|
348
|
+
operationId
|
|
349
|
+
}
|
|
350
|
+
});
|
|
285
351
|
}
|
|
286
352
|
}
|
|
287
353
|
// Export a singleton instance (optional)
|
|
@@ -8,6 +8,7 @@ export declare class MCPManager extends EventEmitter {
|
|
|
8
8
|
initialize(feedFile?: string): Promise<void>;
|
|
9
9
|
listServerCategories(options?: ServerCategoryListOptions): Promise<MCPServerCategory[]>;
|
|
10
10
|
getFeedConfiguration(categoryName: string): Promise<import("./types.js").FeedConfiguration | undefined>;
|
|
11
|
+
getServerMcpConfig(categoryName: string, serverName: string): Promise<import("./types.js").McpConfig | undefined>;
|
|
11
12
|
installServer(categoryName: string, serverName: string, requestOptions?: ServerInstallOptions): Promise<ServerOperationResult>;
|
|
12
13
|
uninstallServer(categoryName: string, serverName: string, options?: ServerUninstallOptions): Promise<ServerOperationResult>;
|
|
13
14
|
updateRequirement(categoryName: string, serverName: string, requirementName: string, updateVersion: string): Promise<ServerOperationResult>;
|
package/dist/core/MCPManager.js
CHANGED
|
@@ -32,6 +32,9 @@ export class MCPManager extends EventEmitter {
|
|
|
32
32
|
async getFeedConfiguration(categoryName) {
|
|
33
33
|
return this.configProvider.getFeedConfiguration(categoryName);
|
|
34
34
|
}
|
|
35
|
+
async getServerMcpConfig(categoryName, serverName) {
|
|
36
|
+
return this.configProvider.getServerMcpConfig(categoryName, serverName);
|
|
37
|
+
}
|
|
35
38
|
async installServer(categoryName, serverName, requestOptions = {}) {
|
|
36
39
|
try {
|
|
37
40
|
const server = await this.configProvider.getServerCategory(categoryName);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RequirementConfig, RequirementStatus } from './types.js';
|
|
1
|
+
import { RequirementConfig, RequirementStatus, ServerInstallOptions } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Service responsible for managing requirements installation and status
|
|
4
4
|
*/
|
|
@@ -16,13 +16,13 @@ export declare class RequirementService {
|
|
|
16
16
|
* @param requirement The requirement to install
|
|
17
17
|
* @returns The installation status
|
|
18
18
|
*/
|
|
19
|
-
installRequirement(requirement: RequirementConfig): Promise<RequirementStatus>;
|
|
19
|
+
installRequirement(requirement: RequirementConfig, options?: ServerInstallOptions): Promise<RequirementStatus>;
|
|
20
20
|
/**
|
|
21
21
|
* Check the installation status of a requirement
|
|
22
22
|
* @param requirement The requirement to check
|
|
23
23
|
* @returns The installation status
|
|
24
24
|
*/
|
|
25
|
-
checkRequirementStatus(requirement: RequirementConfig): Promise<RequirementStatus>;
|
|
25
|
+
checkRequirementStatus(requirement: RequirementConfig, options?: ServerInstallOptions): Promise<RequirementStatus>;
|
|
26
26
|
/**
|
|
27
27
|
* Check if updates are available for a requirement
|
|
28
28
|
* @param requirement The requirement to check for updates
|
|
@@ -35,7 +35,7 @@ export declare class RequirementService {
|
|
|
35
35
|
* @param updateVersion The version to update to
|
|
36
36
|
* @returns The updated requirement status
|
|
37
37
|
*/
|
|
38
|
-
updateRequirement(requirement: RequirementConfig, updateVersion: string): Promise<RequirementStatus>;
|
|
38
|
+
updateRequirement(requirement: RequirementConfig, updateVersion: string, options?: ServerInstallOptions): Promise<RequirementStatus>;
|
|
39
39
|
/**
|
|
40
40
|
* Install multiple requirements
|
|
41
41
|
* @param requirements The requirements to install
|
|
@@ -23,22 +23,22 @@ export class RequirementService {
|
|
|
23
23
|
* @param requirement The requirement to install
|
|
24
24
|
* @returns The installation status
|
|
25
25
|
*/
|
|
26
|
-
async installRequirement(requirement) {
|
|
26
|
+
async installRequirement(requirement, options) {
|
|
27
27
|
// Validate requirement
|
|
28
28
|
this.validateRequirement(requirement);
|
|
29
29
|
// Install the requirement
|
|
30
|
-
return await this.installerFactory.install(requirement);
|
|
30
|
+
return await this.installerFactory.install(requirement, options);
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Check the installation status of a requirement
|
|
34
34
|
* @param requirement The requirement to check
|
|
35
35
|
* @returns The installation status
|
|
36
36
|
*/
|
|
37
|
-
async checkRequirementStatus(requirement) {
|
|
37
|
+
async checkRequirementStatus(requirement, options) {
|
|
38
38
|
// Validate requirement
|
|
39
39
|
this.validateRequirement(requirement);
|
|
40
40
|
// Check the installation status
|
|
41
|
-
return await this.installerFactory.checkInstallation(requirement);
|
|
41
|
+
return await this.installerFactory.checkInstallation(requirement, options);
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
44
|
* Check if updates are available for a requirement
|
|
@@ -54,7 +54,11 @@ export class RequirementService {
|
|
|
54
54
|
if (!installer || !installer.supportCheckUpdates()) {
|
|
55
55
|
return currentStatus;
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
// Pass pythonEnv from currentStatus if it exists for pip packages
|
|
58
|
+
const options = requirement.type === 'pip' && currentStatus.pythonEnv
|
|
59
|
+
? { settings: { pythonEnv: currentStatus.pythonEnv } }
|
|
60
|
+
: undefined;
|
|
61
|
+
const status = await this.checkRequirementStatus(requirement, options);
|
|
58
62
|
return await installer.checkForUpdates(requirement, status);
|
|
59
63
|
}
|
|
60
64
|
/**
|
|
@@ -63,7 +67,7 @@ export class RequirementService {
|
|
|
63
67
|
* @param updateVersion The version to update to
|
|
64
68
|
* @returns The updated requirement status
|
|
65
69
|
*/
|
|
66
|
-
async updateRequirement(requirement, updateVersion) {
|
|
70
|
+
async updateRequirement(requirement, updateVersion, options) {
|
|
67
71
|
// Validate requirement
|
|
68
72
|
this.validateRequirement(requirement);
|
|
69
73
|
// Create an updated requirement with the new version
|
|
@@ -72,7 +76,7 @@ export class RequirementService {
|
|
|
72
76
|
version: updateVersion
|
|
73
77
|
};
|
|
74
78
|
// Install the updated version
|
|
75
|
-
return await this.
|
|
79
|
+
return await this.installerFactory.install(updatedRequirement, options);
|
|
76
80
|
}
|
|
77
81
|
/**
|
|
78
82
|
* Install multiple requirements
|
|
@@ -11,7 +11,7 @@ export declare class ServerSchemaProvider {
|
|
|
11
11
|
initialize(): Promise<void>;
|
|
12
12
|
private loadSchema;
|
|
13
13
|
private loadAllSchemas;
|
|
14
|
-
getSchema(categoryName: string,
|
|
14
|
+
getSchema(categoryName: string, schemaFileName: string): Promise<ServerSchema | undefined>;
|
|
15
15
|
reloadSchemas(): Promise<void>;
|
|
16
16
|
}
|
|
17
17
|
export declare function getServerSchemaProvider(): Promise<ServerSchemaProvider>;
|
|
@@ -42,9 +42,9 @@ export class ServerSchemaProvider {
|
|
|
42
42
|
}
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
-
async loadSchema(categoryName,
|
|
45
|
+
async loadSchema(categoryName, schemaFileName) {
|
|
46
46
|
try {
|
|
47
|
-
const schemaPath = path.join(LOCAL_FEEDS_SCHEMA_DIR, categoryName,
|
|
47
|
+
const schemaPath = path.join(LOCAL_FEEDS_SCHEMA_DIR, categoryName, schemaFileName);
|
|
48
48
|
const content = await fs.readFile(schemaPath, 'utf8');
|
|
49
49
|
const schema = JSON.parse(content);
|
|
50
50
|
return {
|
|
@@ -53,10 +53,10 @@ export class ServerSchemaProvider {
|
|
|
53
53
|
}
|
|
54
54
|
catch (error) {
|
|
55
55
|
if (error.code === 'ENOENT') {
|
|
56
|
-
Logger.debug(`No schema file found for
|
|
56
|
+
Logger.debug(`No schema file found for ${schemaFileName} in category ${categoryName}`);
|
|
57
57
|
return undefined;
|
|
58
58
|
}
|
|
59
|
-
Logger.error(`Error loading schema
|
|
59
|
+
Logger.error(`Error loading schema ${schemaFileName} in category ${categoryName}:`, error);
|
|
60
60
|
throw error;
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -71,15 +71,15 @@ export class ServerSchemaProvider {
|
|
|
71
71
|
const serverSchemas = new Map();
|
|
72
72
|
for (const file of serverFiles) {
|
|
73
73
|
if (file.endsWith('.json')) {
|
|
74
|
-
const serverName = path.basename(file, '.json');
|
|
75
74
|
try {
|
|
76
|
-
const schema = await this.loadSchema(categoryDir.name,
|
|
75
|
+
const schema = await this.loadSchema(categoryDir.name, file);
|
|
77
76
|
if (schema) {
|
|
78
|
-
|
|
77
|
+
// Store with the complete file name for direct lookup
|
|
78
|
+
serverSchemas.set(file, schema);
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
catch (error) {
|
|
82
|
-
Logger.error(`Error loading schema for
|
|
82
|
+
Logger.error(`Error loading schema for file ${file} in category ${categoryDir.name}:`, error);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -89,13 +89,18 @@ export class ServerSchemaProvider {
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
async getSchema(categoryName,
|
|
92
|
+
async getSchema(categoryName, schemaFileName) {
|
|
93
93
|
return await this.withLock(async () => {
|
|
94
94
|
const categorySchemas = this.schemaMap.get(categoryName);
|
|
95
95
|
if (!categorySchemas) {
|
|
96
|
+
Logger.debug(`No schemas found for category ${categoryName}`);
|
|
96
97
|
return undefined;
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
+
const schema = categorySchemas.get(schemaFileName);
|
|
100
|
+
if (!schema) {
|
|
101
|
+
Logger.debug(`Schema ${schemaFileName} not found in category ${categoryName}`);
|
|
102
|
+
}
|
|
103
|
+
return schema;
|
|
99
104
|
});
|
|
100
105
|
}
|
|
101
106
|
async reloadSchemas() {
|
package/dist/core/constants.d.ts
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export declare const GITHUB_REPO: {
|
|
8
8
|
url: string;
|
|
9
|
+
repoName: string;
|
|
9
10
|
feedsPath: string;
|
|
11
|
+
feedAssetsName: string;
|
|
10
12
|
};
|
|
11
13
|
/**
|
|
12
14
|
* Local settings directory path based on OS
|
|
@@ -16,6 +18,7 @@ export declare const SETTINGS_DIR: string;
|
|
|
16
18
|
* Local feeds directory path
|
|
17
19
|
*/
|
|
18
20
|
export declare const LOCAL_FEEDS_DIR: string;
|
|
21
|
+
export declare const LOCAL_FEEDS_SCHEMA_DIR: string;
|
|
19
22
|
/**
|
|
20
23
|
* Supported client configurations.
|
|
21
24
|
* Key: Client name (e.g., 'vscode')
|
package/dist/core/constants.js
CHANGED
|
@@ -8,7 +8,9 @@ import path from 'path';
|
|
|
8
8
|
*/
|
|
9
9
|
export const GITHUB_REPO = {
|
|
10
10
|
url: 'https://github.com/ai-microsoft/imcp-feed.git',
|
|
11
|
-
|
|
11
|
+
repoName: 'ai-microsoft/imcp-feed',
|
|
12
|
+
feedsPath: 'feeds',
|
|
13
|
+
feedAssetsName: 'imcp-feeds-${latest}.zip',
|
|
12
14
|
};
|
|
13
15
|
/**
|
|
14
16
|
* Local settings directory path based on OS
|
|
@@ -25,6 +27,7 @@ export const SETTINGS_DIR = (() => {
|
|
|
25
27
|
* Local feeds directory path
|
|
26
28
|
*/
|
|
27
29
|
export const LOCAL_FEEDS_DIR = path.join(SETTINGS_DIR, 'feeds');
|
|
30
|
+
export const LOCAL_FEEDS_SCHEMA_DIR = path.join(LOCAL_FEEDS_DIR, 'schemas');
|
|
28
31
|
const CODE_STRORAGE_DIR = (() => {
|
|
29
32
|
switch (process.platform) {
|
|
30
33
|
case 'win32':
|