Skip to main content
Glama

get_profile_context

Retrieves repository context using current profile settings to analyze code files and support development workflows.

Instructions

Get repository context based on current profile settings

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
refreshNoWhether to refresh file selection before generating context

Implementation Reference

  • Main handler function that executes the get_profile_context tool logic: fetches profile state, processes full content and outline files with analysis, generates project context with stats, prompts, and structure.
    private async handleGetProfileContext(args: any) { try { const { refresh = false } = args; const spec = await this.profileService.getActiveProfile(); const state = this.profileService.getState(); if (refresh || !state.full_files) { await this.profileService.selectFiles(); } // Read full content files const files = await Promise.all(state.full_files.map(async (path) => { try { const metadata = await this.getFileMetadata(path); const content = await this.processFile(path, metadata); const analysis = await this.codeAnalysisService.analyzeCode(content.content, path); return { ...content, analysis: { metrics: analysis.metrics, complexity: analysis.complexity_metrics.cyclomaticComplexity, maintainability: analysis.complexity_metrics.maintainabilityIndex, quality_issues: analysis.metrics.quality.longLines + analysis.metrics.quality.duplicateLines + analysis.metrics.quality.complexFunctions } }; } catch (error) { await this.loggingService.error('Error processing file', error as Error, { filePath: path, operation: 'get_profile_context' }); return null; } })).then(results => results.filter((f): f is NonNullable<typeof f> => f !== null)); // Generate outlines for selected files const outlines = await Promise.all(state.outline_files.map(async (path) => { try { const metadata = await this.getFileMetadata(path); const content = await this.processFile(path, metadata); const analysis = await this.codeAnalysisService.analyzeCode(content.content, path); return { path, outline: analysis.outline, metadata, analysis: { metrics: analysis.metrics, complexity: analysis.complexity_metrics.cyclomaticComplexity, maintainability: analysis.complexity_metrics.maintainabilityIndex } }; } catch (error) { await this.loggingService.error('Error generating outline', error as Error, { filePath: path, operation: 'get_profile_context' }); return null; } })).then(results => results.filter((o): o is NonNullable<typeof o> => o !== null)); const structure = await this.generateStructure(spec.profile.settings.no_media); // Get prompt if profile specifies it let prompt = ''; if (spec.profile.prompt) { prompt = await this.templateService.getPrompt(); } // Enhanced context with LLM-friendly metadata const context = { project_name: path.basename(process.cwd()), project_root: process.cwd(), timestamp: new Date(state.timestamp).toISOString(), profile: { name: spec.profile.name, description: spec.profile.description || 'Default profile settings', settings: spec.profile.settings }, stats: { total_files: files.length + outlines.length, full_content_files: files.length, outline_files: outlines.length, excluded_files: state.excluded_files?.length || 0, code_metrics: { total_lines: files.reduce((sum, f) => sum + f.analysis.metrics.lineCount.total, 0), code_lines: files.reduce((sum, f) => sum + f.analysis.metrics.lineCount.code, 0), comment_lines: files.reduce((sum, f) => sum + f.analysis.metrics.lineCount.comment, 0), average_complexity: files.length > 0 ? files.reduce((sum, f) => sum + f.analysis.complexity, 0) / files.length : 0, quality_issues: files.reduce((sum, f) => sum + f.analysis.quality_issues, 0) } }, prompt, files: files.map(f => ({ ...f, language: path.extname(f.path).slice(1) || 'text', metadata: { ...f.metadata, relative_path: path.relative(process.cwd(), f.path), file_type: this.getFileType(f.path), last_modified_relative: this.getRelativeTime(new Date(f.metadata.modifiedTime)), analysis: f.analysis } })), highlights: outlines.map(o => ({ ...o, metadata: { ...o.metadata, relative_path: path.relative(process.cwd(), o.path), file_type: this.getFileType(o.path), last_modified_relative: this.getRelativeTime(new Date(o.metadata.modifiedTime)), analysis: o.analysis } })), folder_structure_diagram: structure, tools: { file_access: { name: 'lc-get-files', description: 'Retrieve specific file contents', example: { path: process.cwd(), files: ['example/path/file.ts'] } }, search: { name: 'search_context', description: 'Search for patterns in files', example: { pattern: 'searchTerm', path: process.cwd() } }, changes: { name: 'lc-list-modified-files', description: 'Track file changes since context generation', example: { timestamp: state.timestamp } } } }; return this.createJsonResponse(context); } catch (error) { throw new McpError( ErrorCode.InternalError, `Failed to get profile context: ${error instanceof Error ? error.message : 'Unknown error'}` ); } }
  • Input schema definition for the get_profile_context tool, declared in server capabilities.
    get_profile_context: { description: 'Get repository context based on current profile settings. Includes directory structure, file contents, and code outlines based on profile configuration.', inputSchema: { type: 'object', properties: { refresh: { type: 'boolean', description: 'Whether to refresh file selection before generating context', default: false } } } },
  • src/index.ts:1616-1617 (registration)
    Registration of the get_profile_context handler in the CallToolRequestSchema switch statement.
    return await this.handleGetProfileContext(request.params.arguments); case 'generate_outline':
  • src/index.ts:1532-1544 (registration)
    Tool listing and schema in ListToolsRequestSchema handler response.
    name: 'get_profile_context', description: 'Get repository context based on current profile settings', inputSchema: { type: 'object', properties: { refresh: { type: 'boolean', description: 'Whether to refresh file selection before generating context', default: false } } } },
  • ProfileService class providing helper methods for profile management, file selection based on profiles, state handling - used extensively by the tool handler.
    export class ProfileService { private config: ProfileConfig; private state: ProfileState; private projectRoot: string; private activeProfile: Profile | null; private readonly configPath: string; private logger?: LoggingService; constructor(projectRoot: string, logger?: LoggingService) { this.logger = logger; this.logger?.debug('ProfileService initializing', { projectRoot, operation: 'profile_service_init' }); this.projectRoot = projectRoot; this.configPath = path.join(projectRoot, '.llm-context', 'config.toml'); this.config = this.createDefaultConfig(); this.state = { profile_name: 'code', full_files: [], outline_files: [], excluded_files: [], timestamp: Date.now() }; this.activeProfile = null; } private createDefaultConfig(): ProfileConfig { this.logger?.debug('Creating default configuration', { operation: 'create_default_config' }); const defaultProfile = this.createDefaultProfile(); return { profiles: { code: defaultProfile, 'code-prompt': { ...defaultProfile, name: 'code-prompt', prompt: 'prompt.md' } }, default_profile: 'code' }; } private createDefaultProfile(): Profile { return { name: 'code', gitignores: { full_files: DEFAULT_IGNORE_PATTERNS, outline_files: DEFAULT_IGNORE_PATTERNS }, only_includes: { full_files: INCLUDE_ALL, outline_files: INCLUDE_ALL }, settings: { no_media: true, with_user_notes: false } }; } public async initialize(): Promise<void> { await this.logger?.info('ProfileService starting initialization', { projectRoot: this.projectRoot, configPath: this.configPath, operation: 'profile_service_init' }); await this.loadConfig(); await this.loadState(); } private async loadConfig(): Promise<void> { const configPath = path.join(this.projectRoot, '.llm-context'); try { await fs.mkdir(configPath, { recursive: true }); await this.logger?.debug('Created config directory', { configPath, operation: 'load_config' }); // Create default config if it doesn't exist const configFile = path.join(configPath, 'config.json'); if (!await this.fileExists(configFile)) { await this.logger?.info('Creating default config file', { configFile, operation: 'load_config' }); const defaultConfig = this.createDefaultConfig(); await fs.writeFile(configFile, JSON.stringify(defaultConfig, null, 2)); this.config = defaultConfig; } else { await this.logger?.debug('Loading existing config file', { configFile, operation: 'load_config' }); const content = await fs.readFile(configFile, 'utf8'); this.config = JSON.parse(content); } // Log available profiles await this.logger?.info('Configuration loaded successfully', { availableProfiles: Object.keys(this.config.profiles), currentProfile: this.state.profile_name, operation: 'load_config' }); } catch (error) { await this.logger?.error('Failed to initialize configuration', error as Error, { projectRoot: this.projectRoot, configPath, operation: 'load_config' }); throw error; } } private async loadState(): Promise<void> { const statePath = path.join(this.projectRoot, '.llm-context', 'state.json'); if (!await this.fileExists(statePath)) { await this.logger?.info('Creating default state file', { statePath, operation: 'load_state' }); await fs.writeFile(statePath, JSON.stringify(this.state, null, 2)); } else { await this.logger?.debug('Loading existing state file', { statePath, operation: 'load_state' }); const content = await fs.readFile(statePath, 'utf8'); this.state = JSON.parse(content); } } private async fileExists(filePath: string): Promise<boolean> { try { await fs.access(filePath); return true; } catch { return false; } } public async setProfile(profileName: string): Promise<void> { await this.logger?.info('Attempting to set profile', { profileName, availableProfiles: Object.keys(this.config.profiles), operation: 'set_profile' }); if (!this.config.profiles[profileName]) { throw new Error(`Profile '${profileName}' does not exist. Available profiles: ${Object.keys(this.config.profiles).join(', ')}`); } this.state = { ...this.state, profile_name: profileName, timestamp: Date.now() }; await this.saveState(); await this.logger?.info('Successfully set profile', { profileName, operation: 'set_profile' }); } public getContextSpec(): ContextSpec { const profile = this.resolveProfile(this.state.profile_name); return { profile, state: this.state }; } private resolveProfile(profileName: string): Profile { const profile = this.config.profiles[profileName]; if (!profile) { this.logger?.warning('Profile not found, using default', { requestedProfile: profileName, defaultProfile: this.config.default_profile, operation: 'resolve_profile' }); return this.config.profiles[this.config.default_profile]; } return profile; } private async saveState(): Promise<void> { const statePath = path.join(this.projectRoot, '.llm-context', 'state.json'); await fs.writeFile(statePath, JSON.stringify(this.state, null, 2)); await this.logger?.debug('State saved successfully', { statePath, state: this.state, operation: 'save_state' }); } public async updateFileSelection(fullFiles: string[], outlineFiles: string[]): Promise<void> { this.state = { ...this.state, full_files: fullFiles, outline_files: outlineFiles, timestamp: Date.now() }; await this.saveState(); } public getProfile(): Profile { return this.resolveProfile(this.state.profile_name); } public getState(): ProfileState { return this.state; } public async getActiveProfile(): Promise<{ profile: Profile }> { if (!this.activeProfile) { throw new Error('No active profile'); } return { profile: this.activeProfile }; } public async selectFiles(): Promise<void> { if (!this.activeProfile) { throw new Error('No active profile'); } const fullFiles = await this.getFilteredFiles( this.activeProfile.gitignores.full_files, this.activeProfile.only_includes.full_files ); const outlineFiles = await this.getFilteredFiles( this.activeProfile.gitignores.outline_files, this.activeProfile.only_includes.outline_files ); this.state = { ...this.state, full_files: fullFiles, outline_files: outlineFiles, timestamp: Date.now() }; await this.saveState(); } private async getFilteredFiles(ignorePatterns: string[], includePatterns: string[]): Promise<string[]> { const allFiles: string[] = []; for (const pattern of includePatterns) { const files = await globAsync(pattern, { ignore: ignorePatterns, nodir: true, dot: true }) as string[]; allFiles.push(...files); } return [...new Set(allFiles)]; } }

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/bsmi021/mcp-file-context-server'

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