Search Operations
Overview
Section titled “Overview”In v4.0.0, all search functionality is unified into a single search_files tool. It replaces the four separate v3 tools (smart_search, advanced_text_search, mcp_search, count_occurrences) and automatically routes to the optimal search engine based on the parameters you provide.
For search-and-replace operations, use edit_file with mode:"search_replace" — see the Search and Replace section below.
What Was Consolidated
Section titled “What Was Consolidated”| v3 Tool | v4 Equivalent |
|---|---|
smart_search | search_files({ path, pattern }) |
advanced_text_search | search_files({ path, pattern, case_sensitive: true }) |
mcp_search | search_files({ path, pattern }) |
count_occurrences | search_files({ path, pattern, count_only: true }) |
search_and_replace | edit_file({ path, mode: "search_replace", pattern, replacement }) |
Parameters
Section titled “Parameters”| Parameter | Required | Type | Description |
|---|---|---|---|
path | Yes | string | Base directory or file path (WSL or Windows format) |
pattern | Yes | string | Regex or literal search pattern |
include_content | No | boolean | Search inside file contents (default: false — searches file names). Since v4.5.24 it is auto-enabled when path is a regular file or when content-only params are passed. |
include | No | string | Alias for file_types. |
file_types | No | string | Comma-separated file extensions to filter (e.g., .go,.ts,.js) |
case_sensitive | No | boolean | Case-sensitive matching (default: true; v4.5.24 pinned to true per Bug #32) |
whole_word | No | boolean | Match whole words only (default: false) |
include_context | No | boolean | Include surrounding lines around each match (default: false) |
context_lines | No | number | Number of context lines to include (default: 3). Passing this also forces include_content:true (v4.5.24). |
count_only | No | boolean | Return only the count of matches, not the matches themselves (default: false) |
return_lines | No | string/boolean | When count_only is true, also return line numbers of matches ("true" / "false" or bool). Accepts bool since v4.5.3. |
output_format | No | string | "text" (default) or "json" for structured matches. |
output | No | string | Alias for output_format. Passing this also forces include_content:true (v4.5.24). |
Auto-Routing
Section titled “Auto-Routing”The search_files tool automatically selects the best search engine based on the parameters you provide. You do not need to think about which engine to use — just pass the parameters you need.
| Parameters Provided | Engine Selected | Behavior |
|---|---|---|
path + pattern only AND path is a directory | Fast Smart Search (filename-only) | Fastest path for simple file search |
path is a regular file (v4.5.24) | Advanced Text Search (content) | A filename match over a single explicit file is meaningless, so the search auto-routes to content search |
output_format, output, or context_lines is provided (v4.5.24) | Advanced Text Search (content) | These params apply only to content search, so the tool flips include_content on |
case_sensitive, whole_word, or include_context | Advanced Text Search | Full-featured regex search with context |
count_only: true | Occurrence Counter | Returns match counts per file without full results |
v4.5.24 false-negative fix
Section titled “v4.5.24 false-negative fix”Before v4.5.24, callers frequently hit "No matches found" for a true content match because they passed search_files({ path: "X", pattern: "Y" }) without include_content:true, expecting a content search. The filename-only SmartSearch is the default, so the response silently returned zero even when the pattern appeared inside the file.
Three protections now ensure callers see the right thing on the right call:
- File path forces content search —
pathresolving to a single regular file bypasses the filename-only path entirely. - Content-only params imply content intent —
output_format,output, orcontext_linesflipsinclude_contenton automatically (none of them apply to filename-only search). - Honest no-match message — when zero hits come back from a filename-only search, the response now reads:
No filename matches for pattern 'X' in <path> (filename-only search — file contents were NOT searched; pass include_content:true to search inside files)
case_sensitive still defaults to true since v4.5.24 (Bug #32 decision); pass case_sensitive:false explicitly for case-insensitive matches.
Modes and Examples
Section titled “Modes and Examples”Basic Search (File Names)
Section titled “Basic Search (File Names)”Find files matching a pattern by name:
search_files({ path: "C:\\project", pattern: "main.go" })Response:
Found 3 matches: C:\project\main.go C:\project\cmd\main.go C:\project\tests\main.goContent Search
Section titled “Content Search”Search inside file contents by enabling include_content:
search_files({ path: "C:\\project\\src", pattern: "TODO", include_content: true, file_types: ".go,.ts"})Response:
Found 8 matches in 4 files: src/handler.go:23: // TODO: add error handling src/handler.go:45: // TODO: refactor this src/config.ts:12: // TODO: validate inputs ...Advanced Search with Context
Section titled “Advanced Search with Context”When you need case sensitivity, whole word matching, or surrounding context lines, the tool auto-routes to the advanced text search engine:
search_files({ path: ".", pattern: "func.*Error", case_sensitive: true, include_context: true, context_lines: 2})Response:
Found 5 matches in 3 files:
--- core/engine.go:45 --- 43: } 44: 45: func handleError(ctx context.Context, err error) { 46: if err == nil { 47: return
--- core/errors.go:12 --- ...Whole Word Matching
Section titled “Whole Word Matching”Avoid partial matches (e.g., matching count without matching counter or accounting):
search_files({ path: "src/", pattern: "count", whole_word: true, include_content: true})Count Occurrences
Section titled “Count Occurrences”Get a quick count of how many times a pattern appears without retrieving full results:
search_files({ path: "main.go", pattern: "fmt\\.Sprintf", count_only: true})Response:
Count: 12 occurrences in main.goCount with Line Numbers
Section titled “Count with Line Numbers”When you need to know where each occurrence is but do not need context:
search_files({ path: "main.go", pattern: "TODO", count_only: true, return_lines: "true"})Response:
Count: 5 occurrences in main.goLines: 23, 45, 78, 112, 156File Type Filtering
Section titled “File Type Filtering”Restrict search to specific file extensions:
search_files({ path: ".", pattern: "interface\\{\\}", include_content: true, file_types: ".go"})Search and Replace
Section titled “Search and Replace”Search-and-replace across multiple files is handled by edit_file with mode:"search_replace". This was the search_and_replace tool in v3.
Basic Recursive Replace
Section titled “Basic Recursive Replace”edit_file({ path: "src/", mode: "search_replace", pattern: "oldFunctionName", replacement: "newFunctionName"})This recursively searches all files under src/ and replaces every occurrence of oldFunctionName with newFunctionName.
Recommended Workflow: Search First, Then Replace
Section titled “Recommended Workflow: Search First, Then Replace”For safety, search before replacing to understand the scope:
// Step 1: Count how many files and occurrences are affectedsearch_files({ path: "src/", pattern: "oldFunctionName", include_content: true, count_only: true})
// Step 2: Preview the edit riskanalyze_operation({ operation: "edit", path: "src/specific-file.go", old_text: "oldFunctionName", new_text: "newFunctionName"})
// Step 3: Apply the replacementedit_file({ path: "src/", mode: "search_replace", pattern: "oldFunctionName", replacement: "newFunctionName"})Regex-Based Replace
Section titled “Regex-Based Replace”For advanced pattern-based transformations with capture groups, use edit_file with mode:"regex":
edit_file({ path: "handler.go", mode: "regex", patterns_json: JSON.stringify([ { pattern: "fmt\\.Errorf\\(\"(\\w+): %v\", err\\)", replacement: "fmt.Errorf(\"$1: %w\", err)", limit: -1 } ]), dry_run: true})See the Core Tools API Reference for complete edit_file parameter documentation.
Ripgrep Backend (v4.4.0+)
Section titled “Ripgrep Backend (v4.4.0+)”When ripgrep (rg) is available on PATH or embedded in the binary, search_files with output_format:"json" uses ripgrep for 10-100x faster search on large codebases.
Detection Priority
Section titled “Detection Priority”rgin PATH — System-installed ripgrep- Embedded binary — Built with
embed_rgtag (extracts to temp on first use) - Go-native fallback — Pure Go regex, no external dependency
Build with Embedded Ripgrep
Section titled “Build with Embedded Ripgrep”go build -ldflags="-s -w" -trimpath -tags embed_rg -o filesystem-ultra-v4-embed.exe .This adds ~4MB to the binary but means ripgrep works even without a system installation.
Performance Comparison
Section titled “Performance Comparison”| Codebase Size | Go-native | Ripgrep | Speedup |
|---|---|---|---|
| ~100 files | slower | faster | several x |
| ~1,000 files | slower | faster | order of magnitude |
| ~10,000 files | much slower | faster | 10–40x (depends on pattern & skip-dirs) |
// Use ripgrep when available (automatically selected for JSON output)search_files({ path: ".", pattern: "func.*Error", output_format: "json"})Ripgrep is automatically used when:
rgis available on PATH or embedded in the binaryoutput_format:"json"is specified
Performance Considerations
Section titled “Performance Considerations”Token Efficiency
Section titled “Token Efficiency”Searching before reading is the most token-efficient workflow. Instead of reading an entire 3000-line file, search for the specific section first and read only the lines you need:
// Step 1: Find the locationsearch_files({ path: "large-file.go", pattern: "targetFunction", include_content: true })
// Step 2: Read only the relevant linesread_file({ path: "large-file.go", start_line: 145, end_line: 160 })
// Step 3: Apply the editedit_file({ path: "large-file.go", old_text: "old code", new_text: "new code" })The total is much smaller than a full read-modify-write cycle because only the matched section travels over the wire.
Caching
Section titled “Caching”Search results benefit from the 3-tier caching system. Directory listings and file metadata are cached, so repeated searches in the same directory are faster. The exact cache hit rate depends on how repetitive your workload is.
Result Limits
Section titled “Result Limits”By default, search returns up to 1,000 results. This can be configured with --max-search-results at server startup. For very large codebases, combine file_types filtering with specific path scoping to keep results manageable.
Pipeline Integration
Section titled “Pipeline Integration”For multi-step workflows involving search, use the pipeline system via batch_operations with pipeline_json. The pipeline search action feeds its results directly into subsequent steps:
batch_operations({ pipeline_json: JSON.stringify({ name: "find-and-fix-todos", stop_on_error: true, create_backup: true, steps: [ { id: "find", action: "search", params: { path: "./src", pattern: "TODO", file_types: [".go"] } }, { id: "count", action: "count_occurrences", input_from: "find", params: { pattern: "TODO" } }, { id: "fix", action: "edit", input_from: "find", condition: { type: "count_gt", step_ref: "count", value: "0" }, params: { old_text: "TODO", new_text: "DONE" } } ] })})This executes all three steps in a single MCP call, reducing token overhead by 4-5x compared to individual calls. See Pipeline Transformation System for details.
See Also
Section titled “See Also”- Core Tools API Reference — Complete
search_filesandedit_fileparameters - Tool Selection Guide — Which tool for your task
- Migration from v3 — Upgrading from separate search tools
- Performance and Tokens — Token optimization strategies
- Pipeline System — Multi-step search workflows
Last updated: 2026-07-11 Version: 4.5.29