@mearl/mcp-server 2.8.2 → 2.9.0

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.
@@ -0,0 +1,6 @@
1
+ export type McpCliMode = 'server' | 'configure' | 'uninstall' | 'help' | 'version';
2
+ export interface ParsedMcpArgs {
3
+ forwardedArgs: string[];
4
+ mode: McpCliMode;
5
+ }
6
+ export declare function parseMcpArgs(argv: string[]): Promise<ParsedMcpArgs>;
@@ -0,0 +1,84 @@
1
+ export async function parseMcpArgs(argv) {
2
+ if (argv.length === 0)
3
+ return { forwardedArgs: [], mode: 'server' };
4
+ const { Command, CommanderError } = await import('commander');
5
+ const configureAlias = argv.includes('--configure');
6
+ const uninstallAlias = argv.includes('--uninstall');
7
+ if (configureAlias && uninstallAlias) {
8
+ throw new Error('--configure and --uninstall cannot be used together');
9
+ }
10
+ const compatibilityMode = configureAlias ? 'configure' : uninstallAlias ? 'uninstall' : undefined;
11
+ const normalizedArgv = compatibilityMode
12
+ ? [compatibilityMode, ...argv.filter(arg => arg !== '--configure' && arg !== '--uninstall')]
13
+ : argv;
14
+ const program = new Command()
15
+ .name('mearl-mcp-server')
16
+ .helpOption(false)
17
+ .allowExcessArguments(false)
18
+ .exitOverride()
19
+ .configureOutput({ writeErr: () => { }, writeOut: () => { } })
20
+ .argument('[command]')
21
+ .option('--extension-id <id>')
22
+ .option('--id <id>')
23
+ .option('--skip-mcp')
24
+ .option('--get')
25
+ .option('--global-install')
26
+ .option('--managed-by-setup')
27
+ .option('-y, --yes')
28
+ .option('--non-interactive')
29
+ .option('-h, --help')
30
+ .option('-v, --version');
31
+ try {
32
+ program.parse(['node', 'mearl-mcp-server', ...normalizedArgv]);
33
+ }
34
+ catch (error) {
35
+ if (error instanceof CommanderError) {
36
+ throw new Error(error.message.replace(/^error:\s*/i, ''), { cause: error });
37
+ }
38
+ throw error;
39
+ }
40
+ const options = program.opts();
41
+ if (options.help)
42
+ return { forwardedArgs: [], mode: 'help' };
43
+ if (options.version)
44
+ return { forwardedArgs: [], mode: 'version' };
45
+ const command = program.processedArgs[0];
46
+ if (command !== 'configure' && command !== 'uninstall') {
47
+ throw new Error(command ? `Unknown command: ${command}` : 'configure or uninstall is required');
48
+ }
49
+ const configureOnly = [
50
+ ['extensionId', '--extension-id'],
51
+ ['id', '--id'],
52
+ ['skipMcp', '--skip-mcp'],
53
+ ['get', '--get'],
54
+ ['globalInstall', '--global-install'],
55
+ ];
56
+ const uninstallOnly = [['managedBySetup', '--managed-by-setup']];
57
+ const disallowed = command === 'configure' ? uninstallOnly : configureOnly;
58
+ for (const [name, flag] of disallowed) {
59
+ if (program.getOptionValueSource(name) === 'cli') {
60
+ throw new Error(`${flag} is not available for ${command}`);
61
+ }
62
+ }
63
+ if (options.extensionId && options.id && options.extensionId !== options.id) {
64
+ throw new Error('--extension-id and --id cannot specify different values');
65
+ }
66
+ const forwardedArgs = [];
67
+ if (command === 'configure') {
68
+ const extensionId = options.extensionId ?? options.id;
69
+ if (extensionId)
70
+ forwardedArgs.push('--extension-id', extensionId);
71
+ if (options.skipMcp)
72
+ forwardedArgs.push('--skip-mcp');
73
+ if (options.get)
74
+ forwardedArgs.push('--get');
75
+ if (options.globalInstall)
76
+ forwardedArgs.push('--global-install');
77
+ }
78
+ else if (options.managedBySetup) {
79
+ forwardedArgs.push('--managed-by-setup');
80
+ }
81
+ if (options.yes || options.nonInteractive)
82
+ forwardedArgs.push('--yes');
83
+ return { forwardedArgs, mode: command };
84
+ }
@@ -13,6 +13,7 @@ export interface ConfigureArgs {
13
13
  extensionId?: string;
14
14
  get: boolean;
15
15
  globalInstall: boolean;
16
+ help: boolean;
16
17
  skipMcp: boolean;
17
18
  yes: boolean;
18
19
  }
package/dist/configure.js CHANGED
@@ -15,39 +15,63 @@ import path, { dirname, join } from 'node:path';
15
15
  import { fileURLToPath } from 'node:url';
