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.
- package/dist/cli/commands/install.js +2 -2
- package/dist/cli/commands/list.js +2 -2
- package/dist/cli/commands/serve.js +1 -1
- package/dist/core/RequirementService.d.ts +0 -12
- package/dist/core/RequirementService.js +0 -24
- package/dist/core/installers/clients/BaseClientInstaller.d.ts +1 -1
- package/dist/core/installers/clients/ClientInstaller.d.ts +1 -1
- package/dist/core/installers/clients/ClientInstaller.js +1 -1
- package/dist/core/installers/clients/ClientInstallerFactory.js +1 -1
- package/dist/core/installers/clients/ClineInstaller.d.ts +1 -1
- package/dist/core/installers/clients/ClineInstaller.js +1 -1
- package/dist/core/installers/clients/ExtensionInstaller.js +1 -1
- package/dist/core/installers/clients/GithubCopilotInstaller.d.ts +1 -1
- package/dist/core/installers/clients/GithubCopilotInstaller.js +1 -1
- package/dist/core/installers/clients/MSRooCodeInstaller.d.ts +1 -1
- package/dist/core/installers/clients/MSRooCodeInstaller.js +1 -1
- package/dist/core/installers/requirements/BaseInstaller.d.ts +1 -1
- package/dist/core/installers/requirements/BaseInstaller.js +1 -1
- package/dist/core/installers/requirements/CommandInstaller.d.ts +1 -1
- package/dist/core/installers/requirements/CommandInstaller.js +1 -1
- package/dist/core/installers/requirements/GeneralInstaller.d.ts +1 -1
- package/dist/core/installers/requirements/InstallerFactory.d.ts +1 -1
- package/dist/core/installers/requirements/NpmInstaller.d.ts +1 -1
- package/dist/core/installers/requirements/NpmInstaller.js +1 -1
- package/dist/core/installers/requirements/PipInstaller.d.ts +1 -1
- package/dist/core/installers/requirements/RequirementInstaller.d.ts +1 -1
- package/dist/core/loaders/ConfigurationLoader.d.ts +32 -0
- package/dist/core/loaders/ConfigurationLoader.js +236 -0
- package/dist/core/loaders/ConfigurationProvider.d.ts +35 -0
- package/dist/core/loaders/ConfigurationProvider.js +375 -0
- package/dist/core/loaders/ServerSchemaLoader.d.ts +11 -0
- package/{src/core/ServerSchemaLoader.ts → dist/core/loaders/ServerSchemaLoader.js} +43 -48
- package/dist/core/loaders/ServerSchemaProvider.d.ts +17 -0
- package/{src/core/ServerSchemaProvider.ts → dist/core/loaders/ServerSchemaProvider.js} +120 -137
- package/dist/core/metadatas/constants.d.ts +47 -0
- package/dist/core/metadatas/constants.js +94 -0
- package/dist/core/metadatas/types.d.ts +166 -0
- package/dist/core/metadatas/types.js +16 -0
- package/dist/core/onboard/FeedOnboardService.d.ts +1 -1
- package/dist/core/onboard/FeedOnboardService.js +1 -1
- package/dist/core/onboard/OnboardProcessor.d.ts +1 -1
- package/dist/core/onboard/OnboardProcessor.js +1 -1
- package/dist/core/onboard/OnboardStatus.d.ts +1 -1
- package/dist/core/onboard/OnboardStatusManager.d.ts +1 -1
- package/dist/core/onboard/OnboardStatusManager.js +1 -1
- package/dist/core/validators/FeedValidator.d.ts +1 -1
- package/dist/core/validators/IServerValidator.d.ts +1 -1
- package/dist/core/validators/SSEServerValidator.d.ts +1 -1
- package/dist/core/validators/ServerValidatorFactory.d.ts +1 -1
- package/dist/core/validators/StdioServerValidator.d.ts +1 -1
- package/dist/core/validators/StdioServerValidator.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/services/InstallationService.d.ts +50 -0
- package/dist/services/InstallationService.js +350 -0
- package/dist/services/MCPManager.d.ts +28 -0
- package/dist/services/MCPManager.js +188 -0
- package/dist/services/RequirementService.d.ts +40 -0
- package/dist/services/RequirementService.js +110 -0
- package/dist/services/ServerService.d.ts +2 -2
- package/dist/services/ServerService.js +5 -5
- package/dist/utils/adoUtils.d.ts +2 -2
- package/dist/utils/adoUtils.js +1 -1
- package/dist/utils/feedUtils.js +1 -1
- package/dist/utils/githubUtils.d.ts +1 -1
- package/dist/utils/githubUtils.js +1 -1
- package/dist/utils/logger.js +1 -1
- package/dist/utils/macroExpressionUtils.d.ts +1 -1
- package/dist/utils/osUtils.d.ts +1 -1
- package/dist/utils/osUtils.js +1 -1
- package/dist/web/contract/serverContract.d.ts +1 -1
- package/dist/web/public/index.html +1 -3
- package/dist/web/public/js/api.js +2 -80
- package/dist/web/server.js +2 -2
- package/package.json +1 -1
- package/src/cli/commands/install.ts +3 -3
- package/src/cli/commands/list.ts +2 -2
- package/src/cli/commands/serve.ts +3 -2
- package/src/cli/index.ts +1 -1
- package/src/core/installers/clients/BaseClientInstaller.ts +134 -3
- package/src/core/installers/clients/ClientInstaller.ts +3 -3
- package/src/core/installers/clients/ClientInstallerFactory.ts +1 -1
- package/src/core/installers/clients/ClineInstaller.ts +1 -101
- package/src/core/installers/clients/ExtensionInstaller.ts +1 -1
- package/src/core/installers/clients/GithubCopilotInstaller.ts +1 -101
- package/src/core/installers/clients/MSRooCodeInstaller.ts +1 -102
- package/src/core/installers/requirements/BaseInstaller.ts +2 -2
- package/src/core/installers/requirements/CommandInstaller.ts +1 -1
- package/src/core/installers/requirements/GeneralInstaller.ts +1 -1
- package/src/core/installers/requirements/InstallerFactory.ts +1 -1
- package/src/core/installers/requirements/NpmInstaller.ts +12 -12
- package/src/core/installers/requirements/PipInstaller.ts +1 -1
- package/src/core/installers/requirements/RequirementInstaller.ts +1 -1
- package/src/core/{ConfigurationLoader.ts → loaders/ConfigurationLoader.ts} +31 -7
- package/src/core/{ConfigurationProvider.ts → loaders/ConfigurationProvider.ts} +18 -10
- package/src/core/loaders/ServerSchemaLoader.ts +117 -0
- package/src/core/loaders/ServerSchemaProvider.ts +99 -0
- package/src/core/{types.ts → metadatas/types.ts} +3 -2
- package/src/core/onboard/FeedOnboardService.ts +270 -146
- package/src/core/onboard/OnboardProcessor.ts +60 -11
- package/src/core/onboard/OnboardStatus.ts +7 -2
- package/src/core/onboard/OnboardStatusManager.ts +270 -43
- package/src/core/validators/FeedValidator.ts +65 -9
- package/src/core/validators/IServerValidator.ts +1 -1
- package/src/core/validators/SSEServerValidator.ts +2 -2
- package/src/core/validators/ServerValidatorFactory.ts +1 -1
- package/src/core/validators/StdioServerValidator.ts +86 -34
- package/src/index.ts +3 -3
- package/src/{core → services}/InstallationService.ts +5 -5
- package/src/{core → services}/MCPManager.ts +10 -5
- package/src/{core → services}/RequirementService.ts +2 -31
- package/src/services/ServerService.ts +7 -7
- package/src/utils/adoUtils.ts +3 -3
- package/src/utils/feedUtils.ts +2 -2
- package/src/utils/githubUtils.ts +2 -2
- package/src/utils/logger.ts +13 -1
- package/src/utils/macroExpressionUtils.ts +1 -1
- package/src/utils/osUtils.ts +4 -4
- package/src/web/contract/serverContract.ts +2 -2
- package/src/web/public/index.html +1 -3
- package/src/web/public/js/api.js +2 -80
- package/src/web/public/js/modal/installation.js +1 -1
- package/src/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +41 -9
- package/src/web/public/js/onboard/formProcessor.js +200 -34
- package/src/web/public/js/onboard/index.js +2 -2
- package/src/web/public/js/onboard/publishHandler.js +30 -22
- package/src/web/public/js/onboard/templates.js +34 -40
- package/src/web/public/js/onboard/uiHandlers.js +175 -84
- package/src/web/public/js/onboard/validationHandlers.js +147 -64
- package/src/web/public/js/serverCategoryDetails.js +19 -4
- package/src/web/public/js/serverCategoryList.js +13 -1
- package/src/web/public/onboard.html +1 -1
- package/src/web/server.ts +30 -14
- package/src/services/InstallRequestValidator.ts +0 -112
- /package/src/core/{constants.ts → metadatas/constants.ts} +0 -0
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { FeedConfiguration, McpConfig } from "../metadatas/types.js";
|
|
2
4
|
import { serverValidatorFactory } from "./ServerValidatorFactory.js";
|
|
3
5
|
import { Logger } from "../../utils/logger.js";
|
|
6
|
+
import { onboardStatusManager } from "../onboard/OnboardStatusManager.js";
|
|
7
|
+
import { OnboardingProcessStatus, OperationType } from "../onboard/OnboardStatus.js";
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
10
|
* Validates feed configurations to ensure they meet required criteria
|
|
@@ -9,24 +13,30 @@ export class FeedValidator {
|
|
|
9
13
|
/**
|
|
10
14
|
* Validates a feed configuration
|
|
11
15
|
* @param config The feed configuration to validate
|
|
16
|
+
* @param categoryName The name of the category (feed name) for status updates
|
|
17
|
+
* @param operationType The type of operation for status updates
|
|
12
18
|
* @returns true if valid, throws error if invalid
|
|
13
19
|
*/
|
|
14
|
-
public validate(config: FeedConfiguration): boolean {
|
|
20
|
+
public async validate(config: FeedConfiguration, categoryName: string, operationType: OperationType): Promise<boolean> {
|
|
15
21
|
try {
|
|
22
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Starting feed validation for '${config.name}'`);
|
|
16
23
|
Logger.debug(`Validating feed configuration: ${config.name}`);
|
|
17
24
|
|
|
18
25
|
// Validate required fields
|
|
26
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Validating required fields for '${config.name}'`);
|
|
19
27
|
if (!config.name) throw new Error('Feed name is required');
|
|
20
28
|
if (!config.displayName) throw new Error('Feed display name is required');
|
|
21
29
|
if (!config.description) throw new Error('Feed description is required');
|
|
22
30
|
|
|
23
31
|
// Validate MCP servers array
|
|
32
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Validating MCP servers array for '${config.name}'`);
|
|
24
33
|
if (!Array.isArray(config.mcpServers) || config.mcpServers.length === 0) {
|
|
25
34
|
throw new Error('Feed must contain at least one MCP server');
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
// Validate requirements if present
|
|
29
38
|
if (config.requirements) {
|
|
39
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Validating requirements for '${config.name}'`);
|
|
30
40
|
for (const req of config.requirements) {
|
|
31
41
|
if (!req.name) throw new Error('Requirement name is required');
|
|
32
42
|
if (!req.type) throw new Error('Requirement type is required');
|
|
@@ -34,11 +44,13 @@ export class FeedValidator {
|
|
|
34
44
|
}
|
|
35
45
|
}
|
|
36
46
|
|
|
47
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Feed validation successful for '${config.name}'`, undefined, OnboardingProcessStatus.VALIDATING); // Still in progress until all servers validated
|
|
37
48
|
Logger.debug(`Feed configuration validation successful: ${config.name}`);
|
|
38
49
|
return true;
|
|
39
50
|
} catch (error) {
|
|
40
|
-
const errorMsg = `Feed validation failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
51
|
+
const errorMsg = `Feed validation failed for '${config.name}': ${error instanceof Error ? error.message : String(error)}`;
|
|
41
52
|
Logger.error(errorMsg);
|
|
53
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Feed validation failed for '${config.name}'`, undefined, OnboardingProcessStatus.FAILED, errorMsg);
|
|
42
54
|
throw new Error(errorMsg);
|
|
43
55
|
}
|
|
44
56
|
}
|
|
@@ -47,29 +59,73 @@ export class FeedValidator {
|
|
|
47
59
|
* Validates a single MCP server configuration using the appropriate validator
|
|
48
60
|
* @param server The MCP server configuration to validate
|
|
49
61
|
* @param config The feed configuration containing shared requirements
|
|
62
|
+
* @param categoryName The name of the category (feed name) for status updates
|
|
63
|
+
* @param operationType The type of operation for status updates
|
|
50
64
|
* @returns true if valid, throws error if invalid
|
|
51
65
|
*/
|
|
52
|
-
public async validateServer(server: McpConfig, config: FeedConfiguration): Promise<boolean> {
|
|
66
|
+
public async validateServer(server: McpConfig, config: FeedConfiguration, categoryName: string, operationType: OperationType): Promise<boolean> {
|
|
67
|
+
const feedName = config.name; // categoryName is the feedName in this context
|
|
68
|
+
const serverDisplayName = server.name;
|
|
69
|
+
|
|
53
70
|
try {
|
|
54
|
-
|
|
71
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Starting server validation for '${serverDisplayName}' in feed '${feedName}'`, server.name);
|
|
72
|
+
Logger.debug(`Validating server configuration: ${serverDisplayName} in feed ${feedName}`);
|
|
55
73
|
|
|
56
74
|
// Validate basic required fields
|
|
75
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Validating basic fields for server '${serverDisplayName}'`, server.name);
|
|
57
76
|
if (!server.name) throw new Error('Server name is required');
|
|
58
77
|
if (!server.description) throw new Error('Server description is required');
|
|
59
78
|
if (!server.mode) throw new Error('Server mode is required');
|
|
60
79
|
if (!server.installation) throw new Error('Server installation configuration is required');
|
|
61
80
|
|
|
81
|
+
// Validate schema file existence if schemas is defined
|
|
82
|
+
if (server.schemas) {
|
|
83
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Validating schema file for server '${serverDisplayName}'`, server.name);
|
|
84
|
+
try {
|
|
85
|
+
// Assuming server.schemas is a relative path from the project root or a path that needs to be resolved.
|
|
86
|
+
// For now, let's assume it's relative to the feed file's location or an absolute path.
|
|
87
|
+
// If it's relative to the feed file, we might need the feed file's path.
|
|
88
|
+
// For simplicity, let's assume it's a path that can be directly accessed.
|
|
89
|
+
// If the schema path is relative to the feed config file, this logic will need adjustment.
|
|
90
|
+
// For now, we'll treat it as a path that `fs.access` can check.
|
|
91
|
+
// It's more likely that schema paths are relative to the feed definition file itself.
|
|
92
|
+
// However, the task description implies `server.schemas` is a path to be checked.
|
|
93
|
+
// Let's assume for now it's a path that should exist.
|
|
94
|
+
// If the schemas are stored within the repo, their paths would be relative to the repo root.
|
|
95
|
+
// During validation, we might not have the repo context directly here.
|
|
96
|
+
// This needs clarification on how schema paths are resolved during validation.
|
|
97
|
+
// For now, we'll proceed with a direct check.
|
|
98
|
+
// If the schema is part of the feed package, its path might be relative to the package root.
|
|
99
|
+
// Let's assume the path is resolvable from the current working directory or is absolute.
|
|
100
|
+
// This part might need refinement based on where schema files are expected to be.
|
|
101
|
+
// The task implies `server.schemas` is a string path.
|
|
102
|
+
const schemaPath = server.schemas; // This path needs to be correctly resolved.
|
|
103
|
+
// If it's relative to the feed file, we need that context.
|
|
104
|
+
// For now, we'll assume it's a path that can be checked.
|
|
105
|
+
// This might be an issue if it's relative to a file not yet in the repo.
|
|
106
|
+
// Let's assume it's a path that should be resolvable.
|
|
107
|
+
await fs.access(schemaPath);
|
|
108
|
+
Logger.debug(`Schema file ${schemaPath} exists for server ${serverDisplayName}`);
|
|
109
|
+
} catch (fileAccessError) {
|
|
110
|
+
throw new Error(`Schema file '${server.schemas}' not found for server '${serverDisplayName}'.`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
62
114
|
// Get the appropriate validator for this server type
|
|
115
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Obtaining specific validator for server '${serverDisplayName}'`, server.name);
|
|
63
116
|
const validator = serverValidatorFactory.getValidatorForServer(server);
|
|
64
|
-
|
|
117
|
+
|
|
65
118
|
// Perform mode-specific validation with feed config
|
|
66
|
-
await
|
|
119
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Performing mode-specific validation for server '${serverDisplayName}'`, server.name);
|
|
120
|
+
await validator.validateServer(server, config); // This internal call won't have status updates unless modified too
|
|
67
121
|
|
|
68
|
-
|
|
122
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Server validation successful for '${serverDisplayName}'`, server.name, OnboardingProcessStatus.VALIDATING); // Still in progress until all servers validated
|
|
123
|
+
Logger.debug(`Server configuration validation successful: ${serverDisplayName}`);
|
|
69
124
|
return true;
|
|
70
125
|
} catch (error) {
|
|
71
|
-
const errorMsg = `Server validation failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
126
|
+
const errorMsg = `Server validation failed for '${serverDisplayName}' in feed '${feedName}': ${error instanceof Error ? error.message : String(error)}`;
|
|
72
127
|
Logger.error(errorMsg);
|
|
128
|
+
await onboardStatusManager.recordStep(categoryName, operationType, `Server validation failed for '${serverDisplayName}'`, server.name, OnboardingProcessStatus.FAILED, errorMsg);
|
|
73
129
|
throw new Error(errorMsg);
|
|
74
130
|
}
|
|
75
131
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { McpConfig, FeedConfiguration } from "../types.js";
|
|
1
|
+
import { McpConfig, FeedConfiguration } from "../metadatas/types.js";
|
|
2
2
|
import { IServerValidator } from "./IServerValidator.js";
|
|
3
3
|
import { Logger } from "../../utils/logger.js";
|
|
4
4
|
|
|
@@ -16,7 +16,7 @@ export class SSEServerValidator implements IServerValidator {
|
|
|
16
16
|
public async validateServer(server: McpConfig, config: FeedConfiguration): Promise<boolean> {
|
|
17
17
|
try {
|
|
18
18
|
Logger.debug(`Validating SSE server configuration: ${server.name}`);
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
if (!server.installation?.url) {
|
|
21
21
|
throw new Error('SSE server URL is required in installation configuration');
|
|
22
22
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { McpConfig } from "../types.js";
|
|
1
|
+
import { McpConfig } from "../metadatas/types.js";
|
|
2
2
|
import { IServerValidator, ValidatorType } from "./IServerValidator.js";
|
|
3
3
|
import { StdioServerValidator } from "./StdioServerValidator.js";
|
|
4
4
|
import { SSEServerValidator } from "./SSEServerValidator.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { McpConfig, RequirementConfig, FeedConfiguration } from "../types.js";
|
|
1
|
+
import { McpConfig, RequirementConfig, FeedConfiguration } from "../metadatas/types.js";
|
|
2
2
|
import { IServerValidator } from "./IServerValidator.js";
|
|
3
3
|
import { Logger } from "../../utils/logger.js";
|
|
4
4
|
import { createInstallerFactory } from "../installers/index.js";
|
|
@@ -6,7 +6,7 @@ import { exec, spawn } from 'child_process';
|
|
|
6
6
|
import util from 'util';
|
|
7
7
|
import { MACRO_EXPRESSIONS, resolveNpmModulePath } from "../../utils/macroExpressionUtils.js";
|
|
8
8
|
import { getSystemPythonPackageDirectory } from "../../utils/osUtils.js";
|
|
9
|
-
import { SETTINGS_DIR } from "../constants.js";
|
|
9
|
+
import { SETTINGS_DIR } from "../metadatas/constants.js";
|
|
10
10
|
import path from "path";
|
|
11
11
|
|
|
12
12
|
const execPromise = util.promisify(exec);
|
|
@@ -108,7 +108,10 @@ export class StdioServerValidator implements IServerValidator {
|
|
|
108
108
|
// Resolve npm module paths in arguments
|
|
109
109
|
Logger.debug('Resolving npm module paths in arguments');
|
|
110
110
|
const npmPath = requirement ? this._getRequirementFolderPath(requirement) : undefined;
|
|
111
|
-
finalArgs = args.map(arg => arg
|
|
111
|
+
finalArgs = args.map(arg => arg
|
|
112
|
+
.replace(MACRO_EXPRESSIONS.NPMPATH, resolveNpmModulePath(npmPath))
|
|
113
|
+
.replace(/\\/g, '/')
|
|
114
|
+
);
|
|
112
115
|
Logger.debug(`Resolved npm arguments: ${finalArgs.join(' ')}`);
|
|
113
116
|
} else if (command === 'python' || command === 'python3') {
|
|
114
117
|
// Resolve Python package paths in arguments
|
|
@@ -125,60 +128,109 @@ export class StdioServerValidator implements IServerValidator {
|
|
|
125
128
|
}
|
|
126
129
|
|
|
127
130
|
return await new Promise<boolean>((resolve, reject) => {
|
|
128
|
-
Logger.debug(`Starting process with command: ${command} ${finalArgs.join(' ')}`);
|
|
131
|
+
Logger.debug(`Starting process for server test with command: ${command} ${finalArgs.join(' ')}`);
|
|
129
132
|
|
|
130
|
-
//
|
|
131
|
-
const timeout = setTimeout(() => {
|
|
132
|
-
const msg = 'Server startup test timed out after 10 seconds';
|
|
133
|
-
Logger.error(msg);
|
|
134
|
-
serverProcess.kill();
|
|
135
|
-
reject(new Error(msg));
|
|
136
|
-
}, 20000);
|
|
133
|
+
const timeoutDuration = 20000; // 20 seconds for server startup test
|
|
137
134
|
|
|
138
|
-
// Start the server process
|
|
139
135
|
const serverProcess = spawn(command, finalArgs, {
|
|
140
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
136
|
+
stdio: ['ignore', 'pipe', 'pipe'], // stdin, stdout, stderr
|
|
141
137
|
shell: true
|
|
142
138
|
});
|
|
143
139
|
|
|
144
|
-
let
|
|
145
|
-
let
|
|
140
|
+
let stdoutData = '';
|
|
141
|
+
let stderrData = '';
|
|
142
|
+
let settled = false;
|
|
143
|
+
|
|
144
|
+
const cleanupAndResolve = (value: boolean) => {
|
|
145
|
+
if (settled) return;
|
|
146
|
+
settled = true;
|
|
147
|
+
clearTimeout(timeoutId);
|
|
148
|
+
serverProcess.stdout.removeAllListeners();
|
|
149
|
+
serverProcess.stderr.removeAllListeners();
|
|
150
|
+
serverProcess.removeAllListeners('exit');
|
|
151
|
+
serverProcess.removeAllListeners('error');
|
|
152
|
+
if (serverProcess.exitCode === null && !serverProcess.killed) {
|
|
153
|
+
serverProcess.kill();
|
|
154
|
+
}
|
|
155
|
+
resolve(value);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const cleanupAndReject = (err: Error) => {
|
|
159
|
+
if (settled) return;
|
|
160
|
+
settled = true;
|
|
161
|
+
clearTimeout(timeoutId);
|
|
162
|
+
serverProcess.stdout.removeAllListeners();
|
|
163
|
+
serverProcess.stderr.removeAllListeners();
|
|
164
|
+
serverProcess.removeAllListeners('exit');
|
|
165
|
+
serverProcess.removeAllListeners('error');
|
|
166
|
+
if (serverProcess.exitCode === null && !serverProcess.killed) {
|
|
167
|
+
serverProcess.kill();
|
|
168
|
+
}
|
|
169
|
+
reject(err);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const timeoutId = setTimeout(() => {
|
|
173
|
+
if (settled) return;
|
|
174
|
+
|
|
175
|
+
if (serverProcess.exitCode === null) { // Process is still running
|
|
176
|
+
Logger.debug(`Server startup test: Process still running after ${timeoutDuration / 1000} seconds. Considering it successful.`);
|
|
177
|
+
Logger.debug(`Collected stdout:\n${stdoutData}`);
|
|
178
|
+
Logger.debug(`Collected stderr:\n${stderrData}`);
|
|
179
|
+
cleanupAndResolve(true);
|
|
180
|
+
} else {
|
|
181
|
+
// Process exited before timeout, 'exit' handler should have caught it.
|
|
182
|
+
// This is a fallback or race condition handling.
|
|
183
|
+
const msg = `Server startup test: Process exited with code ${serverProcess.exitCode} before timeout completed.`;
|
|
184
|
+
Logger.error(msg);
|
|
185
|
+
Logger.debug(`Collected stdout:\n${stdoutData}`);
|
|
186
|
+
Logger.error(`Collected stderr:\n${stderrData}`); // Log stderr as error here
|
|
187
|
+
cleanupAndReject(new Error(msg + ` Stderr: ${stderrData}`));
|
|
188
|
+
}
|
|
189
|
+
}, timeoutDuration);
|
|
146
190
|
|
|
147
|
-
// Collect stdout
|
|
148
191
|
serverProcess.stdout.on('data', (data: Buffer) => {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
serverProcess.kill();
|
|
153
|
-
resolve(true);
|
|
192
|
+
const messageChunk = data.toString();
|
|
193
|
+
stdoutData += messageChunk;
|
|
194
|
+
Logger.debug(`Server stdout: ${messageChunk.trim()}`);
|
|
154
195
|
});
|
|
155
196
|
|
|
156
|
-
// Collect stderr
|
|
157
197
|
serverProcess.stderr.on('data', (data: Buffer) => {
|
|
158
|
-
|
|
198
|
+
const messageChunk = data.toString();
|
|
199
|
+
stderrData += messageChunk;
|
|
200
|
+
// Log stderr, but it doesn't automatically mean failure.
|
|
201
|
+
// The exit code or an 'error' event will determine failure.
|
|
202
|
+
Logger.debug(`Server stderr: ${messageChunk.trim()}`);
|
|
159
203
|
});
|
|
160
204
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
205
|
+
serverProcess.on('exit', (code: number | null, signal: string | null) => {
|
|
206
|
+
if (settled) return;
|
|
207
|
+
|
|
208
|
+
Logger.debug(`Server process exited with code ${code}, signal: ${signal}.`);
|
|
209
|
+
Logger.debug(`Final stdout:\n${stdoutData}`);
|
|
210
|
+
Logger.debug(`Final stderr:\n${stderrData}`);
|
|
211
|
+
|
|
212
|
+
if (code === 0) {
|
|
213
|
+
cleanupAndResolve(true);
|
|
214
|
+
} else {
|
|
215
|
+
const msg = `Server process exited with non-zero code ${code} or signal ${signal}. Stderr: ${stderrData.trim()}`;
|
|
166
216
|
Logger.error(msg);
|
|
167
|
-
|
|
217
|
+
cleanupAndReject(new Error(msg));
|
|
168
218
|
}
|
|
169
219
|
});
|
|
170
220
|
|
|
171
|
-
// Handle process error
|
|
172
221
|
serverProcess.on('error', (error: Error) => {
|
|
173
|
-
|
|
174
|
-
const msg = `Server
|
|
222
|
+
if (settled) return;
|
|
223
|
+
const msg = `Server process failed to start or encountered an error: ${error.message}.`;
|
|
175
224
|
Logger.error(msg);
|
|
176
|
-
|
|
225
|
+
Logger.debug(`Stdout at error:\n${stdoutData}`);
|
|
226
|
+
Logger.error(`Stderr at error:\n${stderrData}`);
|
|
227
|
+
cleanupAndReject(new Error(`${msg} Stderr: ${stderrData.trim()}`));
|
|
177
228
|
});
|
|
178
229
|
});
|
|
179
230
|
} catch (error) {
|
|
180
|
-
const msg = `Failed to test server startup: ${error instanceof Error ? error.message : String(error)}`;
|
|
231
|
+
const msg = `Failed to test server startup (outer catch): ${error instanceof Error ? error.message : String(error)}`;
|
|
181
232
|
Logger.error(msg);
|
|
233
|
+
// Ensure the error thrown is an instance of Error
|
|
182
234
|
throw error instanceof Error ? error : new Error(msg);
|
|
183
235
|
}
|
|
184
236
|
}
|
package/src/index.ts
CHANGED
|
@@ -11,14 +11,14 @@ export {
|
|
|
11
11
|
RequirementConfig,
|
|
12
12
|
RequirementStatus,
|
|
13
13
|
RegistryConfig
|
|
14
|
-
} from './core/types.js';
|
|
14
|
+
} from './core/metadatas/types.js';
|
|
15
15
|
|
|
16
16
|
// Core functionality
|
|
17
|
-
export { MCPManager, mcpManager } from './
|
|
17
|
+
export { MCPManager, mcpManager } from './services/MCPManager.js';
|
|
18
18
|
|
|
19
19
|
// Services
|
|
20
20
|
export { ServerService, serverService } from './services/ServerService.js';
|
|
21
|
-
export { RequirementService, requirementService } from './
|
|
21
|
+
export { RequirementService, requirementService } from './services/RequirementService.js';
|
|
22
22
|
|
|
23
23
|
// Installer interfaces and implementations
|
|
24
24
|
export {
|
|
@@ -11,11 +11,11 @@ import {
|
|
|
11
11
|
OperationStatus,
|
|
12
12
|
RequirementStatus,
|
|
13
13
|
McpConfig
|
|
14
|
-
} from '
|
|
15
|
-
import { RequirementInstaller, InstallerFactory, createInstallerFactory } from '
|
|
16
|
-
import { SUPPORTED_CLIENTS } from '
|
|
17
|
-
import { ClientInstaller } from '
|
|
18
|
-
import { ConfigurationProvider } from '
|
|
14
|
+
} from '../core/metadatas/types.js';
|
|
15
|
+
import { RequirementInstaller, InstallerFactory, createInstallerFactory } from '../core/installers/index.js';
|
|
16
|
+
import { SUPPORTED_CLIENTS } from '../core/metadatas/constants.js';
|
|
17
|
+
import { ClientInstaller } from '../core/installers/clients/ClientInstaller.js';
|
|
18
|
+
import { ConfigurationProvider } from '../core/loaders/ConfigurationProvider.js';
|
|
19
19
|
import { Logger } from '../utils/logger.js';
|
|
20
20
|
|
|
21
21
|
const execPromise = util.promisify(exec);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { ConfigurationProvider } from '
|
|
2
|
+
import { ConfigurationProvider } from '../core/loaders/ConfigurationProvider.js';
|
|
3
|
+
import { ServerSchemaProvider } from '../core/loaders/ServerSchemaProvider.js';
|
|
3
4
|
import { InstallationService } from './InstallationService.js';
|
|
4
5
|
import {
|
|
5
6
|
MCPEvent,
|
|
@@ -11,20 +12,23 @@ import {
|
|
|
11
12
|
ServerUninstallOptions,
|
|
12
13
|
InstallationStatus,
|
|
13
14
|
FeedConfiguration,
|
|
14
|
-
} from '
|
|
15
|
-
import { OperationStatus } from '
|
|
15
|
+
} from '../core/metadatas/types.js';
|
|
16
|
+
import { OperationStatus } from '../core/onboard/OnboardStatus.js';
|
|
16
17
|
import { Logger } from '../utils/logger.js';
|
|
17
|
-
import { FeedOnboardService } from '
|
|
18
|
+
import { FeedOnboardService } from '../core/onboard/FeedOnboardService.js';
|
|
18
19
|
import path from 'path';
|
|
20
|
+
import { Server } from 'http';
|
|
19
21
|
|
|
20
22
|
export class MCPManager extends EventEmitter {
|
|
21
23
|
private installationService: InstallationService;
|
|
22
24
|
private configProvider: ConfigurationProvider;
|
|
23
25
|
private feedOnboardService: FeedOnboardService;
|
|
26
|
+
private schemaProvider: ServerSchemaProvider;
|
|
24
27
|
|
|
25
28
|
constructor() {
|
|
26
29
|
super();
|
|
27
30
|
this.configProvider = ConfigurationProvider.getInstance();
|
|
31
|
+
this.schemaProvider = ServerSchemaProvider.getInstance();
|
|
28
32
|
this.installationService = new InstallationService();
|
|
29
33
|
this.feedOnboardService = new FeedOnboardService();
|
|
30
34
|
}
|
|
@@ -33,9 +37,10 @@ export class MCPManager extends EventEmitter {
|
|
|
33
37
|
await this.configProvider.syncFeeds();
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
async initialize(feedFile?: string): Promise<void> {
|
|
40
|
+
async initialize(feedFile?: string, schemasDirectory?: string): Promise<void> {
|
|
37
41
|
try {
|
|
38
42
|
await this.configProvider.initialize(feedFile);
|
|
43
|
+
await this.schemaProvider.initialize(schemasDirectory);
|
|
39
44
|
} catch (error) {
|
|
40
45
|
console.error("Error during MCPManager initialization:", error);
|
|
41
46
|
throw error;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RequirementConfig, RequirementStatus, ServerInstallOptions } from '
|
|
2
|
-
import { createInstallerFactory } from '
|
|
1
|
+
import { RequirementConfig, RequirementStatus, ServerInstallOptions } from '../core/metadatas/types.js';
|
|
2
|
+
import { createInstallerFactory } from '../core/installers/index.js';
|
|
3
3
|
import { exec } from 'child_process';
|
|
4
4
|
import util from 'util';
|
|
5
5
|
|
|
@@ -23,19 +23,6 @@ export class RequirementService {
|
|
|
23
23
|
return RequirementService.instance;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
/**
|
|
27
|
-
* Install a requirement
|
|
28
|
-
* @param requirement The requirement to install
|
|
29
|
-
* @returns The installation status
|
|
30
|
-
*/
|
|
31
|
-
public async installRequirement(requirement: RequirementConfig, options?: ServerInstallOptions): Promise<RequirementStatus> {
|
|
32
|
-
// Validate requirement
|
|
33
|
-
this.validateRequirement(requirement);
|
|
34
|
-
|
|
35
|
-
// Install the requirement
|
|
36
|
-
return await this.installerFactory.install(requirement, options);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
26
|
/**
|
|
40
27
|
* Check the installation status of a requirement
|
|
41
28
|
* @param requirement The requirement to check
|
|
@@ -94,22 +81,6 @@ export class RequirementService {
|
|
|
94
81
|
return await this.installerFactory.install(updatedRequirement, options);
|
|
95
82
|
}
|
|
96
83
|
|
|
97
|
-
/**
|
|
98
|
-
* Install multiple requirements
|
|
99
|
-
* @param requirements The requirements to install
|
|
100
|
-
* @returns A map of requirement names to their installation status
|
|
101
|
-
*/
|
|
102
|
-
public async installRequirements(requirements: RequirementConfig[]): Promise<Record<string, RequirementStatus>> {
|
|
103
|
-
const results: Record<string, RequirementStatus> = {};
|
|
104
|
-
|
|
105
|
-
// Process each requirement sequentially to avoid conflicts
|
|
106
|
-
for (const requirement of requirements) {
|
|
107
|
-
results[requirement.name] = await this.installRequirement(requirement);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return results;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
84
|
/**
|
|
114
85
|
* Validate a requirement configuration
|
|
115
86
|
* @param requirement The requirement to validate
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { fileURLToPath } from 'url';
|
|
3
3
|
import { Logger } from '../utils/logger.js';
|
|
4
|
-
import {
|
|
4
|
+
import { ServerSchema, ServerSchemaProvider } from '../core/loaders/ServerSchemaProvider.js';
|
|
5
5
|
import {
|
|
6
6
|
MCPServerCategory,
|
|
7
7
|
ServerInstallOptions,
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
ServerUninstallOptions,
|
|
11
11
|
FeedConfiguration,
|
|
12
12
|
OperationStatus as CoreOperationStatus
|
|
13
|
-
} from '../core/types.js';
|
|
14
|
-
import { mcpManager } from '
|
|
13
|
+
} from '../core/metadatas/types.js';
|
|
14
|
+
import { mcpManager } from './MCPManager.js';
|
|
15
15
|
import { OperationStatus } from '../core/onboard/OnboardStatus.js';
|
|
16
|
-
import { UPDATE_CHECK_INTERVAL_MS } from '../core/constants.js';
|
|
16
|
+
import { UPDATE_CHECK_INTERVAL_MS } from '../core/metadatas/constants.js';
|
|
17
17
|
import { updateCheckTracker } from '../utils/UpdateCheckTracker.js';
|
|
18
18
|
|
|
19
19
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -70,8 +70,8 @@ export class ServerService {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
try {
|
|
73
|
-
const { requirementService } = await import('
|
|
74
|
-
const { configProvider } = await import('../core/ConfigurationProvider.js');
|
|
73
|
+
const { requirementService } = await import('./RequirementService.js');
|
|
74
|
+
const { configProvider } = await import('../core/loaders/ConfigurationProvider.js');
|
|
75
75
|
|
|
76
76
|
for (const requirement of serverCategory.feedConfiguration.requirements) {
|
|
77
77
|
if (requirement.version.includes('latest')) {
|
|
@@ -132,7 +132,7 @@ export class ServerService {
|
|
|
132
132
|
*/
|
|
133
133
|
async getServerSchema(categoryName: string, serverName: string): Promise<ServerSchema | undefined> {
|
|
134
134
|
try {
|
|
135
|
-
const provider =
|
|
135
|
+
const provider = ServerSchemaProvider.getInstance();
|
|
136
136
|
const serverMcpConfig = await mcpManager.getServerMcpConfig(categoryName, serverName);
|
|
137
137
|
return await provider.getSchema(categoryName, serverMcpConfig?.schemas || `${serverName}.json`);
|
|
138
138
|
} catch (error) {
|
package/src/utils/adoUtils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RequirementConfig, RegistryConfig } from '../core/types.js';
|
|
2
|
-
import { SETTINGS_DIR } from '../core/constants.js';
|
|
1
|
+
import { RequirementConfig, RegistryConfig } from '../core/metadatas/types.js';
|
|
2
|
+
import { SETTINGS_DIR } from '../core/metadatas/constants.js';
|
|
3
3
|
import { Logger } from './logger.js';
|
|
4
4
|
import { exec, execSync } from 'child_process';
|
|
5
5
|
import util from 'util';
|
|
@@ -183,7 +183,7 @@ export async function handleArtifact(
|
|
|
183
183
|
export async function getArtifactLatestVersion(
|
|
184
184
|
requirement: RequirementConfig,
|
|
185
185
|
registry: RegistryConfig['artifacts'],
|
|
186
|
-
options?: import('../core/types.js').ServerInstallOptions, // Added import for ServerInstallOptions
|
|
186
|
+
options?: import('../core/metadatas/types.js').ServerInstallOptions, // Added import for ServerInstallOptions
|
|
187
187
|
targetDir?: string // Optional target directory for npm
|
|
188
188
|
): Promise<string | undefined> {
|
|
189
189
|
if (!registry || !registry.registryUrl) {
|
package/src/utils/feedUtils.ts
CHANGED
|
@@ -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
|
/**
|
|
6
6
|
* Checks if local feeds exist in the LOCAL_FEEDS_DIR
|
|
@@ -21,7 +21,7 @@ export async function hasLocalFeeds(): Promise<boolean> {
|
|
|
21
21
|
// Check if directory contains any json files
|
|
22
22
|
const files = await fs.readdir(LOCAL_FEEDS_DIR);
|
|
23
23
|
const hasJsonFiles = files.some(file => file.endsWith('.json'));
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
Logger.debug(`Local feeds directory ${hasJsonFiles ? 'contains' : 'does not contain'} JSON files`);
|
|
26
26
|
return hasJsonFiles;
|
|
27
27
|
} catch (error) {
|
package/src/utils/githubUtils.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { RegistryConfig, RequirementConfig } from '../core/types.js';
|
|
1
|
+
import { RegistryConfig, RequirementConfig } from '../core/metadatas/types.js';
|
|
2
2
|
import { exec } from 'child_process';
|
|
3
3
|
import util from 'util';
|
|
4
4
|
import fs from 'fs/promises';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { extractZipFile } from './clientUtils.js';
|
|
7
7
|
import { Logger } from './logger.js';
|
|
8
|
-
import { SETTINGS_DIR } from '../core/constants.js';
|
|
8
|
+
import { SETTINGS_DIR } from '../core/metadatas/constants.js';
|
|
9
9
|
|
|
10
10
|
const execAsync = util.promisify(exec);
|
|
11
11
|
|
package/src/utils/logger.ts
CHANGED
|
@@ -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
|
|
|
5
5
|
export class Logger {
|
|
6
6
|
private static verbose = false;
|
|
@@ -56,6 +56,18 @@ export class Logger {
|
|
|
56
56
|
await this.writeToLogFile('INFO', message);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
static async info(message: string): Promise<void> {
|
|
60
|
+
console.info(message);
|
|
61
|
+
await this.writeToLogFile('INFO', message);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static async warn(message: string): Promise<void> {
|
|
65
|
+
const yellowColor = '\x1b[33m';
|
|
66
|
+
const resetColor = '\x1b[0m';
|
|
67
|
+
console.warn(`${yellowColor}${message}${resetColor}`);
|
|
68
|
+
await this.writeToLogFile('WARN', message);
|
|
69
|
+
}
|
|
70
|
+
|
|
59
71
|
static async debug(message: string | object): Promise<void> {
|
|
60
72
|
let formattedMessage: string;
|
|
61
73
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Logger } from './logger.js';
|
|
2
2
|
import { getPythonPackagePath, getSystemPythonPackageDirectory, GetBrowserPath } from './osUtils.js';
|
|
3
|
-
import { ServerInstallOptions } from '../core/types.js'; // Adjusted path
|
|
3
|
+
import { ServerInstallOptions } from '../core/metadatas/types.js'; // Adjusted path
|
|
4
4
|
import * as fsSync from 'fs';
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import { execSync } from 'child_process';
|
package/src/utils/osUtils.ts
CHANGED
|
@@ -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';
|
|
@@ -322,7 +322,7 @@ export function getPythonPackagePath(pythonExecutablePath: string): string {
|
|
|
322
322
|
const minorVer = parts[3].split('_')[0];
|
|
323
323
|
const version = majorVer + minorVer; // Combines "3" and "13" to "313"
|
|
324
324
|
const localAppData = process.env.LOCALAPPDATA;
|
|
325
|
-
|
|
325
|
+
|
|
326
326
|
if (localAppData) {
|
|
327
327
|
const sitePkgsPath = path.join(
|
|
328
328
|
localAppData,
|
|
@@ -333,12 +333,12 @@ export function getPythonPackagePath(pythonExecutablePath: string): string {
|
|
|
333
333
|
'Python' + version,
|
|
334
334
|
'site-packages'
|
|
335
335
|
);
|
|
336
|
-
|
|
336
|
+
|
|
337
337
|
Logger.debug(`Resolved Windows Store Python site-packages path: ${sitePkgsPath}`);
|
|
338
338
|
return sitePkgsPath;
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
|
-
|
|
341
|
+
|
|
342
342
|
Logger.debug('Could not resolve Windows Store Python site-packages path');
|
|
343
343
|
// Fallback to user's site-packages
|
|
344
344
|
return path.join(process.env.APPDATA || '', 'Python', 'Python3', 'site-packages');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DependencyConfig, RegistryConfig, ServerInstallOptions, EnvVariableConfig } from '../../core/types.js';
|
|
2
|
-
import { ServerSchema } from '../../core/ServerSchemaProvider.js';
|
|
1
|
+
import { DependencyConfig, RegistryConfig, ServerInstallOptions, EnvVariableConfig } from '../../core/metadatas/types.js';
|
|
2
|
+
import { ServerSchema } from '../../core/loaders/ServerSchemaProvider.js';
|
|
3
3
|
|
|
4
4
|
export interface OnboardServerConfig {
|
|
5
5
|
name: string;
|