search_in_large_file
Search for patterns in large files using regex and case-sensitive options, displaying results with surrounding context lines for better analysis.
Instructions
Search for a pattern in a large file with context lines. Supports regex and case-sensitive search.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filePath | Yes | Absolute path to the file | |
| pattern | Yes | Search pattern (supports regex if regex=true) | |
| caseSensitive | No | Case sensitive search (default: false) | |
| regex | No | Use regex pattern (default: false) | |
| maxResults | No | Maximum number of results (default: 100) | |
| contextBefore | No | Number of context lines before match (default: 2) | |
| contextAfter | No | Number of context lines after match (default: 2) | |
| startLine | No | Start searching from line number (optional) | |
| endLine | No | End searching at line number (optional) |
Implementation Reference
- src/fileHandler.ts:283-368 (handler)The core handler function implementing the search logic for 'search_in_large_file'. It streams the large file using readline, performs regex or literal pattern matching, extracts context lines, and returns structured SearchResult objects.static async search( filePath: string, pattern: string, options: SearchOptions = {} ): Promise<SearchResult[]> { await this.verifyFile(filePath); const results: SearchResult[] = []; const maxResults = options.maxResults || 100; const contextBefore = options.contextBefore || 2; const contextAfter = options.contextAfter || 2; const regex = options.regex ? new RegExp(pattern, options.caseSensitive ? 'g' : 'gi') : new RegExp( pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), options.caseSensitive ? 'g' : 'gi' ); return new Promise((resolve, reject) => { let lineNumber = 0; const lineBuffer: string[] = []; const stream = fs.createReadStream(filePath); const rl = readline.createInterface({ input: stream, crlfDelay: Infinity, }); rl.on('line', (line) => { lineNumber++; lineBuffer.push(line); // Keep buffer for context if (lineBuffer.length > contextBefore + contextAfter + 1) { lineBuffer.shift(); } // Check if within search range if (options.startLine && lineNumber < options.startLine) return; if (options.endLine && lineNumber > options.endLine) { rl.close(); return; } // Search for pattern const matches = Array.from(line.matchAll(regex)); if (matches.length > 0) { const matchPositions = matches.map(m => ({ start: m.index!, end: m.index! + m[0].length, })); const bufferIndex = lineBuffer.length - 1; const before = lineBuffer.slice( Math.max(0, bufferIndex - contextBefore), bufferIndex ); results.push({ lineNumber, lineContent: line, matchPositions, contextBefore: before, contextAfter: [], // Will be filled after chunkIndex: Math.floor((lineNumber - 1) / 500), }); if (results.length >= maxResults) { rl.close(); } } // Fill context after for previous results if (results.length > 0) { const lastResult = results[results.length - 1]; const linesSince = lineNumber - lastResult.lineNumber; if (linesSince > 0 && linesSince <= contextAfter) { lastResult.contextAfter.push(line); } } }); rl.on('close', () => resolve(results)); rl.on('error', reject); }); }
- src/server.ts:116-161 (registration)Tool registration in the MCP server's getTools() method, defining the tool name, description, and input schema.{ name: 'search_in_large_file', description: 'Search for a pattern in a large file with context lines. Supports regex and case-sensitive search.', inputSchema: { type: 'object', properties: { filePath: { type: 'string', description: 'Absolute path to the file', }, pattern: { type: 'string', description: 'Search pattern (supports regex if regex=true)', }, caseSensitive: { type: 'boolean', description: 'Case sensitive search (default: false)', }, regex: { type: 'boolean', description: 'Use regex pattern (default: false)', }, maxResults: { type: 'number', description: 'Maximum number of results (default: 100)', }, contextBefore: { type: 'number', description: 'Number of context lines before match (default: 2)', }, contextAfter: { type: 'number', description: 'Number of context lines after match (default: 2)', }, startLine: { type: 'number', description: 'Start searching from line number (optional)', }, endLine: { type: 'number', description: 'End searching at line number (optional)', }, }, required: ['filePath', 'pattern'], }, },
- src/types.ts:83-98 (schema)TypeScript interface defining the input options for the search tool, matching the inputSchema.export interface SearchOptions { /** Case sensitive search */ caseSensitive?: boolean; /** Regular expression search */ regex?: boolean; /** Maximum results to return */ maxResults?: number; /** Number of context lines before match */ contextBefore?: number; /** Number of context lines after match */ contextAfter?: number; /** Start searching from line */ startLine?: number; /** End searching at line */ endLine?: number; }
- src/types.ts:68-81 (schema)TypeScript interface for search results output structure.export interface SearchResult { /** Line number (1-indexed) */ lineNumber: number; /** Line content */ lineContent: string; /** Match positions in line */ matchPositions: Array<{ start: number; end: number }>; /** Context lines before */ contextBefore: string[]; /** Context lines after */ contextAfter: string[]; /** Chunk index containing this result */ chunkIndex: number; }
- src/server.ts:297-324 (handler)Server-side handler wrapper that validates arguments, calls FileHandler.search, and formats response for MCP protocol.private async handleSearch( args: Record<string, unknown> ): Promise<{ content: Array<{ type: string; text: string }> }> { const filePath = args.filePath as string; const pattern = args.pattern as string; const results: SearchResult[] = await FileHandler.search(filePath, pattern, { caseSensitive: args.caseSensitive as boolean, regex: args.regex as boolean, maxResults: (args.maxResults as number) || 100, contextBefore: (args.contextBefore as number) || 2, contextAfter: (args.contextAfter as number) || 2, startLine: args.startLine as number | undefined, endLine: args.endLine as number | undefined, }); return { content: [ { type: 'text', text: JSON.stringify({ totalResults: results.length, results, }, null, 2), }, ], }; }