Skip to main content
Glama
saiprashanths

Code Analysis MCP Server

read_file

Read and display file contents from a repository to analyze code structure and understand system architecture during development.

Instructions

Read and display the contents of a file from the repository.

Args:
    file_path: Path to the file relative to repository root

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
file_pathYes

Implementation Reference

  • The primary handler for the 'read_file' MCP tool. Registered with @mcp.tool(), performs prerequisite checks, gitignore filtering, invokes the FileReader helper, and returns formatted file content or error message.
    @mcp.tool()
    async def read_file(file_path: str) -> str:
        """Read and display the contents of a file from the repository.
        
        Args:
            file_path: Path to the file relative to repository root
        """
        if not mcp.repo_path or not mcp.file_reader or not mcp.analyzer:
            return "No code repository has been initialized yet. Please use initialize_repository first."
    
        try:
            # Check if file should be ignored based on gitignore patterns
            if mcp.analyzer.should_ignore(file_path):
                return f"File {file_path} is ignored based on .gitignore patterns"
    
            result = mcp.file_reader.read_file(file_path)
            
            if result.get("isError", False):
                return result["content"][0]["text"]
            
            return result["content"][0]["text"]
            
        except Exception as e:
            return f"Error reading file: {str(e)}"
  • The core helper method in the FileReader class that implements file reading logic: path safety checks, size/line limits, language detection, content formatting, and error handling for the MCP tool.
    def read_file(self, file_path: str) -> Dict[str, Union[List[Dict[str, str]], bool]]:
        """Read and format file contents for LLM consumption."""
        try:
            full_path = self.repo_path / file_path
            
            # Check if path is safe
            if not full_path.resolve().is_relative_to(self.repo_path.resolve()):
                return {
                    "content": [{
                        "type": "text",
                        "text": f"Error: Attempted to access file outside repository: {file_path}"
                    }],
                    "isError": True
                }
            
            # Check if file exists
            if not full_path.exists():
                return {
                    "content": [{
                        "type": "text",
                        "text": f"File {file_path} not found"
                    }],
                    "isError": True
                }
            
            # Check if it's a symbolic link
            if full_path.is_symlink():
                return {
                    "content": [{
                        "type": "text",
                        "text": f"Error: Symbolic links are not supported: {file_path}"
                    }],
                    "isError": True
                }
            
            # Get file stats
            stats = full_path.stat()
            
            # Check file size
            if stats.st_size > self.MAX_SIZE:
                return {
                    "content": [{
                        "type": "text",
                        "text": f"File {file_path} is too large ({stats.st_size} bytes). "
                             f"Maximum size is {self.MAX_SIZE} bytes."
                    }],
                    "isError": True
                }
            
            # Read file content with line limit
            lines = []
            line_count = 0
            truncated = False
            
            with open(full_path, 'r', encoding='utf-8') as f:
                for line in f:
                    line_count += 1
                    if line_count <= self.MAX_LINES:
                        lines.append(line.rstrip('\n'))
                    else:
                        truncated = True
                        break
            
            content = '\n'.join(lines)
            if truncated:
                content += f"\n\n[File truncated after {self.MAX_LINES} lines]"
            
            # Detect language
            language = self._detect_language(file_path)
            
            return {
                "content": [{
                    "type": "text",
                    "text": f"File: {file_path}\n"
                           f"Language: {language}\n"
                           f"Size: {stats.st_size} bytes\n"
                           f"Total lines: {line_count}\n\n"
                           f"{content}"
                }]
            }
            
        except UnicodeDecodeError:
            return {
                "content": [{
                    "type": "text",
                    "text": f"Error: File {file_path} appears to be a binary file"
                }],
                "isError": True
            }
        except Exception as error:
            return {
                "content": [{
                    "type": "text",
                    "text": f"Error reading file: {str(error)}"
                }],
                "isError": True
            }

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/saiprashanths/code-analysis-mcp'

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