@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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/bin/cli.js +33 -1088
- package/bin/meldoc-mcp-proxy.js +134 -1264
- package/lib/cli/commands.js +277 -0
- package/lib/cli/formatters.js +137 -0
- package/lib/core/constants.js +98 -0
- package/lib/http/client.js +61 -0
- package/lib/http/error-handler.js +195 -0
- package/lib/install/config-manager.js +203 -0
- package/lib/install/config-paths.js +198 -0
- package/lib/install/installers.js +328 -0
- package/lib/install/templates.js +266 -0
- package/lib/mcp/handlers.js +185 -0
- package/lib/mcp/tools-call.js +179 -0
- package/lib/protocol/error-codes.js +143 -0
- package/lib/protocol/json-rpc.js +183 -0
- package/lib/protocol/tools-schema.js +239 -0
- package/package.json +1 -1
- package/lib/constants.js +0 -31
- /package/lib/{auth.js → core/auth.js} +0 -0
- /package/lib/{config.js → core/config.js} +0 -0
- /package/lib/{credentials.js → core/credentials.js} +0 -0
- /package/lib/{device-flow.js → core/device-flow.js} +0 -0
- /package/lib/{logger.js → core/logger.js} +0 -0
- /package/lib/{workspace.js → core/workspace.js} +0 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Installation Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Unified installer for all MCP clients (Claude Desktop, Cursor, Claude Code, Local).
|
|
5
|
+
* Consolidates installation logic to eliminate code duplication.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const logger = require('../core/logger');
|
|
9
|
+
const { getConfigPath, getClientDisplayName } = require('./config-paths');
|
|
10
|
+
const { getConfigTemplate, configsEqual, mergeClaudeDesktopConfig, mergeCursorConfig, mergeClaudeCodeConfig, removeMeldocConfig, removeMeldocClaudeCodeConfig } = require('./templates');
|
|
11
|
+
const { readConfigSafe, writeConfig, fileExists } = require('./config-manager');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Installation result codes
|
|
16
|
+
*/
|
|
17
|
+
const INSTALL_RESULTS = {
|
|
18
|
+
SUCCESS: 'success',
|
|
19
|
+
ALREADY_CONFIGURED: 'already_configured',
|
|
20
|
+
UPDATED: 'updated',
|
|
21
|
+
ERROR: 'error'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Unified MCP Installer
|
|
26
|
+
* Handles installation for all supported clients
|
|
27
|
+
*/
|
|
28
|
+
class Installer {
|
|
29
|
+
/**
|
|
30
|
+
* Create an installer for a specific client
|
|
31
|
+
* @param {string} client - Client type: 'claude-desktop', 'cursor', 'claude-code', 'local'
|
|
32
|
+
* @param {string} [scope='project'] - Installation scope: 'global', 'project', 'user', 'local'
|
|
33
|
+
*/
|
|
34
|
+
constructor(client, scope = 'project') {
|
|
35
|
+
this.client = client;
|
|
36
|
+
this.scope = scope;
|
|
37
|
+
this.clientName = getClientDisplayName(client);
|
|
38
|
+
this.configPath = getConfigPath(client, scope);
|
|
39
|
+
this.expectedConfig = getConfigTemplate(client);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get the server key name based on client type
|
|
44
|
+
* @returns {string} Server key ('meldoc' or 'meldoc-mcp')
|
|
45
|
+
*/
|
|
46
|
+
getServerKey() {
|
|
47
|
+
return this.client === 'claude-code' ? 'meldoc-mcp' : 'meldoc';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Check if Meldoc is already configured
|
|
52
|
+
* @returns {Object} { configured: boolean, isEqual: boolean, existingConfig: Object|null }
|
|
53
|
+
*/
|
|
54
|
+
checkExistingConfig() {
|
|
55
|
+
const config = readConfigSafe(this.configPath);
|
|
56
|
+
const serverKey = this.getServerKey();
|
|
57
|
+
|
|
58
|
+
if (!config.mcpServers || !config.mcpServers[serverKey]) {
|
|
59
|
+
return {
|
|
60
|
+
configured: false,
|
|
61
|
+
isEqual: false,
|
|
62
|
+
existingConfig: null
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const existingConfig = config.mcpServers[serverKey];
|
|
67
|
+
const isEqual = configsEqual(existingConfig, this.expectedConfig);
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
configured: true,
|
|
71
|
+
isEqual,
|
|
72
|
+
existingConfig
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Install Meldoc MCP configuration
|
|
78
|
+
* @returns {Object} { result: string, message: string, configPath: string }
|
|
79
|
+
*/
|
|
80
|
+
install() {
|
|
81
|
+
try {
|
|
82
|
+
logger.section(`🚀 Installing Meldoc MCP for ${this.clientName}`);
|
|
83
|
+
console.log();
|
|
84
|
+
|
|
85
|
+
logger.info(`Config file location: ${logger.highlight(this.configPath)}`);
|
|
86
|
+
console.log();
|
|
87
|
+
|
|
88
|
+
// Check existing configuration
|
|
89
|
+
const { configured, isEqual, existingConfig } = this.checkExistingConfig();
|
|
90
|
+
|
|
91
|
+
if (configured && isEqual) {
|
|
92
|
+
logger.success('Meldoc MCP is already configured correctly!');
|
|
93
|
+
console.log();
|
|
94
|
+
logger.info('Current configuration:');
|
|
95
|
+
console.log(' ' + logger.highlight(JSON.stringify(existingConfig, null, 2)));
|
|
96
|
+
console.log();
|
|
97
|
+
this.printNextSteps();
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
result: INSTALL_RESULTS.ALREADY_CONFIGURED,
|
|
101
|
+
message: 'Configuration already exists and is correct',
|
|
102
|
+
configPath: this.configPath
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (configured && !isEqual) {
|
|
107
|
+
logger.warn('Meldoc MCP is already configured, but with different settings');
|
|
108
|
+
console.log();
|
|
109
|
+
logger.info('Current configuration:');
|
|
110
|
+
console.log(' ' + logger.highlight(JSON.stringify(existingConfig, null, 2)));
|
|
111
|
+
console.log();
|
|
112
|
+
logger.info('Expected configuration:');
|
|
113
|
+
console.log(' ' + logger.highlight(JSON.stringify(this.expectedConfig, null, 2)));
|
|
114
|
+
console.log();
|
|
115
|
+
logger.info('To update the configuration, run:');
|
|
116
|
+
console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy uninstall'));
|
|
117
|
+
console.log(' ' + logger.highlight('npx @meldocio/mcp-stdio-proxy install'));
|
|
118
|
+
console.log();
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
result: INSTALL_RESULTS.ALREADY_CONFIGURED,
|
|
122
|
+
message: 'Configuration exists but differs from expected',
|
|
123
|
+
configPath: this.configPath
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Read existing config or create new
|
|
128
|
+
const config = readConfigSafe(this.configPath);
|
|
129
|
+
const configExists = fileExists(this.configPath);
|
|
130
|
+
|
|
131
|
+
if (configExists) {
|
|
132
|
+
logger.info('Found existing configuration file');
|
|
133
|
+
} else {
|
|
134
|
+
logger.info('Configuration file does not exist, will create it');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Merge Meldoc configuration
|
|
138
|
+
const { merged } = this.mergeConfig(config, this.expectedConfig);
|
|
139
|
+
|
|
140
|
+
// Create directory if needed
|
|
141
|
+
const configDir = path.dirname(this.configPath);
|
|
142
|
+
if (!fileExists(configDir)) {
|
|
143
|
+
logger.info(`Creating directory: ${configDir}`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Write config
|
|
147
|
+
writeConfig(this.configPath, merged);
|
|
148
|
+
|
|
149
|
+
logger.success('Configuration added successfully!');
|
|
150
|
+
console.log();
|
|
151
|
+
|
|
152
|
+
// Show what was added
|
|
153
|
+
logger.info('Added configuration:');
|
|
154
|
+
console.log(' ' + logger.highlight(JSON.stringify(this.expectedConfig, null, 2)));
|
|
155
|
+
console.log();
|
|
156
|
+
|
|
157
|
+
this.printNextSteps();
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
result: INSTALL_RESULTS.SUCCESS,
|
|
161
|
+
message: 'Configuration installed successfully',
|
|
162
|
+
configPath: this.configPath
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
} catch (error) {
|
|
166
|
+
logger.error(`Installation failed: ${error.message}`);
|
|
167
|
+
return {
|
|
168
|
+
result: INSTALL_RESULTS.ERROR,
|
|
169
|
+
message: error.message,
|
|
170
|
+
configPath: this.configPath
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Merge Meldoc config into existing config based on client type
|
|
177
|
+
* @param {Object} config - Existing configuration
|
|
178
|
+
* @param {Object} newServer - New Meldoc server configuration
|
|
179
|
+
* @returns {Object} { merged: Object, changed: boolean }
|
|
180
|
+
*/
|
|
181
|
+
mergeConfig(config, newServer) {
|
|
182
|
+
switch (this.client) {
|
|
183
|
+
case 'claude-desktop':
|
|
184
|
+
return mergeClaudeDesktopConfig(config, newServer);
|
|
185
|
+
case 'cursor':
|
|
186
|
+
return mergeCursorConfig(config, newServer);
|
|
187
|
+
case 'claude-code':
|
|
188
|
+
return mergeClaudeCodeConfig(config, newServer);
|
|
189
|
+
case 'local':
|
|
190
|
+
return mergeCursorConfig(config, newServer); // Uses same format as Cursor
|
|
191
|
+
default:
|
|
192
|
+
throw new Error(`Unknown client type: ${this.client}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Uninstall Meldoc MCP configuration
|
|
198
|
+
* @returns {Object} { result: string, message: string, configPath: string }
|
|
199
|
+
*/
|
|
200
|
+
uninstall() {
|
|
201
|
+
try {
|
|
202
|
+
logger.section(`🗑️ Uninstalling Meldoc MCP from ${this.clientName}`);
|
|
203
|
+
console.log();
|
|
204
|
+
|
|
205
|
+
logger.info(`Config file location: ${logger.highlight(this.configPath)}`);
|
|
206
|
+
console.log();
|
|
207
|
+
|
|
208
|
+
// Check if config exists
|
|
209
|
+
if (!fileExists(this.configPath)) {
|
|
210
|
+
logger.info('Configuration file does not exist');
|
|
211
|
+
logger.success('Nothing to uninstall');
|
|
212
|
+
console.log();
|
|
213
|
+
return {
|
|
214
|
+
result: INSTALL_RESULTS.SUCCESS,
|
|
215
|
+
message: 'No configuration found',
|
|
216
|
+
configPath: this.configPath
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Read config
|
|
221
|
+
const config = readConfigSafe(this.configPath);
|
|
222
|
+
const serverKey = this.getServerKey();
|
|
223
|
+
|
|
224
|
+
// Check if Meldoc is configured
|
|
225
|
+
if (!config.mcpServers || !config.mcpServers[serverKey]) {
|
|
226
|
+
logger.info('Meldoc MCP is not configured');
|
|
227
|
+
logger.success('Nothing to uninstall');
|
|
228
|
+
console.log();
|
|
229
|
+
return {
|
|
230
|
+
result: INSTALL_RESULTS.SUCCESS,
|
|
231
|
+
message: 'Meldoc not configured',
|
|
232
|
+
configPath: this.configPath
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Remove Meldoc configuration
|
|
237
|
+
const { merged } = this.client === 'claude-code'
|
|
238
|
+
? removeMeldocClaudeCodeConfig(config)
|
|
239
|
+
: removeMeldocConfig(config);
|
|
240
|
+
|
|
241
|
+
// Write updated config
|
|
242
|
+
writeConfig(this.configPath, merged);
|
|
243
|
+
|
|
244
|
+
logger.success('Configuration removed successfully!');
|
|
245
|
+
console.log();
|
|
246
|
+
logger.info(`Remember to restart ${this.clientName} to apply changes`);
|
|
247
|
+
console.log();
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
result: INSTALL_RESULTS.SUCCESS,
|
|
251
|
+
message: 'Configuration uninstalled successfully',
|
|
252
|
+
configPath: this.configPath
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
} catch (error) {
|
|
256
|
+
logger.error(`Uninstallation failed: ${error.message}`);
|
|
257
|
+
return {
|
|
258
|
+
result: INSTALL_RESULTS.ERROR,
|
|
259
|
+
message: error.message,
|
|
260
|
+
configPath: this.configPath
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Print next steps after installation
|
|
267
|
+
*/
|
|
268
|
+
printNextSteps() {
|
|
269
|
+
logger.info('✅ Next steps:');
|
|
270
|
+
console.log();
|
|
271
|
+
|
|
272
|
+
if (this.client === 'claude-desktop') {
|
|
273
|
+
console.log(' 1. Restart Claude Desktop (if you haven\'t already)');
|
|
274
|
+
console.log(' 2. Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
|
|
275
|
+
} else if (this.client === 'cursor') {
|
|
276
|
+
console.log(` 1. Restart Cursor (if you haven't already)`);
|
|
277
|
+
console.log(' 2. Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
|
|
278
|
+
} else if (this.client === 'claude-code') {
|
|
279
|
+
console.log(' 1. Restart Claude Code (if you haven\'t already)');
|
|
280
|
+
console.log(' 2. Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
|
|
281
|
+
} else {
|
|
282
|
+
console.log(' 1. Restart your MCP client');
|
|
283
|
+
console.log(' 2. Run: ' + logger.highlight('npx @meldocio/mcp-stdio-proxy auth login'));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
console.log();
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Factory function to create installer
|
|
292
|
+
* @param {string} client - Client type
|
|
293
|
+
* @param {string} [scope='project'] - Installation scope
|
|
294
|
+
* @returns {Installer} Installer instance
|
|
295
|
+
*/
|
|
296
|
+
function createInstaller(client, scope = 'project') {
|
|
297
|
+
return new Installer(client, scope);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Quick install function
|
|
302
|
+
* @param {string} client - Client type
|
|
303
|
+
* @param {string} [scope='project'] - Installation scope
|
|
304
|
+
* @returns {Object} Installation result
|
|
305
|
+
*/
|
|
306
|
+
function install(client, scope = 'project') {
|
|
307
|
+
const installer = createInstaller(client, scope);
|
|
308
|
+
return installer.install();
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Quick uninstall function
|
|
313
|
+
* @param {string} client - Client type
|
|
314
|
+
* @param {string} [scope='project'] - Installation scope
|
|
315
|
+
* @returns {Object} Uninstallation result
|
|
316
|
+
*/
|
|
317
|
+
function uninstall(client, scope = 'project') {
|
|
318
|
+
const installer = createInstaller(client, scope);
|
|
319
|
+
return installer.uninstall();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
module.exports = {
|
|
323
|
+
Installer,
|
|
324
|
+
createInstaller,
|
|
325
|
+
install,
|
|
326
|
+
uninstall,
|
|
327
|
+
INSTALL_RESULTS
|
|
328
|
+
};
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Configuration Templates
|
|
3
|
+
*
|
|
4
|
+
* Standard configuration templates for different MCP clients.
|
|
5
|
+
* Includes comparison and merging utilities.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get expected Meldoc MCP configuration for Claude Desktop
|
|
10
|
+
* @returns {Object} Claude Desktop MCP configuration
|
|
11
|
+
*/
|
|
12
|
+
function getClaudeDesktopConfig() {
|
|
13
|
+
return {
|
|
14
|
+
command: 'npx',
|
|
15
|
+
args: ['-y', '@meldocio/mcp-stdio-proxy@latest']
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get expected Meldoc MCP configuration for Cursor
|
|
21
|
+
* @returns {Object} Cursor MCP configuration
|
|
22
|
+
*/
|
|
23
|
+
function getCursorConfig() {
|
|
24
|
+
return {
|
|
25
|
+
command: 'npx',
|
|
26
|
+
args: ['-y', '@meldocio/mcp-stdio-proxy@latest']
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get expected Meldoc MCP configuration for Claude Code
|
|
32
|
+
* @returns {Object} Claude Code MCP configuration
|
|
33
|
+
*/
|
|
34
|
+
function getClaudeCodeConfig() {
|
|
35
|
+
return {
|
|
36
|
+
type: 'stdio',
|
|
37
|
+
command: 'npx',
|
|
38
|
+
args: ['-y', '@meldocio/mcp-stdio-proxy@latest']
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get expected Meldoc MCP configuration for local (generic) installation
|
|
44
|
+
* @returns {Object} Local MCP configuration
|
|
45
|
+
*/
|
|
46
|
+
function getLocalConfig() {
|
|
47
|
+
return {
|
|
48
|
+
type: 'stdio',
|
|
49
|
+
command: 'npx',
|
|
50
|
+
args: ['-y', '@meldocio/mcp-stdio-proxy@latest']
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get configuration template by client type
|
|
56
|
+
* @param {string} client - Client type: 'claude-desktop', 'cursor', 'claude-code', 'local'
|
|
57
|
+
* @returns {Object} Configuration template
|
|
58
|
+
* @throws {Error} If client type is unknown
|
|
59
|
+
*/
|
|
60
|
+
function getConfigTemplate(client) {
|
|
61
|
+
switch (client) {
|
|
62
|
+
case 'claude-desktop':
|
|
63
|
+
return getClaudeDesktopConfig();
|
|
64
|
+
case 'cursor':
|
|
65
|
+
return getCursorConfig();
|
|
66
|
+
case 'claude-code':
|
|
67
|
+
return getClaudeCodeConfig();
|
|
68
|
+
case 'local':
|
|
69
|
+
return getLocalConfig();
|
|
70
|
+
default:
|
|
71
|
+
throw new Error(`Unknown client type: ${client}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Deep equality comparison for configuration objects
|
|
77
|
+
* @param {any} a - First value
|
|
78
|
+
* @param {any} b - Second value
|
|
79
|
+
* @returns {boolean} True if values are deeply equal
|
|
80
|
+
*/
|
|
81
|
+
function deepEqual(a, b) {
|
|
82
|
+
// Handle null/undefined
|
|
83
|
+
if (a === b) return true;
|
|
84
|
+
if (a == null || b == null) return false;
|
|
85
|
+
if (typeof a !== typeof b) return false;
|
|
86
|
+
|
|
87
|
+
// Handle non-objects
|
|
88
|
+
if (typeof a !== 'object') return a === b;
|
|
89
|
+
|
|
90
|
+
// Handle arrays
|
|
91
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
92
|
+
if (a.length !== b.length) return false;
|
|
93
|
+
return a.every((val, idx) => deepEqual(val, b[idx]));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Handle objects
|
|
97
|
+
if (Array.isArray(a) || Array.isArray(b)) return false;
|
|
98
|
+
|
|
99
|
+
const keysA = Object.keys(a);
|
|
100
|
+
const keysB = Object.keys(b);
|
|
101
|
+
|
|
102
|
+
if (keysA.length !== keysB.length) return false;
|
|
103
|
+
|
|
104
|
+
return keysA.every(key => {
|
|
105
|
+
if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
|
|
106
|
+
return deepEqual(a[key], b[key]);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Check if two configurations are equal
|
|
112
|
+
* @param {Object} config1 - First configuration
|
|
113
|
+
* @param {Object} config2 - Second configuration
|
|
114
|
+
* @returns {boolean} True if configurations are equal
|
|
115
|
+
*/
|
|
116
|
+
function configsEqual(config1, config2) {
|
|
117
|
+
return deepEqual(config1, config2);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Merge Meldoc server configuration into existing config
|
|
122
|
+
* For Claude Desktop format (mcpServers.meldoc)
|
|
123
|
+
* @param {Object} existingConfig - Existing configuration object
|
|
124
|
+
* @param {Object} newServer - New Meldoc server configuration
|
|
125
|
+
* @returns {Object} { merged: Object, changed: boolean }
|
|
126
|
+
*/
|
|
127
|
+
function mergeClaudeDesktopConfig(existingConfig, newServer) {
|
|
128
|
+
const merged = { ...existingConfig };
|
|
129
|
+
|
|
130
|
+
// Ensure mcpServers exists
|
|
131
|
+
if (!merged.mcpServers) {
|
|
132
|
+
merged.mcpServers = {};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Check if meldoc server exists
|
|
136
|
+
if (!merged.mcpServers.meldoc) {
|
|
137
|
+
merged.mcpServers.meldoc = newServer;
|
|
138
|
+
return { merged, changed: true };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Check if configs are equal
|
|
142
|
+
if (configsEqual(merged.mcpServers.meldoc, newServer)) {
|
|
143
|
+
return { merged, changed: false };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Update if different
|
|
147
|
+
merged.mcpServers.meldoc = newServer;
|
|
148
|
+
return { merged, changed: true };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Merge Meldoc server configuration into existing config
|
|
153
|
+
* For Cursor/Local format (mcpServers.meldoc)
|
|
154
|
+
* @param {Object} existingConfig - Existing configuration object
|
|
155
|
+
* @param {Object} newServer - New Meldoc server configuration
|
|
156
|
+
* @returns {Object} { merged: Object, changed: boolean }
|
|
157
|
+
*/
|
|
158
|
+
function mergeCursorConfig(existingConfig, newServer) {
|
|
159
|
+
const merged = { ...existingConfig };
|
|
160
|
+
|
|
161
|
+
// Ensure mcpServers exists
|
|
162
|
+
if (!merged.mcpServers) {
|
|
163
|
+
merged.mcpServers = {};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Check if meldoc server exists
|
|
167
|
+
if (!merged.mcpServers.meldoc) {
|
|
168
|
+
merged.mcpServers.meldoc = newServer;
|
|
169
|
+
return { merged, changed: true };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Check if configs are equal
|
|
173
|
+
if (configsEqual(merged.mcpServers.meldoc, newServer)) {
|
|
174
|
+
return { merged, changed: false };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Update if different
|
|
178
|
+
merged.mcpServers.meldoc = newServer;
|
|
179
|
+
return { merged, changed: true };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Merge Meldoc server configuration into existing config
|
|
184
|
+
* For Claude Code format (mcpServers.meldoc-mcp)
|
|
185
|
+
* @param {Object} existingConfig - Existing configuration object
|
|
186
|
+
* @param {Object} newServer - New Meldoc server configuration
|
|
187
|
+
* @returns {Object} { merged: Object, changed: boolean }
|
|
188
|
+
*/
|
|
189
|
+
function mergeClaudeCodeConfig(existingConfig, newServer) {
|
|
190
|
+
const merged = { ...existingConfig };
|
|
191
|
+
|
|
192
|
+
// Ensure mcpServers exists
|
|
193
|
+
if (!merged.mcpServers) {
|
|
194
|
+
merged.mcpServers = {};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Check if meldoc-mcp server exists (Claude Code uses different key)
|
|
198
|
+
if (!merged.mcpServers['meldoc-mcp']) {
|
|
199
|
+
merged.mcpServers['meldoc-mcp'] = newServer;
|
|
200
|
+
return { merged, changed: true };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Check if configs are equal
|
|
204
|
+
if (configsEqual(merged.mcpServers['meldoc-mcp'], newServer)) {
|
|
205
|
+
return { merged, changed: false };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Update if different
|
|
209
|
+
merged.mcpServers['meldoc-mcp'] = newServer;
|
|
210
|
+
return { merged, changed: true };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Remove Meldoc server from configuration
|
|
215
|
+
* For Claude Desktop/Cursor format
|
|
216
|
+
* @param {Object} config - Configuration object
|
|
217
|
+
* @returns {Object} { merged: Object, changed: boolean }
|
|
218
|
+
*/
|
|
219
|
+
function removeMeldocConfig(config) {
|
|
220
|
+
const merged = { ...config };
|
|
221
|
+
|
|
222
|
+
if (!merged.mcpServers || !merged.mcpServers.meldoc) {
|
|
223
|
+
return { merged, changed: false };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
delete merged.mcpServers.meldoc;
|
|
227
|
+
return { merged, changed: true };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Remove Meldoc server from Claude Code configuration
|
|
232
|
+
* @param {Object} config - Configuration object
|
|
233
|
+
* @returns {Object} { merged: Object, changed: boolean }
|
|
234
|
+
*/
|
|
235
|
+
function removeMeldocClaudeCodeConfig(config) {
|
|
236
|
+
const merged = { ...config };
|
|
237
|
+
|
|
238
|
+
if (!merged.mcpServers || !merged.mcpServers['meldoc-mcp']) {
|
|
239
|
+
return { merged, changed: false };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
delete merged.mcpServers['meldoc-mcp'];
|
|
243
|
+
return { merged, changed: true };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
module.exports = {
|
|
247
|
+
// Template getters
|
|
248
|
+
getClaudeDesktopConfig,
|
|
249
|
+
getCursorConfig,
|
|
250
|
+
getClaudeCodeConfig,
|
|
251
|
+
getLocalConfig,
|
|
252
|
+
getConfigTemplate,
|
|
253
|
+
|
|
254
|
+
// Comparison utilities
|
|
255
|
+
deepEqual,
|
|
256
|
+
configsEqual,
|
|
257
|
+
|
|
258
|
+
// Merge utilities
|
|
259
|
+
mergeClaudeDesktopConfig,
|
|
260
|
+
mergeCursorConfig,
|
|
261
|
+
mergeClaudeCodeConfig,
|
|
262
|
+
|
|
263
|
+
// Remove utilities
|
|
264
|
+
removeMeldocConfig,
|
|
265
|
+
removeMeldocClaudeCodeConfig
|
|
266
|
+
};
|