Symbra
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@SymbraWhich functions call sendRequest and are affected by my current diff?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Symbra
Local-first, live code intelligence for AI coding agents.
Symbra weaves a repository into a symbol graph — every function, class, method, route, test and config key with its exact range, signature, doc comment, callers, callees, imports and inheritance — stores it in SQLite, keeps it fresh as you edit, and serves it to Claude Code, Cursor, Codex, Windsurf, VS Code and Gemini over MCP. One tool call replaces a grep-and-read loop.
Zero LLM, zero cloud, zero native compilation. Parsing is tree-sitter compiled to WebAssembly; storage is Node's built-in SQLite. Nothing leaves your machine.
Live, not static. The index is a database, not a JSON dump. Changed files re-index in milliseconds; the MCP server refreshes itself on every call and flags stale symbols.
Symbols, not strings. Calls resolve through lexical scope, real module resolution (tsconfig paths, Python packages, re-exports), declared receiver types and inheritance. Ambiguous references are kept as candidate sets instead of being guessed.
Answers in one call.
explore("how does connection pooling work")returns the ranked symbols with source, relations and the paths between them, packed under a token budget.Blast radius from your diff.
impactwith no arguments readsgit diff, walks reverse dependencies and lists the tests to run.
npx symbra index # build the index for the current repo (seconds)
npx symbra install # register the MCP server with Claude Code (+ Cursor, Codex, ... via --tool)
npx symbra explore "where are timeouts configured"Why another code graph
Graphify popularised the idea of a knowledge graph for AI assistants, and its 114K stars show the demand. Symbra was built after reading graphify end to end (see docs/graphify-teardown.md) to fix what makes agents ignore such graphs in practice:
Graphify 0.9.53 | Symbra | |
Node data | label, file, start line | kind, start/end line, byte range, signature, doc, modifiers, exported, declared type |
Call resolution | corpus-wide name table with a hand-written builtin blocklist | scope → imports → receiver type → unique global; unresolved kept as candidates |
Parallel edges | collapsed to one relation per pair | every call site is an edge with line and resolver provenance |
Query | substring match over labels, fixed-depth BFS, advisory token budget | BM25 over names/split identifiers/signatures/docs + personalised PageRank, packed by relevance under a real budget, with source |
Storage | pretty-printed JSON, 512 MiB cap, parsed whole on every read | SQLite with FTS5, incremental per-file upsert |
Freshness | full re-extract on every watch event | only changed files and their dependents |
Agent integration | 700 KB of duplicated skill prompts, MCP server not registered at install | MCP server registered at install, 9 tools, short marker-fenced guidance |
Visualisation | vis-network from a CDN, breaks above 5,000 nodes | self-contained offline map with search, filters, a details drawer and light/dark themes, semantic zoom from subsystems to symbols |
Install | Python, |
|
Measured on the same machine (Apple M-series, 8 cores):
Repository | graphify extract | Symbra index | Notes |
httpx (17.7K LOC Python) | 6.3 s | 0.6 s | Symbra resolves |
express (21.5K LOC JS) | 1.4 s | 0.7 s | graphify extracted 3 symbols from |
graphify itself (764 files, 153K lines Python plus fixtures in 18 other languages) | 21.8 s | 8.0 s (4.5 s for the Python alone) | 11,059 symbols, 22,758 edges |
Django (2,375 files, about 1M lines) | not measured | 20 s | 59,850 symbols, 135,881 edges, 750 MB peak memory (best of four |
Retrieval quality is measured, not asserted. npm run bench runs 132 hand-written questions over 11
indexed repositories (httpx, express, gin, gson, moshi, MediatR, Slim, sinatra, bytes, fmt,
Alamofire — Python, JS, Go, Java, Kotlin, C#, PHP, Ruby, Rust, C++, Swift) across five question
kinds, with the gold answer recorded as a symbol fqn:
Retrieval | recall@1 | recall@5 | found | MRR |
lexical only (BM25 + PageRank) | 43.9 | 61.4 | 74.2 | 0.514 |
+ semantic tier ( | 47.7 | 72.0 | 81.8 | 0.573 |
The graph questions (callers, impact, search) already find the gold symbol in 100% of cases;
the movement is in free-form explore questions, where recall@5 goes from 30.9 to 51.5. Full
harness, questions and per-repo results are in bench/.
Related MCP server: OpenCodeHub MCP Server
Install
Requires Node 22.5 or newer (for built-in SQLite). The launcher runs Node with --liftoff-only because V8's optimizing wasm compiler runs out of memory on the largest grammars; parsing speed is unaffected.
npm install -g symbra # or use npx symbra ... without installing
cd your-repo
symbra index
symbra install --tool claude,cursor # claude | cursor | codex | windsurf | vscode | gemini | arcturn | allinstall writes the MCP server entry (.mcp.json, .cursor/mcp.json, ~/.codex/config.toml, .arcturn/mcp.json, …), a short guidance section in CLAUDE.md / AGENTS.md / GEMINI.md / ARCTURN.md between <!-- symbra:start --> markers, and adds .symbra/ to .gitignore. Add --hooks for a once-per-session Claude Code hint when the agent reaches for grep; it never blocks a tool call (Arcturn's hook protocol has no channel for a hint, so --hooks is a no-op there — its guidance comes from ARCTURN.md alone). Use --command "<cmd>" to register a different server command (e.g. a local checkout) instead of the default npx -y symbra.
Arcturn
symbra index
symbra install --tool arcturn
arcturn trust --allowsymbra install --tool arcturn writes .arcturn/mcp.json and also merges nine allow rules (one per read-only tool: explore, search, symbol, callers, callees, path, impact, overview, status) into .arcturn/config.json, since Arcturn's project MCP tools are permission-gated — a non-interactive run denies them without an explicit rule. The merge is additive and idempotent: it only appends rules that are missing and never touches unrelated config or permissions. Running install again does not duplicate rules. Arcturn also requires arcturn trust --allow once per repo before it will start project MCP servers at all. The Arcturn VS Code extension reads the same .arcturn/ configuration, so no separate setup is needed there.
For a local checkout of symbra (instead of the published npm package), point the server entry at your build directly:
symbra install --tool arcturn --command "node /path/to/symbra/bin/symbra.js"The npm package ships wasm grammars for 21 core languages (Python, JS/TS/TSX, Go, Rust, Java, C#, C, C++, Ruby, PHP, Kotlin, Swift, Scala, Bash, JSON, YAML, TOML, CSS, HTML — plus Markdown, which needs no grammar at all). Everything else (Dart, Elixir, Lua, Zig, HCL/Terraform, Objective-C, Groovy, PowerShell, Haskell, OCaml, F#, Julia, Solidity, Svelte, Make, Vue) is fetched from npm on first use and cached under ~/.cache/symbra/grammars, verified against the registry's published sha512 before it's trusted — still zero native compilation, just a one-time download for the long tail. Prefetch before going offline with symbra grammars --all (or name specific languages, e.g. symbra grammars dart lua); symbra grammars --list shows what's shipped, cached, or missing. SYMBRA_OFFLINE=1 (or a network failure) makes indexing skip files in a not-yet-fetched language with a one-line warning instead of failing the run; SYMBRA_GRAMMARS=<dir> points at a directory of your own prebuilt grammars.
CLI
symbra index [path] [--full] build or update the index (incremental)
symbra status freshness, counts, resolver statistics
symbra explore "<question>" one-shot context pack (alias: query)
symbra search <terms> ranked symbol search
symbra symbol <name> signature, doc, relations, tests, source (alias: explain)
symbra callers <name> [-d 2] who calls or references it
symbra callees <name> what it calls
symbra path <from> <to> shortest structural path
symbra impact [name] [--base ref] blast radius of a symbol or of the git diff, with tests to run
symbra overview subsystems, hubs, entry points, env vars, import cycles
symbra embed compute local semantic vectors (optional tier)
symbra import-scip <index.scip> upgrade edges with compiler-accurate references
symbra viz [--open] self-contained HTML map at .symbra/map.html, with search, filters and a details drawer
symbra grammars [names…|--all|--list] prefetch or show status of tree-sitter grammars
symbra watch re-index as files change
symbra serve MCP server over stdio (what the agents use)explore understands intent: "who calls X", "what breaks if I change X", "how does X reach Y" and "where is X defined" dispatch to the graph tools; anything else runs hybrid retrieval.
Example, on httpx:
$ symbra path Client HTTPTransport
2 hops
[class] Client httpx/_client.py:594-1304
--> [contains] [method private] Client._init_transport httpx/_client.py:718-738
--> [calls L731] [class] HTTPTransport httpx/_transports/default.py:135-262
$ symbra impact Timeout -d 2
12 dependent symbols in 2 files · 29 tests
depth 1:
[constructor] BaseClient.__init__ httpx/_client.py:189-221 calls Timeout
[method] BaseClient.build_request httpx/_client.py:340-389 calls Timeout
...
tests to run:
tests/client/test_client.py::test_build_request
tests/test_config.py::test_timeout_eqMCP tools
Tool | What it returns |
| ranked symbols with signatures, docs, source bodies and the relations among them; ranked symbols that did not fit the budget are counted, not silently dropped |
| definition, supertypes and subtypes, members, callers, callees, tests, source |
| direct or transitive edges with call-site lines and resolver confidence; a reference the resolver could not narrow to one definition is labelled |
| shortest chain of contains/calls/extends/passes edges |
| reverse dependency closure grouped by depth plus tests to run; no name means the git diff |
| ranked symbol search |
| subsystems with labels, hubs, entry points, env vars, import cycles, index quality |
| freshness and counts |
Every response starts with [symbra] index 3m ago, checked 2s ago @ 1a2b3c4d · 1802 symbols · 3779 edges — when the index was last written and when it was last verified against the working tree, which are the same clock only when the last check found a change. Symbols whose file changed after indexing are marked STALE.
Map
symbra viz --open builds a self-contained HTML file and opens it in your browser — no server, no
network calls. It starts at a subsystem overview (gradient spheres sized by member count, edges
weighted by call traffic) and drills into a symbol-level graph with importance-sized nodes,
coloured edge kinds and a details drawer showing overview, relations and syntax-highlighted
source, with a link to open the symbol in VS Code. Search with /, clear with Esc, fit the
view with f, toggle light/dark with t, and move between nodes with the arrow keys and Enter.
Optional: semantic search
BM25 finds a symbol when you know a word in its name. It does not find _redirect_headers from
"what gets stripped when a 302 points at a different domain". An optional local embedding tier
closes that gap; it fuses with BM25 and PageRank by reciprocal rank rather than replacing them.
npm i @huggingface/transformers # optional, not installed by default
symbra embed # downloads Xenova/bge-small-en-v1.5 once (~32 MB), then vectorisesVectors live in the same SQLite file and are incremental by text hash, so symbra embed after an
edit only re-embeds what changed. Throughput is about 130 symbols/s on an M-series laptop (httpx:
929 symbols in 7 s). Nothing is sent anywhere: the model runs locally through onnxruntime-node, with
a WASM fallback.
Variable | Effect |
| switch the tier off entirely — no model load, no fusion |
| pin the runtime (default: native first, WASM as fallback) |
| move the model cache (default |
Without the package, without the model, or with no vectors computed, every query behaves exactly as it did before — the tier is additive. The MCP server preloads the model when the store has vectors, so the first question does not pay the session-creation cost.
Measured effect on the benchmark: overall recall@5 61.4 → 68.9, and 30.9 → 45.6 on free-form
explore questions.
Compiler-accurate references (SCIP)
Symbra's resolver is a tiered approximation of a compiler. When you already have a real one, feed
it in: SCIP indexes from scip-typescript, scip-python,
scip-java, scip-go, rust-analyzer or scip-clang upgrade the graph in place.
scip-typescript index # or your language's indexer
symbra import-scip index.scip --dry-run # report what would change
symbra import-scip index.scipHeuristic call edges at a SCIP-resolved call site are replaced by edges with resolver = scip and
confidence = 1, and the candidate sets they came from are collapsed. On express: 920 edges over
141/141 documents, 467 heuristic edges replaced, 259 candidate sets resolved, in 0.3 s.
A SCIP index names every binding, including the module-scope consts, destructured locals and
re-export aliases that Symbra deliberately does not extract. By default those are not turned into
new symbol rows — references to variables Symbra did extract still resolve. --include-variables
opts in; on express it adds 1112 variable rows, growing the symbol count by 53%.
What gets indexed
35 languages (counting TypeScript/TSX as one and OCaml's .ml/.mli as one; 37 grammars are
registered once those are split out). The core set ships with the package; the long tail downloads
on first use — see Install. In monorepos, pnpm/npm workspace packages resolve by
package name into their source (@scope/pkg, subpaths), and tsconfig/jsconfig paths are read
from the nearest config up the tree, following extends.
Language | Definitions | Resolution |
TypeScript, TSX, JavaScript | functions, classes, interfaces, types, enums, namespaces, methods, fields, CommonJS and prototype assignments ( | ES and CommonJS imports, re-exports and |
Python | functions, classes, methods, properties, dataclasses, enums, constants, | relative and package imports, |
Go | functions, methods with receivers, structs and embedded fields, interfaces, consts and vars, | package-directory scope, module-path imports via |
Rust | functions, |
|
Java, Kotlin, Scala | classes, interfaces, records, enums, annotations, methods, fields, JUnit tests, Spring and JAX-RS routes, Ktor routes, ScalaTest specs | declared package recorded per file; imports ( |
C# | namespaces (block and file-scoped), classes, records, structs, interfaces, enums, properties, events, primary constructors, xUnit/NUnit/MSTest tests, ASP.NET attribute and minimal-API routes |
|
C, C++ | functions and prototypes, structs, unions, enums, typedefs, macros, classes, namespaces, templates, out-of-class methods, gtest and Catch2 tests |
|
Ruby, PHP | modules, classes, mixins, |
|
Swift, Dart, Elixir, Zig, Lua, Bash | classes, structs, protocols, extensions, mixins, | relative imports, |
Markdown | headings as sections, links as edges, backticked identifiers as references to code | relative links |
Terraform, HCL | every block kind ( | traversals as references addressed like the blocks they point at, local module sources resolved to the module's files |
YAML shapes (GitHub Actions, GitLab CI, docker-compose, Kubernetes, OpenAPI) | jobs and steps, services with their dependencies and env keys, each Kubernetes document as | secrets/env keys as config reads, compose service dependencies |
Makefiles ( | targets and variables with docs and | prerequisites, variable references, |
SQL (grammar-less scanner) | tables, columns, views, functions, triggers, with | foreign keys and body table reads as references |
Objective-C ( |
|
|
Groovy, Gradle build scripts | classes, members, Spock specifications and feature methods; Gradle | JVM-style imports, project dependency references resolved to the subproject build script, task |
PowerShell ( | functions with comment-based help as docs, classes, members, enums, Pester blocks as nested tests |
|
Haskell | modules, types, classes, functions (multiple equations collapsed into one symbol), instances modeled as impl blocks reparented onto their type, hspec | imports, qualified calls, config reads |
OCaml ( | types, modules, classes, |
|
F# | namespaces, modules, types, members, attributed test functions |
|
Julia | modules, structs, functions and constants, macros, multiple methods collapsed into one symbol with a method count, |
|
Solidity | contracts, interfaces, libraries, functions, constructors, modifiers, events, errors, structs, enums, state variables, Foundry tests | imports, calls, |
Vue, Svelte single-file components (grammar-less: script/template/style blocks scanned and the script parsed as JS/TS) | one component symbol named after the file, props ( | imports and calls from the script block, template component usage as references (PascalCased for kebab-case tags), |
Environment variable reads (process.env.X, os.environ["X"], os.Getenv, …) become config_key symbols with reads_config edges, so "where is DATABASE_URL used" is a graph question.
Every edge records the resolver tier that produced it (scope, import, receiver, unique, heuristic, structural) and a confidence, so you can audit or filter.
How it works
scan (gitignore-aware) → parse (tree-sitter WASM, worker threads) → IR per file
→ SQLite (symbols, refs, imports, local types, FTS5)
→ resolve changed files and their importers (scope → import → receiver → unique)
→ PageRank over production code, Louvain communities with directory prior and hierarchical refinement
→ CLI · MCP · HTML mapDesign notes: docs/DESIGN.md. Determinism is a requirement: same input, same IDs, same community numbering, on every machine.
Built output — hashed bundle names (index-DrLLgu_7.js, main.a1b2c3d4.js), known chunk names (chunk-*.js, vendor.js), and directories like site/assets/, public/assets/, static/js/, storybook-static/ — is skipped by name before extraction, and a plain-named file (any language) is still skipped at read time if it's minified (very long lines) or carries an @generated/DO NOT EDIT marker in its first few lines; both counts are reported as "N generated/minified files skipped" when you index. If a legitimate file gets caught by mistake, force it back in with a negation in .symbraignore (!site/assets/hand-written.js) — symbra already reads that file for every ignore rule, including these heuristics.
Development
npm install
npm run grammars # vendor core grammars into ./grammars and long-tail ones into ./grammars-optional (already committed; the loader checks both locally, so a source checkout never needs network for any language)
npm run build
npm test # vitest: extractor fixtures + an end-to-end index of tests/fixtures/repo
npm run bench # retrieval quality over bench/questions.json (needs the repos in bench/repos.json indexed)
node bin/symbra.js index ../some-repoAdding a language is one file in src/languages/ implementing LanguageSupport (definitions, imports, references, module resolution) plus a fixture and a test. node scripts/dump-node-types.mjs <grammar> prints the node and field names a grammar exposes.
👤 Author
Sitharaj Seenivasan
🌐 Website: sitharaj.in
💼 LinkedIn: sitharaj08
💻 GitHub: sitharaj88
☕ Support
If this project helps you, consider buying me a coffee — it keeps the work going.
📄 License
Licensed under the Apache License 2.0. © 2026 Sitharaj Seenivasan.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Hosted code graph over MCP: exact callers, dependencies, and cross-repo blast radius for AI agents.
251Ground-truth code graph for your codebase: exact callers, callees, symbols & dependencies.
Code intelligence for coding agents: semantic, AST, graph, and full-text search. 279+ languages.
Ask a codebase what calls what: search, blast radius, paths between symbols, and diffs.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to search code by meaning, explore codebase structure, store and query knowledge with temporal facts, and read source code through a set of MCP tools.4817MIT
- AlicenseNot gradedqualityAmaintenanceProvides code intelligence for AI coding agents by indexing repositories into a hybrid knowledge graph, enabling agents to query dependencies, impact, and context through 28 MCP tools.3Apache 2.0
- AlicenseNot gradedqualityAmaintenanceEnables AI coding agents to query a codebase as a knowledge graph, providing token-budgeted context, search, and impact analysis via MCP tools.MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to locally search, query, and understand codebases with token-efficient context, dependency graphs, history, architecture diagrams, and metrics through MCP.1051MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/sitharaj88/Symbra'
If you have feedback or need assistance with the MCP directory API, please join our Discord server