Skip to main content
Glama

grep_search

Search file contents using regex patterns to find specific text within files or directories, with options for case sensitivity, file filtering, and context lines around matches.

Instructions

Search file contents with regex

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
patternYesRegex pattern to search for
pathNoFile or directory to search
globNoFile pattern filter (e.g., *.ts)
case_sensitiveNoCase sensitive search
max_resultsNoMaximum results (default: 100)
context_linesNoLines of context around matches

Implementation Reference

  • The grepSearchImpl function performs the regex-based content search across files.
    async function grepSearchImpl(input: GrepSearchInput): Promise<ToolResult> {
      try {
        const searchPath = input.path ? path.resolve(input.path) : process.cwd();
        const matches: GrepMatch[] = [];
    
        // Create regex
        const flags = input.case_sensitive ? '' : 'i';
        let regex: RegExp;
        try {
          regex = new RegExp(input.pattern, flags);
        } catch {
          return {
            isError: true,
            content: [
              {
                type: 'text',
                text: JSON.stringify({
                  code: 'INVALID_PATH',
                  message: `Invalid regex pattern: ${input.pattern}`,
                }),
              },
            ],
          };
        }
    
        // Determine files to search
        let files: string[];
    
        const stats = await fs.stat(searchPath);
        if (stats.isFile()) {
          files = [searchPath];
        } else {
          // Use glob to find files in directory
          const globPattern = input.glob ?? '**/*';
          files = await glob(globPattern, {
            cwd: searchPath,
            nodir: true,
            absolute: true,
            maxDepth: 20,
          });
        }
    
        // Search each file
        for (const file of files) {
          if (matches.length >= input.max_results) break;
    
          try {
            const content = await fs.readFile(file, 'utf-8');
            const lines = content.split('\n');
    
            for (let i = 0; i < lines.length; i++) {
              if (matches.length >= input.max_results) break;
    
              const line = lines[i];
              const match = regex.exec(line);
    
              if (match) {
                const grepMatch: GrepMatch = {
                  file,
                  line: i + 1,
                  column: match.index + 1,
                  match: line.trim(),
                };
    
                // Add context if requested
                if (input.context_lines > 0) {
                  const beforeStart = Math.max(0, i - input.context_lines);
                  const afterEnd = Math.min(lines.length, i + input.context_lines + 1);
    
                  grepMatch.context = {
                    before: lines.slice(beforeStart, i).map((l) => l.trim()),
                    after: lines.slice(i + 1, afterEnd).map((l) => l.trim()),
                  };
                }
    
                matches.push(grepMatch);
              }
            }
          } catch {
            // Skip files that can't be read (binary, permissions, etc.)
          }
        }
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(
                {
                  pattern: input.pattern,
                  count: matches.length,
                  truncated: matches.length >= input.max_results,
                  matches,
                },
                null,
                2
              ),
            },
          ],
        };
      } catch (error) {
        const err = error as NodeJS.ErrnoException;
    
        if (err.code === 'ENOENT') {
          return {
            isError: true,
            content: [
              {
                type: 'text',
                text: JSON.stringify({
                  code: 'FILE_NOT_FOUND',
                  message: `Path not found: ${input.path}`,
                }),
              },
            ],
          };
        }
    
        return {
          isError: true,
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                code: 'UNKNOWN_ERROR',
                message: `Error in grep search: ${err.message}`,
              }),
            },
          ],
        };
      }
    }
  • Registration of the grep_search tool in the MCP server.
    // grep_search tool
    server.tool(
      'grep_search',
      'Search file contents with regex',
      {
        pattern: z.string().describe('Regex pattern to search for'),
        path: z.string().optional().describe('File or directory to search'),
        glob: z.string().optional().describe('File pattern filter (e.g., *.ts)'),
        case_sensitive: z.boolean().optional().describe('Case sensitive search'),
        max_results: z.number().optional().describe('Maximum results (default: 100)'),
        context_lines: z.number().optional().describe('Lines of context around matches'),
      },
      async (args) => {
        const input = GrepSearchInputSchema.parse(args);
        return await grepSearchImpl(input);
      }
    );

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/mcp-tool-shop-org/mcp-file-forge'

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