devdoq-install-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +162 -0
  2. package/package.json +20 -0
package/index.js ADDED
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import os from 'os';
6
+ import { execSync } from 'child_process';
7
+
8
+ // Get npx absolute path
9
+ function getNpxPath() {
10
+ try {
11
+ const isWin = os.platform() === 'win32';
12
+ const cmd = isWin ? 'where npx' : 'which npx';
13
+ const output = execSync(cmd, { encoding: 'utf8' }).trim();
14
+ if (output) {
15
+ // Possible multiple lines on some OS
16
+ return output.split('\n')[0].trim();
17
+ }
18
+ } catch (err) {
19
+ // Ignore error
20
+ }
21
+ return 'npx'; // Fallback
22
+ }
23
+
24
+ function printUsage() {
25
+ console.log(`
26
+ Usage: npx devdoq-install-mcp <url> <apiKey> [options]
27
+
28
+ Options:
29
+ --client <name> Specify which client to configure (claude, cline, all). Default is all.
30
+ --name <name> Name of the MCP server. Default is 'devdoq'.
31
+
32
+ Example:
33
+ npx devdoq-install-mcp https://mcp.devdoq.com/mcp mcp_abc123 --client claude
34
+ `);
35
+ }
36
+
37
+ const args = process.argv.slice(2);
38
+ const positional = [];
39
+ let clientType = 'all';
40
+ let serverName = 'devdoq';
41
+
42
+ for (let i = 0; i < args.length; i++) {
43
+ if (args[i] === '--client') {
44
+ clientType = args[++i];
45
+ } else if (args[i] === '--name') {
46
+ serverName = args[++i];
47
+ } else if (args[i] === '--help' || args[i] === '-h') {
48
+ printUsage();
49
+ process.exit(0);
50
+ } else if (!args[i].startsWith('-')) {
51
+ positional.push(args[i]);
52
+ }
53
+ }
54
+
55
+ if (positional.length < 2) {
56
+ console.error("Error: Missing <url> or <apiKey>\n");
57
+ printUsage();
58
+ process.exit(1);
59
+ }
60
+
61
+ const targetUrl = positional[0];
62
+ const targetApiKey = positional[1];
63
+
64
+ const platform = os.platform();
65
+ const homeDir = os.homedir();
66
+ const appData = process.env.APPDATA || path.join(homeDir, 'AppData', 'Roaming');
67
+
68
+ const CONFIG_PATHS = {
69
+ claude: platform === 'darwin'
70
+ ? path.join(homeDir, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json')
71
+ : platform === 'win32'
72
+ ? path.join(appData, 'Claude', 'claude_desktop_config.json')
73
+ : null,
74
+
75
+ cline_vscode: platform === 'darwin'
76
+ ? path.join(homeDir, 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json')
77
+ : platform === 'win32'
78
+ ? path.join(appData, 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json')
79
+ : path.join(homeDir, '.config', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
80
+
81
+ cline_cursor: platform === 'darwin'
82
+ ? path.join(homeDir, 'Library', 'Application Support', 'Cursor', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json')
83
+ : platform === 'win32'
84
+ ? path.join(appData, 'Cursor', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json')
85
+ : path.join(homeDir, '.config', 'Cursor', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
86
+ };
87
+
88
+ const npxPath = getNpxPath();
89
+
90
+ const mcpConfigBlock = {
91
+ command: npxPath,
92
+ args: [
93
+ "-y",
94
+ "mcp-remote",
95
+ targetUrl,
96
+ "--header",
97
+ `Authorization: Bearer ${targetApiKey}`
98
+ ]
99
+ };
100
+
101
+ function updateJsonConfig(filePath, serverName, configObj) {
102
+ let data = {};
103
+ if (fs.existsSync(filePath)) {
104
+ try {
105
+ const content = fs.readFileSync(filePath, 'utf8');
106
+ data = JSON.parse(content);
107
+ } catch (err) {
108
+ console.error(`Error reading or parsing ${filePath}: ${err.message}`);
109
+ return false;
110
+ }
111
+ }
112
+
113
+ if (!data.mcpServers) {
114
+ data.mcpServers = {};
115
+ }
116
+
117
+ data.mcpServers[serverName] = configObj;
118
+
119
+ try {
120
+ // Ensure directory exists
121
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
122
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
123
+ console.log(`✅ Successfully updated: ${filePath}`);
124
+ return true;
125
+ } catch (err) {
126
+ console.error(`❌ Failed to write ${filePath}: ${err.message}`);
127
+ return false;
128
+ }
129
+ }
130
+
131
+ console.log(`\nConfiguring '${serverName}' MCP server with URL: ${targetUrl}`);
132
+ console.log(`Using npx path: ${npxPath}\n`);
133
+
134
+ let updatedAny = false;
135
+
136
+ const clientsToAttempt = [];
137
+ if (clientType === 'all' || clientType === 'claude') clientsToAttempt.push(CONFIG_PATHS.claude);
138
+ if (clientType === 'all' || clientType === 'cline') {
139
+ clientsToAttempt.push(CONFIG_PATHS.cline_vscode);
140
+ clientsToAttempt.push(CONFIG_PATHS.cline_cursor);
141
+ }
142
+
143
+ for (const targetPath of clientsToAttempt) {
144
+ if (targetPath) {
145
+ // Only attempt to write if the directory exists OR if it's the exact requested client
146
+ // For "all", we only populate if the parent config directory exists to avoid cluttering unused apps
147
+ if (fs.existsSync(path.dirname(targetPath)) || clientType !== 'all') {
148
+ const success = updateJsonConfig(targetPath, serverName, mcpConfigBlock);
149
+ if (success) updatedAny = true;
150
+ } else {
151
+ console.log(`(Skipped) App data not found for: ${targetPath}`);
152
+ }
153
+ }
154
+ }
155
+
156
+ if (!updatedAny) {
157
+ console.log(`\n⚠️ Could not automatically configure native configuration files.`);
158
+ }
159
+
160
+ console.log(`\nIf your client (e.g. Cursor, Windsurf) requires manual configuration, simply copy and paste the JSON block below into its MCP Settings:\n`);
161
+ console.log(`"${serverName}": ${JSON.stringify(mcpConfigBlock, null, 2)}`);
162
+ console.log(`\nDone! Restart your MCP client to apply changes.`);
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "devdoq-install-mcp",
3
+ "version": "1.0.0",
4
+ "description": "Auto-configure MCP server connections for Claude Desktop, Cline, and others.",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "devdoq-install-mcp": "index.js"
8
+ },
9
+ "type": "module",
10
+ "scripts": {
11
+ "test": "echo \"Error: no test specified\" && exit 1"
12
+ },
13
+ "keywords": [
14
+ "mcp",
15
+ "claude",
16
+ "cursor"
17
+ ],
18
+ "author": "",
19
+ "license": "MIT"
20
+ }