Skip to main content
Glama
projectConfig.ts5.47 kB
/** * Project Configuration Management * Handles mcp.config.json for tracking project settings and engine mode */ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs'; import { join, dirname } from 'path'; import chalk from 'chalk'; /** * MCP Project Configuration * Stores metadata about project creation and execution engine preferences */ export interface McpProjectConfig { /** Project name (parsed from description or user input) */ projectName: string; /** Original project description/prompt */ description: string; /** ISO-8601 UTC datetime when project was created */ createdAt: string; /** CLI version used to create the project */ cliVersion: string; /** Execution engine: multi-layer (API-based) or claude-code (local binary) */ engine: 'multi-layer' | 'claude-code'; /** Quick boolean flag for Claude Code usage */ useClaudeCode: boolean; /** Layer routing configuration */ layers: { /** Whether layer-based routing is enabled */ enabled: boolean; /** Default escalation path */ defaultEscalation: string[]; }; /** Cost tracking preferences */ costTracking: { /** Include planning phase costs in total */ includePlanningPhase: boolean; }; } const CONFIG_FILENAME = 'mcp.config.json'; /** * Load project configuration from directory * * @param projectRoot Root directory of the project * @returns Configuration object or null if not found */ export async function loadProjectConfig(projectRoot: string): Promise<McpProjectConfig | null> { const configPath = join(projectRoot, CONFIG_FILENAME); if (!existsSync(configPath)) { return null; } try { const content = readFileSync(configPath, 'utf-8'); const parsed = JSON.parse(content) as Partial<McpProjectConfig>; // Validate and apply defaults for missing fields const config: McpProjectConfig = { projectName: parsed.projectName || 'Unnamed Project', description: parsed.description || '', createdAt: parsed.createdAt || new Date().toISOString(), cliVersion: parsed.cliVersion || '0.1.0', engine: parsed.engine || 'multi-layer', useClaudeCode: parsed.useClaudeCode ?? (parsed.engine === 'claude-code'), layers: { enabled: parsed.layers?.enabled ?? true, defaultEscalation: parsed.layers?.defaultEscalation || ['L0', 'L1', 'L2', 'L3'], }, costTracking: { includePlanningPhase: parsed.costTracking?.includePlanningPhase ?? true, }, }; return config; } catch (error) { console.error(chalk.yellow(`⚠️ Failed to parse ${CONFIG_FILENAME}: ${error instanceof Error ? error.message : String(error)}`)); return null; } } /** * Save project configuration to directory * * @param projectRoot Root directory of the project * @param config Configuration object to save */ export async function saveProjectConfig(projectRoot: string, config: McpProjectConfig): Promise<void> { const configPath = join(projectRoot, CONFIG_FILENAME); try { // Ensure directory exists const dir = dirname(configPath); if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }); } // Write with pretty formatting const content = JSON.stringify(config, null, 2); writeFileSync(configPath, content, 'utf-8'); console.log(chalk.dim(` 📝 Created ${CONFIG_FILENAME}`)); } catch (error) { console.error(chalk.red(`❌ Failed to save ${CONFIG_FILENAME}: ${error instanceof Error ? error.message : String(error)}`)); throw error; } } /** * Create default project configuration * * @param projectName Name of the project * @param description Project description/prompt * @param cliVersion Current CLI version * @param useClaudeCode Whether to use Claude Code engine * @returns Default configuration object */ export function createDefaultConfig( projectName: string, description: string, cliVersion: string, useClaudeCode: boolean = false ): McpProjectConfig { return { projectName, description, createdAt: new Date().toISOString(), cliVersion, engine: useClaudeCode ? 'claude-code' : 'multi-layer', useClaudeCode, layers: { enabled: true, defaultEscalation: ['L0', 'L1', 'L2', 'L3'], }, costTracking: { includePlanningPhase: true, }, }; } /** * Find project root by searching for mcp.config.json upwards * * @param startDir Starting directory (default: cwd) * @param maxDepth Maximum depth to search upwards (default: 5) * @returns Project root path or null if not found */ export function findProjectRoot(startDir: string = process.cwd(), maxDepth: number = 5): string | null { let currentDir = startDir; let depth = 0; while (depth < maxDepth) { const configPath = join(currentDir, CONFIG_FILENAME); if (existsSync(configPath)) { return currentDir; } const parentDir = dirname(currentDir); if (parentDir === currentDir) { // Reached filesystem root break; } currentDir = parentDir; depth++; } return null; }

Latest Blog Posts

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/babasida246/ai-mcp-gateway'

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