Skip to main content
Glama

Code Summarizer MCP

by nicobailon
index.ts8.45 kB
// index.ts import dotenv from 'dotenv'; import { Command } from 'commander'; import * as fs from 'fs'; import * as path from 'path'; // Load environment variables dotenv.config(); // Import core summarizer functionality import { GeminiLLM } from './src/summarizer/llm.js'; import { findCodeFiles, summarizeFile, summarizeFiles, writeSummariesToFile } from './src/summarizer/files.js'; import { SummaryOptions, MAX_FILE_SIZE_BYTES, DEFAULT_BATCH_SIZE } from './src/summarizer/types.js'; // Import MCP server import { startServer } from './src/mcp/server.js'; // Import configuration import { getConfig, updateConfig, setApiKey, setPort, setSummaryOptions, resetConfig } from './src/config/config.js'; // Main function async function main() { try { const program = new Command(); program .name('code-summarizer') .description('A tool to summarize code files using Gemini Flash 2.0') .version('1.0.0'); // Default summarize command (original functionality) program .command('summarize') .description('Summarize code files in a directory') .argument('[rootDir]', 'Root directory to scan', process.cwd()) .argument('[outputFile]', 'Output file for summaries', 'summaries.txt') .option('-d, --detail <level>', 'Detail level (low, medium, high)', 'medium') .option('-l, --max-length <number>', 'Maximum summary length in characters', '500') .action(async (rootDir, outputFile, options) => { // Validate detail level if (!['low', 'medium', 'high'].includes(options.detail)) { throw new Error(`Invalid detail level: ${options.detail}. Use 'low', 'medium', or 'high'.`); } // Validate max length const maxLength = parseInt(options.maxLength); if (isNaN(maxLength) || maxLength <= 0) { throw new Error(`Invalid max length: ${options.maxLength}. Use a positive number.`); } // Validate the path exists if (!fs.existsSync(rootDir)) { throw new Error(`Path not found: ${rootDir}`); } // Get config for API key const config = getConfig(); const apiKey = config.apiKey || process.env.GOOGLE_API_KEY; if (!apiKey) { throw new Error('API key not set. Use the "config set --api-key <key>" command or set GOOGLE_API_KEY in .env file.'); } // Initialize the LLM const llm = new GeminiLLM(apiKey); // Create summary options const summaryOptions: SummaryOptions = { detailLevel: options.detail as 'low' | 'medium' | 'high', maxLength: maxLength }; // Check if the path is a file or directory const isFile = fs.statSync(rootDir).isFile(); if (isFile) { console.log(`Summarizing file: ${rootDir}`); console.log(`Output file: ${outputFile}`); console.log(`Detail level: ${options.detail}`); console.log(`Max length: ${maxLength}`); // Import the getSingleFileSummary function dynamically const { getSingleFileSummary } = await import('./src/summarizer/summarize.js'); // Summarize the single file const summary = await getSingleFileSummary(rootDir, llm, summaryOptions); // Write the summary to the output file const fileSummary = { relativePath: path.basename(rootDir), summary }; await writeSummariesToFile([fileSummary], outputFile); console.log('File summary written to', outputFile); } else { // It's a directory, follow original flow console.log(`Scanning directory: ${rootDir}`); console.log(`Output file: ${outputFile}`); console.log(`Detail level: ${options.detail}`); console.log(`Max length: ${maxLength}`); // Find all code files console.log('Finding code files...'); const codeFiles = await findCodeFiles(rootDir); console.log(`Found ${codeFiles.length} code files to process`); if (codeFiles.length === 0) { console.log('No code files found to summarize.'); return; } // Summarize the files console.log('Generating summaries...'); const summaries = await summarizeFiles(codeFiles, rootDir, llm, 5, summaryOptions); // Write summaries to the output file await writeSummariesToFile(summaries, outputFile); console.log('Code summarization completed successfully!'); } }); // MCP server command program .command('server') .description('Start the MCP server') .action(async () => { await startServer(); }); // Configuration commands const configCommand = program .command('config') .description('Manage configuration settings'); configCommand .command('show') .description('Show current configuration') .action(() => { const config = getConfig(); console.log(JSON.stringify(config, null, 2)); }); configCommand .command('set') .description('Set configuration options') .option('--api-key <key>', 'Set the Gemini API key') .option('--port <port>', 'Set the MCP server port') .option('--detail-level <level>', 'Set default detail level (low, medium, high)') .option('--max-length <length>', 'Set default maximum summary length') .action((options) => { const updates: any = {}; if (options.apiKey) { updates.apiKey = options.apiKey; } if (options.port) { const port = parseInt(options.port); if (isNaN(port) || port <= 0) { throw new Error(`Invalid port: ${options.port}. Use a positive number.`); } updates.port = port; } if (options.detailLevel) { if (!['low', 'medium', 'high'].includes(options.detailLevel)) { throw new Error(`Invalid detail level: ${options.detailLevel}. Use 'low', 'medium', or 'high'.`); } updates.summaryOptions = { ...getConfig().summaryOptions, detailLevel: options.detailLevel }; } if (options.maxLength) { const maxLength = parseInt(options.maxLength); if (isNaN(maxLength) || maxLength <= 0) { throw new Error(`Invalid max length: ${options.maxLength}. Use a positive number.`); } updates.summaryOptions = { ...updates.summaryOptions || getConfig().summaryOptions, maxLength }; } // Update config if (Object.keys(updates).length > 0) { const newConfig = updateConfig(updates); console.log('Configuration updated:'); console.log(JSON.stringify(newConfig, null, 2)); } else { console.log('No configuration changes specified.'); } }); configCommand .command('reset') .description('Reset configuration to defaults') .action(() => { resetConfig(); console.log('Configuration reset to defaults.'); }); program.parse(process.argv); // If no command is specified, show help if (!process.argv.slice(2).length) { program.outputHelp(); } } catch (error) { console.error(`Error: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } } // Export for testing export { findCodeFiles, summarizeFile, summarizeFiles, writeSummariesToFile, GeminiLLM, MAX_FILE_SIZE_BYTES, DEFAULT_BATCH_SIZE }; // Re-export types and constants for backward compatibility with tests export { extensionToLanguage, skipDirectories } from './src/summarizer/types.js'; export type { SummaryOptions } from './src/summarizer/types.js'; export type { LLM } from './src/summarizer/llm.js'; // Only run main when file is executed directly, not when imported // For ESM we need to check if this is the main module const isMainModule = import.meta.url.endsWith(process.argv[1].replace(/^file:\/\//, '')); if (isMainModule) { main(); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nicobailon/code-summarizer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server