Skip to main content
Glama

AutoDev Codebase MCP Server

by anrgct
tui-runner.ts•14.3 kB
import React from 'react'; import { Box, Text } from 'ink'; import * as path from 'path'; import fs from 'fs'; import { createNodeDependencies } from '../adapters/nodejs'; import { CodeIndexManager } from '../code-index/manager'; import { App } from '../examples/tui/App'; import { CliOptions } from './args-parser'; import createSampleFiles from '../examples/create-sample-files'; import { CodebaseMCPServer, createMCPServer } from '../mcp/server'; import { CodebaseHTTPMCPServer } from '../mcp/http-server.js'; // Extract sample files creation from original demo export function createTUIApp(options: CliOptions) { const AppWithOptions: React.FC = () => { const [codeIndexManager, setCodeIndexManager] = React.useState<any>(null); const [dependencies, setDependencies] = React.useState<any>(null); const [error, setError] = React.useState<string | null>(null); React.useEffect(() => { async function initialize() { // Ensure options.path is absolute; if not, prepend process.cwd() let resolvedPath = options.path; if (!path.isAbsolute(resolvedPath)) { resolvedPath = path.join(process.cwd(), resolvedPath); } // Create workspace path - use demo subdirectory if --demo flag is set const workspacePath = options.demo ? path.join(resolvedPath, 'demo') : resolvedPath; // Use config file from workspace directory const configPath = options.config || path.join(workspacePath, 'autodev-config.json'); // console.log('[tui-runner]šŸ“‚ Workspace path:', workspacePath); const deps = createNodeDependencies({ workspacePath, storageOptions: { globalStoragePath: options.storage || path.join(process.cwd(), '.autodev-storage'), ...(options.cache && { cacheBasePath: options.cache }) }, loggerOptions: { name: 'Autodev-Codebase-TUI', level: options.logLevel, timestamps: true, colors: true }, configOptions: { configPath, cliOverrides: { ollamaUrl: options.ollamaUrl, model: options.model, qdrantUrl: options.qdrantUrl } } }); try { // Log workspace path after deps are created so we can use the logger deps.logger?.info('[tui-runner]šŸ“‚ Workspace path:', workspacePath); // Create demo files if requested if (options.demo) { const workspaceExists = await deps.fileSystem.exists(workspacePath); if (!workspaceExists) { fs.mkdirSync(workspacePath, { recursive: true }); await createSampleFiles(deps.fileSystem, workspacePath); deps.logger?.info('[tui-runner]šŸ“ Demo files created in:', workspacePath); } } deps.logger?.info('[tui-runner]āš™ļø Loading configuration...'); const config = await deps.configProvider.loadConfig(); deps.logger?.info('[tui-runner]šŸ“ Configuration:', JSON.stringify(config, null, 2)); deps.logger?.info('[tui-runner]āœ… Validating configuration...'); const validation = await deps.configProvider.validateConfig(); deps.logger?.info('[tui-runner]šŸ“ Validation result:', validation); if (!validation.isValid) { deps.logger?.warn('[tui-runner]āš ļø Configuration validation warnings:', validation.errors); deps.logger?.info('[tui-runner]āš ļø Continuing initialization (debug mode)'); } else { deps.logger?.info('[tui-runner]āœ… Configuration validation passed'); } setDependencies(deps); deps.logger?.info('Creating CodeIndexManager with dependencies:', { hasFileSystem: !!deps.fileSystem, hasStorage: !!deps.storage, hasEventBus: !!deps.eventBus, hasWorkspace: !!deps.workspace, hasPathUtils: !!deps.pathUtils, hasConfigProvider: !!deps.configProvider, workspaceRootPath: deps.workspace.getRootPath() }); const manager = CodeIndexManager.getInstance(deps); deps.logger?.info('CodeIndexManager instance created:', !!manager); if (!manager) { setError('Failed to create CodeIndexManager - workspace root path may be invalid'); return; } deps.logger?.info('[tui-runner]āš™ļø Initializing CodeIndexManager...'); const initResult = await manager.initialize({ force: options.force }); deps.logger?.info('[tui-runner]āœ… CodeIndexManager initialization success:', initResult); deps.logger?.info('[tui-runner]šŸ“ Manager state:', { isInitialized: manager.isInitialized, isFeatureEnabled: manager.isFeatureEnabled, isFeatureConfigured: manager.isFeatureConfigured, state: manager.state }); deps.logger?.info('[tui-runner]šŸ”„ Setting CodeIndexManager to state...'); setCodeIndexManager(manager); deps.logger?.info('[tui-runner]āœ… CodeIndexManager set to state'); // Start indexing in background deps.logger?.info('[tui-runner]šŸš€ Preparing to start indexing...'); manager.onProgressUpdate((progressInfo) => { deps.logger?.info('[tui-runner]šŸ“Š Indexing progress:', JSON.stringify(progressInfo)); }); setTimeout(() => { if (manager.isFeatureEnabled && manager.isInitialized) { deps.logger?.info('[tui-runner]šŸš€ Starting indexing process...'); deps.logger?.info('[tui-runner]šŸ“Š Current state:', manager.state); const indexingTimeout = setTimeout(() => { deps.logger?.warn('[tui-runner]āš ļø Indexing process timeout (30s), may be stuck'); }, 30000); manager.startIndexing() .then(() => { clearTimeout(indexingTimeout); deps.logger?.info('[tui-runner]āœ… Indexing completed'); }) .catch((err: any) => { clearTimeout(indexingTimeout); deps.logger?.error('[tui-runner]āŒ Indexing failed:', err); deps.logger?.error('[tui-runner]āŒ Error stack:', err.stack); setError(`Indexing failed: ${err.message}`); }); } else { deps.logger?.warn('[tui-runner]āš ļø Skipping indexing - feature not enabled or not initialized'); deps.logger?.error('[tui-runner]šŸ“Š Feature state:', { isFeatureEnabled: manager.isFeatureEnabled, isInitialized: manager.isInitialized, state: manager.state }); } }, 1000); deps.logger?.info('[tui-runner]āœ… Initialization completed'); } catch (err: any) { deps.logger?.error('[tui-runner]āŒ Initialization failed:', err); deps.logger?.error('[tui-runner]āŒ Error stack:', err.stack); setError(`Initialization failed: ${err.message}`); } } initialize(); // Cleanup function to dispose of singleton instances return () => { CodeIndexManager.disposeAll(); }; }, []); if (error) { return React.createElement(Box, { flexDirection: "column", padding: 1 }, React.createElement(Text, { bold: true, color: "red" }, "X Initialization Failed"), React.createElement(Text, { color: "white" }, error), React.createElement(Text, { color: "gray" }, "Please check configuration or service connection status") ); } const DummyApp = () => null; return React.createElement(App, { codeIndexManager, dependencies }); }; return AppWithOptions; } // Helper function to create HTTP MCP server async function createHTTPMCPServer(manager: CodeIndexManager, options?: { port?: number; host?: string }): Promise<CodebaseHTTPMCPServer> { const server = new CodebaseHTTPMCPServer({ codeIndexManager: manager, port: options?.port, host: options?.host }); await server.start(); return server; } export async function startStdioAdapterMode(options: CliOptions): Promise<void> { // console.log('šŸ”Œ Starting Stdio Adapter Mode'); // console.log(`🌐 Connecting to server: ${options.stdioServerUrl || 'http://localhost:3001'}`); // console.log(`ā±ļø Request timeout: ${options.stdioTimeout || 30000}ms`); const { StdioToSSEAdapter } = await import('../mcp/stdio-adapter'); const adapter = new StdioToSSEAdapter({ serverUrl: options.stdioServerUrl || 'http://localhost:3001/sse', timeout: options.stdioTimeout || 30000 }); try { await adapter.start(); // Handle graceful shutdown const handleShutdown = () => { console.error('šŸ”„ Shutting down stdio adapter...'); adapter.stop(); process.exit(0); }; process.on('SIGINT', handleShutdown); process.on('SIGTERM', handleShutdown); // Keep the process alive to handle stdio communication return new Promise(() => {}); // Never resolves } catch (error) { console.error('āŒ Stdio adapter failed to start:', error); process.exit(1); } } export async function startMCPServerMode(options: CliOptions): Promise<void> { // Ensure options.path is absolute; if not, prepend process.cwd() let resolvedPath = options.path; if (!path.isAbsolute(resolvedPath)) { resolvedPath = path.join(process.cwd(), resolvedPath); } // Create workspace path - use demo subdirectory if --demo flag is set const workspacePath = options.demo ? path.join(resolvedPath, 'demo') : resolvedPath; // Use config file from workspace directory const configPath = options.config || path.join(workspacePath, 'autodev-config.json'); console.log('šŸš€ Starting MCP Server Mode'); console.log(`šŸ“‚ Workspace: ${workspacePath}`); console.log(`āš™ļø Config: ${configPath}`); const deps = createNodeDependencies({ workspacePath, storageOptions: { globalStoragePath: options.storage || path.join(process.cwd(), '.autodev-storage'), ...(options.cache && { cacheBasePath: options.cache }) }, loggerOptions: { name: 'Autodev-Codebase-MCP', level: options.logLevel, timestamps: true, colors: false // Disable colors for MCP server mode }, configOptions: { configPath, cliOverrides: { ollamaUrl: options.ollamaUrl, model: options.model, qdrantUrl: options.qdrantUrl } } }); try { // Create demo files if requested if (options.demo) { const workspaceExists = await deps.fileSystem.exists(workspacePath); if (!workspaceExists) { fs.mkdirSync(workspacePath, { recursive: true }); await createSampleFiles(deps.fileSystem, workspacePath); console.log(`šŸ“ Demo files created in: ${workspacePath}`); } } console.log('āš™ļø Loading configuration...'); const config = await deps.configProvider.loadConfig(); console.log('āœ… Validating configuration...'); const validation = await deps.configProvider.validateConfig(); if (!validation.isValid) { console.warn('āš ļø Configuration validation warnings:', validation.errors); console.log('āš ļø Continuing initialization (debug mode)'); } else { console.log('āœ… Configuration validation passed'); } console.log('šŸ”§ Creating CodeIndexManager...'); const manager = CodeIndexManager.getInstance(deps); if (!manager) { throw new Error('Failed to create CodeIndexManager - workspace root path may be invalid'); } console.log('āš™ļø Initializing CodeIndexManager...'); const initResult = await manager.initialize({ force: options.force }); console.log('āœ… CodeIndexManager initialization success'); // Start MCP Server console.log('šŸš€ Starting MCP Server...'); const server = await createHTTPMCPServer(manager, { port: options.mcpPort, host: options.mcpHost }); console.log('āœ… MCP Server started successfully'); // Display configuration instructions console.log('\nšŸ”— MCP Server is now running!'); console.log('To connect your IDE to the HTTP SSE MCP server, use the following configuration:'); console.log(JSON.stringify({ "mcpServers": { "codebase": { "url": `http://${options.mcpHost || 'localhost'}:${options.mcpPort || 3001}/sse` } } }, null, 2)); console.log('Alternatively, to use MCP in stdio mode:'); console.log(JSON.stringify({ "mcpServers": { "codebase": { "command": "codebase", "args": ["stdio-adapter", `--server-url=http://${options.mcpHost || 'localhost'}:${options.mcpPort || 3001}/sse`] } } }, null, 2)); console.log(''); // Start indexing in background console.log('šŸš€ Starting indexing process...'); manager.onProgressUpdate((progressInfo) => { console.log(`šŸ“Š Indexing progress: ${progressInfo.systemStatus} - ${progressInfo.message || ''}`); }); if (manager.isFeatureEnabled && manager.isInitialized) { manager.startIndexing() .then(() => { console.log('āœ… Indexing completed'); }) .catch((err: any) => { console.error('āŒ Indexing failed:', err.message); }); } else { console.warn('āš ļø Skipping indexing - feature not enabled or not initialized'); } // Handle graceful shutdown const handleShutdown = async () => { console.log('\nšŸ”„ Shutting down MCP Server...'); await server.stop(); console.log('āœ… MCP Server stopped'); process.exit(0); }; process.on('SIGINT', handleShutdown); process.on('SIGTERM', handleShutdown); console.log('šŸ“” MCP Server is ready for connections. Press Ctrl+C to stop.'); // Keep the process alive return new Promise(() => {}); // This never resolves, keeping the server running } catch (err: any) { console.error('āŒ MCP Server initialization failed:', err.message); process.exit(1); } }

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/anrgct/autodev-codebase'

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