imcp 0.0.17 → 0.0.18

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 (46) hide show
  1. package/dist/cli/commands/serve.js +2 -1
  2. package/dist/core/installers/clients/BaseClientInstaller.d.ts +25 -2
  3. package/dist/core/installers/clients/BaseClientInstaller.js +121 -0
  4. package/dist/core/installers/clients/ClineInstaller.d.ts +1 -6
  5. package/dist/core/installers/clients/ClineInstaller.js +1 -94
  6. package/dist/core/installers/clients/GithubCopilotInstaller.d.ts +1 -6
  7. package/dist/core/installers/clients/GithubCopilotInstaller.js +1 -94
  8. package/dist/core/installers/clients/MSRooCodeInstaller.d.ts +1 -5
  9. package/dist/core/installers/clients/MSRooCodeInstaller.js +1 -94
  10. package/dist/core/loaders/ConfigurationLoader.d.ts +4 -1
  11. package/dist/core/loaders/ConfigurationLoader.js +24 -3
  12. package/dist/core/loaders/ConfigurationProvider.d.ts +4 -1
  13. package/dist/core/loaders/ConfigurationProvider.js +13 -4
  14. package/dist/core/loaders/ServerSchemaLoader.d.ts +15 -4
  15. package/dist/core/loaders/ServerSchemaLoader.js +86 -20
  16. package/dist/core/loaders/ServerSchemaProvider.d.ts +2 -5
  17. package/dist/core/loaders/ServerSchemaProvider.js +32 -62
  18. package/dist/core/metadatas/types.d.ts +3 -2
  19. package/dist/core/onboard/FeedOnboardService.d.ts +14 -7
  20. package/dist/core/onboard/FeedOnboardService.js +214 -129
  21. package/dist/core/onboard/OnboardProcessor.d.ts +7 -1
  22. package/dist/core/onboard/OnboardProcessor.js +52 -8
  23. package/dist/core/onboard/OnboardStatus.d.ts +6 -1
  24. package/dist/core/onboard/OnboardStatusManager.d.ts +70 -24
  25. package/dist/core/onboard/OnboardStatusManager.js +230 -46
  26. package/dist/core/validators/FeedValidator.d.ts +7 -2
  27. package/dist/core/validators/FeedValidator.js +61 -7
  28. package/dist/core/validators/StdioServerValidator.js +84 -32
  29. package/dist/services/MCPManager.d.ts +2 -1
  30. package/dist/services/MCPManager.js +5 -1
  31. package/dist/services/ServerService.js +2 -2
  32. package/dist/utils/logger.d.ts +2 -0
  33. package/dist/utils/logger.js +10 -0
  34. package/dist/web/public/js/modal/installation.js +1 -1
  35. package/dist/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +41 -9
  36. package/dist/web/public/js/onboard/formProcessor.js +200 -34
  37. package/dist/web/public/js/onboard/index.js +2 -2
  38. package/dist/web/public/js/onboard/publishHandler.js +30 -22
  39. package/dist/web/public/js/onboard/templates.js +34 -40
  40. package/dist/web/public/js/onboard/uiHandlers.js +175 -84
  41. package/dist/web/public/js/onboard/validationHandlers.js +147 -64
  42. package/dist/web/public/js/serverCategoryDetails.js +19 -4
  43. package/dist/web/public/js/serverCategoryList.js +13 -1
  44. package/dist/web/public/onboard.html +1 -1
  45. package/dist/web/server.js +19 -6
  46. package/package.json +1 -1
@@ -43,10 +43,19 @@ export class ConfigurationProvider {
43
43
  resolve();
44
44
  }
45
45
  }
