deveco-mcp-server 0.1.13 → 0.1.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.
Files changed (2) hide show
  1. package/index.js +36 -357
  2. package/package.json +2 -8
package/index.js CHANGED
@@ -1,375 +1,54 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { spawn, execSync } = require('child_process');
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 OFFICIAL_REGISTRY = 'https://registry.npmjs.org';
9
- const INSTALL_TIMEOUT = 60000;
10
- const VERSION_CHECK_TIMEOUT = 5000; // 版本检查超时时间(5秒)
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 getPlatformPackage() {
13
- const platform = process.platform;
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) {
34
- return null;
35
- }
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
- try {
149
- const output = execSync(`npm view ${packageName} version --registry=${OFFICIAL_REGISTRY}`, {
150
- encoding: 'utf-8',
151
- timeout: VERSION_CHECK_TIMEOUT,
152
- stdio: ['ignore', 'pipe', 'ignore']
153
- });
154
- return output.trim();
155
- } catch (err) {
9
+ function safeParseJson(value) {
10
+ if (!value) {
156
11
  return null;
157
12
  }
158
- }
159
-
160
- function compareVersions(version1, version2) {
161
- // 简单的版本比较,如果需要更复杂的可以使用 semver 库
162
- const v1parts = version1.split('.').map(Number);
163
- const v2parts = version2.split('.').map(Number);
164
-
165
- for (let i = 0; i < Math.max(v1parts.length, v2parts.length); i++) {
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
13
  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
- }
14
+ return JSON.parse(value);
15
+ } catch (_) {
204
16
  return null;
205
17
  }
206
18
  }
207
19
 
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
- function getBinaryPaths() {
261
- const packageName = getPlatformPackage();
262
-
263
- // Try to resolve existing package
264
- try {
265
- const packagePath = require.resolve(packageName);
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
- function ensureExecutablePermissions(filePath) {
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
- function startServer() {
346
- const { server: serverExePath } = getBinaryPaths();
347
-
348
- if (!fs.existsSync(serverExePath)) {
349
- console.error(`Error: Server executable not found at ${serverExePath}`);
350
- console.error('Please run: npm install --force');
351
- process.exit(1);
352
- }
353
-
354
- // Ensure execution permissions on Unix-like systems
355
- ensureExecutablePermissions(serverExePath);
37
+ const forwardTarget = isOfficialChannelInvocation()
38
+ ? NEW_PACKAGE_LATEST_SPEC
39
+ : NEW_PACKAGE_BETA_SPEC;
40
+ const args = ['-y', forwardTarget, ...process.argv.slice(2)];
356
41
 
357
- const args = process.argv.slice(2);
358
- const env = { ...process.env };
42
+ const child = spawn(npxCommand, args, {
43
+ stdio: 'inherit',
44
+ env: { ...process.env }
45
+ });
359
46
 
360
- const child = spawn(serverExePath, args, {
361
- stdio: 'inherit',
362
- env: env
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
- }
47
+ child.on('error', (err) => {
48
+ console.error(`Failed to forward to ${forwardTarget}:`, err.message);
49
+ process.exit(1);
50
+ });
374
51
 
375
- startServer();
52
+ child.on('close', (code) => {
53
+ process.exit(code ?? 1);
54
+ });
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "deveco-mcp-server",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
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"