Skip to main content
Glama

count-matches

Count occurrences of a specific pattern in files or directories using ripgrep, with options for case sensitivity, file filtering, line-based counting, and colored output.

Instructions

Count matches in files using ripgrep

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
caseSensitiveNoUse case sensitive search (default: auto)
countLinesNoCount matching lines instead of total matches
filePatternNoFilter by file type or glob
pathYesDirectory or file(s) to search.
patternYesThe search pattern (regex by default)
useColorsNoUse colors in output (default: false)

Implementation Reference

  • The handler for the 'count-matches' tool. Parses input arguments, constructs a ripgrep command with appropriate flags for counting matches (either lines with -c or total matches with --count-matches), executes it via the exec helper, processes the output, and returns the result.
    case "count-matches": { const pattern = String(args.pattern || ""); const path = String(args.path); const caseSensitive = typeof args.caseSensitive === 'boolean' ? args.caseSensitive : undefined; const filePattern = args.filePattern ? String(args.filePattern) : undefined; const countLines = typeof args.countLines === 'boolean' ? args.countLines : true; const useColors = typeof args.useColors === 'boolean' ? args.useColors : false; if (!pattern) { return { isError: true, content: [{ type: "text", text: "Error: Pattern is required" }] }; } // Build the rg command with flags let command = "rg"; // Add case sensitivity flag if specified if (caseSensitive === true) { command += " -s"; // Case sensitive } else if (caseSensitive === false) { command += " -i"; // Case insensitive } // Add file pattern if specified if (filePattern) { command += ` -g ${escapeShellArg(filePattern)}`; } // Add count flag if (countLines) { command += " -c"; // Count lines } else { command += " --count-matches"; // Count total matches } // Add color setting command += useColors ? " --color always" : " --color never"; // Add pattern and path command += ` ${escapeShellArg(pattern)} ${escapeShellArg(path)}`; console.error(`Executing: ${command}`); const { stdout, stderr } = await exec(command); // If there's anything in stderr, log it for debugging if (stderr) { console.error(`ripgrep stderr: ${stderr}`); } return { content: [ { type: "text", text: processOutput(stdout, useColors) || "No matches found" } ] }; }
  • Input schema defining parameters for the 'count-matches' tool, including pattern, path, case sensitivity, file filtering, count type, and color options.
    inputSchema: { type: "object", properties: { pattern: { type: "string", description: "The search pattern (regex by default)" }, path: { type: "string", description: "Directory or file(s) to search." }, caseSensitive: { type: "boolean", description: "Use case sensitive search (default: auto)" }, filePattern: { type: "string", description: "Filter by file type or glob" }, countLines: { type: "boolean", description: "Count matching lines instead of total matches" }, useColors: { type: "boolean", description: "Use colors in output (default: false)" } }, required: ["pattern", "path"]
  • src/index.ts:139-154 (registration)
    Tool registration in the ListTools response, specifying name, description, and input schema for 'count-matches'.
    { name: "count-matches", description: "Count matches in files using ripgrep", inputSchema: { type: "object", properties: { pattern: { type: "string", description: "The search pattern (regex by default)" }, path: { type: "string", description: "Directory or file(s) to search." }, caseSensitive: { type: "boolean", description: "Use case sensitive search (default: auto)" }, filePattern: { type: "string", description: "Filter by file type or glob" }, countLines: { type: "boolean", description: "Count matching lines instead of total matches" }, useColors: { type: "boolean", description: "Use colors in output (default: false)" } }, required: ["pattern", "path"] } },
  • src/index.ts:185-188 (registration)
    Checks if the requested tool name is 'count-matches' (among others) before handling the CallToolRequest in the switch statement.
    if (!["search", "advanced-search", "count-matches", "list-files", "list-file-types"].includes(toolName)) { // Return ServerResult.NEXT to allow the next handler to process the request return Object.create(null); }
  • Helper function to execute shell commands (ripgrep) safely with spawn, capturing stdout/stderr, handling exit codes appropriately for ripgrep.
    function exec(command: string): Promise<{ stdout: string; stderr: string }> { return new Promise((resolve, reject) => { const parts = command.split(" "); const program = parts[0]; const args = parts.slice(1).filter(arg => arg.length > 0); // Use spawn with explicit stdio control const child = spawn(program, args, { shell: true, // Use shell to handle quotes and escaping }); let stdout = ""; let stderr = ""; child.stdout.setEncoding("utf8"); child.stderr.setEncoding("utf8"); child.stdout.on("data", (data) => { stdout += data; }); child.stderr.on("data", (data) => { stderr += data; }); child.on("close", (code) => { if (code === 0 || code === 1) { // Code 1 is "no matches" for ripgrep resolve({ stdout, stderr }); } else { const error = new Error(`Command failed with exit code ${code}`); Object.assign(error, { code, stdout, stderr }); reject(error); } }); // Handle process errors child.on("error", (error) => { reject(error); }); }); }

Other Tools

Related Tools

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/mcollina/mcp-ripgrep'

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