search_files
Search within files using a regex pattern to identify matching lines, displaying file paths and line numbers.
Instructions
Search for a regex pattern inside files. Returns matching lines with file and line number.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| directory | Yes | Directory to search in | |
| pattern | Yes | Regex pattern to search for | |
| file_glob | No | Glob to filter files (e.g. '*.ts') | |
| ignore_case | No | Case-insensitive search | |
| max_results | No | Max results to return (default 100) | |
| workspace_root | No | Workspace root directory (optional) |
Implementation Reference
- src/index.ts:86-128 (handler)The core searchInFiles function that recursively walks a directory, reads files, and matches lines against a regex pattern. Returns matching file, line number, and content.
async function searchInFiles( dir: string, pattern: string, options: { glob?: string; ignoreCase?: boolean; maxResults?: number } ): Promise<Array<{ file: string; line: number; content: string }>> { const results: Array<{ file: string; line: number; content: string }> = []; const max = options.maxResults ?? 100; const regex = new RegExp(pattern, options.ignoreCase ? "i" : ""); async function walk(current: string) { if (results.length >= max) return; let entries; try { entries = await readdir(current, { withFileTypes: true }); } catch { return; } for (const entry of entries) { if (results.length >= max) return; if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist") continue; const full = join(current, entry.name); if (entry.isDirectory()) { await walk(full); } else if (entry.isFile()) { if (options.glob && !matchGlob(entry.name, options.glob)) continue; try { const content = await readFile(full, "utf-8"); const lines = content.split("\n"); lines.forEach((line, idx) => { if (results.length < max && regex.test(line)) { results.push({ file: full, line: idx + 1, content: line.trim() }); } }); } catch { // skip binary files } } } } await walk(dir); return results; } - src/index.ts:259-271 (schema)Input schema for the 'search_files' tool, defining parameters: directory, pattern, file_glob, ignore_case, max_results, and workspace_root.
{ name: "search_files", description: "Search for a regex pattern inside files. Returns matching lines with file and line number.", inputSchema: { type: "object", properties: { directory: { type: "string", description: "Directory to search in" }, pattern: { type: "string", description: "Regex pattern to search for" }, file_glob: { type: "string", description: "Glob to filter files (e.g. '*.ts')" }, ignore_case: { type: "boolean", description: "Case-insensitive search" }, max_results: { type: "number", description: "Max results to return (default 100)" }, workspace_root: { type: "string", description: "Workspace root directory (optional)" }, }, - src/index.ts:505-519 (handler)The tool handler case for 'search_files' that resolves the workspace path, calls searchInFiles(), and formats the results as text output.
case "search_files": { const dir = resolveWorkspacePath(a.directory as string, a.workspace_root as string | undefined); const results = await searchInFiles(dir, a.pattern as string, { glob: a.file_glob as string | undefined, ignoreCase: (a.ignore_case as boolean | undefined) ?? false, maxResults: (a.max_results as number | undefined) ?? 100, }); if (results.length === 0) { return { content: [{ type: "text", text: "No matches found." }] }; } const text = results .map((r) => `${r.file}:${r.line}: ${r.content}`) .join("\n"); return { content: [{ type: "text", text: text }] }; } - src/index.ts:59-63 (helper)Helper function resolveWorkspacePath used by the handler to resolve relative paths against a workspace root or current working directory.
function resolveWorkspacePath(filePath: string, workspaceRoot?: string): string { if (filePath.startsWith("/") || /^[A-Za-z]:/.test(filePath)) return filePath; const base = workspaceRoot ?? process.cwd(); return resolve(join(base, filePath)); } - src/index.ts:130-133 (helper)Helper function matchGlob used by searchInFiles to filter filenames against a glob pattern (e.g. '*.ts') by converting glob to regex.
function matchGlob(name: string, pattern: string): boolean { const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, "."); return new RegExp(`^${escaped}$`).test(name); }