search
Locate code symbols by name, signature, or natural-language meaning across an indexed repository, returning ranked records with kind, signature, and line ranges instead of raw grep matches.
Instructions
Hybrid structural + semantic code search across the indexed codebase. Fuses FST exact + BM25 + semantic channels in a single ranked list (~4ms FST hit, ~7-15ms with semantic). Prefer over grep for symbol or identifier lookup — grep does a full-scan (seconds on large repos) and returns line matches; this returns ranked symbol records with kind, signature, and line ranges. Use this when you need to find a definition by name, signature shape, or meaning rather than guessing a regex. Supports filter (substring path filter), kind (kind-boost / restrict), context_path (proximity hint), no_bm25 (disable BM25 channel), and no_stale_check (skip pre-call staleness probe).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| why | No | Surface a JSON trace under `_meta.why` in the response: normalized query, per-channel hits (FST/BM25/semantic/fuzzy), filter_applied snapshot | |
| kind | No | Boost results matching one or more kinds (repeatable). Canonical names (function, struct, class, …) plus aliases: def, comment, test, ref. | |
| limit | No | Max results | |
| query | Yes | Free-text query: symbol name, partial name, signature snippet, or natural-language description. Not for regex (use grep) or exact-only resolution (use find_symbol). | |
| since | No | Restrict results to files changed between `<rev>..HEAD` (accepts anything `git diff` understands: `main`, `HEAD~3`, `origin/main`, SHA). Mutually exclusive with `since_branched` and `changed_only`. | |
| exclude | No | Blacklist results by path glob (wins over include); repeat for multiple globs | |
| include | No | Whitelist results by path glob, gitignore syntax (e.g. 'tests/**'); repeat for multiple globs | |
| no_bm25 | No | Disable the BM25 channel for this query (auto-on when the index has BM25 data otherwise). | |
| no_async | No | Exclude async/suspend functions | |
| semantic | No | Enable the semantic vector channel (requires `vex index --semantic`); adds ~3-10ms but lets natural-language queries hit | |
| code_only | No | (v1.20.0 D4) Drop results in prose-format files (`*.md`/`*.markdown`/`*.txt`/`*.rst`/`*.adoc`). Default off so 'README' still finds the README; pass for code-intent queries where CHANGELOG/README headings would pollute the top of the result list. | |
| workspace | No | Multi-repo: fan out across every repo declared in the nearest `.vex-workspace.toml` (set `project_root` at or above it — the manifest is found by walking up). Results become an object `{workspace, repos:[...]}` grouped by repo, NOT the flat per-tool array — branch on shape. `why` is ignored in workspace mode (single-repo only). | |
| async_only | No | Keep only async/suspend functions | |
| visibility | No | Keep only symbols whose signature contains this explicit visibility keyword (no inferred defaults) | |
| auto_update | No | Auto-update the index if stale, or bootstrap it if missing, before running (default: true) | |
| filter_path | No | Substring path filter applied to result paths (single substring; use include/exclude for glob patterns). Legacy alias: `filter`. | |
| sealed_only | No | Keep only sealed (or Java-`final`) types | |
| static_only | No | Keep only static class members | |
| async_update | No | With auto_update, refresh a stale index in the background instead of waiting for it: results come from the index already on disk and _meta.vex.dev/stale says so (default: false) | |
| changed_only | No | Restrict results to working-tree changes (staged + unstaged + untracked). Mutually exclusive with `since` and `since_branched`. | |
| context_path | No | Boost results near this file path (e.g. the agent's current editor file). | |
| project_root | No | Absolute path to the project root (defaults to the MCP working directory) | |
| exclude_tests | No | Drop test files from the results (tests/ dirs, *_test.*, test_*.py, *.spec.ts, __tests__/, tests.rs, ...; same set as tests_for). Composes with include/exclude. Path-based only: Rust unit tests inside a `#[cfg(test)] mod tests` block of a non-test file are not excluded. | |
| no_stale_check | No | Skip the staleness check that runs before each call; assumes the index is fresh. Redundant when `auto_update` is true (which already refreshes). | |
| since_branched | No | Restrict results to files changed since this branch diverged from `origin/main` (or `main`/`master`). Mutually exclusive with `since` and `changed_only`. | |
| exclude_generated | No | Drop machine-generated files (protobuf stubs, sqlc output, bindgen bindings, ORM schemas) from the results, recognised from the generator's header banner. Pass on repos that check in generated code, where the stubs outnumber and outrank hand-written symbols. Heuristic: a generator that writes no banner is not detected, so it under-reports rather than hiding hand-written code. |