46
- async initialize(feedFile) {
46
+ async initialize(feedFile, settings) {
47
47
  await this.withLock(async () => {
48
48
  const configDir = path.dirname(this.configPath);
49
49
  await fs.mkdir(configDir, { recursive: true });
50
+ // remove the old configuration file if it exists
51
+ try {
52
+ await fs.rm(this.configPath, { recursive: true, force: true });
53
+ }
54
+ catch (error) {
55
+ if (error.code !== 'ENOENT') {
56
+ throw error;
57
+ }
58
+ }
50
59
  try {
51
60
  try {
52
61
  const config = JSON.parse(await fs.readFile(this.configPath, 'utf8'));
@@ -60,7 +69,7 @@ export class ConfigurationProvider {
60
69
  await this.saveConfiguration();
61
70
  }
62
71
  // Always load feeds and client settings, whether file existed or not
63
- await this.loadFeedsIntoConfiguration(feedFile);
72
+ await this.loadFeedsIntoConfiguration(feedFile, settings);
64
73
  await this.loadClientMCPSettings();
65
74
  }
66
75
  catch (error) {
@@ -291,8 +300,8 @@ export class ConfigurationProvider {
291
300
  }
292
301
  });
293
302
  }
294
- async loadFeedsIntoConfiguration(feedFile) {
295
- this.configuration = await ConfigurationLoader.loadFeedsIntoConfiguration(this.configuration, feedFile);
303
+ async loadFeedsIntoConfiguration(feedFile, settings) {
304
+ this.configuration = await ConfigurationLoader.loadFeedsIntoConfiguration(this.configuration, feedFile, settings);
296
305
  await this.saveConfiguration();
297
306
  }
298
307
  async loadClientMCPSettings() {
@@ -1,11 +1,22 @@
1
1
  import { ServerSchema } from './ServerSchemaProvider.js';
2
2
  export declare class ServerSchemaLoader {
3
3
  /**
4
- * Load schema for a specific server in a category
4
+ * Loads a single schema file.
5
+ * @param filePath The absolute path to the schema file.
6
+ * @returns A Promise that resolves to the ServerSchema or undefined if not found or error.
5
7
  */
6
- static loadSchema(categoryName: string, serverName: string): Promise<ServerSchema | undefined>;
8
+ static loadSchema(filePath: string): Promise<ServerSchema | undefined>;
7
9
  /**
8
- * Validate schema content against expected format
10
+ * Loads all schemas from the default feeds directory.
11
+ * @param defaultFeedsDir The path to the default feeds directory.
12
+ * @param schemaMap The map to populate with loaded schemas.
9
13
  */
10
- static validateSchema(schema: any): boolean;
14
+ static loadAllDefaultSchemas(defaultFeedsDir: string, schemaMap: Map<string, Map<string, ServerSchema>>): Promise<void>;
15
+ /**
16
+ * Loads schemas from an adhoc directory for a specific category.
17
+ * @param adhocSchemasDir The path to the adhoc schemas directory.
18
+ * @param categoryName The name of the category for these adhoc schemas.
19
+ * @param schemaMap The map to update with loaded adhoc schemas.
20
+ */
21
+ static loadAdhocSchemas(adhocSchemasDir: string, categoryName: string, schemaMap: Map<string, Map<string, ServerSchema>>): Promise<void>;
11
22
  }
@@ -1,43 +1,109 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
- import { LOCAL_FEEDS_SCHEMA_DIR } from '../metadatas/constants.js';
4
3
  import { Logger } from '../../utils/logger.js';
5
4
  export class ServerSchemaLoader {
6
5
  /**
7
- * Load schema for a specific server in a category
6
+ * Loads a single schema file.
7
+ * @param filePath The absolute path to the schema file.
8
+ * @returns A Promise that resolves to the ServerSchema or undefined if not found or error.
8
9
  */
9
- static async loadSchema(categoryName, serverName) {
10
+ static async loadSchema(filePath) {
10
11
  try {
11
- const schemaPath = path.join(LOCAL_FEEDS_SCHEMA_DIR, categoryName, `${serverName}.json`);
12
- const content = await fs.readFile(schemaPath, 'utf8');
12
+ const content = await fs.readFile(filePath, 'utf8');
13
13
  const schema = JSON.parse(content);
14
- // Validate schema structure
15
- if (!schema.version || !schema.schema) {
16
- Logger.debug(`Invalid schema format for server ${serverName} in category ${categoryName}`);
17
- return undefined;
18
- }
19
14
  return {
20
15
  schema: schema
21
16
  };
22
17
  }
23
18
  catch (error) {
24
19
  if (error.code === 'ENOENT') {
25
- Logger.debug(`No schema file found for server ${serverName} in category ${categoryName}`);
20
+ Logger.debug(`No schema file found at ${filePath}`);
26
21
  return undefined;
27
22
  }
28
- Logger.error(`Error loading schema for server ${serverName} in category ${categoryName}:`, error);
29
- throw error;
23
+ Logger.error(`Error loading schema from ${filePath}:`, error);
24
+ // Optionally rethrow or return undefined based on desired error handling
25
+ return undefined;
26
+ }
27
+ }
28
+ /**
29
+ * Loads all schemas from the default feeds directory.
30
+ * @param defaultFeedsDir The path to the default feeds directory.
31
+ * @param schemaMap The map to populate with loaded schemas.
32
+ */
33
+ static async loadAllDefaultSchemas(defaultFeedsDir, schemaMap) {
34
+ schemaMap.clear(); // Clear map for initial load from default directory
35
+ try {
36
+ const categoryDirs = await fs.readdir(defaultFeedsDir, { withFileTypes: true });
37
+ for (const categoryDir of categoryDirs) {
38
+ if (categoryDir.isDirectory()) {
39
+ const categoryName = categoryDir.name;
40
+ const categoryPath = path.join(defaultFeedsDir, categoryName);
41
+ const serverFiles = await fs.readdir(categoryPath);
42
+ const serverSchemas = new Map();
43
+ for (const file of serverFiles) {
44
+ if (file.endsWith('.json')) {
45
+ try {
46
+ const schemaFilePath = path.join(categoryPath, file);
47
+ const schema = await this.loadSchema(schemaFilePath);
48
+ if (schema) {
49
+ serverSchemas.set(file, schema); // file is serverName
50
+ Logger.debug(`Loaded schema '${file}' for category '${categoryName}' from default directory`);
51
+ }
52
+ }
53
+ catch (error) { // Error already logged in loadSchema
54
+ Logger.error(`Skipping schema file ${file} in category ${categoryName} due to loading error.`);
55
+ }
56
+ }
57
+ }
58
+ if (serverSchemas.size > 0) {
59
+ schemaMap.set(categoryName, serverSchemas);
60
+ }
61
+ }
62
+ }
63
+ }
64
+ catch (error) {
65
+ Logger.error(`Error reading schemas from default directory ${defaultFeedsDir}:`, error);
30
66
  }
31
67
  }
32
68
  /**
33
- * Validate schema content against expected format
69
+ * Loads schemas from an adhoc directory for a specific category.
70
+ * @param adhocSchemasDir The path to the adhoc schemas directory.
71
+ * @param categoryName The name of the category for these adhoc schemas.
72
+ * @param schemaMap The map to update with loaded adhoc schemas.
34
73
  */
35
- static validateSchema(schema) {
36
- return (typeof schema === 'object' &&
37
- schema !== null &&
38
- typeof schema.version === 'string' &&
39
- typeof schema.schema === 'object' &&
40
- schema.schema !== null);
74
+ static async loadAdhocSchemas(adhocSchemasDir, categoryName, schemaMap) {
75
+ try {
76
+ const serverFiles = await fs.readdir(adhocSchemasDir);
77
+ if (schemaMap.has(categoryName)) {
78
+ Logger.warn(`\x1b[33mAdhoc schema category '${categoryName}' (from dir: ${adhocSchemasDir}) conflicts with an existing category. Adhoc schemas in this category will override existing ones.\x1b[0m`);
79
+ }
80
+ let serverSchemas = schemaMap.get(categoryName);
81
+ if (!serverSchemas) {
82
+ serverSchemas = new Map();
83
+ }
84
+ for (const file of serverFiles) {
85
+ if (file.endsWith('.json')) {
86
+ try {
87
+ const schemaFilePath = path.join(adhocSchemasDir, file);
88
+ const schema = await this.loadSchema(schemaFilePath);
89
+ if (schema) {
90
+ serverSchemas.set(file, schema); // file is serverName
91
+ Logger.debug(`Loaded adhoc schema '${file}' for category '${categoryName}'`);
92
+ }
93
+ }
94
+ catch (error) { // Error already logged in loadSchema
95
+ Logger.error(`Skipping adhoc schema file ${file} in category ${categoryName} due to loading error.`);
96
+ }
97
+ }
98
+ }
99
+ if (serverSchemas.size > 0) {
100
+ schemaMap.set(categoryName, serverSchemas);
101
+ }
102
+ }
103
+ catch (error) {
104
+ // This case should ideally be caught by the fs.access check in ServerSchemaProvider.initialize
105
+ Logger.error(`Error reading adhoc schemas from directory ${adhocSchemasDir} for category ${categoryName}:`, error);
106
+ }
41
107
  }
42
108
  }
43
109
  //# sourceMappingURL=ServerSchemaLoader.js.map
@@ -6,12 +6,9 @@ export declare class ServerSchemaProvider {
6
6
  private schemaMap;
7
7
  private schemaLock;
8
8
  private constructor();
9
- static getInstance(): Promise<ServerSchemaProvider>;
9
+ static getInstance(): ServerSchemaProvider;
10
10
  private withLock;
11
- initialize(): Promise<void>;
12
- private loadSchema;
13
- private loadAllSchemas;
11
+ initialize(adhocSchemasDir?: string): Promise<void>;
14
12
  getSchema(categoryName: string, schemaFileName: string): Promise<ServerSchema | undefined>;
15
13
  reloadSchemas(): Promise<void>;
16
14
  }
17
- export declare function getServerSchemaProvider(): Promise<ServerSchemaProvider>;
@@ -2,6 +2,7 @@ import fs from 'fs/promises';
2
2
  import path from 'path';
3
3
  import { LOCAL_FEEDS_SCHEMA_DIR } from '../metadatas/constants.js';
4
4
  import { Logger } from '../../utils/logger.js';
5
+ import { ServerSchemaLoader } from './ServerSchemaLoader.js';
5
6
  export class ServerSchemaProvider {
6
7
  static instance;
7
8
  schemaMap;
@@ -9,10 +10,12 @@ export class ServerSchemaProvider {
9
10
  constructor() {
10
11
  this.schemaMap = new Map();
11
12
  }
12
- static async getInstance() {
13
+ static getInstance() {
13
14
  if (!ServerSchemaProvider.instance) {
14
15
  ServerSchemaProvider.instance = new ServerSchemaProvider();
15
- await ServerSchemaProvider.instance.initialize();
16
+ // Initialize is now called with optional adhocSchemasDir,
17
+ // but getInstance is often called without it initially.
18
+ // The actual loading with adhoc dir will happen when MCPManager calls initialize.
16
19
  }
17
20
  return ServerSchemaProvider.instance;
18
21
  }
@@ -28,13 +31,30 @@ export class ServerSchemaProvider {
28
31
  resolve();
29
32
  }
30
33
  }
31
- async initialize() {
34
+ async initialize(adhocSchemasDir) {
32
35
  await this.withLock(async () => {
33
36
  try {
34
- // Create feeds directory if it doesn't exist
37
+ // Create default feeds directory if it doesn't exist
35
38
  await fs.mkdir(LOCAL_FEEDS_SCHEMA_DIR, { recursive: true });
36
- // Load all schemas from the feeds directory
37
- await this.loadAllSchemas();
39
+ // Load all schemas from the default feeds directory
40
+ await ServerSchemaLoader.loadAllDefaultSchemas(LOCAL_FEEDS_SCHEMA_DIR, this.schemaMap);
41
+ // Load schemas from adhoc directory if provided
42
+ if (adhocSchemasDir) {
43
+ try {
44
+ await fs.access(adhocSchemasDir); // Check if directory exists
45
+ const adhocCategoryName = path.basename(adhocSchemasDir);
46
+ Logger.info(`Loading adhoc schemas from: ${adhocSchemasDir} for category: ${adhocCategoryName}`);
47
+ await ServerSchemaLoader.loadAdhocSchemas(adhocSchemasDir, adhocCategoryName, this.schemaMap);
48
+ }
49
+ catch (error) {
50
+ if (error.code === 'ENOENT') {
51
+ Logger.warn(`Adhoc schemas directory not found: ${adhocSchemasDir}`);
52
+ }
53
+ else {
54
+ Logger.error(`Error accessing adhoc schemas directory ${adhocSchemasDir}:`, error);
55
+ }
56
+ }
57
+ }
38
58
  }
39
59
  catch (error) {
40
60
  Logger.error('Error during schema initialization:', error);
@@ -42,53 +62,8 @@ export class ServerSchemaProvider {
42
62
  }
43
63
  });
44
64
  }
45
- async loadSchema(categoryName, schemaFileName) {
46
- try {
47
- const schemaPath = path.join(LOCAL_FEEDS_SCHEMA_DIR, categoryName, schemaFileName);
48
- const content = await fs.readFile(schemaPath, 'utf8');
49
- const schema = JSON.parse(content);
50
- return {
51
- schema: schema
52
- };
53
- }
54
- catch (error) {
55
- if (error.code === 'ENOENT') {
56
- Logger.debug(`No schema file found for ${schemaFileName} in category ${categoryName}`);
57
- return undefined;
58
- }
59
- Logger.error(`Error loading schema ${schemaFileName} in category ${categoryName}:`, error);
60
- throw error;
61
- }
62
- }
63
- async loadAllSchemas() {
64
- this.schemaMap.clear();
65
- // Read server category directories
66
- const categoryDirs = await fs.readdir(LOCAL_FEEDS_SCHEMA_DIR, { withFileTypes: true });
67
- for (const categoryDir of categoryDirs) {
68
- if (categoryDir.isDirectory()) {
69
- const categoryPath = path.join(LOCAL_FEEDS_SCHEMA_DIR, categoryDir.name);
70
- const serverFiles = await fs.readdir(categoryPath);
71
- const serverSchemas = new Map();
72
- for (const file of serverFiles) {
73
- if (file.endsWith('.json')) {
74
- try {
75
- const schema = await this.loadSchema(categoryDir.name, file);
76
- if (schema) {
77
- // Store with the complete file name for direct lookup
78
- serverSchemas.set(file, schema);
79
- }
80
- }
81
- catch (error) {
82
- Logger.error(`Error loading schema for file ${file} in category ${categoryDir.name}:`, error);
83
- }
84
- }
85
- }
86
- if (serverSchemas.size > 0) {
87
- this.schemaMap.set(categoryDir.name, serverSchemas);
88
- }
89
- }
90
- }
91
- }
65
+ // The actual loading methods (loadSchema, loadAllSchemas, loadAdhocSchemas) have been moved to ServerSchemaLoader.
66
+ // ServerSchemaProvider now delegates to ServerSchemaLoader for these operations.
92
67
  async getSchema(categoryName, schemaFileName) {
93
68
  return await this.withLock(async () => {
94
69
  const categorySchemas = this.schemaMap.get(categoryName);
@@ -105,16 +80,11 @@ export class ServerSchemaProvider {
105
80
  }
106
81
  async reloadSchemas() {
107
82
  return await this.withLock(async () => {
108
- await this.loadAllSchemas();
83
+ // Reloading should re-evaluate both default and any configured adhoc directory
84
+ // For simplicity, we assume initialize would be called again if adhoc path changes.
85
+ // This reload will just reload from the paths known during the last full initialize.
86
+ await this.initialize(); // This will re-load default and adhoc if adhocSchemasDir was set
109
87
  });
110
88
  }
111
89
  }
112
- // Export a lazy initialized singleton instance getter
113
- let initPromise = null;
114
- export function getServerSchemaProvider() {
115
- if (!initPromise) {
116
- initPromise = ServerSchemaProvider.getInstance();
117
- }
118
- return initPromise;
119
- }
120
90
  //# sourceMappingURL=ServerSchemaProvider.js.map
@@ -22,7 +22,6 @@ export interface RequirementStatus {
22
22
  export interface MCPServerStatus {
23
23
  installedStatus: Record<string, OperationStatus>;
24
24
  name: string;
25
- tags?: string[];
26
25
  error?: string;
27
26
  }
28
27
  export interface OperationStatus {
@@ -43,7 +42,6 @@ export interface MCPServerCategory {
43
42
  displayName: string;
44
43
  description?: string;
45
44
  type: 'local';
46
- tags?: string[];
47
45
  path?: string;
48
46
  installationStatus?: InstallationStatus;
49
47
  feedConfiguration?: FeedConfiguration;
@@ -107,6 +105,7 @@ export interface McpConfig {
107
105
  dependencies?: DependencyConfig;
108
106
  schemas?: string;
109
107
  repository?: string;
108
+ systemTags?: Record<string, string>;
110
109
  installation: InstallationConfig;
111
110
  }
112
111
  export interface RegistryConfig {
@@ -132,8 +131,10 @@ export interface FeedConfiguration {
132
131
  displayName: string;
133
132
  description: string;
134
133
  repository?: string;
134
+ PullRequest?: string;
135
135
  requirements: RequirementConfig[];
136
136
  mcpServers: McpConfig[];
137
+ systemTags?: Record<string, string>;
137
138
  }
138
139
  export interface ClientSettings {
139
140
  codeSettingPath: string;
@@ -5,6 +5,13 @@ import { OperationStatus } from './OnboardStatus.js';
5
5
  */
6
6
  export declare class FeedOnboardService {
7
7
  constructor();
8
+ /**
9
+ * Creates an operation ID that combines feed name and operation type.
10
+ * @param feedName The name of the feed.
11
+ * @param operationType The type of operation.
12
+ * @returns Combined operation ID string.
13
+ */
14
+ private createOperationId;
8
15
  /**
9
16
  * Onboard a new feed configuration
10
17
  * @param config Feed configuration to onboard
@@ -26,20 +33,15 @@ export declare class FeedOnboardService {
26
33
  * If an existing operation is found, its status is returned. Otherwise, a new operation is created and started.
27
34
  * @param config The feed configuration.
28
35
  * @param operationType The type of operation to initiate (FULL_ONBOARDING or VALIDATION_ONLY).
36
+ * @param serverList The list of server names to process.
29
37
  * @returns A promise that resolves to the operation status.
30
38
  */
31
39
  private _initiateOperation;
32
- /**
33
- * Finds an existing non-completed operation for a given feed name, server name, and operation type.
34
- * @param feedName The name of the feed.
35
- * @param operationType The type of operation.
36
- * @returns A promise that resolves to the OnboardStatus of the existing operation, or undefined if not found.
37
- */
38
- private _findExistingNonCompletedOperation;
39
40
  /**
40
41
  * Performs static validation of the feed configuration.
41
42
  * @param config The feed configuration to validate.
42
43
  * @param forExistingCategory Whether this is for an existing category.
44
+ * @returns A promise that resolves to a list of server names to be processed.
43
45
  * @throws Error if validation fails.
44
46
  */
45
47
  private validateStaticConfig;
@@ -48,6 +50,8 @@ export declare class FeedOnboardService {
48
50
  * Updates the onboarding status to VALIDATING, then to VALIDATED or FAILED based on the validation result.
49
51
  * @param onboardingId The ID of the onboarding process.
50
52
  * @param config The feed configuration to validate.
53
+ * @param operationType The type of operation this validation is for.
54
+ * @param serverList The list of server names to validate.
51
55
  * @throws Error if validation fails, to be caught by the calling process.
52
56
  */
53
57
  private _validateFeedConfiguration;
@@ -57,6 +61,8 @@ export declare class FeedOnboardService {
57
61
  * If validation fails, the error is handled by _validateFeedConfiguration and the calling _initiateOperation method.
58
62
  * @param onboardingId The ID of the onboarding process.
59
63
  * @param config The feed configuration.
64
+ * @param operationType The type of operation (should be 'VALIDATION_ONLY').
65
+ * @param serverList The list of server names to validate.
60
66
  */
61
67
  private processValidationOnly;
62
68
  /**
@@ -65,6 +71,7 @@ export declare class FeedOnboardService {
65
71
  * Manages status updates throughout the process and handles cleanup of temporary directories.
66
72
  * @param onboardingId The ID of the onboarding process.
67
73
  * @param config The feed configuration.
74
+ * @param operationType The type of operation (should be 'FULL_ONBOARDING').
68
75
  * @throws Error if any step of the full onboarding process fails.
69
76
  */
70
77
  private processFullOnboarding;