@meldocio/mcp-stdio-proxy 1.0.19 → 1.0.21

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,87 @@
1
+ # Meldoc MCP Integration
2
+
3
+ Connect to your Meldoc documentation directly from Claude Desktop, Claude Code, and other MCP clients.
4
+
5
+ ## Overview
6
+
7
+ Meldoc MCP provides seamless access to your Meldoc documentation workspace through the Model Context Protocol. Once configured, you can interact with your documentation naturally through AI conversations.
8
+
9
+ ## Available Tools
10
+
11
+ ### Document Operations
12
+
13
+ - **`docs_list`** - List all documents in a workspace or project
14
+ - **`docs_get`** - Get the complete content of a specific document
15
+ - **`docs_tree`** - Display the hierarchical structure of documents in a project
16
+ - **`docs_search`** - Search through all documents using full-text search
17
+ - **`docs_create`** - Create a new document (requires write permissions)
18
+ - **`docs_update`** - Update an existing document's content or metadata (requires write permissions)
19
+ - **`docs_delete`** - Delete a document (requires write permissions)
20
+ - **`docs_links`** - Show all outgoing links from a document
21
+ - **`docs_backlinks`** - Find all documents that link to a specific document
22
+
23
+ ### Project Operations
24
+
25
+ - **`projects_list`** - List all projects available in your workspace
26
+
27
+ ### Management Operations
28
+
29
+ - **`server_info`** - Get information about your account and access permissions
30
+ - **`list_workspaces`** - Show all workspaces you have access to
31
+ - **`set_workspace`** - Set the default workspace for operations
32
+ - **`get_workspace`** - Get information about the currently active workspace
33
+ - **`auth_status`** - Check your current authentication status
34
+
35
+ ## Usage Examples
36
+
37
+ Simply ask Claude naturally! For example:
38
+
39
+ - "Show me all documents in the API project"
40
+ - "Find information about authentication"
41
+ - "Search for documents about error handling"
42
+ - "Create a new document about our deployment process"
43
+ - "Which documents link to the database schema?"
44
+ - "Show me the document tree for the frontend project"
45
+ - "Update the getting started guide with new information"
46
+
47
+ Your AI assistant will automatically:
48
+
49
+ - Select the appropriate tool
50
+ - Handle authentication
51
+ - Format the results nicely
52
+ - Provide context and explanations
53
+
54
+ ## Authentication
55
+
56
+ Before using Meldoc MCP, you need to authenticate:
57
+
58
+ ```bash
59
+ npx @meldocio/mcp-stdio-proxy@latest auth login
60
+ ```
61
+
62
+ This will open a browser flow for secure authentication. Your credentials are stored locally and automatically refreshed.
63
+
64
+ ## Workspace Management
65
+
66
+ If you have multiple workspaces, you can:
67
+
68
+ 1. List all workspaces: `npx @meldocio/mcp-stdio-proxy@latest config list-workspaces`
69
+ 2. Set default workspace: `npx @meldocio/mcp-stdio-proxy@latest config set-workspace <name>`
70
+ 3. Or specify workspace in requests directly
71
+
72
+ ## Permissions
73
+
74
+ Some operations require write permissions to your workspace:
75
+
76
+ - Creating documents
77
+ - Updating documents
78
+ - Deleting documents
79
+
80
+ Read-only operations (list, get, search) work with any authenticated account.
81
+
82
+ ## Related Documentation
83
+
84
+ - [Getting Started Guide](docs/getting-started.meldoc.md)
85
+ - [Authentication Guide](docs/authentication.meldoc.md)
86
+ - [MCP Tools Reference](docs/mcp-tools.meldoc.md)
87
+ - [Full Documentation](https://docs.meldoc.io/integrations/mcp)
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "meldoc-mcp",
3
+ "owner": {
4
+ "name": "Meldoc",
5
+ "email": "support@meldoc.io"
6
+ },
7
+ "metadata": {
8
+ "description": "Official Meldoc plugin marketplace for Claude Code MCP integrations"
9
+ },
10
+ "plugins": [
11
+ {
12
+ "name": "meldoc-mcp",
13
+ "source": {
14
+ "source": "github",
15
+ "repo": "meldoc-io/mcp-stdio-proxy"
16
+ },
17
+ "version": "1.0.21",
18
+ "description": "Connect Claude Desktop, Claude Code, and other MCP clients to your Meldoc documentation workspace. Read, search, create, and update your documentation directly from AI conversations.",
19
+ "author": {
20
+ "name": "Meldoc",
21
+ "email": "support@meldoc.io"
22
+ },
23
+ "homepage": "https://github.com/meldoc-io/mcp-stdio-proxy#readme",
24
+ "repository": "https://github.com/meldoc-io/mcp-stdio-proxy",
25
+ "license": "MIT",
26
+ "category": "productivity",
27
+ "keywords": [
28
+ "mcp",
29
+ "meldoc",
30
+ "documentation",
31
+ "claude",
32
+ "claude-code",
33
+ "ai",
34
+ "productivity",
35
+ "knowledge-base"
36
+ ]
37
+ }
38
+ ]
39
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "meldoc-mcp",
3
+ "version": "1.0.21",
4
+ "description": "Connect Claude Desktop, Claude Code, and other MCP clients to your Meldoc documentation workspace. Read, search, create, and update your documentation directly from AI conversations through the Model Context Protocol.",
5
+ "author": {
6
+ "name": "Meldoc",
7
+ "email": "support@meldoc.io"
8
+ },
9
+ "homepage": "https://github.com/meldoc-io/mcp-stdio-proxy"
10
+ }
package/.mcp.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meldoc-mcp": {
3
+ "command": "npx",
4
+ "args": ["-y", "@meldocio/mcp-stdio-proxy@latest"]
5
+ }
6
+ }
package/README.md CHANGED
@@ -1,39 +1,45 @@
1
- # Meldoc MCP for Claude Desktop
1
+ # Meldoc MCP for Claude Desktop & Claude Code
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/@meldocio%2Fmcp-stdio-proxy.svg)](https://www.npmjs.com/package/@meldocio/mcp-stdio-proxy)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- This package allows you to connect Claude Desktop to your Meldoc account, so you can use all your documentation directly in Claude.
6
+ This package allows you to connect Claude Desktop and Claude Code to your Meldoc account, so you can use all your documentation directly in Claude.
7
+
8
+ ## 🚀 Quick Start - Install from Claude Marketplace
9
+
10
+ The easiest way to install Meldoc MCP is through the Claude Marketplace:
11
+
12
+ ```bash
13
+ # Add the marketplace
14
+ claude plugin marketplace add meldoc-io/mcp-stdio-proxy
15
+
16
+ # Install the plugin
17
+ claude plugin install meldoc-mcp@meldoc-mcp
18
+ ```
19
+
20
+ After installation:
21
+
22
+ 1. Restart Claude Desktop or Claude Code
23
+ 2. Run `npx @meldocio/mcp-stdio-proxy@latest auth login` to authenticate
24
+
25
+ Done! 🎉 Now you can ask Claude to work with your Meldoc documentation.
7
26
 
8
27
  ## What is this?
9
28
 
10
- This is a bridge between Claude Desktop and Meldoc. After setup, Claude will be able to:
29
+ This is a bridge between Claude (Desktop & Code) and Meldoc. After setup, Claude will be able to:
11
30
 
12
31
  - 📖 Read your documentation from Meldoc
13
32
  - 🔍 Search through documents
14
33
  - ✏️ Create and update documents (if you have permissions)
15
34
  - 📁 Work with projects and workspaces
16
35
 
17
- **No additional installation required** - everything works automatically through Claude Desktop.
36
+ **No additional installation required** - everything works automatically through Claude Desktop and Claude Code.
18
37
 
19
38
  ## Installation
20
39
 
21
40
  ### Via Claude Marketplace (Recommended) 🚀
22
41
 
23
- The easiest way to install Meldoc MCP is through the Claude Marketplace:
24
-
25
- ```bash
26
- # Add the marketplace
27
- claude plugin marketplace add meldoc/mcp-stdio-proxy
28
-
29
- # Install the plugin
30
- claude plugin install meldoc-mcp@meldoc
31
- ```
32
-
33
- After installation:
34
-
35
- 1. Restart Claude Desktop (or your MCP client)
36
- 2. Run `npx @meldocio/mcp-stdio-proxy@latest auth login` to authenticate
42
+ See [Quick Start](#-quick-start---install-from-claude-marketplace) section above for the easiest installation method.
37
43
 
38
44
  ### Via NPM
39
45
 
@@ -481,7 +487,7 @@ If you're experiencing connection errors:
481
487
  ### Setup
482
488
 
483
489
  ```bash
484
- git clone https://github.com/meldoc/mcp-stdio-proxy.git
490
+ git clone https://github.com/meldoc-io/mcp-stdio-proxy.git
485
491
  cd mcp-stdio-proxy
486
492
  npm install
487
493
  ```
@@ -545,7 +551,7 @@ MIT License - see [LICENSE](LICENSE) file for details.
545
551
 
546
552
  For issues, questions, or contributions, please visit:
547
553
 
548
- - GitHub Issues: <https://github.com/meldoc/mcp-stdio-proxy/issues>
554
+ - GitHub Issues: <https://github.com/meldoc-io/mcp-stdio-proxy/issues>
549
555
  - Documentation: <https://docs.meldoc.io>
550
556
 
551
557
  ## Related
package/bin/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { deviceFlowLogin } = require('../lib/device-flow');
3
+ const { interactiveLogin } = require('../lib/device-flow');
4
4
  const { readCredentials, deleteCredentials } = require('../lib/credentials');
5
5
  const { getAuthStatus } = require('../lib/auth');
6
6
  const { setWorkspaceAlias, getWorkspaceAlias } = require('../lib/config');
@@ -30,31 +30,15 @@ if (process.env.MELDOC_APP_URL) {
30
30
  */
31
31
  async function handleAuthLogin() {
32
32
  try {
33
- logger.section('🔐 Authentication');
34
- await deviceFlowLogin(
35
- (url, code) => {
36
- console.log('\n' + logger.label('Visit this URL:'));
37
- console.log(' ' + logger.url(url));
38
- console.log('\n' + logger.label('Enter this code:'));
39
- console.log(' ' + logger.code(code) + '\n');
40
- logger.info('Waiting for authentication...');
41
- },
42
- (status) => {
43
- if (status === 'denied') {
44
- logger.error('Login denied by user');
45
- process.exit(1);
46
- } else if (status === 'expired') {
47
- logger.error('Authentication code expired');
48
- process.exit(1);
49
- }
50
- },
51
- API_URL,
52
- APP_URL
53
- );
54
- logger.success('Login successful!');
33
+ await interactiveLogin({
34
+ autoOpen: true,
35
+ showQR: false,
36
+ timeout: 120000,
37
+ apiBaseUrl: API_URL,
38
+ appUrl: APP_URL
39
+ });
55
40
  process.exit(0);
56
41
  } catch (error) {
57
- logger.error(`Login failed: ${error.message}`);
58
42
  process.exit(1);
59
43
  }
60
44
  }
@@ -66,15 +66,21 @@ const LOG_LEVELS = {
66
66
  // Import new auth and workspace modules
67
67
  const { getAccessToken, getAuthStatus } = require('../lib/auth');
68
68
  const { resolveWorkspaceAlias } = require('../lib/workspace');
69
- const { getApiUrl } = require('../lib/constants');
69
+ const { getApiUrl, getAppUrl } = require('../lib/constants');
70
70
  const { setWorkspaceAlias, getWorkspaceAlias } = require('../lib/config');
71
+ const { interactiveLogin, canOpenBrowser } = require('../lib/device-flow');
71
72
 
72
73
  // Configuration
73
74
  const apiUrl = getApiUrl();
75
+ const appUrl = getAppUrl();
74
76
  const rpcEndpoint = `${apiUrl}/mcp/v1/rpc`;
75
77
  const REQUEST_TIMEOUT = 25000; // 25 seconds (less than Claude Desktop's 30s timeout)
76
78
  const LOG_LEVEL = getLogLevel(process.env.LOG_LEVEL || 'ERROR');
77
79
 
80
+ // Track if we've attempted auto-authentication
81
+ let autoAuthAttempted = false;
82
+ let autoAuthInProgress = false;
83
+
78
84
  // Get log level from environment
79
85
  function getLogLevel(level) {
80
86
  const upper = (level || '').toUpperCase();
@@ -803,13 +809,74 @@ async function handleToolsCall(request) {
803
809
  }
804
810
  }
805
811
 
812
+ /**
813
+ * Attempt automatic authentication if conditions are met
814
+ * @returns {Promise<boolean>} True if authentication was attempted and succeeded
815
+ */
816
+ async function attemptAutoAuth() {
817
+ // Only attempt once per session
818
+ if (autoAuthAttempted || autoAuthInProgress) {
819
+ return false;
820
+ }
821
+
822
+ // Only in interactive mode (TTY) and not in CI
823
+ if (!canOpenBrowser()) {
824
+ return false;
825
+ }
826
+
827
+ // Check if NO_AUTO_AUTH is set
828
+ if (process.env.NO_AUTO_AUTH === '1' || process.env.NO_AUTO_AUTH === 'true') {
829
+ return false;
830
+ }
831
+
832
+ // Check if token already exists
833
+ const tokenInfo = await getAccessToken();
834
+ if (tokenInfo) {
835
+ return false;
836
+ }
837
+
838
+ autoAuthAttempted = true;
839
+ autoAuthInProgress = true;
840
+
841
+ try {
842
+ log(LOG_LEVELS.INFO, '🔐 First time setup - authentication required');
843
+ process.stderr.write('\n');
844
+
845
+ await interactiveLogin({
846
+ autoOpen: true,
847
+ showQR: false,
848
+ timeout: 120000,
849
+ apiBaseUrl: apiUrl,
850
+ appUrl: appUrl
851
+ });
852
+
853
+ autoAuthInProgress = false;
854
+ return true;
855
+ } catch (error) {
856
+ autoAuthInProgress = false;
857
+ log(LOG_LEVELS.WARN, `Auto-authentication failed: ${error.message}`);
858
+ log(LOG_LEVELS.INFO, 'You can authenticate manually: npx @meldocio/mcp-stdio-proxy@latest auth login');
859
+ return false;
860
+ }
861
+ }
862
+
806
863
  /**
807
864
  * Process a single JSON-RPC request
808
865
  * Forwards the request to the backend MCP API
809
866
  */
810
867
  async function processSingleRequest(request) {
811
868
  // Get access token with priority and auto-refresh
812
- const tokenInfo = await getAccessToken();
869
+ let tokenInfo = await getAccessToken();
870
+
871
+ // If no token and we haven't attempted auto-auth, try it
872
+ if (!tokenInfo && !autoAuthAttempted && !autoAuthInProgress) {
873
+ const authSucceeded = await attemptAutoAuth();
874
+ if (authSucceeded) {
875
+ // Retry getting token after successful auth
876
+ tokenInfo = await getAccessToken();
877
+ }
878
+ }
879
+
813
880
  if (!tokenInfo) {
814
881
  sendError(request.id, CUSTOM_ERROR_CODES.AUTH_REQUIRED,
815
882
  'Meldoc token not found. Set MELDOC_ACCESS_TOKEN environment variable or run: npx @meldocio/mcp-stdio-proxy@latest auth login', {
@@ -3,6 +3,8 @@ const https = require('https');
3
3
  const { writeCredentials } = require('./credentials');
4
4
  const { getApiUrl, getAppUrl } = require('./constants');
5
5
  const logger = require('./logger');
6
+ const os = require('os');
7
+ const { exec } = require('child_process');
6
8
 
7
9
  /**
8
10
  * Start device flow authentication
@@ -256,8 +258,321 @@ async function deviceFlowLogin(onCodeDisplay, onStatusChange = null, apiBaseUrl
256
258
  throw new Error('Device code expired');
257
259
  }
258
260
 
261
+ /**
262
+ * Check if browser can be opened automatically
263
+ * @returns {boolean} True if browser can be opened
264
+ */
265
+ function canOpenBrowser() {
266
+ return process.stdout.isTTY && !process.env.CI && !process.env.NO_BROWSER;
267
+ }
268
+
269
+ /**
270
+ * Open browser automatically
271
+ * @param {string} url - URL to open
272
+ * @returns {Promise<void>}
273
+ */
274
+ async function openBrowser(url) {
275
+ try {
276
+ // Try using 'open' package first (cross-platform)
277
+ const open = require('open');
278
+ await open(url);
279
+ } catch (error) {
280
+ // Fallback to platform-specific commands
281
+ try {
282
+ const platform = os.platform();
283
+ let command;
284
+
285
+ if (platform === 'darwin') {
286
+ command = `open "${url}"`;
287
+ } else if (platform === 'win32') {
288
+ command = `start "" "${url}"`;
289
+ } else {
290
+ command = `xdg-open "${url}"`;
291
+ }
292
+
293
+ exec(command, (err) => {
294
+ if (err) {
295
+ // Silent fail - browser opening is optional
296
+ }
297
+ });
298
+ } catch (fallbackError) {
299
+ // Silent fail - browser opening is optional
300
+ }
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Copy text to clipboard
306
+ * @param {string} text - Text to copy
307
+ * @returns {Promise<void>}
308
+ */
309
+ async function copyToClipboard(text) {
310
+ try {
311
+ const clipboardy = require('clipboardy');
312
+ await clipboardy.write(text);
313
+ } catch (error) {
314
+ // Silent fail - clipboard copy is optional
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Show QR code for mobile authentication
320
+ * @param {string} url - URL to encode in QR code
321
+ */
322
+ function showQRCode(url) {
323
+ try {
324
+ const qrcode = require('qrcode-terminal');
325
+ qrcode.generate(url, { small: true });
326
+ } catch (error) {
327
+ // Silent fail - QR code is optional
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Sleep utility
333
+ * @param {number} ms - Milliseconds to sleep
334
+ * @returns {Promise<void>}
335
+ */
336
+ function sleep(ms) {
337
+ return new Promise(resolve => setTimeout(resolve, ms));
338
+ }
339
+
340
+ /**
341
+ * Poll for tokens with spinner and progress
342
+ * @param {string} deviceCode - Device code
343
+ * @param {number} interval - Polling interval in seconds
344
+ * @param {number} timeout - Timeout in milliseconds
345
+ * @param {string} apiBaseUrl - API base URL
346
+ * @returns {Promise<Object>} Credentials object
347
+ */
348
+ async function pollForTokens({ deviceCode, interval, timeout, apiBaseUrl }) {
349
+ const startTime = Date.now();
350
+ const spinner = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
351
+ let spinnerIndex = 0;
352
+ let spinnerInterval = null;
353
+
354
+ // Start spinner animation if stderr is TTY
355
+ if (process.stderr.isTTY) {
356
+ spinnerInterval = setInterval(() => {
357
+ const elapsed = Math.floor((Date.now() - startTime) / 1000);
358
+ process.stderr.write(
359
+ `\r${spinner[spinnerIndex]} Waiting for authorization... (${elapsed}s)`
360
+ );
361
+ spinnerIndex = (spinnerIndex + 1) % spinner.length;
362
+ }, 100);
363
+ }
364
+
365
+ try {
366
+ while (true) {
367
+ // Check timeout
368
+ if (Date.now() - startTime > timeout) {
369
+ throw new Error('Authentication timeout. Please try again.');
370
+ }
371
+
372
+ try {
373
+ // Poll for status
374
+ const pollResponse = await pollDeviceFlow(deviceCode, apiBaseUrl);
375
+
376
+ if (pollResponse.status === 'approved') {
377
+ // Clear spinner
378
+ if (spinnerInterval) {
379
+ clearInterval(spinnerInterval);
380
+ process.stderr.write('\r✅ Authorization confirmed! \n');
381
+ }
382
+
383
+ // Validate that we have required fields
384
+ if (!pollResponse.accessToken) {
385
+ throw new Error(`Invalid poll response: missing accessToken. Response: ${JSON.stringify(pollResponse)}`);
386
+ }
387
+
388
+ return pollResponse;
389
+ }
390
+
391
+ if (pollResponse.status === 'denied') {
392
+ throw new Error('Authorization denied by user');
393
+ }
394
+
395
+ if (pollResponse.status === 'expired') {
396
+ throw new Error('Device code expired');
397
+ }
398
+
399
+ // status === 'pending' - continue polling
400
+ await sleep(interval * 1000);
401
+
402
+ } catch (error) {
403
+ // If network error, retry
404
+ if (error.code === 'ECONNREFUSED' || error.code === 'ETIMEDOUT' || error.message.includes('No response')) {
405
+ await sleep(interval * 1000);
406
+ continue;
407
+ }
408
+ throw error;
409
+ }
410
+ }
411
+ } finally {
412
+ if (spinnerInterval) {
413
+ clearInterval(spinnerInterval);
414
+ process.stderr.write('\r \r');
415
+ }
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Interactive login with automatic browser opening and enhanced UX
421
+ * @param {Object} options - Login options
422
+ * @param {boolean} options.autoOpen - Automatically open browser (default: true)
423
+ * @param {boolean} options.showQR - Show QR code (default: false)
424
+ * @param {number} options.timeout - Timeout in milliseconds (default: 120000)
425
+ * @param {string} options.apiBaseUrl - API base URL
426
+ * @param {string} options.appUrl - App URL
427
+ * @returns {Promise<Object>} Credentials object
428
+ */
429
+ async function interactiveLogin(options = {}) {
430
+ const {
431
+ autoOpen = true,
432
+ showQR = false,
433
+ timeout = 120000,
434
+ apiBaseUrl = null,
435
+ appUrl = null
436
+ } = options;
437
+
438
+ const url = apiBaseUrl || getApiUrl();
439
+ const frontendUrl = appUrl || getAppUrl();
440
+
441
+ try {
442
+ // Step 1: Get device code from server
443
+ const startResponse = await startDeviceFlow(url);
444
+ const { deviceCode, userCode, verificationUrl, expiresIn, interval } = startResponse;
445
+
446
+ // Step 2: Build full URL
447
+ let displayUrl = verificationUrl;
448
+
449
+ // Check if verificationUrl already contains code in query parameter
450
+ let urlHasCode = false;
451
+ try {
452
+ const urlObj = new URL(verificationUrl);
453
+ if (urlObj.searchParams.has('code')) {
454
+ urlHasCode = true;
455
+ }
456
+ } catch (e) {
457
+ // URL parsing failed, continue
458
+ }
459
+
460
+ if (process.env.MELDOC_APP_URL || appUrl) {
461
+ try {
462
+ const urlObj = new URL(verificationUrl);
463
+ const appUrlObj = new URL(frontendUrl);
464
+ displayUrl = `${appUrlObj.origin}${urlObj.pathname}${urlObj.search}`;
465
+ } catch (e) {
466
+ displayUrl = verificationUrl;
467
+ }
468
+ }
469
+
470
+ // If URL doesn't have code, add it as path parameter
471
+ let fullUrl = displayUrl;
472
+ if (!urlHasCode) {
473
+ if (displayUrl.endsWith('/')) {
474
+ fullUrl = `${displayUrl}${userCode}`;
475
+ } else {
476
+ fullUrl = `${displayUrl}/${userCode}`;
477
+ }
478
+ }
479
+
480
+ // Step 3: Display authentication UI
481
+ process.stderr.write('\n');
482
+ process.stderr.write('╔═══════════════════════════════════════════════════════╗\n');
483
+ process.stderr.write('║ ║\n');
484
+ process.stderr.write('║ 🔐 Meldoc Authentication Required ║\n');
485
+ process.stderr.write('║ ║\n');
486
+ process.stderr.write('╚═══════════════════════════════════════════════════════╝\n');
487
+ process.stderr.write('\n');
488
+
489
+ // Show QR code if requested
490
+ if (showQR) {
491
+ process.stderr.write('📱 Scan QR code with your phone:\n\n');
492
+ showQRCode(fullUrl);
493
+ process.stderr.write('\n');
494
+ }
495
+
496
+ // Show URL and code
497
+ process.stderr.write(`🌐 Visit: ${fullUrl}\n`);
498
+ process.stderr.write(`📝 Enter this code: ${userCode}\n\n`);
499
+ process.stderr.write('───────────────────────────────────────────────────────\n\n');
500
+
501
+ // Step 4: Automatically open browser if enabled
502
+ const shouldOpenBrowser = autoOpen && canOpenBrowser();
503
+ if (shouldOpenBrowser) {
504
+ process.stderr.write('🚀 Opening browser automatically...\n\n');
505
+ await openBrowser(fullUrl);
506
+ } else if (!canOpenBrowser()) {
507
+ process.stderr.write('⚠️ Please open the link manually in your browser\n\n');
508
+ }
509
+
510
+ // Step 5: Copy code to clipboard
511
+ try {
512
+ await copyToClipboard(userCode);
513
+ process.stderr.write('✅ Code copied to clipboard!\n\n');
514
+ } catch (error) {
515
+ // Silent fail
516
+ }
517
+
518
+ // Step 6: Poll for authorization with spinner
519
+ process.stderr.write('⏳ Waiting for authorization...\n\n');
520
+
521
+ const pollResponse = await pollForTokens({
522
+ deviceCode,
523
+ interval,
524
+ timeout,
525
+ apiBaseUrl: url
526
+ });
527
+
528
+ // Step 7: Save credentials
529
+ const credentials = {
530
+ type: 'user_session',
531
+ apiBaseUrl: url,
532
+ user: pollResponse.user,
533
+ tokens: {
534
+ accessToken: pollResponse.accessToken,
535
+ accessExpiresAt: pollResponse.expiresAt || new Date(Date.now() + 3600000).toISOString(),
536
+ refreshToken: pollResponse.refreshToken || null
537
+ },
538
+ updatedAt: new Date().toISOString()
539
+ };
540
+
541
+ writeCredentials(credentials);
542
+
543
+ process.stderr.write('\n✅ Successfully authenticated!\n\n');
544
+
545
+ return credentials;
546
+
547
+ } catch (error) {
548
+ // Handle specific errors with helpful messages
549
+ if (error.code === 'ECONNREFUSED' || error.message.includes('No response')) {
550
+ process.stderr.write('\n❌ Cannot connect to Meldoc API\n');
551
+ process.stderr.write(' Please check your internet connection\n\n');
552
+ } else if (error.message.includes('timeout')) {
553
+ process.stderr.write('\n⏱️ Authentication timed out\n');
554
+ process.stderr.write(' Please try again or authenticate manually:\n');
555
+ process.stderr.write(' npx @meldocio/mcp-stdio-proxy@latest auth login\n\n');
556
+ } else if (error.message.includes('denied')) {
557
+ process.stderr.write('\n🚫 Authentication was denied\n');
558
+ process.stderr.write(' Please try again if this was a mistake\n\n');
559
+ } else {
560
+ process.stderr.write(`\n❌ Authentication failed: ${error.message}\n\n`);
561
+ process.stderr.write(' Manual authentication:\n');
562
+ process.stderr.write(' npx @meldocio/mcp-stdio-proxy@latest auth login\n\n');
563
+ }
564
+
565
+ throw error;
566
+ }
567
+ }
568
+
259
569
  module.exports = {
260
570
  startDeviceFlow,
261
571
  pollDeviceFlow,
262
- deviceFlowLogin
572
+ deviceFlowLogin,
573
+ interactiveLogin,
574
+ openBrowser,
575
+ copyToClipboard,
576
+ showQRCode,
577
+ canOpenBrowser
263
578
  };
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@meldocio/mcp-stdio-proxy",
3
- "version": "1.0.19",
4
- "description": "MCP stdio proxy for meldoc - connects Claude Desktop to meldoc MCP API",
3
+ "version": "1.0.21",
4
+ "description": "MCP stdio proxy for meldoc - connects Claude Desktop and Claude Code to meldoc MCP API",
5
5
  "bin": {
6
6
  "meldoc-mcp": "bin/meldoc-mcp-proxy.js"
7
7
  },
8
8
  "files": [
9
9
  "bin/**",
10
10
  "lib/**",
11
+ ".claude-plugin/**",
12
+ ".mcp.json",
11
13
  "README.md",
12
14
  "LICENSE"
13
15
  ],
@@ -18,6 +20,7 @@
18
20
  "mcp",
19
21
  "meldoc",
20
22
  "claude",
23
+ "claude-code",
21
24
  "stdio",
22
25
  "proxy",
23
26
  "json-rpc"