@meldocio/mcp-stdio-proxy 1.0.23 → 1.0.24

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/bin/cli.js CHANGED
@@ -1,1083 +1,59 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { interactiveLogin } = require('../lib/device-flow');
4
- const { readCredentials, deleteCredentials } = require('../lib/credentials');
5
- const { getAuthStatus } = require('../lib/auth');
6
- const { setWorkspaceAlias, getWorkspaceAlias } = require('../lib/config');
7
- const { getAccessToken } = require('../lib/auth');
8
- const { getApiUrl, getAppUrl } = require('../lib/constants');
9
- const axios = require('axios');
10
- const https = require('https');
11
- const chalk = require('chalk');
12
- const logger = require('../lib/logger');
13
- const fs = require('fs');
14
- const path = require('path');
15
- const os = require('os');
16
-
17
- const API_URL = getApiUrl();
18
- const APP_URL = getAppUrl();
19
-
20
- // Support localhost testing
21
- if (process.env.MELDOC_API_URL) {
22
- logger.debug(`Using API URL: ${process.env.MELDOC_API_URL}`);
23
- }
24
- if (process.env.MELDOC_APP_URL) {
25
- logger.debug(`Using App URL: ${process.env.MELDOC_APP_URL}`);
26
- }
27
-
28
- /**
29
- * Handle auth login command
30
- */
31
- async function handleAuthLogin() {
32
- try {
33
- await interactiveLogin({
34
- autoOpen: true,
35
- showQR: false,
36
- timeout: 120000,
37
- apiBaseUrl: API_URL,
38
- appUrl: APP_URL
39
- });
40
- process.exit(0);
41
- } catch (error) {
42
- process.exit(1);
43
- }
44
- }
45
-
46
- /**
47
- * Handle auth status command
48
- */
49
- async function handleAuthStatus() {
50
- const status = await getAuthStatus();
51
- if (!status || !status.authenticated) {
52
- logger.error('Not authenticated');
53
- console.log('\n' + logger.label('To authenticate, run:'));
54
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login') + '\n');
55
- process.exit(1);
56
- }
57
-
58
- logger.section('🔑 Authentication Status');
59
-
60
- if (status.type === 'user_session' && status.user) {
61
- logger.item('Email', logger.value(status.user.email));
62
- if (status.expiresAt) {
63
- logger.item('Token expires', logger.value(new Date(status.expiresAt).toLocaleString()));
64
- }
65
- } else {
66
- logger.item('Type', logger.value(status.type));
67
- }
68
-
69
- console.log();
70
- process.exit(0);
71
- }
72
-
73
- /**
74
- * Handle auth logout command
75
- */
76
- async function handleAuthLogout() {
77
- deleteCredentials();
78
- logger.success('Logged out successfully');
79
- process.exit(0);
80
- }
81
-
82
- /**
83
- * Handle config set-workspace command
84
- */
85
- function handleConfigSetWorkspace(alias) {
86
- if (!alias) {
87
- logger.error('Workspace alias is required');
88
- console.log('\n' + logger.label('Usage:'));
89
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy config set-workspace <alias>') + '\n');
90
- process.exit(1);
91
- }
92
-
93
- try {
94
- setWorkspaceAlias(alias);
95
- logger.success(`Workspace set to: ${logger.highlight(alias)}`);
96
- process.exit(0);
97
- } catch (error) {
98
- logger.error(`Failed to set workspace: ${error.message}`);
99
- process.exit(1);
100
- }
101
- }
102
-
103
- /**
104
- * Handle config get-workspace command
105
- */
106
- function handleConfigGetWorkspace() {
107
- const alias = getWorkspaceAlias();
108
- if (alias) {
109
- console.log(logger.highlight(alias));
110
- }
111
- process.exit(0);
112
- }
113
-
114
- /**
115
- * Handle config list-workspaces command
116
- */
117
- async function handleConfigListWorkspaces() {
118
- try {
119
- const tokenInfo = await getAccessToken();
120
- if (!tokenInfo) {
121
- logger.error('Not authenticated');
122
- console.log('\n' + logger.label('To authenticate, run:'));
123
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login') + '\n');
124
- process.exit(1);
125
- }
126
-
127
- // Call MCP tool meldoc.list_workspaces via POST /mcp/v1/rpc
128
- const response = await axios.post(`${API_URL}/mcp/v1/rpc`, {
129
- jsonrpc: '2.0',
130
- id: 1,
131
- method: 'tools/call',
132
- params: {
133
- name: 'meldoc.list_workspaces',
134
- arguments: {}
135
- }
136
- }, {
137
- headers: {
138
- 'Authorization': `Bearer ${tokenInfo.token}`,
139
- 'Content-Type': 'application/json'
140
- },
141
- timeout: 10000,
142
- httpsAgent: new https.Agent({ keepAlive: true })
143
- });
144
-
145
- if (response.data.error) {
146
- logger.error(`Error: ${response.data.error.message}`);
147
- process.exit(1);
148
- }
149
-
150
- const workspaces = response.data.result?.workspaces || [];
151
- if (workspaces.length === 0) {
152
- logger.info('No workspaces available');
153
- process.exit(0);
154
- }
155
-
156
- logger.section('📁 Available Workspaces');
157
- for (const ws of workspaces) {
158
- const role = ws.role || 'member';
159
- const roleColor = role === 'owner' ? chalk.red : role === 'admin' ? chalk.yellow : chalk.gray;
160
- logger.item(
161
- `${logger.highlight(ws.alias)} ${chalk.gray('(' + ws.name + ')')}`,
162
- roleColor(`[${role}]`)
163
- );
164
- }
165
- console.log();
166
-
167
- process.exit(0);
168
- } catch (error) {
169
- if (error.response?.data?.error) {
170
- const errorData = error.response.data.error;
171
- if (errorData.code === 'AUTH_REQUIRED' || errorData.data?.code === 'AUTH_REQUIRED') {
172
- logger.error('Not authenticated');
173
- console.log('\n' + logger.label('To authenticate, run:'));
174
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login') + '\n');
175
- process.exit(1);
176
- }
177
- logger.error(`Error: ${errorData.message || error.message}`);
178
- } else {
179
- logger.error(`Error: ${error.message}`);
180
- }
181
- process.exit(1);
182
- }
183
- }
184
-
185
- /**
186
- * Get Claude Desktop config file path based on OS
187
- */
188
- function getClaudeDesktopConfigPath() {
189
- const platform = os.platform();
190
- const homeDir = os.homedir();
191
-
192
- if (platform === 'darwin') {
193
- // macOS
194
- return path.join(homeDir, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
195
- } else if (platform === 'win32') {
196
- // Windows
197
- const appData = process.env.APPDATA || path.join(homeDir, 'AppData', 'Roaming');
198
- return path.join(appData, 'Claude', 'claude_desktop_config.json');
199
- } else {
200
- // Linux and others
201
- return path.join(homeDir, '.config', 'Claude', 'claude_desktop_config.json');
202
- }
203
- }
204
-
205
- /**
206
- * Get Cursor config file path (project-specific)
207
- */
208
- function getCursorProjectConfigPath() {
209
- const cwd = process.cwd();
210
- return path.join(cwd, '.cursor', 'mcp.json');
211
- }
212
-
213
- /**
214
- * Get Cursor global config file path
215
- */
216
- function getCursorGlobalConfigPath() {
217
- const homeDir = os.homedir();
218
- return path.join(homeDir, '.cursor', 'mcp.json');
219
- }
220
-
221
- /**
222
- * Get local mcp.json path (in current directory)
223
- */
224
- function getLocalMcpJsonPath() {
225
- return path.join(process.cwd(), 'mcp.json');
226
- }
227
-
228
- /**
229
- * Get Claude Code project config path (.mcp.json)
230
- */
231
- function getClaudeCodeProjectConfigPath() {
232
- return path.join(process.cwd(), '.mcp.json');
233
- }
234
-
235
- /**
236
- * Get Claude Code user config path (~/.claude.json)
237
- */
238
- function getClaudeCodeUserConfigPath() {
239
- return path.join(os.homedir(), '.claude.json');
240
- }
241
-
242
- /**
243
- * Get Claude Code local config path (~/.claude.json in project path)
244
- * Note: Local scope uses ~/.claude.json but stores project-specific paths
245
- */
246
- function getClaudeCodeLocalConfigPath() {
247
- // For local scope, Claude Code uses ~/.claude.json with project-specific paths
248
- // This is the same file as user scope, but with different path context
249
- return path.join(os.homedir(), '.claude.json');
250
- }
251
-
252
- /**
253
- * Get expected Meldoc MCP configuration for Claude Desktop
254
- */
255
- function getExpectedMeldocConfig() {
256
- return {
257
- command: 'npx',
258
- args: ['-y', '@meldocio/mcp-stdio-proxy@latest']
259
- };
260
- }
261
-
262
- /**
263
- * Get expected Meldoc MCP configuration for Cursor (stdio)
264
- */
265
- function getExpectedMeldocConfigForCursor() {
266
- return {
267
- command: 'npx',
268
- args: ['-y', '@meldocio/mcp-stdio-proxy@latest']
269
- };
270
- }
271
-
272
- /**
273
- * Get expected Meldoc MCP configuration for Claude Code (stdio)
274
- */
275
- function getExpectedMeldocConfigForClaudeCode() {
276
- return {
277
- type: 'stdio',
278
- command: 'npx',
279
- args: ['-y', '@meldocio/mcp-stdio-proxy@latest']
280
- };
281
- }
282
-
283
- /**
284
- * Check if two configurations are equal (deep comparison)
285
- */
286
- function configsEqual(config1, config2) {
287
- if (!config1 || !config2) return false;
288
- if (config1.command !== config2.command) return false;
289
- if (!Array.isArray(config1.args) || !Array.isArray(config2.args)) return false;
290
- if (config1.args.length !== config2.args.length) return false;
291
- return config1.args.every((arg, i) => arg === config2.args[i]);
292
- }
293
-
294
- /**
295
- * Merge MCP server configurations (preserve existing, add new)
296
- */
297
- function mergeMcpServers(existing, newServer) {
298
- const merged = { ...existing };
299
- if (!merged.meldoc) {
300
- merged.meldoc = newServer;
301
- } else {
302
- // Check if it's the same config
303
- if (configsEqual(merged.meldoc, newServer)) {
304
- return { merged, changed: false };
305
- }
306
- // Update if different
307
- merged.meldoc = newServer;
308
- }
309
- return { merged, changed: true };
310
- }
311
-
312
- /**
313
- * Install for Claude Desktop
314
- */
315
- function installClaudeDesktop() {
316
- try {
317
- logger.section('🚀 Installing Meldoc MCP for Claude Desktop');
318
- console.log();
319
-
320
- const configPath = getClaudeDesktopConfigPath();
321
- const configDir = path.dirname(configPath);
322
- const expectedConfig = getExpectedMeldocConfig();
323
-
324
- logger.info(`Config file location: ${logger.highlight(configPath)}`);
325
- console.log();
326
-
327
- // Read existing config or create new one
328
- let config = {};
329
- let configExists = false;
330
-
331
- if (fs.existsSync(configPath)) {
332
- try {
333
- const content = fs.readFileSync(configPath, 'utf8');
334
- config = JSON.parse(content);
335
- configExists = true;
336
- logger.info('Found existing Claude Desktop configuration');
337
- } catch (error) {
338
- logger.warn(`Failed to parse existing config: ${error.message}`);
339
- logger.info('Will create a new configuration file');
340
- }
341
- } else {
342
- logger.info('Configuration file does not exist, will create it');
343
- }
344
-
345
- // Ensure mcpServers object exists
346
- if (!config.mcpServers) {
347
- config.mcpServers = {};
348
- }
349
-
350
- // Check if meldoc is already configured
351
- if (config.mcpServers.meldoc) {
352
- const existingConfig = config.mcpServers.meldoc;
353
- const isEqual = configsEqual(existingConfig, expectedConfig);
354
-
355
- if (isEqual) {
356
- logger.success('Meldoc MCP is already configured correctly!');
357
- console.log();
358
- logger.info('Current configuration:');
359
- console.log(' ' + logger.highlight(JSON.stringify(existingConfig, null, 2)));
360
- console.log();
361
- logger.info('No changes needed. Next steps:');
362
- console.log(' 1. Restart Claude Desktop (if you haven\'t already)');
363
- console.log(' 2. Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
364
- console.log();
365
- process.exit(0);
366
- } else {
367
- logger.warn('Meldoc MCP is already configured, but with different settings');
368
- console.log();
369
- logger.info('Current configuration:');
370
- console.log(' ' + logger.highlight(JSON.stringify(existingConfig, null, 2)));
371
- console.log();
372
- logger.info('Expected configuration:');
373
- console.log(' ' + logger.highlight(JSON.stringify(expectedConfig, null, 2)));
374
- console.log();
375
- logger.info('To update the configuration, run:');
376
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy uninstall'));
377
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install'));
378
- console.log();
379
- process.exit(0);
380
- }
381
- }
382
-
383
- // Add meldoc configuration
384
- config.mcpServers.meldoc = expectedConfig;
385
-
386
- // Create directory if it doesn't exist
387
- if (!fs.existsSync(configDir)) {
388
- logger.info(`Creating directory: ${configDir}`);
389
- fs.mkdirSync(configDir, { recursive: true });
390
- }
391
-
392
- // Write config file
393
- const configContent = JSON.stringify(config, null, 2);
394
- fs.writeFileSync(configPath, configContent, 'utf8');
395
-
396
- logger.success('Configuration added successfully!');
397
- console.log();
398
-
399
- // Show what was added
400
- logger.info('Added MCP server configuration:');
401
- console.log(' ' + logger.highlight(JSON.stringify(config.mcpServers.meldoc, null, 2)));
402
- console.log();
403
-
404
- // Count other MCP servers
405
- const otherServers = Object.keys(config.mcpServers).filter(key => key !== 'meldoc');
406
- if (otherServers.length > 0) {
407
- logger.info(`Found ${otherServers.length} other MCP server(s): ${otherServers.join(', ')}`);
408
- console.log();
409
- }
410
-
411
- // Next steps
412
- logger.section('✅ Installation Complete!');
413
- console.log();
414
- logger.info('Next steps:');
415
- console.log();
416
- console.log(' 1. ' + logger.label('Restart Claude Desktop'));
417
- console.log(' Completely close and reopen Claude Desktop for changes to take effect.');
418
- console.log();
419
- console.log(' 2. ' + logger.label('Authenticate with Meldoc'));
420
- console.log(' Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
421
- console.log();
422
- console.log(' 3. ' + logger.label('Start using Claude with Meldoc!'));
423
- console.log(' Ask Claude to read, search, or update your documentation.');
424
- console.log();
425
-
426
- process.exit(0);
427
- } catch (error) {
428
- logger.error(`Installation failed: ${error.message}`);
429
- console.log();
430
- logger.info('You can manually configure Claude Desktop by:');
431
- console.log(' 1. Opening the config file: ' + logger.highlight(getClaudeDesktopConfigPath()));
432
- console.log(' 2. Adding this configuration:');
433
- console.log(' ' + logger.highlight(JSON.stringify({
434
- mcpServers: {
435
- meldoc: getExpectedMeldocConfig()
436
- }
437
- }, null, 2)));
438
- console.log();
439
- process.exit(1);
440
- }
441
- }
442
-
443
- /**
444
- * Install for Cursor (project or global)
445
- */
446
- function installCursor(isGlobal = false) {
447
- try {
448
- const configPath = isGlobal ? getCursorGlobalConfigPath() : getCursorProjectConfigPath();
449
- const configDir = path.dirname(configPath);
450
- const expectedConfig = getExpectedMeldocConfigForCursor();
451
-
452
- logger.section(`🚀 Installing Meldoc MCP for Cursor (${isGlobal ? 'global' : 'project'})`);
453
- console.log();
454
-
455
- logger.info(`Config file location: ${logger.highlight(configPath)}`);
456
- console.log();
457
-
458
- // Read existing config or create new one
459
- let config = {};
460
- let configExists = false;
461
-
462
- if (fs.existsSync(configPath)) {
463
- try {
464
- const content = fs.readFileSync(configPath, 'utf8');
465
- config = JSON.parse(content);
466
- configExists = true;
467
- logger.info('Found existing Cursor MCP configuration');
468
- } catch (error) {
469
- logger.warn(`Failed to parse existing config: ${error.message}`);
470
- logger.info('Will create a new configuration file');
471
- }
472
- } else {
473
- logger.info('Configuration file does not exist, will create it');
474
- }
475
-
476
- // Ensure mcpServers object exists
477
- if (!config.mcpServers) {
478
- config.mcpServers = {};
479
- }
480
-
481
- // Check if meldoc is already configured
482
- if (config.mcpServers.meldoc) {
483
- const existingConfig = config.mcpServers.meldoc;
484
- const isEqual = configsEqual(existingConfig, expectedConfig);
485
-
486
- if (isEqual) {
487
- logger.success('Meldoc MCP is already configured correctly!');
488
- console.log();
489
- logger.info('Current configuration:');
490
- console.log(' ' + logger.highlight(JSON.stringify(existingConfig, null, 2)));
491
- console.log();
492
- logger.info('No changes needed. Next steps:');
493
- console.log(' 1. Restart Cursor (if you haven\'t already)');
494
- console.log(' 2. Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
495
- console.log();
496
- process.exit(0);
497
- } else {
498
- logger.warn('Meldoc MCP is already configured, but with different settings');
499
- console.log();
500
- logger.info('Current configuration:');
501
- console.log(' ' + logger.highlight(JSON.stringify(existingConfig, null, 2)));
502
- console.log();
503
- logger.info('Expected configuration:');
504
- console.log(' ' + logger.highlight(JSON.stringify(expectedConfig, null, 2)));
505
- console.log();
506
- logger.info('To update the configuration, run:');
507
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install cursor'));
508
- console.log();
509
- process.exit(0);
510
- }
511
- }
512
-
513
- // Add meldoc configuration
514
- config.mcpServers.meldoc = expectedConfig;
515
-
516
- // Create directory if it doesn't exist
517
- if (!fs.existsSync(configDir)) {
518
- logger.info(`Creating directory: ${configDir}`);
519
- fs.mkdirSync(configDir, { recursive: true });
520
- }
521
-
522
- // Write config file
523
- const configContent = JSON.stringify(config, null, 2);
524
- fs.writeFileSync(configPath, configContent, 'utf8');
525
-
526
- logger.success('Configuration added successfully!');
527
- console.log();
528
-
529
- // Show what was added
530
- logger.info('Added MCP server configuration:');
531
- console.log(' ' + logger.highlight(JSON.stringify(config.mcpServers.meldoc, null, 2)));
532
- console.log();
533
-
534
- // Count other MCP servers
535
- const otherServers = Object.keys(config.mcpServers).filter(key => key !== 'meldoc');
536
- if (otherServers.length > 0) {
537
- logger.info(`Found ${otherServers.length} other MCP server(s): ${otherServers.join(', ')}`);
538
- console.log();
539
- }
540
-
541
- // Next steps
542
- logger.section('✅ Installation Complete!');
543
- console.log();
544
- logger.info('Next steps:');
545
- console.log();
546
- console.log(' 1. ' + logger.label('Restart Cursor'));
547
- console.log(' Completely close and reopen Cursor for changes to take effect.');
548
- console.log();
549
- console.log(' 2. ' + logger.label('Authenticate with Meldoc'));
550
- console.log(' Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
551
- console.log();
552
- console.log(' 3. ' + logger.label('Start using Cursor with Meldoc!'));
553
- console.log(' Ask Cursor to read, search, or update your documentation.');
554
- console.log();
555
-
556
- process.exit(0);
557
- } catch (error) {
558
- const configPath = isGlobal ? getCursorGlobalConfigPath() : getCursorProjectConfigPath();
559
- logger.error(`Installation failed: ${error.message}`);
560
- console.log();
561
- logger.info('You can manually configure Cursor by:');
562
- console.log(' 1. Opening the config file: ' + logger.highlight(configPath));
563
- console.log(' 2. Adding this configuration:');
564
- console.log(' ' + logger.highlight(JSON.stringify({
565
- mcpServers: {
566
- meldoc: getExpectedMeldocConfigForCursor()
567
- }
568
- }, null, 2)));
569
- console.log();
570
- process.exit(1);
571
- }
572
- }
573
-
574
- /**
575
- * Install local mcp.json file
576
- */
577
- function installLocal() {
578
- try {
579
- logger.section('🚀 Installing Meldoc MCP (Local mcp.json)');
580
- console.log();
581
-
582
- const configPath = getLocalMcpJsonPath();
583
- const expectedConfig = getExpectedMeldocConfig();
584
-
585
- logger.info(`Config file location: ${logger.highlight(configPath)}`);
586
- console.log();
587
-
588
- // Read existing config or create new one
589
- let config = {};
590
- let configExists = false;
591
-
592
- if (fs.existsSync(configPath)) {
593
- try {
594
- const content = fs.readFileSync(configPath, 'utf8');
595
- config = JSON.parse(content);
596
- configExists = true;
597
- logger.info('Found existing mcp.json configuration');
598
- } catch (error) {
599
- logger.warn(`Failed to parse existing config: ${error.message}`);
600
- logger.info('Will create a new configuration file');
601
- }
602
- } else {
603
- logger.info('Configuration file does not exist, will create it');
604
- }
605
-
606
- // Ensure mcpServers object exists
607
- if (!config.mcpServers) {
608
- config.mcpServers = {};
609
- }
610
-
611
- // Check if meldoc is already configured
612
- if (config.mcpServers.meldoc) {
613
- const existingConfig = config.mcpServers.meldoc;
614
- const isEqual = configsEqual(existingConfig, expectedConfig);
615
-
616
- if (isEqual) {
617
- logger.success('Meldoc MCP is already configured correctly!');
618
- console.log();
619
- logger.info('Current configuration:');
620
- console.log(' ' + logger.highlight(JSON.stringify(existingConfig, null, 2)));
621
- console.log();
622
- logger.info('No changes needed. Next steps:');
623
- console.log(' 1. Restart your MCP client (if needed)');
624
- console.log(' 2. Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
625
- console.log();
626
- process.exit(0);
627
- } else {
628
- logger.warn('Meldoc MCP is already configured, but with different settings');
629
- console.log();
630
- logger.info('Current configuration:');
631
- console.log(' ' + logger.highlight(JSON.stringify(existingConfig, null, 2)));
632
- console.log();
633
- logger.info('Expected configuration:');
634
- console.log(' ' + logger.highlight(JSON.stringify(expectedConfig, null, 2)));
635
- console.log();
636
- logger.info('Updating configuration...');
637
- console.log();
638
- }
639
- }
640
-
641
- // Add/update meldoc configuration
642
- config.mcpServers.meldoc = expectedConfig;
643
-
644
- // Write config file
645
- const configContent = JSON.stringify(config, null, 2);
646
- fs.writeFileSync(configPath, configContent, 'utf8');
647
-
648
- logger.success('Configuration ' + (configExists && config.mcpServers.meldoc ? 'updated' : 'added') + ' successfully!');
649
- console.log();
650
-
651
- // Show what was added
652
- logger.info('MCP server configuration:');
653
- console.log(' ' + logger.highlight(JSON.stringify(config.mcpServers.meldoc, null, 2)));
654
- console.log();
655
-
656
- // Count other MCP servers
657
- const otherServers = Object.keys(config.mcpServers).filter(key => key !== 'meldoc');
658
- if (otherServers.length > 0) {
659
- logger.info(`Found ${otherServers.length} other MCP server(s): ${otherServers.join(', ')}`);
660
- console.log();
661
- }
662
-
663
- // Next steps
664
- logger.section('✅ Installation Complete!');
665
- console.log();
666
- logger.info('Next steps:');
667
- console.log();
668
- console.log(' 1. ' + logger.label('Use this mcp.json with your MCP client'));
669
- console.log(' This file can be imported or referenced by MCP clients that support JSON configuration.');
670
- console.log();
671
- console.log(' 2. ' + logger.label('Authenticate with Meldoc'));
672
- console.log(' Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
673
- console.log();
674
-
675
- process.exit(0);
676
- } catch (error) {
677
- logger.error(`Installation failed: ${error.message}`);
678
- console.log();
679
- logger.info('You can manually create mcp.json with this configuration:');
680
- console.log(' ' + logger.highlight(JSON.stringify({
681
- mcpServers: {
682
- meldoc: getExpectedMeldocConfig()
683
- }
684
- }, null, 2)));
685
- console.log();
686
- process.exit(1);
687
- }
688
- }
689
-
690
- /**
691
- * Install for Claude Code (project, user, or local scope)
692
- */
693
- function installClaudeCode(scope = 'project') {
694
- try {
695
- let configPath;
696
- if (scope === 'project') {
697
- configPath = getClaudeCodeProjectConfigPath();
698
- } else if (scope === 'user') {
699
- configPath = getClaudeCodeUserConfigPath();
700
- } else {
701
- // local scope
702
- configPath = getClaudeCodeLocalConfigPath();
703
- }
704
- const configDir = path.dirname(configPath);
705
- const expectedConfig = getExpectedMeldocConfigForClaudeCode();
706
-
707
- logger.section(`🚀 Installing Meldoc MCP for Claude Code (${scope} scope)`);
708
- console.log();
709
-
710
- logger.info(`Config file location: ${logger.highlight(configPath)}`);
711
- console.log();
712
-
713
- // Read existing config or create new one
714
- let config = {};
715
- let configExists = false;
716
-
717
- if (fs.existsSync(configPath)) {
718
- try {
719
- const content = fs.readFileSync(configPath, 'utf8');
720
- config = JSON.parse(content);
721
- configExists = true;
722
- logger.info('Found existing Claude Code MCP configuration');
723
- } catch (error) {
724
- logger.warn(`Failed to parse existing config: ${error.message}`);
725
- logger.info('Will create a new configuration file');
726
- }
727
- } else {
728
- logger.info('Configuration file does not exist, will create it');
729
- }
730
-
731
- // Ensure mcpServers object exists
732
- if (!config.mcpServers) {
733
- config.mcpServers = {};
734
- }
735
-
736
- // Check if meldoc is already configured
737
- if (config.mcpServers.meldoc) {
738
- const existingConfig = config.mcpServers.meldoc;
739
- // For Claude Code, compare type, command, and args
740
- const isEqual = existingConfig.type === expectedConfig.type &&
741
- existingConfig.command === expectedConfig.command &&
742
- Array.isArray(existingConfig.args) &&
743
- Array.isArray(expectedConfig.args) &&
744
- existingConfig.args.length === expectedConfig.args.length &&
745
- existingConfig.args.every((arg, i) => arg === expectedConfig.args[i]);
746
-
747
- if (isEqual) {
748
- logger.success('Meldoc MCP is already configured correctly!');
749
- console.log();
750
- logger.info('Current configuration:');
751
- console.log(' ' + logger.highlight(JSON.stringify(existingConfig, null, 2)));
752
- console.log();
753
- logger.info('No changes needed. Next steps:');
754
- console.log(' 1. Restart Claude Code (if you haven\'t already)');
755
- console.log(' 2. Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
756
- console.log();
757
- process.exit(0);
758
- } else {
759
- logger.warn('Meldoc MCP is already configured, but with different settings');
760
- console.log();
761
- logger.info('Current configuration:');
762
- console.log(' ' + logger.highlight(JSON.stringify(existingConfig, null, 2)));
763
- console.log();
764
- logger.info('Expected configuration:');
765
- console.log(' ' + logger.highlight(JSON.stringify(expectedConfig, null, 2)));
766
- console.log();
767
- logger.info('Updating configuration...');
768
- console.log();
769
- }
770
- }
771
-
772
- // Add/update meldoc configuration
773
- config.mcpServers.meldoc = expectedConfig;
774
-
775
- // Create directory if it doesn't exist (for user/local scope)
776
- if (scope !== 'project' && !fs.existsSync(configDir)) {
777
- logger.info(`Creating directory: ${configDir}`);
778
- fs.mkdirSync(configDir, { recursive: true });
779
- }
780
-
781
- // Write config file
782
- const configContent = JSON.stringify(config, null, 2);
783
- fs.writeFileSync(configPath, configContent, 'utf8');
784
-
785
- logger.success('Configuration ' + (configExists && config.mcpServers.meldoc ? 'updated' : 'added') + ' successfully!');
786
- console.log();
787
-
788
- // Show what was added
789
- logger.info('MCP server configuration:');
790
- console.log(' ' + logger.highlight(JSON.stringify(config.mcpServers.meldoc, null, 2)));
791
- console.log();
792
-
793
- // Count other MCP servers
794
- const otherServers = Object.keys(config.mcpServers).filter(key => key !== 'meldoc');
795
- if (otherServers.length > 0) {
796
- logger.info(`Found ${otherServers.length} other MCP server(s): ${otherServers.join(', ')}`);
797
- console.log();
798
- }
799
-
800
- // Next steps
801
- logger.section('✅ Installation Complete!');
802
- console.log();
803
- logger.info('Next steps:');
804
- console.log();
805
- console.log(' 1. ' + logger.label('Restart Claude Code'));
806
- console.log(' Completely close and reopen Claude Code for changes to take effect.');
807
- console.log();
808
- console.log(' 2. ' + logger.label('Authenticate with Meldoc'));
809
- console.log(' Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
810
- console.log();
811
- console.log(' 3. ' + logger.label('Start using Claude Code with Meldoc!'));
812
- console.log(' Ask Claude Code to read, search, or update your documentation.');
813
- console.log();
814
-
815
- process.exit(0);
816
- } catch (error) {
817
- const configPath = scope === 'project' ? getClaudeCodeProjectConfigPath() : getClaudeCodeUserConfigPath();
818
- logger.error(`Installation failed: ${error.message}`);
819
- console.log();
820
- logger.info('You can manually configure Claude Code by:');
821
- console.log(' 1. Opening the config file: ' + logger.highlight(configPath));
822
- console.log(' 2. Adding this configuration:');
823
- console.log(' ' + logger.highlight(JSON.stringify({
824
- mcpServers: {
825
- meldoc: getExpectedMeldocConfigForClaudeCode()
826
- }
827
- }, null, 2)));
828
- console.log();
829
- logger.info('Or use the CLI command:');
830
- console.log(' ' + logger.highlight(`claude mcp add --transport stdio meldoc -- npx -y @meldocio/mcp-stdio-proxy@latest --scope ${scope}`));
831
- console.log();
832
- process.exit(1);
833
- }
834
- }
835
-
836
3
  /**
837
- * Handle install command - automatically configure MCP client
4
+ * CLI Entry Point
5
+ *
6
+ * This is the main entry point for the Meldoc MCP CLI.
7
+ * All command handlers are in lib/cli/commands.js
8
+ * All formatters are in lib/cli/formatters.js
838
9
  */
839
- function handleInstall(consumer, isLocal) {
840
- if (isLocal) {
841
- installLocal();
842
- return;
843
- }
844
-
845
- const consumerLower = (consumer || 'claude-desktop').toLowerCase();
846
-
847
- switch (consumerLower) {
848
- case 'claude-desktop':
849
- case 'claude':
850
- installClaudeDesktop();
851
- break;
852
- case 'cursor':
853
- installCursor(false); // Project-specific by default
854
- break;
855
- case 'cursor-global':
856
- installCursor(true);
857
- break;
858
- case 'claude-code':
859
- installClaudeCode('project'); // Project scope by default
860
- break;
861
- case 'claude-code-user':
862
- installClaudeCode('user');
863
- break;
864
- case 'claude-code-local':
865
- installClaudeCode('local');
866
- break;
867
- default:
868
- logger.error(`Unknown consumer: ${consumer}`);
869
- console.log();
870
- logger.info('Supported consumers:');
871
- console.log(' ' + logger.highlight('claude-desktop') + ' (or claude) - Claude Desktop');
872
- console.log(' ' + logger.highlight('cursor') + ' - Cursor IDE (project-specific)');
873
- console.log(' ' + logger.highlight('cursor-global') + ' - Cursor IDE (global)');
874
- console.log(' ' + logger.highlight('claude-code') + ' - Claude Code (project scope)');
875
- console.log(' ' + logger.highlight('claude-code-user') + ' - Claude Code (user scope)');
876
- console.log(' ' + logger.highlight('claude-code-local') + ' - Claude Code (local scope)');
877
- console.log();
878
- logger.info('Or use ' + logger.highlight('--local') + ' flag to create local mcp.json');
879
- console.log();
880
- process.exit(1);
881
- }
882
- }
883
10
 
884
- /**
885
- * Handle uninstall command - remove Meldoc MCP configuration from Claude Desktop
886
- */
887
- function handleUninstall() {
888
- try {
889
- logger.section('🗑️ Uninstalling Meldoc MCP from Claude Desktop');
890
- console.log();
891
-
892
- const configPath = getClaudeDesktopConfigPath();
893
-
894
- logger.info(`Config file location: ${logger.highlight(configPath)}`);
895
- console.log();
896
-
897
- // Check if config file exists
898
- if (!fs.existsSync(configPath)) {
899
- logger.warn('Claude Desktop configuration file not found');
900
- logger.info('Meldoc MCP is not configured (nothing to remove)');
901
- console.log();
902
- process.exit(0);
903
- }
904
-
905
- // Read existing config
906
- let config = {};
907
- try {
908
- const content = fs.readFileSync(configPath, 'utf8');
909
- config = JSON.parse(content);
910
- } catch (error) {
911
- logger.error(`Failed to read config file: ${error.message}`);
912
- process.exit(1);
913
- }
914
-
915
- // Check if meldoc is configured
916
- if (!config.mcpServers || !config.mcpServers.meldoc) {
917
- logger.warn('Meldoc MCP is not configured in Claude Desktop');
918
- logger.info('Nothing to remove');
919
- console.log();
920
- process.exit(0);
921
- }
922
-
923
- // Show what will be removed
924
- logger.info('Current Meldoc configuration:');
925
- console.log(' ' + logger.highlight(JSON.stringify(config.mcpServers.meldoc, null, 2)));
926
- console.log();
927
-
928
- // Remove meldoc configuration
929
- delete config.mcpServers.meldoc;
930
-
931
- // If mcpServers is now empty, remove it too
932
- if (Object.keys(config.mcpServers).length === 0) {
933
- delete config.mcpServers;
934
- }
935
-
936
- // Write config file back
937
- const configContent = JSON.stringify(config, null, 2);
938
- fs.writeFileSync(configPath, configContent, 'utf8');
939
-
940
- logger.success('Meldoc MCP configuration removed successfully!');
941
- console.log();
942
-
943
- // Count remaining MCP servers
944
- if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
945
- const remainingServers = Object.keys(config.mcpServers);
946
- logger.info(`Remaining MCP server(s): ${remainingServers.join(', ')}`);
947
- console.log();
948
- } else {
949
- logger.info('No other MCP servers configured');
950
- console.log();
951
- }
952
-
953
- // Next steps
954
- logger.section('✅ Uninstallation Complete!');
955
- console.log();
956
- logger.info('Next steps:');
957
- console.log(' 1. Restart Claude Desktop for changes to take effect');
958
- console.log(' 2. To reinstall, run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install'));
959
- console.log();
960
-
961
- process.exit(0);
962
- } catch (error) {
963
- logger.error(`Uninstallation failed: ${error.message}`);
964
- console.log();
965
- logger.info('You can manually remove Meldoc MCP by:');
966
- console.log(' 1. Opening the config file: ' + logger.highlight(getClaudeDesktopConfigPath()));
967
- console.log(' 2. Removing the "meldoc" entry from "mcpServers" object');
968
- console.log();
969
- process.exit(1);
970
- }
971
- }
11
+ // Import command handlers
12
+ const {
13
+ handleAuthLogin,
14
+ handleAuthStatus,
15
+ handleAuthLogout,
16
+ handleConfigSetWorkspace,
17
+ handleConfigGetWorkspace,
18
+ handleConfigListWorkspaces,
19
+ handleInstall,
20
+ handleUninstall
21
+ } = require('../lib/cli/commands');
972
22
 
973
- /**
974
- * Handle help command
975
- */
976
- function handleHelp() {
977
- console.log('\n' + logger.section('📖 Meldoc MCP CLI Help'));
978
- console.log();
979
-
980
- console.log(logger.label('Available Commands:'));
981
- console.log();
982
-
983
- console.log(' ' + logger.highlight('auth login'));
984
- console.log(' Authenticate with Meldoc using device flow');
985
- console.log();
986
-
987
- console.log(' ' + logger.highlight('auth status'));
988
- console.log(' Check authentication status');
989
- console.log();
990
-
991
- console.log(' ' + logger.highlight('auth logout'));
992
- console.log(' Log out and clear credentials');
993
- console.log();
994
-
995
- console.log(' ' + logger.highlight('config set-workspace <alias>'));
996
- console.log(' Set the active workspace alias');
997
- console.log();
998
-
999
- console.log(' ' + logger.highlight('config get-workspace'));
1000
- console.log(' Get the current workspace alias');
1001
- console.log();
1002
-
1003
- console.log(' ' + logger.highlight('config list-workspaces'));
1004
- console.log(' List all available workspaces');
1005
- console.log();
1006
-
1007
- console.log(' ' + logger.highlight('install [consumer] [--local]'));
1008
- console.log(' Automatically configure MCP client for Meldoc MCP');
1009
- console.log(' Consumers: claude-desktop (default), cursor, cursor-global, claude-code');
1010
- console.log(' Use --local flag to create local mcp.json file');
1011
- console.log();
1012
-
1013
- console.log(' ' + logger.highlight('uninstall'));
1014
- console.log(' Remove Meldoc MCP configuration from Claude Desktop');
1015
- console.log();
1016
-
1017
- console.log(' ' + logger.highlight('help'));
1018
- console.log(' Show this help message');
1019
- console.log();
1020
-
1021
- console.log(logger.label('Examples:'));
1022
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install'));
1023
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install claude-desktop'));
1024
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install cursor'));
1025
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install claude-code'));
1026
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install --local'));
1027
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy uninstall'));
1028
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
1029
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy config set-workspace my-workspace'));
1030
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy config list-workspaces'));
1031
- console.log();
1032
-
1033
- process.exit(0);
1034
- }
23
+ // Import formatters
24
+ const {
25
+ handleHelp,
26
+ showUsageHints,
27
+ showUnknownCommandError,
28
+ showUnknownAuthCommandError,
29
+ showUnknownConfigCommandError
30
+ } = require('../lib/cli/formatters');
1035
31
 
1036
- /**
1037
- * Show usage hints when no arguments provided
1038
- */
1039
- function showUsageHints() {
1040
- console.log('\n' + logger.section('🔧 Meldoc MCP CLI'));
1041
- console.log();
1042
- console.log(logger.label('Available commands:'));
1043
- console.log(' ' + logger.highlight('auth login') + ' - Authenticate with Meldoc');
1044
- console.log(' ' + logger.highlight('auth status') + ' - Check authentication status');
1045
- console.log(' ' + logger.highlight('auth logout') + ' - Log out');
1046
- console.log(' ' + logger.highlight('config set-workspace') + ' - Set workspace alias');
1047
- console.log(' ' + logger.highlight('config get-workspace') + ' - Get current workspace');
1048
- console.log(' ' + logger.highlight('config list-workspaces') + ' - List workspaces');
1049
- console.log(' ' + logger.highlight('install [consumer]') + ' - Configure MCP client');
1050
- console.log(' ' + logger.highlight('uninstall') + ' - Remove configuration');
1051
- console.log(' ' + logger.highlight('help') + ' - Show detailed help');
1052
- console.log();
1053
- console.log(logger.label('For more information, run:'));
1054
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy help') + '\n');
1055
- process.exit(0);
1056
- }
32
+ const logger = require('../lib/core/logger');
1057
33
 
1058
34
  /**
1059
35
  * Main CLI handler
1060
36
  */
1061
37
  async function main() {
1062
38
  const args = process.argv.slice(2);
1063
-
39
+
1064
40
  if (args.length === 0) {
1065
41
  // No arguments - show usage hints
1066
42
  showUsageHints();
1067
43
  return;
1068
44
  }
1069
-
45
+
1070
46
  const command = args[0];
1071
47
  const subcommand = args[1];
1072
48
  const value = args[2];
1073
-
49
+
1074
50
  if (command === 'help' || command === '--help' || command === '-h') {
1075
51
  handleHelp();
1076
52
  } else if (command === 'install') {
1077
53
  // Parse install arguments
1078
54
  let consumer = null;
1079
55
  let isLocal = false;
1080
-
56
+
1081
57
  for (let i = 1; i < args.length; i++) {
1082
58
  if (args[i] === '--local' || args[i] === '-l') {
1083
59
  isLocal = true;
@@ -1085,7 +61,7 @@ async function main() {
1085
61
  consumer = args[i];
1086
62
  }
1087
63
  }
1088
-
64
+
1089
65
  handleInstall(consumer, isLocal);
1090
66
  } else if (command === 'uninstall') {
1091
67
  handleUninstall();
@@ -1097,10 +73,7 @@ async function main() {
1097
73
  } else if (subcommand === 'logout') {
1098
74
  handleAuthLogout();
1099
75
  } else {
1100
- logger.error(`Unknown auth command: ${subcommand}`);
1101
- console.log('\n' + logger.label('Usage:'));
1102
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth <login|status|logout>') + '\n');
1103
- process.exit(1);
76
+ showUnknownAuthCommandError(subcommand);
1104
77
  }
1105
78
  } else if (command === 'config') {
1106
79
  if (subcommand === 'set-workspace') {
@@ -1110,24 +83,11 @@ async function main() {
1110
83
  } else if (subcommand === 'list-workspaces') {
1111
84
  await handleConfigListWorkspaces();
1112
85
  } else {
1113
- logger.error(`Unknown config command: ${subcommand}`);
1114
- console.log('\n' + logger.label('Usage:'));
1115
- console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy config <set-workspace|get-workspace|list-workspaces>') + '\n');
1116
- process.exit(1);
86
+ showUnknownConfigCommandError(subcommand);
1117
87
  }
1118
88
  } else {
1119
89
  // Unknown command
1120
- logger.error(`Unknown command: ${command}`);
1121
- console.log('\n' + logger.label('Available commands:'));
1122
- console.log(' ' + logger.highlight('install') + ' - Configure Claude Desktop');
1123
- console.log(' ' + logger.highlight('uninstall') + ' - Remove configuration');
1124
- console.log(' ' + logger.highlight('auth') + ' <cmd> - Authentication commands');
1125
- console.log(' ' + logger.highlight('config') + ' <cmd> - Configuration commands');
1126
- console.log(' ' + logger.highlight('help') + ' - Show help');
1127
- console.log();
1128
- console.log(logger.label('Run') + ' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy help') + ' ' + logger.label('for more information'));
1129
- console.log();
1130
- process.exit(1);
90
+ showUnknownCommandError(command);
1131
91
  }
1132
92
  }
1133
93
 
@@ -1137,18 +97,3 @@ main().catch((error) => {
1137
97
  logger.error(`Unexpected error: ${error.message}`);
1138
98
  process.exit(1);
1139
99
  });
1140
-
1141
- module.exports = {
1142
- handleAuthLogin,
1143
- handleAuthStatus,
1144
- handleAuthLogout,
1145
- handleConfigSetWorkspace,
1146
- handleConfigGetWorkspace,
1147
- handleConfigListWorkspaces,
1148
- handleInstall,
1149
- handleUninstall,
1150
- installClaudeDesktop,
1151
- installCursor,
1152
- installClaudeCode,
1153
- installLocal
1154
- };