deveco-mcp-server 0.1.13 → 0.1.15
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/index.js +41 -356
- package/package.json +2 -8
package/index.js
CHANGED
|
@@ -1,375 +1,60 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { spawn
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const os = require('os');
|
|
3
|
+
const { spawn } = require('child_process');
|
|
7
4
|
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
5
|
+
const NEW_PACKAGE_BETA_SPEC = '@deveco-codegenie/mcp@beta';
|
|
6
|
+
const NEW_PACKAGE_LATEST_SPEC = '@deveco-codegenie/mcp@latest';
|
|
7
|
+
const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
11
8
|
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
const arch = process.arch;
|
|
15
|
-
|
|
16
|
-
const platformMap = {
|
|
17
|
-
'win32-x64': 'deveco-mcp-server-win32-x64',
|
|
18
|
-
'darwin-x64': 'deveco-mcp-server-darwin-x64',
|
|
19
|
-
'darwin-arm64': 'deveco-mcp-server-darwin-arm64'
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const key = `${platform}-${arch}`;
|
|
23
|
-
if (platformMap[key]) {
|
|
24
|
-
return platformMap[key];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
throw new Error(`Unsupported platform: ${platform}-${arch}`);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function getNpmRegistry() {
|
|
31
|
-
try {
|
|
32
|
-
return execSync('npm config get registry', { encoding: 'utf-8' }).trim();
|
|
33
|
-
} catch (err) {
|
|
9
|
+
function safeParseJson(value) {
|
|
10
|
+
if (!value) {
|
|
34
11
|
return null;
|
|
35
12
|
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function checkAndWarnRegistry() {
|
|
39
|
-
const registry = getNpmRegistry();
|
|
40
|
-
if (registry && !registry.includes('npmjs.org')) {
|
|
41
|
-
console.warn(`\n⚠️ Detected non-official npm registry: ${registry}`);
|
|
42
|
-
console.warn(`Auto-install will use official registry (${OFFICIAL_REGISTRY}) to ensure package availability.\n`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function buildBinaryPaths(binDir) {
|
|
47
|
-
if (process.platform === 'win32') {
|
|
48
|
-
return {
|
|
49
|
-
server: path.join(binDir, 'deveco-mcp-server.exe')
|
|
50
|
-
};
|
|
51
|
-
} else {
|
|
52
|
-
return {
|
|
53
|
-
server: path.join(binDir, 'Contents', 'MacOS', 'deveco-mcp-server')
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function isNpxEnvironment() {
|
|
59
|
-
return __dirname.includes('_npx') ||
|
|
60
|
-
__dirname.includes('npm-cache') ||
|
|
61
|
-
__dirname.includes('npx-') ||
|
|
62
|
-
!!process.env.npm_config_user_config;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function getInstallDirectory() {
|
|
66
|
-
if (isNpxEnvironment()) {
|
|
67
|
-
const installDir = path.join(os.homedir(), '.deveco-mcp-cache');
|
|
68
|
-
if (!fs.existsSync(installDir)) {
|
|
69
|
-
fs.mkdirSync(installDir, { recursive: true });
|
|
70
|
-
}
|
|
71
|
-
return installDir;
|
|
72
|
-
}
|
|
73
|
-
return __dirname;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function findInstalledPackage(packageName, installDir) {
|
|
77
|
-
const nodeModulesPath = path.join(installDir, 'node_modules', packageName);
|
|
78
|
-
const packageJsonPath = path.join(nodeModulesPath, 'package.json');
|
|
79
|
-
|
|
80
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
81
|
-
return nodeModulesPath;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Try to resolve using require with multiple paths
|
|
85
|
-
const searchPaths = [
|
|
86
|
-
installDir,
|
|
87
|
-
path.join(installDir, 'node_modules'),
|
|
88
|
-
__dirname,
|
|
89
|
-
path.join(__dirname, 'node_modules')
|
|
90
|
-
];
|
|
91
|
-
|
|
92
|
-
for (const searchPath of searchPaths) {
|
|
93
|
-
try {
|
|
94
|
-
const packagePath = require.resolve(packageName, { paths: [searchPath] });
|
|
95
|
-
return path.dirname(packagePath);
|
|
96
|
-
} catch (resolveErr) {
|
|
97
|
-
// Continue to next path
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return nodeModulesPath;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function installPackage(packageName, installDir) {
|
|
105
|
-
try {
|
|
106
|
-
execSync(`npm install ${packageName}`, {
|
|
107
|
-
stdio: 'ignore',
|
|
108
|
-
cwd: installDir,
|
|
109
|
-
timeout: INSTALL_TIMEOUT
|
|
110
|
-
});
|
|
111
|
-
return findInstalledPackage(packageName, installDir);
|
|
112
|
-
} catch (installErr) {
|
|
113
|
-
// Try alternative: install to current directory with official registry
|
|
114
|
-
try {
|
|
115
|
-
execSync(`npm install --registry=${OFFICIAL_REGISTRY} ${packageName}`, {
|
|
116
|
-
stdio: 'ignore',
|
|
117
|
-
cwd: __dirname,
|
|
118
|
-
timeout: INSTALL_TIMEOUT
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
const localNodeModules = path.join(__dirname, 'node_modules', packageName);
|
|
122
|
-
const localPackageJson = path.join(localNodeModules, 'package.json');
|
|
123
|
-
|
|
124
|
-
if (fs.existsSync(localPackageJson)) {
|
|
125
|
-
return localNodeModules;
|
|
126
|
-
}
|
|
127
|
-
throw installErr;
|
|
128
|
-
} catch (altErr) {
|
|
129
|
-
throw new Error('All installation attempts failed');
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function getLocalVersion(packageName, binDir) {
|
|
135
|
-
try {
|
|
136
|
-
const packageJsonPath = path.join(binDir, 'package.json');
|
|
137
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
138
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
139
|
-
return packageJson.version || null;
|
|
140
|
-
}
|
|
141
|
-
} catch (err) {
|
|
142
|
-
// 忽略错误
|
|
143
|
-
}
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function getLatestVersion(packageName) {
|
|
148
13
|
try {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
timeout: VERSION_CHECK_TIMEOUT,
|
|
152
|
-
stdio: ['ignore', 'pipe', 'ignore']
|
|
153
|
-
});
|
|
154
|
-
return output.trim();
|
|
155
|
-
} catch (err) {
|
|
14
|
+
return JSON.parse(value);
|
|
15
|
+
} catch (_) {
|
|
156
16
|
return null;
|
|
157
17
|
}
|
|
158
18
|
}
|
|
159
19
|
|
|
160
|
-
function
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const v1part = v1parts[i] || 0;
|
|
167
|
-
const v2part = v2parts[i] || 0;
|
|
168
|
-
if (v1part < v2part) return -1;
|
|
169
|
-
if (v1part > v2part) return 1;
|
|
170
|
-
}
|
|
171
|
-
return 0;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function shouldSkipUpdate() {
|
|
175
|
-
// 默认自动更新,除非明确禁用
|
|
176
|
-
return process.env.DEVECO_MCP_NO_AUTO_UPDATE === 'true' ||
|
|
177
|
-
process.argv.includes('--no-update') ||
|
|
178
|
-
process.argv.includes('--skip-update');
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function updatePackage(packageName, installDir) {
|
|
182
|
-
try {
|
|
183
|
-
execSync(`npm install ${packageName}@latest --registry=${OFFICIAL_REGISTRY}`, {
|
|
184
|
-
stdio: 'ignore',
|
|
185
|
-
cwd: installDir,
|
|
186
|
-
timeout: INSTALL_TIMEOUT
|
|
187
|
-
});
|
|
188
|
-
return findInstalledPackage(packageName, installDir);
|
|
189
|
-
} catch (err) {
|
|
190
|
-
// 如果更新失败,尝试在当前目录更新
|
|
191
|
-
try {
|
|
192
|
-
execSync(`npm install ${packageName}@latest --registry=${OFFICIAL_REGISTRY}`, {
|
|
193
|
-
stdio: 'ignore',
|
|
194
|
-
cwd: __dirname,
|
|
195
|
-
timeout: INSTALL_TIMEOUT
|
|
196
|
-
});
|
|
197
|
-
const localNodeModules = path.join(__dirname, 'node_modules', packageName);
|
|
198
|
-
if (fs.existsSync(path.join(localNodeModules, 'package.json'))) {
|
|
199
|
-
return localNodeModules;
|
|
200
|
-
}
|
|
201
|
-
} catch (altErr) {
|
|
202
|
-
// 更新失败,返回null
|
|
203
|
-
}
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function checkAndUpdateIfNeeded(packageName, binDir) {
|
|
209
|
-
const localVersion = getLocalVersion(packageName, binDir);
|
|
210
|
-
if (!localVersion) {
|
|
211
|
-
return binDir; // 无法获取本地版本,直接返回
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const latestVersion = getLatestVersion(packageName);
|
|
215
|
-
if (!latestVersion) {
|
|
216
|
-
return binDir; // 无法获取最新版本,直接返回
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (compareVersions(localVersion, latestVersion) < 0) {
|
|
220
|
-
// 本地版本较旧,默认自动更新
|
|
221
|
-
if (shouldSkipUpdate()) {
|
|
222
|
-
// 用户明确禁用了自动更新,仅提示
|
|
223
|
-
console.warn(`\n⚠️ New version available: ${latestVersion} (current: ${localVersion})`);
|
|
224
|
-
console.warn(` To enable auto-update, remove --no-update flag or DEVECO_MCP_NO_AUTO_UPDATE env var`);
|
|
225
|
-
console.warn(` Or manually run: npm install -g ${packageName}@latest\n`);
|
|
226
|
-
return binDir;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// 默认自动更新
|
|
230
|
-
const installDir = getInstallDirectory();
|
|
231
|
-
const updatedBinDir = updatePackage(packageName, installDir);
|
|
232
|
-
if (updatedBinDir) {
|
|
233
|
-
return updatedBinDir;
|
|
234
|
-
} else {
|
|
235
|
-
console.error(`⚠️ Failed to update ${packageName}, using existing version ${localVersion}`);
|
|
236
|
-
return binDir;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return binDir;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function printTroubleshootingSteps(packageName) {
|
|
244
|
-
console.error('\n❌ Failed to install platform package automatically.');
|
|
245
|
-
console.error('\nTroubleshooting steps:');
|
|
246
|
-
console.error(`\n1. Check npm registry (should be ${OFFICIAL_REGISTRY}/):`);
|
|
247
|
-
console.error(` npm config get registry`);
|
|
248
|
-
console.error(` npm config set registry ${OFFICIAL_REGISTRY}/`);
|
|
249
|
-
console.error(`\n2. Clear npm cache:`);
|
|
250
|
-
console.error(` npm cache clean --force`);
|
|
251
|
-
console.error(`\n3. Manual install (recommended):`);
|
|
252
|
-
console.error(` npm install -g ${packageName}`);
|
|
253
|
-
console.error(` npm install -g deveco-mcp-server`);
|
|
254
|
-
console.error(`\n4. Or use with registry flag in MCP config:`);
|
|
255
|
-
console.error(` "args": ["--registry=${OFFICIAL_REGISTRY}", "-y", "deveco-mcp-server"]`);
|
|
256
|
-
console.error(`\n5. Check if package exists:`);
|
|
257
|
-
console.error(` npm view ${packageName}`);
|
|
258
|
-
}
|
|
20
|
+
function isOfficialChannelInvocation() {
|
|
21
|
+
const npmArgv = safeParseJson(process.env.npm_config_argv);
|
|
22
|
+
const argvHints = [
|
|
23
|
+
...(Array.isArray(npmArgv?.original) ? npmArgv.original : []),
|
|
24
|
+
...(Array.isArray(npmArgv?.cooked) ? npmArgv.cooked : [])
|
|
25
|
+
];
|
|
259
26
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
let binDir = path.dirname(packagePath);
|
|
267
|
-
|
|
268
|
-
// Check for updates if package is found locally
|
|
269
|
-
binDir = checkAndUpdateIfNeeded(packageName, binDir);
|
|
270
|
-
|
|
271
|
-
const binaryPaths = buildBinaryPaths(binDir);
|
|
272
|
-
|
|
273
|
-
// Verify server binary exists
|
|
274
|
-
if (!fs.existsSync(binaryPaths.server)) {
|
|
275
|
-
console.error(`Error: Server executable not found at ${binaryPaths.server}`);
|
|
276
|
-
console.error('Please run: npm install --force');
|
|
277
|
-
process.exit(1);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return binaryPaths;
|
|
281
|
-
} catch (err) {
|
|
282
|
-
|
|
283
|
-
checkAndWarnRegistry();
|
|
284
|
-
|
|
285
|
-
const installDir = getInstallDirectory();
|
|
286
|
-
let binDir;
|
|
287
|
-
|
|
288
|
-
try {
|
|
289
|
-
binDir = installPackage(packageName, installDir);
|
|
290
|
-
} catch (installErr) {
|
|
291
|
-
printTroubleshootingSteps(packageName);
|
|
292
|
-
process.exit(1);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Verify the installed package exists and has the expected structure
|
|
296
|
-
if (!binDir || !fs.existsSync(binDir)) {
|
|
297
|
-
console.error('Failed to locate installed platform package.');
|
|
298
|
-
process.exit(1);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const binaryPaths = buildBinaryPaths(binDir);
|
|
302
|
-
|
|
303
|
-
// Verify server binary exists
|
|
304
|
-
if (!fs.existsSync(binaryPaths.server)) {
|
|
305
|
-
console.error(`Installed package found at ${binDir}, but binary not at expected location.`);
|
|
306
|
-
console.error(`Expected: ${binaryPaths.server}`);
|
|
307
|
-
process.exit(1);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return binaryPaths;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
27
|
+
const textHints = [
|
|
28
|
+
process.env.npm_config_argv,
|
|
29
|
+
process.env.npm_lifecycle_script,
|
|
30
|
+
process.env.npm_config_call,
|
|
31
|
+
...argvHints
|
|
32
|
+
].filter(Boolean);
|
|
313
33
|
|
|
314
|
-
|
|
315
|
-
if (process.platform === 'win32') {
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
try {
|
|
320
|
-
fs.chmodSync(filePath, 0o755);
|
|
321
|
-
} catch (err) {
|
|
322
|
-
console.error(`Warning: Failed to set executable permissions for ${filePath}: ${err.message}`);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// On macOS, remove quarantine attribute and ad-hoc sign to avoid "Unknown system error -86"
|
|
326
|
-
if (process.platform === 'darwin') {
|
|
327
|
-
try {
|
|
328
|
-
// Remove quarantine attribute
|
|
329
|
-
execSync(`xattr -d com.apple.quarantine "${filePath}" 2>/dev/null || true`, {
|
|
330
|
-
stdio: 'ignore',
|
|
331
|
-
timeout: 5000
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
// Ad-hoc sign the binary
|
|
335
|
-
execSync(`codesign --force --sign - "${filePath}" 2>/dev/null`, {
|
|
336
|
-
stdio: 'ignore',
|
|
337
|
-
timeout: 10000
|
|
338
|
-
});
|
|
339
|
-
} catch (err) {
|
|
340
|
-
// Silently ignore - binary might already be signed or user lacks permissions
|
|
341
|
-
}
|
|
342
|
-
}
|
|
34
|
+
return textHints.some((value) => /deveco-mcp-server@official\b/i.test(String(value)));
|
|
343
35
|
}
|
|
344
36
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
console.error('Please run: npm install --force');
|
|
351
|
-
process.exit(1);
|
|
352
|
-
}
|
|
37
|
+
const forwardTarget = isOfficialChannelInvocation()
|
|
38
|
+
? NEW_PACKAGE_LATEST_SPEC
|
|
39
|
+
: NEW_PACKAGE_BETA_SPEC;
|
|
40
|
+
const passthroughArgs = process.argv.slice(2);
|
|
41
|
+
const npmExecPath = process.env.npm_execpath;
|
|
353
42
|
|
|
354
|
-
|
|
355
|
-
|
|
43
|
+
const command = npmExecPath ? process.execPath : npxCommand;
|
|
44
|
+
const args = npmExecPath
|
|
45
|
+
? [npmExecPath, 'exec', '--yes', forwardTarget, '--', ...passthroughArgs]
|
|
46
|
+
: ['-y', forwardTarget, ...passthroughArgs];
|
|
356
47
|
|
|
357
|
-
|
|
358
|
-
|
|
48
|
+
const child = spawn(command, args, {
|
|
49
|
+
stdio: 'inherit',
|
|
50
|
+
env: { ...process.env }
|
|
51
|
+
});
|
|
359
52
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
child.on('error', (err) => {
|
|
366
|
-
console.error('Failed to start deveco-mcp-server:', err);
|
|
367
|
-
process.exit(1);
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
child.on('close', (code) => {
|
|
371
|
-
process.exit(code);
|
|
372
|
-
});
|
|
373
|
-
}
|
|
53
|
+
child.on('error', (err) => {
|
|
54
|
+
console.error(`Failed to forward to ${forwardTarget}:`, err.message);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
});
|
|
374
57
|
|
|
375
|
-
|
|
58
|
+
child.on('close', (code) => {
|
|
59
|
+
process.exit(code ?? 1);
|
|
60
|
+
});
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deveco-mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "NPM wrapper for deveco-mcp-server - HarmonyOS development MCP server with platform-specific binaries",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
7
7
|
"harmonyos",
|
|
8
8
|
"deveco",
|
|
9
|
-
"arkts"
|
|
10
|
-
"language-server"
|
|
9
|
+
"arkts"
|
|
11
10
|
],
|
|
12
11
|
"files": [
|
|
13
12
|
"index.js"
|
|
@@ -15,11 +14,6 @@
|
|
|
15
14
|
"bin": {
|
|
16
15
|
"deveco-mcp-server": "index.js"
|
|
17
16
|
},
|
|
18
|
-
"optionalDependencies": {
|
|
19
|
-
"deveco-mcp-server-darwin-arm64": "0.1.13",
|
|
20
|
-
"deveco-mcp-server-darwin-x64": "0.1.13",
|
|
21
|
-
"deveco-mcp-server-win32-x64": "^0.1.13"
|
|
22
|
-
},
|
|
23
17
|
"repository": {
|
|
24
18
|
"type": "git",
|
|
25
19
|
"url": "https://github.com/open-deveco/deveco-toolbox.git"
|