@meldocio/mcp-stdio-proxy 1.0.22 → 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.
@@ -0,0 +1,277 @@
1
+ /**
2
+ * CLI Command Handlers
3
+ *
4
+ * Handles all CLI commands for auth, config, and installation.
5
+ */
6
+
7
+ const { interactiveLogin } = require('../core/device-flow');
8
+ const { deleteCredentials } = require('../core/credentials');
9
+ const { getAuthStatus, getAccessToken } = require('../core/auth');
10
+ const { setWorkspaceAlias, getWorkspaceAlias } = require('../core/config');
11
+ const { getApiUrl, getAppUrl } = require('../core/constants');
12
+ const { createInstaller } = require('../install/installers');
13
+ const axios = require('axios');
14
+ const https = require('https');
15
+ const chalk = require('chalk');
16
+ const logger = require('../core/logger');
17
+
18
+ const API_URL = getApiUrl();
19
+ const APP_URL = getAppUrl();
20
+
21
+ /**
22
+ * Authentication Commands
23
+ */
24
+
25
+ /**
26
+ * Handle auth login command
27
+ */
28
+ async function handleAuthLogin() {
29
+ try {
30
+ await interactiveLogin({
31
+ autoOpen: true,
32
+ showQR: false,
33
+ timeout: 120000,
34
+ apiBaseUrl: API_URL,
35
+ appUrl: APP_URL
36
+ });
37
+ process.exit(0);
38
+ } catch (error) {
39
+ process.exit(1);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Handle auth status command
45
+ */
46
+ async function handleAuthStatus() {
47
+ const status = await getAuthStatus();
48
+ if (!status || !status.authenticated) {
49
+ logger.error('Not authenticated');
50
+ console.log('\n' + logger.label('To authenticate, run:'));
51
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login') + '\n');
52
+ process.exit(1);
53
+ }
54
+
55
+ logger.section('🔑 Authentication Status');
56
+
57
+ if (status.type === 'user_session' && status.user) {
58
+ logger.item('Email', logger.value(status.user.email));
59
+ if (status.expiresAt) {
60
+ logger.item('Token expires', logger.value(new Date(status.expiresAt).toLocaleString()));
61
+ }
62
+ } else {
63
+ logger.item('Type', logger.value(status.type));
64
+ }
65
+
66
+ console.log();
67
+ process.exit(0);
68
+ }
69
+
70
+ /**
71
+ * Handle auth logout command
72
+ */
73
+ async function handleAuthLogout() {
74
+ deleteCredentials();
75
+ logger.success('Logged out successfully');
76
+ process.exit(0);
77
+ }
78
+
79
+ /**
80
+ * Configuration Commands
81
+ */
82
+
83
+ /**
84
+ * Handle config set-workspace command
85
+ */
86
+ function handleConfigSetWorkspace(alias) {
87
+ if (!alias) {
88
+ logger.error('Workspace alias is required');
89
+ console.log('\n' + logger.label('Usage:'));
90
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy config set-workspace <alias>') + '\n');
91
+ process.exit(1);
92
+ }
93
+
94
+ try {
95
+ setWorkspaceAlias(alias);
96
+ logger.success(`Workspace set to: ${logger.highlight(alias)}`);
97
+ process.exit(0);
98
+ } catch (error) {
99
+ logger.error(`Failed to set workspace: ${error.message}`);
100
+ process.exit(1);
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Handle config get-workspace command
106
+ */
107
+ function handleConfigGetWorkspace() {
108
+ const alias = getWorkspaceAlias();
109
+ if (alias) {
110
+ console.log(logger.highlight(alias));
111
+ }
112
+ process.exit(0);
113
+ }
114
+
115
+ /**
116
+ * Handle config list-workspaces command
117
+ */
118
+ async function handleConfigListWorkspaces() {
119
+ try {
120
+ const tokenInfo = await getAccessToken();
121
+ if (!tokenInfo) {
122
+ logger.error('Not authenticated');
123
+ console.log('\n' + logger.label('To authenticate, run:'));
124
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login') + '\n');
125
+ process.exit(1);
126
+ }
127
+
128
+ // Call MCP tool meldoc.list_workspaces via POST /mcp/v1/rpc
129
+ const response = await axios.post(`${API_URL}/mcp/v1/rpc`, {
130
+ jsonrpc: '2.0',
131
+ id: 1,
132
+ method: 'tools/call',
133
+ params: {
134
+ name: 'meldoc.list_workspaces',
135
+ arguments: {}
136
+ }
137
+ }, {
138
+ headers: {
139
+ 'Authorization': `Bearer ${tokenInfo.token}`,
140
+ 'Content-Type': 'application/json'
141
+ },
142
+ timeout: 10000,
143
+ httpsAgent: new https.Agent({ keepAlive: true })
144
+ });
145
+
146
+ if (response.data.error) {
147
+ logger.error(`Error: ${response.data.error.message}`);
148
+ process.exit(1);
149
+ }
150
+
151
+ const workspaces = response.data.result?.workspaces || [];
152
+ if (workspaces.length === 0) {
153
+ logger.info('No workspaces available');
154
+ process.exit(0);
155
+ }
156
+
157
+ logger.section('📁 Available Workspaces');
158
+ for (const ws of workspaces) {
159
+ const role = ws.role || 'member';
160
+ const roleColor = role === 'owner' ? chalk.red : role === 'admin' ? chalk.yellow : chalk.gray;
161
+ logger.item(
162
+ `${logger.highlight(ws.alias)} ${chalk.gray('(' + ws.name + ')')}`,
163
+ roleColor(`[${role}]`)
164
+ );
165
+ }
166
+ console.log();
167
+
168
+ process.exit(0);
169
+ } catch (error) {
170
+ if (error.response?.data?.error) {
171
+ const errorData = error.response.data.error;
172
+ if (errorData.code === 'AUTH_REQUIRED' || errorData.data?.code === 'AUTH_REQUIRED') {
173
+ logger.error('Not authenticated');
174
+ console.log('\n' + logger.label('To authenticate, run:'));
175
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login') + '\n');
176
+ process.exit(1);
177
+ }
178
+ logger.error(`Error: ${errorData.message || error.message}`);
179
+ } else {
180
+ logger.error(`Error: ${error.message}`);
181
+ }
182
+ process.exit(1);
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Installation Commands
188
+ */
189
+
190
+ /**
191
+ * Handle install command - automatically configure MCP client
192
+ */
193
+ function handleInstall(consumer, isLocal) {
194
+ if (isLocal) {
195
+ const installer = createInstaller('local');
196
+ const result = installer.install();
197
+ process.exit(result.result === 'error' ? 1 : 0);
198
+ return;
199
+ }
200
+
201
+ const consumerLower = (consumer || 'claude-desktop').toLowerCase();
202
+ let client, scope;
203
+
204
+ switch (consumerLower) {
205
+ case 'claude-desktop':
206
+ case 'claude':
207
+ client = 'claude-desktop';
208
+ scope = 'project';
209
+ break;
210
+ case 'cursor':
211
+ client = 'cursor';
212
+ scope = 'project';
213
+ break;
214
+ case 'cursor-global':
215
+ client = 'cursor';
216
+ scope = 'global';
217
+ break;
218
+ case 'claude-code':
219
+ client = 'claude-code';
220
+ scope = 'project';
221
+ break;
222
+ case 'claude-code-user':
223
+ client = 'claude-code';
224
+ scope = 'user';
225
+ break;
226
+ case 'claude-code-local':
227
+ client = 'claude-code';
228
+ scope = 'local';
229
+ break;
230
+ default:
231
+ logger.error(`Unknown consumer: ${consumer}`);
232
+ console.log();
233
+ logger.info('Supported consumers:');
234
+ console.log(' ' + logger.highlight('claude-desktop') + ' (or claude) - Claude Desktop');
235
+ console.log(' ' + logger.highlight('cursor') + ' - Cursor IDE (project-specific)');
236
+ console.log(' ' + logger.highlight('cursor-global') + ' - Cursor IDE (global)');
237
+ console.log(' ' + logger.highlight('claude-code') + ' - Claude Code (project scope)');
238
+ console.log(' ' + logger.highlight('claude-code-user') + ' - Claude Code (user scope)');
239
+ console.log(' ' + logger.highlight('claude-code-local') + ' - Claude Code (local scope)');
240
+ console.log();
241
+ logger.info('Or use ' + logger.highlight('--local') + ' flag to create local mcp.json');
242
+ console.log();
243
+ process.exit(1);
244
+ return;
245
+ }
246
+
247
+ // Use new unified installer
248
+ const installer = createInstaller(client, scope);
249
+ const result = installer.install();
250
+ process.exit(result.result === 'error' ? 1 : 0);
251
+ }
252
+
253
+ /**
254
+ * Handle uninstall command - remove Meldoc MCP configuration
255
+ */
256
+ function handleUninstall() {
257
+ // Default to Claude Desktop for backward compatibility
258
+ const installer = createInstaller('claude-desktop');
259
+ const result = installer.uninstall();
260
+ process.exit(result.result === 'error' ? 1 : 0);
261
+ }
262
+
263
+ module.exports = {
264
+ // Auth commands
265
+ handleAuthLogin,
266
+ handleAuthStatus,
267
+ handleAuthLogout,
268
+
269
+ // Config commands
270
+ handleConfigSetWorkspace,
271
+ handleConfigGetWorkspace,
272
+ handleConfigListWorkspaces,
273
+
274
+ // Installation commands
275
+ handleInstall,
276
+ handleUninstall
277
+ };
@@ -0,0 +1,137 @@
1
+ /**
2
+ * CLI Output Formatters
3
+ *
4
+ * Handles help text, usage hints, and other formatted CLI output.
5
+ */
6
+
7
+ const logger = require('../core/logger');
8
+
9
+ /**
10
+ * Show detailed help message with all commands and examples
11
+ */
12
+ function handleHelp() {
13
+ console.log('\n' + logger.section('📖 Meldoc MCP CLI Help'));
14
+ console.log();
15
+
16
+ console.log(logger.label('Available Commands:'));
17
+ console.log();
18
+
19
+ console.log(' ' + logger.highlight('auth login'));
20
+ console.log(' Authenticate with Meldoc using device flow');
21
+ console.log();
22
+
23
+ console.log(' ' + logger.highlight('auth status'));
24
+ console.log(' Check authentication status');
25
+ console.log();
26
+
27
+ console.log(' ' + logger.highlight('auth logout'));
28
+ console.log(' Log out and clear credentials');
29
+ console.log();
30
+
31
+ console.log(' ' + logger.highlight('config set-workspace <alias>'));
32
+ console.log(' Set the active workspace alias');
33
+ console.log();
34
+
35
+ console.log(' ' + logger.highlight('config get-workspace'));
36
+ console.log(' Get the current workspace alias');
37
+ console.log();
38
+
39
+ console.log(' ' + logger.highlight('config list-workspaces'));
40
+ console.log(' List all available workspaces');
41
+ console.log();
42
+
43
+ console.log(' ' + logger.highlight('install [consumer] [--local]'));
44
+ console.log(' Automatically configure MCP client for Meldoc MCP');
45
+ console.log(' Consumers: claude-desktop (default), cursor, cursor-global, claude-code');
46
+ console.log(' Use --local flag to create local mcp.json file');
47
+ console.log();
48
+
49
+ console.log(' ' + logger.highlight('uninstall'));
50
+ console.log(' Remove Meldoc MCP configuration from Claude Desktop');
51
+ console.log();
52
+
53
+ console.log(' ' + logger.highlight('help'));
54
+ console.log(' Show this help message');
55
+ console.log();
56
+
57
+ console.log(logger.label('Examples:'));
58
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install'));
59
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install claude-desktop'));
60
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install cursor'));
61
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install claude-code'));
62
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install --local'));
63
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy uninstall'));
64
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
65
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy config set-workspace my-workspace'));
66
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy config list-workspaces'));
67
+ console.log();
68
+
69
+ process.exit(0);
70
+ }
71
+
72
+ /**
73
+ * Show brief usage hints when no arguments provided
74
+ */
75
+ function showUsageHints() {
76
+ console.log('\n' + logger.section('🔧 Meldoc MCP CLI'));
77
+ console.log();
78
+ console.log(logger.label('Available commands:'));
79
+ console.log(' ' + logger.highlight('auth login') + ' - Authenticate with Meldoc');
80
+ console.log(' ' + logger.highlight('auth status') + ' - Check authentication status');
81
+ console.log(' ' + logger.highlight('auth logout') + ' - Log out');
82
+ console.log(' ' + logger.highlight('config set-workspace') + ' - Set workspace alias');
83
+ console.log(' ' + logger.highlight('config get-workspace') + ' - Get current workspace');
84
+ console.log(' ' + logger.highlight('config list-workspaces') + ' - List workspaces');
85
+ console.log(' ' + logger.highlight('install [consumer]') + ' - Configure MCP client');
86
+ console.log(' ' + logger.highlight('uninstall') + ' - Remove configuration');
87
+ console.log(' ' + logger.highlight('help') + ' - Show detailed help');
88
+ console.log();
89
+ console.log(logger.label('For more information, run:'));
90
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy help') + '\n');
91
+ process.exit(0);
92
+ }
93
+
94
+ /**
95
+ * Show unknown command error with available commands
96
+ */
97
+ function showUnknownCommandError(command) {
98
+ logger.error(`Unknown command: ${command}`);
99
+ console.log('\n' + logger.label('Available commands:'));
100
+ console.log(' ' + logger.highlight('install') + ' - Configure Claude Desktop');
101
+ console.log(' ' + logger.highlight('uninstall') + ' - Remove configuration');
102
+ console.log(' ' + logger.highlight('auth') + ' <cmd> - Authentication commands');
103
+ console.log(' ' + logger.highlight('config') + ' <cmd> - Configuration commands');
104
+ console.log(' ' + logger.highlight('help') + ' - Show help');
105
+ console.log();
106
+ console.log(logger.label('Run') + ' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy help') + ' ' + logger.label('for more information'));
107
+ console.log();
108
+ process.exit(1);
109
+ }
110
+
111
+ /**
112
+ * Show unknown auth subcommand error
113
+ */
114
+ function showUnknownAuthCommandError(subcommand) {
115
+ logger.error(`Unknown auth command: ${subcommand}`);
116
+ console.log('\n' + logger.label('Usage:'));
117
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth <login|status|logout>') + '\n');
118
+ process.exit(1);
119
+ }
120
+
121
+ /**
122
+ * Show unknown config subcommand error
123
+ */
124
+ function showUnknownConfigCommandError(subcommand) {
125
+ logger.error(`Unknown config command: ${subcommand}`);
126
+ console.log('\n' + logger.label('Usage:'));
127
+ console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy config <set-workspace|get-workspace|list-workspaces>') + '\n');
128
+ process.exit(1);
129
+ }
130
+
131
+ module.exports = {
132
+ handleHelp,
133
+ showUsageHints,
134
+ showUnknownCommandError,
135
+ showUnknownAuthCommandError,
136
+ showUnknownConfigCommandError
137
+ };
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Default configuration constants
3
+ * Production values used when environment variables are not set
4
+ */
5
+
6
+ // Production API URL
7
+ const DEFAULT_API_URL = 'https://api.meldoc.io';
8
+
9
+ // Production App URL (frontend)
10
+ const DEFAULT_APP_URL = 'https://app.meldoc.io';
11
+
12
+ /**
13
+ * Request timeout configuration
14
+ * 25 seconds - less than Claude Desktop's 30s timeout to allow for proper error handling
15
+ */
16
+ const REQUEST_TIMEOUT = 25000;
17
+
18
+ /**
19
+ * Log levels for severity filtering
20
+ */
21
+ const LOG_LEVELS = {
22
+ ERROR: 0,
23
+ WARN: 1,
24
+ INFO: 2,
25
+ DEBUG: 3
26
+ };
27
+
28
+ /**
29
+ * Default log level names mapped to numeric values
30
+ */
31
+ const LOG_LEVEL_NAMES = {
32
+ 0: 'ERROR',
33
+ 1: 'WARN',
34
+ 2: 'INFO',
35
+ 3: 'DEBUG'
36
+ };
37
+
38
+ /**
39
+ * MCP protocol version
40
+ */
41
+ const MCP_PROTOCOL_VERSION = '2025-06-18';
42
+
43
+ /**
44
+ * Server capability flags
45
+ */
46
+ const SERVER_CAPABILITIES = {
47
+ TOOLS: true,
48
+ PROMPTS: false,
49
+ RESOURCES: false,
50
+ LOGGING: false
51
+ };
52
+
53
+ /**
54
+ * Get API URL from environment or use production default
55
+ */
56
+ function getApiUrl() {
57
+ return process.env.MELDOC_API_URL || DEFAULT_API_URL;
58
+ }
59
+
60
+ /**
61
+ * Get App URL from environment or use production default
62
+ */
63
+ function getAppUrl() {
64
+ return process.env.MELDOC_APP_URL || DEFAULT_APP_URL;
65
+ }
66
+
67
+ /**
68
+ * Get log level from environment variable
69
+ * @param {string} [level] - Log level string (ERROR, WARN, INFO, DEBUG)
70
+ * @returns {number} Numeric log level
71
+ */
72
+ function getLogLevel(level) {
73
+ const upper = (level || '').toUpperCase();
74
+ return LOG_LEVELS[upper] !== undefined ? LOG_LEVELS[upper] : LOG_LEVELS.ERROR;
75
+ }
76
+
77
+ /**
78
+ * Get log level name from numeric value
79
+ * @param {number} level - Numeric log level
80
+ * @returns {string} Log level name
81
+ */
82
+ function getLogLevelName(level) {
83
+ return LOG_LEVEL_NAMES[level] || 'UNKNOWN';
84
+ }
85
+
86
+ module.exports = {
87
+ DEFAULT_API_URL,
88
+ DEFAULT_APP_URL,
89
+ REQUEST_TIMEOUT,
90
+ LOG_LEVELS,
91
+ LOG_LEVEL_NAMES,
92
+ MCP_PROTOCOL_VERSION,
93
+ SERVER_CAPABILITIES,
94
+ getApiUrl,
95
+ getAppUrl,
96
+ getLogLevel,
97
+ getLogLevelName
98
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * HTTP Client for MCP Backend Communication
3
+ *
4
+ * Handles HTTP requests to the Meldoc API backend.
5
+ */
6
+
7
+ const axios = require('axios');
8
+ const https = require('https');
9
+ const { getApiUrl, REQUEST_TIMEOUT } = require('../core/constants');
10
+ const { getAccessToken } = require('../core/auth');
11
+ const { resolveWorkspaceAlias } = require('../core/workspace');
12
+
13
+ /**
14
+ * Make an authenticated JSON-RPC request to the backend
15
+ * @param {Object} request - JSON-RPC request object
16
+ * @returns {Promise<Object>} Response data
17
+ */
18
+ async function makeBackendRequest(request) {
19
+ const apiUrl = getApiUrl();
20
+ const rpcEndpoint = `${apiUrl}/mcp/v1/rpc`;
21
+
22
+ // Get access token
23
+ const tokenInfo = await getAccessToken();
24
+ if (!tokenInfo) {
25
+ throw new Error('Not authenticated');
26
+ }
27
+
28
+ // Ensure request has jsonrpc field
29
+ const requestWithJsonRpc = {
30
+ ...request,
31
+ jsonrpc: request.jsonrpc || '2.0'
32
+ };
33
+
34
+ // Resolve workspace if not provided
35
+ const workspaceAlias = await resolveWorkspaceAlias();
36
+
37
+ // Build headers
38
+ const headers = {
39
+ 'Authorization': `Bearer ${tokenInfo.token}`,
40
+ 'Content-Type': 'application/json'
41
+ };
42
+
43
+ // Add workspace header if available
44
+ if (workspaceAlias) {
45
+ headers['X-Workspace-Alias'] = workspaceAlias;
46
+ }
47
+
48
+ // Make request
49
+ const response = await axios.post(rpcEndpoint, requestWithJsonRpc, {
50
+ headers,
51
+ timeout: REQUEST_TIMEOUT,
52
+ httpsAgent: new https.Agent({ keepAlive: true }),
53
+ validateStatus: () => true // Accept all status codes
54
+ });
55
+
56
+ return response;
57
+ }
58
+
59
+ module.exports = {
60
+ makeBackendRequest
61
+ };