Symforge
Rust native MCP server intended for speed of execution and token saving. Especially for large codebases and very large code files.
Ask AI about Symforge
Powered by Claude Β· Grounded in docs
I know everything about Symforge. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation

A code-native MCP server that gives AI coding agents structured, symbol-aware navigation across your codebase. Built in Rust with tree-sitter, it replaces raw file scanning with tools that understand code as symbols, references, dependency graphs, and git history through a single MCP connection.
Works with MCP-compatible clients including Claude Code, Claude Desktop, Codex, Gemini CLI, VS Code MCP, Kilo Code, Roo Code, Cline, Continue, JetBrains plugins, and custom agents.
[!IMPORTANT] Rust-native Β· 31 tools Β· 19 source languages Β· 5 config formats Β· 6 prompts Β· Built-in resources
Use SymForge first for source-code reads, search, repo orientation, symbol tracing, and structural edits. Use raw file reads for docs and config when exact wording is the point. Use shell tools for builds, tests, package managers, Docker, and general system tasks.
What's new in v7.5
- Frecency ranking for
search_filesβ opt-inrank_by="frecency"fuses a per-workspace frecency signal (7-day half-life) with the existing path-match and co-change signals. Commitment tools bump the signal (edit tools plus reads that imply active work on a file); discovery tools never bump. RequiresSYMFORGE_FRECENCY=1. See ADR 0011. - Weighted-sum ranker β
search_filesnow composes rank signals through a weightedRankSignalregistry, so new signals (frecency, coupling, β¦) plug in without amending handlers. See ADR 0012. - Daemon-fallback hooks β when the sidecar port file is missing, PreToolUse/PostToolUse hooks now try the shared
symforge daemonfor an active session before failing open. Silent-degrade when both are unavailable. - Hook-adoption metrics in
healthβhealthreports per-workflow routing rates (owned workflows routed, daemon-fallback routed, no-sidecar outcomes split by workflow) so you can see at a glance whether hooks are actually reaching the index. - Co-change coupling store (diagnostic) β a per-workspace SQLite-backed coupling graph ships with
SYMFORGE_COUPLING=1. Its strongest pair surfaces inhealthunder "Strongest coupling". Ranker fusion is deferred to a later phase (see ADR 0013); until then, coupling signals insearch_filesare available only viachanged_with=path. SYMFORGE_HOMEoverride honored end-to-end β the npm launcher, install script, and binary now agree onSYMFORGE_HOMEso CI runs and sandboxed installs can point the whole install tree at a scratch directory without patching code.
v7.4 highlights
- ast-grep structural search β
search_textnow supportsstructural=truefor AST-pattern matching. Use$VARfor single-node metavariables and$$$for multi-node wildcards (e.g.,fn $NAME($$$) { $$$ }). Powered by ast-grep-core with full tree-sitter integration across all 19 languages. - Adaptive detail levels β Tools with
max_tokensauto-cascade verbosity from full to compact to signature to summary to stay within budget. No more truncated output β responses degrade gracefully. - Lock-free concurrent reads β Replaced
RwLockwithArcSwapfor the shared index handle. Zero reader contention under concurrent tool calls. - Per-result confidence scores β Search and navigation tools now report confidence (high/medium/low) on each result based on match quality, caller count, and churn.
- Token budget enforcement β 11 search/navigation tools accept
max_tokensand truncate at line boundaries when exceeded. - MCP tool annotations β All tools now declare
readOnlyHintandopenWorldHintper the MCP spec, enabling smarter client-side tool selection. - Claude Desktop support β
symforge init --client claude-desktopregisters the MCP server in Claude Desktop's config. On Windows, generates a.cmdwrapper to avoid the System32 CWD issue. - Smarter PreToolUse hooks β When the SymForge sidecar is already running, tool-preference hints are suppressed to reduce noise for agents that are actively using SymForge.
- Release profile optimization (v7.4.2) β LTO, single codegen unit, and symbol stripping reduce the release binary by ~3%. Cross-crate inlining across 330 packages improves runtime performance.
- Aho-Corasick multi-term search (v7.4.2) β Multi-term OR searches in
search_textnow use a single-pass Aho-Corasick automaton instead of sequential substring matching, eliminating per-line allocations for case-insensitive queries.
When to use SymForge
Use SymForge when an agent needs to:
- understand a repo without reading large files blindly
- find symbols, call sites, dependencies, and changed code
- search code by AST structure instead of text patterns
- edit code structurally by symbol instead of by raw text
- reindex and inspect impact after edits
Do not expect SymForge to replace normal shell workflows for process execution, runtime debugging, package management, or OS-level tasks.
Install
Prerequisite: Node.js 18+
Prebuilt binaries: Windows x64, Linux x64, macOS arm64, macOS x64
npm install -g symforge
This installs the npm wrapper and downloads the platform binary to ~/.symforge/bin/symforge (or symforge.exe on Windows). Set SYMFORGE_HOME to override the default home directory.
Auto-configured clients
During global install, SymForge auto-configures these home-scoped clients if their home directories already exist:
- Claude Code
- Claude Desktop
- Codex
- Gemini CLI
Kilo Code is workspace-local:
symforge init --client kilo-code
Run that from the target project directory. It writes .kilocode/mcp.json, .kilocode/rules/symforge.md, and .symforge/ in that workspace.
Re-run setup manually
symforge init
symforge init --client claude
symforge init --client claude-desktop
symforge init --client codex
symforge init --client gemini
symforge init --client kilo-code
symforge init --client all
After setup, confirm in your client that the SymForge MCP server is connected or ready.
Tool reference
Orientation and context
| Tool | Purpose |
|---|---|
health | Index status, file/symbol counts, watcher state, parse diagnostics, hook-adoption metrics, git temporal status with hotspots and strongest coupling, worktree-awareness misuse |
get_repo_map | Structured overview of the entire repository (auto-adapts detail to token budget) |
explore | Concept-driven exploration with stemmed matching and convention enrichment |
ask | Natural language questions routed to the right tool internally |
conventions | Auto-detect project coding patterns |
context_inventory | See what symbols and files you've already fetched this session |
investigation_suggest | Find gaps in your loaded context |
Reading code
| Tool | Purpose |
|---|---|
get_file_context | File outline, imports, consumers β call before reading a source file |
get_file_content | Exact raw text with optional line ranges β for docs, config, or when you need the literal source |
get_symbol | Full source of a function, struct, class, etc. by name (batch mode supported) |
get_symbol_context | Symbol body + callers + callees + type dependencies (supports bundle mode for edit prep) |
Searching
| Tool | Purpose |
|---|---|
search_symbols | Find symbols by name, kind, language, path prefix |
search_text | Full-text search with enclosing symbol context. Supports literal, OR-terms, regex, and structural AST patterns (structural=true) |
search_files | File path discovery β three modes: default fuzzy ranking, changed_with=path for git-temporal co-change coupling, resolve=true for exact path resolution. Opt-in rank_by="frecency" with SYMFORGE_FRECENCY=1 |
Tracing impact
| Tool | Purpose |
|---|---|
find_references | Call sites, imports, type usages, implementations |
find_dependents | File-level dependency graph |
get_symbol_context (with sections=[...]) | Multi-hop caller/callee chains for a symbol β consolidated from the former trace_symbol tool; the old name remains as a daemon-side alias for one release cycle |
what_changed | Files changed since a timestamp, ref, or uncommitted |
diff_symbols | Symbol-level diff between git refs (AST-based for supported languages) |
analyze_file_impact | Re-index a file after editing and report affected dependents |
inspect_match | Deep-dive a search match with full symbol context |
Editing code
| Tool | Purpose |
|---|---|
edit_plan | Analyze impact and suggest the right edit tool sequence |
replace_symbol_body | Replace a symbol's entire definition by name |
edit_within_symbol | Scoped find-and-replace within a symbol's range |
insert_symbol | Insert code before or after a named symbol |
delete_symbol | Remove a symbol and its doc comments by name |
batch_edit | Multiple symbol-addressed edits atomically across files |
batch_insert | Insert code before/after multiple symbols across files |
batch_rename | Rename a symbol and update all references project-wide |
Worktree awareness
All seven edit tools accept an optional working_directory parameter pointing at a sibling git worktree of the indexed repo. With SYMFORGE_WORKTREE_AWARE=1 set, SymForge re-roots the symbol's indexed path onto the supplied worktree before writing β so an agent running inside ../my-feature-worktree can call an edit tool without silently writing to the indexed copy. Reads still come from the indexed path; only writes reroute. Responses include wrote_to, indexed_path, and rerouted so callers can verify the target. Omit the parameter (or leave the flag unset) for byte-identical pre-flag behavior. See ADR 0010.
{
"path": "src/lib.rs",
"name": "hello",
"find": "println!(\"hi\")",
"replace": "println!(\"hi, world\")",
"working_directory": "/abs/path/to/sibling/worktree"
}
Frecency ranking
search_files accepts an optional rank_by="frecency" parameter that fuses a per-workspace frecency signal with the existing path-match and co-change signals. Frecency decays on a 7-day half-life, so a file you touched five minutes ago outranks one you hit ten times six months ago. Feature-gated on SYMFORGE_FRECENCY=1; when the flag is unset or rank_by is omitted, ranking is byte-identical to pre-flag releases. See ADR 0011.
{
"query": "cache",
"rank_by": "frecency"
}
Frecency scores bump on commitment tools β every edit tool plus the read tools that imply you're working on a known file (get_file_context, get_file_content, get_symbol, get_symbol_context). Discovery tools (search_files, search_text, search_symbols) deliberately never bump: searching for a file is not the same as working on it, and a searching-bumps-too policy corrupts rankings via a positive feedback loop. Batch tools dedup bumps per invocation, so editing 20 symbols in one batch_edit call bumps each touched path exactly once. Set SYMFORGE_DEBUG_RANKING=1 to surface per-signal scores in search_files responses and a last-10 bumps list in health.
Validation and indexing
| Tool | Purpose |
|---|---|
validate_file_syntax | Parse diagnostics with line/column location for code and config files |
index_folder | Full reindex of a directory |
Structural search examples
With structural=true, the search_text tool uses ast-grep pattern syntax to match code by AST structure rather than text:
# Find all functions in Rust
search_text(query="fn $NAME($$$) { $$$ }", structural=true, language="Rust")
# Find all React useState hooks
search_text(query="const [$STATE, $SETTER] = useState($$$)", structural=true, language="TypeScript")
# Find all try-catch blocks in Java
search_text(query="try { $$$ } catch ($E) { $$$ }", structural=true, language="Java")
Metavariable syntax: $NAME matches a single AST node, $$$ matches zero or more nodes. Captures are shown in results.
Practical defaults
- Call
get_file_contextbefore reading a source file - Use
search_textorsearch_symbolsbefore broad grep or raw file scans - Use
structural=truewhen you need pattern matching that respects code structure (ignores comments, whitespace, formatting) - Use
get_file_contentwhen exact docs/config text matters - Run
analyze_file_impactafter small edits;index_folderafter larger multi-file work edit_planaccepts a bare symbol, a file path, orpath::symbolbatch_editandbatch_insertaccept shorthand strings likesrc/lib.rs::helper => delete- Use
max_tokenson any search/navigation tool to control response size β output adapts verbosity automatically
Agent setup prompt
If your AI agent still falls back to built-in file reads, grep, or text-based edits after SymForge is installed, give it the setup prompt from the wiki:
This prompt detects installed clients, configures SymForge for each, updates instruction files, and validates the setup.
Architecture
SymForge is organized around a tree-sitter index, a set of query layers over that index, and the MCP tool surface. For the full runtime and module map, see Architecture and How It Works in the wiki.
Extension points
Two trait-based registries let feature code plug into the shared edit and ranker paths without amending the handlers themselves.
EditHook wraps the per-edit lifecycle for the seven edit tools (replace_symbol_body, edit_within_symbol, insert_symbol, delete_symbol, batch_edit, batch_insert, batch_rename). Implementations register at startup; the handlers delegate to the registry to resolve the target path before writing and to run bookkeeping after the edit commits. For example, a worktree-aware feature registers a hook that rewrites a symbol's indexed path onto the active worktree before the write lands.
Each of the seven edit tools accepts an optional working_directory parameter pointing at a git worktree sibling of the indexed repo. When supplied, SymForge reroutes the write into that worktree and includes rerouted: true, wrote_to:, and indexed_path: lines in the response so callers can verify the target. Set SYMFORGE_WORKTREE_AWARE=1 to enable this routing. Example:
{
"path": "src/lib.rs",
"name": "hello",
"new_body": "fn hello() { println!(\"hi\"); }",
"working_directory": "/abs/path/to/sibling/worktree"
}
RankSignal wraps search_files scoring contributions. Each signal carries a name, a weight, and a score() function, and the ranker combines registered signals into a weighted sum. The current path-match and co-change signals ship as default registrations; additional signals β frecency, for example β register at startup and join the fusion without touching the handler or the other signals.
See ADR 0012 for the rationale and the feature plug-in pattern.
Operational notes
symforge daemonis optional if you want a shared index across multiple terminal sessions.- Index snapshots persist at
.symforge/index.binfor fast restarts. - Use
validate_file_syntaxwhen a config file may be malformed β it reports tree-sitter parse diagnostics with line and column locations. - PreToolUse hooks auto-suppress when the sidecar is active β no redundant "use SymForge" hints when you're already using it.
Environment variables
| Variable | Default | Effect |
|---|---|---|
SYMFORGE_HOME | ~/.symforge | Home directory for the binary and daemon metadata |
SYMFORGE_AUTO_INDEX | true | Enables project discovery and startup indexing |
SYMFORGE_HOOK_VERBOSE | unset | Set to 1 for stderr hook diagnostics |
SYMFORGE_CB_THRESHOLD | 0.20 | Parse-failure circuit-breaker threshold |
SYMFORGE_RECONCILE_INTERVAL | 30 | Watcher reconciliation interval in seconds; 0 disables periodic sweeps |
SYMFORGE_SIDECAR_BIND | 127.0.0.1 | Sidecar bind host for local in-process mode |
SYMFORGE_DAEMON_BIND | 127.0.0.1 | Daemon bind host for shared local daemon |
SYMFORGE_FRECENCY | unset | Set to 1 to enable the frecency rank signal in search_files (rank_by="frecency") |
SYMFORGE_DEBUG_RANKING | unset | Set to 1 to surface per-signal scores in search_files responses and a last-10 bumps list in health |
SYMFORGE_COUPLING | unset | Set to 1 to enable the co-change coupling store lifecycle (diagnostic only; ranker fusion pending) |
SYMFORGE_WORKTREE_AWARE | unset | Set to 1 to enable worktree routing on edit tools via the working_directory parameter |
SYMFORGE_INDEXING_THREAD_STACK_BYTES | 4194304 (Windows only) | Override the indexing worker-thread stack size. Minimum 3 MiB on Windows; ignored elsewhere |
For platform-specific setup scripts (PowerShell, CMD, bash, zsh), see the wiki:
Deeper reference
- SymForge Wiki Home
- Architecture and How It Works
- Tool Reference
- Runtime Model
- Supported Languages and Config Formats
- Benchmarks and Token Savings
Build from source
cargo build --release
cargo test --all-targets -- --test-threads=1
The release profile enables LTO and single codegen unit for smaller binaries and better cross-crate optimization. Release builds take longer (~4 min) than dev builds (~15 sec). The Cargo package name is symforge.
License
SymForge is licensed under PolyForm Noncommercial License 1.0.0. The official license text is also available from the PolyForm Project.
You may inspect, study, and use the source code for noncommercial purposes, but commercial use is prohibited unless separately licensed.
