config-wizard.js•9.89 kB
#!/usr/bin/env node
import { readFileSync, writeFileSync, existsSync, mkdirSync, statSync } from 'fs';
import { join, dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
import { createInterface } from 'readline';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const rootDir = join(__dirname, '..');
// Create readline interface for user input
const rl = createInterface({
input: process.stdin,
output: process.stdout
});
// Helper function to ask questions
function askQuestion(question) {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer.trim());
});
});
}
// Helper function to ask yes/no questions
async function askYesNo(question, defaultValue = true) {
const defaultText = defaultValue ? 'Y/n' : 'y/N';
const answer = await askQuestion(`${question} [${defaultText}]: `);
if (answer === '') return defaultValue;
return answer.toLowerCase().startsWith('y');
}
// Helper function to validate file path
function validatePath(path, isDirectory = false) {
if (!path) return false;
const resolvedPath = resolve(rootDir, path);
if (isDirectory) {
return existsSync(resolvedPath) && statSync(resolvedPath).isDirectory();
} else {
// For files, check if directory exists and file can be created
const dir = dirname(resolvedPath);
return existsSync(dir) || mkdirSync(dir, { recursive: true });
}
}
// Helper function to create directory if it doesn't exist
function ensureDirectory(path) {
const resolvedPath = resolve(rootDir, path);
const dir = dirname(resolvedPath);
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
}
async function loadExistingConfig() {
const envPath = join(rootDir, '.env');
const config = {};
if (existsSync(envPath)) {
const envContent = readFileSync(envPath, 'utf8');
const lines = envContent.split('\n');
for (const line of lines) {
const trimmedLine = line.trim();
if (trimmedLine && !trimmedLine.startsWith('#')) {
const [key, ...valueParts] = trimmedLine.split('=');
if (key && valueParts.length > 0) {
config[key.trim()] = valueParts.join('=').trim();
}
}
}
}
return config;
}
async function saveConfig(config) {
const envPath = join(rootDir, '.env');
// Read template to get all possible variables
const templatePath = join(rootDir, 'env.template');
let templateContent = '';
if (existsSync(templatePath)) {
templateContent = readFileSync(templatePath, 'utf8');
}
// Create .env content
let envContent = '# MCP Content Analyzer Configuration\n';
envContent += '# Generated by config wizard\n\n';
// Add core paths section
envContent += '# =============================================================================\n';
envContent += '# CORE PATHS - REQUIRED\n';
envContent += '# =============================================================================\n\n';
envContent += `EXCEL_DATABASE_PATH=${config.EXCEL_DATABASE_PATH || './data/content-database.xlsx'}\n`;
envContent += `CONTENT_CATALOG_PATH=${config.CONTENT_CATALOG_PATH || './data/content-catalog-guidelines.md'}\n\n`;
// Add other configuration sections
const sections = [
{ name: 'EXCEL CONFIGURATION', vars: ['EXCEL_BACKUP_ENABLED', 'EXCEL_AUTO_SAVE', 'EXCEL_TEMPLATE_PATH', 'EXCEL_SCHEMA_VERSION'] },
{ name: 'CONTENT CATALOG CONFIGURATION', vars: ['SUPPORT_DOCUMENT_VALIDATION', 'AUTO_REJECT_UNSUITABLE', 'DEFAULT_CATALOG_ENABLED'] },
{ name: 'ANALYSIS CONFIGURATION', vars: ['AI_ANALYSIS_ENABLED', 'QUOTE_EXTRACTION_ENABLED', 'CASE_STUDY_DETECTION_ENABLED', 'CULTURAL_CONTEXT_ANALYSIS', 'AUTO_CATEGORIZATION', 'ENHANCED_SEARCH_ENABLED'] },
{ name: 'QUALITY CONTROL', vars: ['MIN_SOURCE_CREDIBILITY', 'REQUIRE_PUBLICATION_DATE', 'REQUIRE_AUTHOR_INFO', 'MIN_WORD_COUNT', 'MAX_CONTENT_AGE', 'CULTURAL_RELEVANCE_THRESHOLD'] },
{ name: 'SCRAPER CONFIGURATION', vars: ['SCRAPER_USER_AGENT', 'SCRAPER_TIMEOUT', 'SCRAPER_RATE_LIMIT'] },
{ name: 'OCR CONFIGURATION', vars: ['OCR_FALLBACK_ENABLED'] },
{ name: 'SERVER CONFIGURATION', vars: ['MCP_SERVER_PORT', 'LOG_LEVEL', 'MAX_CONTENT_LENGTH'] },
{ name: 'TEAM CONFIGURATION', vars: ['TEAM_NAME', 'SERVER_NAME'] }
];
for (const section of sections) {
envContent += `# =============================================================================\n`;
envContent += `# ${section.name}\n`;
envContent += `# =============================================================================\n\n`;
for (const varName of section.vars) {
const value = config[varName] || getDefaultValue(varName);
envContent += `${varName}=${value}\n`;
}
envContent += '\n';
}
writeFileSync(envPath, envContent);
console.log(`✅ Configuration saved to ${envPath}`);
}
function getDefaultValue(varName) {
const defaults = {
'EXCEL_BACKUP_ENABLED': 'true',
'EXCEL_AUTO_SAVE': 'true',
'EXCEL_TEMPLATE_PATH': './config/excel-template.xlsx',
'EXCEL_SCHEMA_VERSION': '2.0',
'SUPPORT_DOCUMENT_VALIDATION': 'true',
'AUTO_REJECT_UNSUITABLE': 'false',
'DEFAULT_CATALOG_ENABLED': 'true',
'AI_ANALYSIS_ENABLED': 'true',
'QUOTE_EXTRACTION_ENABLED': 'true',
'CASE_STUDY_DETECTION_ENABLED': 'true',
'CULTURAL_CONTEXT_ANALYSIS': 'true',
'AUTO_CATEGORIZATION': 'false',
'ENHANCED_SEARCH_ENABLED': 'true',
'MIN_SOURCE_CREDIBILITY': 'Medium',
'REQUIRE_PUBLICATION_DATE': 'false',
'REQUIRE_AUTHOR_INFO': 'false',
'MIN_WORD_COUNT': '100',
'MAX_CONTENT_AGE': '365',
'CULTURAL_RELEVANCE_THRESHOLD': '0.3',
'SCRAPER_USER_AGENT': 'MCP Content Analyzer 1.0',
'SCRAPER_TIMEOUT': '30000',
'SCRAPER_RATE_LIMIT': '5',
'OCR_FALLBACK_ENABLED': 'true',
'MCP_SERVER_PORT': '3000',
'LOG_LEVEL': 'info',
'MAX_CONTENT_LENGTH': '50000',
'TEAM_NAME': 'default_team',
'SERVER_NAME': 'my-mcp'
};
return defaults[varName] || '';
}
async function main() {
console.log('🔧 MCP Content Analyzer Configuration Wizard\n');
try {
// Load existing configuration
const existingConfig = await loadExistingConfig();
console.log('This wizard will help you configure the MCP Content Analyzer.');
console.log('Press Enter to use default values or existing configuration.\n');
// Core paths configuration
console.log('📁 CORE PATHS CONFIGURATION');
console.log('These are the most important paths for the system to function.\n');
// Excel Database Path
let excelPath = existingConfig.EXCEL_DATABASE_PATH || './data/content-database.xlsx';
console.log(`Current Excel database path: ${excelPath}`);
const newExcelPath = await askQuestion('Enter Excel database path (or press Enter to keep current): ');
if (newExcelPath) {
excelPath = newExcelPath;
}
// Ensure directory exists
ensureDirectory(excelPath);
// Content Catalog Path
let catalogPath = existingConfig.CONTENT_CATALOG_PATH || './data/content-catalog-guidelines.md';
console.log(`\nCurrent content catalog path: ${catalogPath}`);
const newCatalogPath = await askQuestion('Enter content catalog guidelines path (or press Enter to keep current): ');
if (newCatalogPath) {
catalogPath = newCatalogPath;
}
// Ensure directory exists
ensureDirectory(catalogPath);
// Ask about advanced configuration
console.log('\n⚙️ ADVANCED CONFIGURATION');
const configureAdvanced = await askYesNo('Would you like to configure advanced options?', false);
const config = {
EXCEL_DATABASE_PATH: excelPath,
CONTENT_CATALOG_PATH: catalogPath,
...existingConfig
};
if (configureAdvanced) {
console.log('\n📊 EXCEL CONFIGURATION');
config.EXCEL_BACKUP_ENABLED = (await askYesNo('Enable automatic Excel backup?',
existingConfig.EXCEL_BACKUP_ENABLED !== 'false')).toString();
config.EXCEL_AUTO_SAVE = (await askYesNo('Enable automatic Excel saving?',
existingConfig.EXCEL_AUTO_SAVE !== 'false')).toString();
console.log('\n🔍 ANALYSIS CONFIGURATION');
config.AI_ANALYSIS_ENABLED = (await askYesNo('Enable AI-powered analysis?',
existingConfig.AI_ANALYSIS_ENABLED !== 'false')).toString();
config.AUTO_CATEGORIZATION = (await askYesNo('Enable automatic categorization?',
existingConfig.AUTO_CATEGORIZATION === 'true')).toString();
console.log('\n🌐 SCRAPER CONFIGURATION');
const timeout = await askQuestion(`Scraper timeout in milliseconds [${existingConfig.SCRAPER_TIMEOUT || '30000'}]: `);
if (timeout) config.SCRAPER_TIMEOUT = timeout;
const rateLimit = await askQuestion(`Rate limit (requests per minute) [${existingConfig.SCRAPER_RATE_LIMIT || '5'}]: `);
if (rateLimit) config.SCRAPER_RATE_LIMIT = rateLimit;
console.log('\n🏢 TEAM CONFIGURATION');
const teamName = await askQuestion(`Team name [${existingConfig.TEAM_NAME || 'default_team'}]: `);
if (teamName) config.TEAM_NAME = teamName;
const serverName = await askQuestion(`Server name [${existingConfig.SERVER_NAME || 'my-mcp'}]: `);
if (serverName) config.SERVER_NAME = serverName;
}
// Save configuration
await saveConfig(config);
console.log('\n✅ Configuration completed successfully!');
console.log('\n📋 Next steps:');
console.log('1. Restart Claude Desktop to load the new configuration');
console.log('2. Test the connection with: my-mcp test');
console.log('3. Start the server with: my-mcp start');
} catch (error) {
console.error('\n❌ Configuration failed:', error.message);
process.exit(1);
} finally {
rl.close();
}
}
main();