-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathinstall-mcp.js
More file actions
264 lines (226 loc) · 8.89 KB
/
install-mcp.js
File metadata and controls
264 lines (226 loc) · 8.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
#!/usr/bin/env node
/**
* Archy MCP Server Installation Script
*
* This script helps install the Archy MCP server configuration
* in the appropriate locations for your MCP clients (VS Code and Claude).
* It also prompts for a GitHub token for repository analysis.
*/
import fs from 'fs';
import path from 'path';
import os from 'os';
import { execSync } from 'child_process';
import { fileURLToPath } from 'url';
import readline from 'readline';
// Get the absolute path to the current directory
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const currentDir = process.cwd();
// Create readline interface for user input
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
/**
* Promisified version of readline question
* @param {string} question - The question to ask the user
* @returns {Promise<string>} - The user's response
*/
function promptUser(question) {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer);
});
});
}
/**
* Determine the VS Code MCP settings location based on the OS
* @returns {string} The path to the VS Code MCP settings file
*/
function getVSCodeMcpSettingsPath() {
const homeDir = os.homedir();
// For Windows
if (process.platform === 'win32') {
return path.join(homeDir, 'AppData', 'Roaming', 'Code', 'User', 'globalStorage', 'rooveterinaryinc.roo-cline', 'settings', 'mcp_settings.json');
}
// For macOS
if (process.platform === 'darwin') {
return path.join(homeDir, 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'rooveterinaryinc.roo-cline', 'settings', 'mcp_settings.json');
}
// For Linux
return path.join(homeDir, '.config', 'Code', 'User', 'globalStorage', 'rooveterinaryinc.roo-cline', 'settings', 'mcp_settings.json');
}
/**
* Determine the Claude MCP settings location based on the OS
* @returns {string} The path to the Claude MCP settings file
*/
function getClaudeMcpSettingsPath() {
const homeDir = os.homedir();
// For Windows
if (process.platform === 'win32') {
return path.join(homeDir, 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json');
}
// For macOS
if (process.platform === 'darwin') {
return path.join(homeDir, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
}
// For Linux
return path.join(homeDir, '.config', 'Claude', 'claude_desktop_config.json');
}
/**
* Read the Archy MCP configuration
* @returns {Object} The parsed Archy MCP configuration
*/
function readArchyConfig() {
const configPath = path.join(currentDir, 'archy-mcp-config.json');
try {
const configData = fs.readFileSync(configPath, 'utf8');
return JSON.parse(configData);
} catch (error) {
console.error('Error reading Archy MCP configuration:', error.message);
process.exit(1);
}
}
/**
* Update the MCP settings file at the specified path
* @param {string} mcpSettingsPath - The path to the MCP settings file
* @param {Object} archyConfig - The Archy MCP configuration
* @param {string} clientName - The name of the client (VS Code or Claude)
* @returns {boolean} Whether the update was successful
*/
function updateMcpSettingsFile(mcpSettingsPath, archyConfig, clientName) {
try {
// Create the directory if it doesn't exist
const settingsDir = path.dirname(mcpSettingsPath);
if (!fs.existsSync(settingsDir)) {
fs.mkdirSync(settingsDir, { recursive: true });
}
// Read existing settings if available
let mcpSettings = { mcpServers: {} };
if (fs.existsSync(mcpSettingsPath)) {
const settingsData = fs.readFileSync(mcpSettingsPath, 'utf8');
try {
mcpSettings = JSON.parse(settingsData);
// Ensure mcpServers exists
if (!mcpSettings.mcpServers) {
mcpSettings.mcpServers = {};
}
} catch (error) {
console.warn(`Warning: Could not parse existing ${clientName} MCP settings, creating new file.`);
}
}
// Merge the Archy configuration with existing settings
mcpSettings.mcpServers = {
...mcpSettings.mcpServers,
...archyConfig.mcpServers
};
// Write the updated settings
fs.writeFileSync(mcpSettingsPath, JSON.stringify(mcpSettings, null, 2), 'utf8');
console.log(`Archy MCP server configuration installed for ${clientName} at: ${mcpSettingsPath}`);
return true;
} catch (error) {
console.error(`Error updating ${clientName} MCP settings:`, error.message);
return false;
}
}
/**
* Prompt the user for their GitHub token
* @returns {Promise<string>} The GitHub token
*/
async function promptForGitHubToken() {
console.log('\nGitHub Token Configuration');
console.log('-------------------------');
console.log('A GitHub token is needed to access GitHub repositories for analysis.');
console.log('If you don\'t have a token, you can create one at: https://github.com/settings/tokens');
console.log('The token needs "repo" scope for accessing repositories.');
console.log('Leave blank if you don\'t want to use GitHub repository analysis.\n');
const token = await promptUser('Enter your GitHub token (or press Enter to skip): ');
return token.trim();
}
/**
* Prompt the user for their OpenRouter API key
* @returns {Promise<string>} The OpenRouter API key
*/
async function promptForOpenRouterApiKey() {
console.log('\nOpenRouter API Key Configuration');
console.log('-------------------------------');
console.log('An OpenRouter API key enables AI-powered diagram generation features.');
console.log('If you don\'t have an API key, you can sign up at: https://openrouter.ai/');
console.log('Leave blank if you don\'t want to use AI-powered diagram generation.\n');
const apiKey = await promptUser('Enter your OpenRouter API key (or press Enter to skip): ');
return apiKey.trim();
}
/**
* Update the MCP settings for both VS Code and Claude
* @param {string} githubToken - The GitHub token to use
* @param {string} openRouterApiKey - The OpenRouter API key to use
* @returns {Promise<boolean>} Whether the update was successful for at least one client
*/
async function updateMcpSettings(githubToken, openRouterApiKey) {
const archyConfig = readArchyConfig();
// Update the args path to use the absolute path to the build directory
const buildPath = path.join(currentDir, 'build', 'index.js');
archyConfig.mcpServers.archy.args = [buildPath];
// Initialize environment variables if not already present
archyConfig.mcpServers.archy.env = archyConfig.mcpServers.archy.env || {};
// Add the GitHub token to the environment variables if provided
if (githubToken) {
archyConfig.mcpServers.archy.env.GITHUB_TOKEN = githubToken;
}
// Add the OpenRouter API key to the environment variables if provided
if (openRouterApiKey) {
archyConfig.mcpServers.archy.env.OPENROUTER_API_KEY = openRouterApiKey;
}
// Make the build/index.js file executable
if (process.platform !== 'win32') {
try {
execSync(`chmod +x "${buildPath}"`);
console.log('Made the server executable');
} catch (error) {
console.warn('Warning: Could not make the server executable:', error.message);
}
}
// Update VS Code MCP settings
const vsCodePath = getVSCodeMcpSettingsPath();
const vsCodeSuccess = updateMcpSettingsFile(vsCodePath, archyConfig, 'VS Code');
// Update Claude MCP settings
const claudePath = getClaudeMcpSettingsPath();
const claudeSuccess = updateMcpSettingsFile(claudePath, archyConfig, 'Claude');
// Return true if at least one update was successful
return vsCodeSuccess || claudeSuccess;
}
/**
* Main function
*/
async function main() {
console.log('Installing Archy MCP server...');
try {
// Prompt for GitHub token
const githubToken = await promptForGitHubToken();
// Prompt for OpenRouter API key
const openRouterApiKey = await promptForOpenRouterApiKey();
if (await updateMcpSettings(githubToken, openRouterApiKey)) {
console.log('\nInstallation successful!');
console.log('\nYou can now use the Archy MCP server with your MCP clients (VS Code and/or Claude).');
if (githubToken) {
console.log('GitHub token has been configured for repository analysis.');
} else {
console.log('No GitHub token was provided. GitHub repository analysis will be limited to public repositories.');
}
if (openRouterApiKey) {
console.log('OpenRouter API key has been configured for AI-powered diagram generation.');
} else {
console.log('No OpenRouter API key was provided. AI-powered diagram generation will not be available.');
}
} else {
console.error('\nInstallation failed. Please check the error messages above.');
}
} catch (error) {
console.error('Error during installation:', error.message);
} finally {
// Close the readline interface
rl.close();
}
}
// Run the main function
main();