16
16
  import { HOST_NAME, DEFAULT_EXTENSION_ID } from './constants.js';
17
17
  import prompts from 'prompts';
18
+ import { Command, CommanderError } from 'commander';
18
19
  import { MCP_CLIENTS, getMCPServerConfig, isNpxMode, isClientInstalled, } from './mcp-clients.js';
19
20
  // 日志输出
20
21
  const log = (...args) => {
21
22
  console.log('[Configure]', ...args);
22
23
  };
23
- // 解析命令行参数
24
+ class ConfigureUsageError extends Error {
25
+ name = 'ConfigureUsageError';
26
+ }
24
27
  export function parseConfigureArgs(args = process.argv.slice(2)) {
25
- let extensionId;
26
- let skipMcp = false;
27
- let get = false;
28
- let globalInstall = false;
29
- let yes = false;
30
- for (const arg of args) {
31
- if (arg.startsWith('--extension-id=')) {
32
- extensionId = arg.split('=')[1];
33
- }
34
- else if (arg.startsWith('--id=')) {
35
- extensionId = arg.split('=')[1];
36
- }
37
- else if (arg === '--skip-mcp') {
38
- skipMcp = true;
39
- }
40
- else if (arg === '--get') {
41
- get = true;
42
- }
43
- else if (arg === '--global-install') {
44
- globalInstall = true;
45
- }
46
- else if (arg === '--yes' || arg === '-y' || arg === '--non-interactive') {
47
- yes = true;
28
+ const program = new Command()
29
+ .name('mearl-mcp-configure')
30
+ .helpOption(false)
31
+ .allowExcessArguments(false)
32
+ .exitOverride()
33
+ .configureOutput({ writeErr: () => { }, writeOut: () => { } })
34
+ .option('--extension-id <id>')
35
+ .option('--id <id>')
36
+ .option('--skip-mcp')
37
+ .option('--get')
38
+ .option('--global-install')
39
+ .option('-y, --yes')
40
+ .option('--non-interactive')
41
+ .option('-h, --help');
42
+ try {
43
+ program.parse(['node', 'mearl-mcp-configure', ...args]);
44
+ }
45
+ catch (error) {
46
+ if (error instanceof CommanderError) {
47
+ throw new ConfigureUsageError(error.message.replace(/^error:\s*/i, ''), { cause: error });
48
48
  }
49
+ throw error;
50
+ }
51
+ const options = program.opts();
52
+ if (options.extensionId && options.id && options.extensionId !== options.id) {
53
+ throw new ConfigureUsageError('--extension-id and --id cannot specify different values');
49
54
  }
50
- return { extensionId, skipMcp, get, globalInstall, yes };
55
+ return {
56
+ extensionId: options.extensionId ?? options.id,
57
+ get: options.get === true,
58
+ globalInstall: options.globalInstall === true,
59
+ help: options.help === true,
60
+ skipMcp: options.skipMcp === true,
61
+ yes: options.yes === true || options.nonInteractive === true,
62
+ };
63
+ }
64
+ function printConfigureHelp() {
65
+ console.log(`Usage: mearl-mcp-configure [options]
66
+
67
+ Options:
68
+ --extension-id <id> Configure a custom extension ID
69
+ --skip-mcp Skip MCP client configuration
70
+ --get Print current configuration
71
+ --global-install Use the globally installed command
72
+ --yes, -y Configure detected clients without prompts
73
+ --non-interactive Alias for --yes
74
+ --help, -h Show this help`);
51
75
  }
52
76
  // 替换或追加 TOML 中的 mcp_servers.xxx 节
53
77
  function replaceTOMLSection(content, serverName, newSectionLines) {
@@ -211,7 +235,11 @@ export function shouldUseNpx(globalInstall, detectNpxMode = isNpxMode) {
211
235
  return !globalInstall && detectNpxMode();
212
236
  }
213
237
  export async function runConfigure(argv = process.argv.slice(2)) {
214
- const { extensionId, get, globalInstall, skipMcp, yes } = parseConfigureArgs(argv);
238
+ const { extensionId, get, globalInstall, help, skipMcp, yes } = parseConfigureArgs(argv);
239
+ if (help) {
240
+ printConfigureHelp();
241
+ return;
242
+ }
215
243
  // 如果是查看配置,显示后退出
216
244
  if (get) {
217
245
  showCurrentConfig();
@@ -328,7 +356,7 @@ if (process.argv[1] && path.resolve(process.argv[1]) === currentFile) {
328
356
  await runConfigure();
329
357
  }
330
358
  catch (error) {
331
- console.error('Configuration failed:', error);
332
- process.exitCode = 1;
359
+ console.error(`Configuration failed: ${error instanceof Error ? error.message : String(error)}`);
360
+ process.exitCode = error instanceof ConfigureUsageError ? 2 : 1;
333
361
  }
334
362
  }