The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Srclight listing page.
Deep code indexing for AI agents. SQLite FTS5 + tree-sitter + embeddings + MCP.
Srclight builds a rich, searchable index of your codebase that AI coding agents can query instantly — replacing dozens of grep/glob calls with precise, structured lookups. It is the most comprehensive code intelligence MCP server available: 42 tools covering symbol search, relationship graphs, community detection, impact analysis, git change intelligence, semantic search, build system awareness, and document extraction — capabilities no other single MCP server combines. Fully local and private: your code never leaves your machine.
AI coding agents (Claude Code, Cursor, etc.) spend 40-60% of their tokens on orientation — searching for files, reading code to understand structure, hunting for callers and callees. Srclight eliminates this waste.
| Without Srclight | With Srclight |
|---|---|
| 8-12 grep rounds to find callers | get_callers("lookup") — one call |
| Read 5 files to understand module | codebase_map() — instant overview |
| "Find code that does X" → 20 greps | semantic_search("dictionary lookup") — one call |
| Edit a function, break 47 callers | detect_changes() — shows blast radius before you commit |
| 15-25 tool calls per bug fix | 5-8 tool calls per bug fix |
Srclight's MCP server refuses unknown tool arguments instead of silently dropping them — a
mistyped filter like projects= (for project=) is rejected with an error, never answered as if
the constraint were applied. Every tool advertises additionalProperties: false. The guard is the
shared mcpkit policy, vendored as one hash-verified file
(src/srclight/_mcpkit.py).
AI agents: if a call returns unknown argument(s): … running older code than you think … reconnect, the running server predates the argument you sent (a long-lived daemon serves the code
it launched with). Nothing ran — check the reported revision and reconnect the MCP; don't retry the
same call.
Every symbol/graph result carries index_freshness: the short string
"verified-fresh" when the files behind the answer are byte-identical to what
was indexed, or a bounded object naming which files are stale, missing, or
not indexed. check_freshness(paths?) probes any paths — or the whole index —
on demand (unchanged files cost one stat each; never writes), and
index_status reports whole-index checked/stale_count.
AI agents: a result stamped stale describes the code as indexed, not as
it is now — reindex (srclight index) or read the live file before acting on
line numbers or bodies from it. "verified-fresh" is the affirmative signal;
its absence on a workspace-mode result means freshness was not checkable for
that result, never that it is fresh.
Reference edges are built by name matching plus ranked evidence, and every
caller/callee edge carries a resolution label saying how its target was
chosen: same_file (the caller's own file defines the name), unique_file
(all same-named candidates live in one file), import (the caller's imports
single out one file), same_dir, or name_only. Names appearing only in
comments or strings never become edges.
AI agents: name_only means a ranked candidate list across same-named
symbols — read it as "one of these", not a confirmed link; verify with
get_symbol or a reference search before acting on it. The stronger labels
are safe to treat as resolved.
apt install poppler-utils / brew install popplerNote:
srclight indexautomatically adds.srclight/to your.gitignore. Index databases and embedding files can be large and should never be committed.
Srclight supports embedding-based semantic search for natural language queries like "find code that handles authentication" or "where is the database connection pool".
symbol_embeddings table (SQLite).npy sidecar snapshot is built and loaded to GPU VRAM (cupy) or CPU RAM (numpy) for fast searchsemantic_search(query) embeds the query and runs cosine similarity against the GPU-resident matrix (~3ms for 27K vectors on a modern GPU)hybrid_search(query) combines FTS5 keyword results + embedding results via Reciprocal Rank Fusion (RRF)| Provider | Model | Quality | Local? | Notes |
|---|---|---|---|---|
| Ollama (default) | qwen3-embedding | Best local | Yes | Needs ~6GB VRAM |
| Ollama | nomic-embed-text | Good | Yes | Lighter, works on 8GB VRAM |
| Voyage AI (API) | voyage-code-3 | Best overall | No | Requires VOYAGE_API_KEY |
Embeddings are stored in symbol_embeddings table in .srclight/index.db. After indexing, a .npy sidecar snapshot is built for fast GPU loading:
| File | Purpose |
|---|---|
index.db | Write path — per-symbol CRUD during indexing |
embeddings.npy | Read path — contiguous float32 matrix for GPU/CPU search |
embeddings_norms.npy | Pre-computed row norms (avoids recomputation per query) |
embeddings_meta.json | Symbol ID mapping, model info, version for cache invalidation |
For ~27K symbols at 4096 dims (qwen3-embedding), that's ~428 MB on disk, ~450 MB in VRAM. Incremental: only re-embeds symbols whose content changed; sidecar rebuilt after each indexing run.
Search across multiple repos simultaneously. Each repo keeps its own .srclight/index.db; at query time, srclight ATTACHes them all and UNIONs across schemas.
Git submodules are not indexed automatically — git ls-files does not recurse into them. To index a submodule, clone it separately and add it as its own workspace project. See docs/usage-guide.md for details.
Srclight supports two transport modes: stdio (one server per session) and SSE (persistent server, multiple sessions). SSE is recommended for workspaces.
Stdio (simplest — one server per session):
SSE (persistent server — recommended for workspaces):
Run srclight as a long-lived server, then point Claude Code at it:
SSE mode supports multiple concurrent sessions and survives Claude Code restarts.
SSE (recommended): Run srclight once, then connect Cursor to it. Best for responsiveness and no cold-start per session.
Start the server: srclight serve --workspace myworkspace (default SSE on port 8742).
streamableHttp, URL: http://127.0.0.1:8742/sse..cursor/mcp.json or global ~/.cursor/mcp.json):Stdio (alternative): One server process per Cursor session.
command, Command: srclight, Args: serve --workspace myworkspace (or serve for single-repo).For single-repo: "args": ["serve"]. Restart Cursor completely after adding the server.
Verify: In Cursor chat, ask "What projects are in the srclight workspace?" or "List srclight tools" — the agent should call list_projects() or show srclight tools.
OpenClaw connects to srclight via mcporter, its built-in MCP tool server CLI.
The OpenClaw agent can then use srclight tools via the mcporter skill:
Prerequisite: Srclight must be running as an SSE server (see above). OpenClaw's mcporter connects over HTTP — stdio mode is not supported.
claude_desktop_config.json)Any MCP-compatible client can connect to the SSE endpoint:
Srclight exposes 42 MCP tools organized in seven tiers. The MCP server includes built-in instructions that guide AI agents on which tool to use and when — agents receive a session protocol, tool selection guide, and project parameter documentation automatically on connection.
| Tool | What it does |
|---|---|
codebase_map() | Full project overview — call first every session |
search_symbols(query) | Search across symbol names, code, and docs |
get_symbol(name) | Full source code + metadata for a symbol |
get_signature(name) | Just the signature (lightweight) |
symbols_in_file(path) | Table of contents for a file |
list_projects() | All projects in workspace with stats |
| Tool | What it does |
|---|---|
get_callers(name) | Who calls this symbol? |
get_callees(name) | What does this symbol call? |
get_dependents(name, transitive) | Blast radius — what breaks if I change this? |
get_implementors(interface) | All classes implementing an interface |
get_tests_for(name) | Test functions covering a symbol |
get_type_hierarchy(name) | Inheritance tree (base classes + subclasses) |
| Tool | What it does |
|---|---|
get_communities(project) | Auto-detected functional module clusters (Louvain algorithm) |
get_community(name, project) | Which community a symbol belongs to, with all co-members |
get_execution_flows(project) | Traced execution paths from entry points through the call graph |
get_impact(name, project) | Blast radius + risk level (LOW / MEDIUM / HIGH / CRITICAL) |
detect_changes(project, ref?) | Map git diff to affected symbols — aggregate blast radius of your edits |
| Tool | What it does |
|---|---|
blame_symbol(name) | Who changed this, when, and why |
recent_changes(n) | Commit feed (cross-project in workspace) |
git_hotspots(n, since) | Most frequently changed files (bug magnets) |
whats_changed() | Uncommitted work in progress |
changes_to(name) | Commit history for a symbol's file |
| Tool | What it does |
|---|---|
get_build_targets() | CMake/.csproj/npm targets with dependencies |
get_platform_variants(name) | #ifdef platform guards around a symbol |
platform_conditionals() | All platform-conditional code blocks |
| Tool | What it does |
|---|---|
semantic_search(query) | Find code by meaning (natural language) |
hybrid_search(query) | Best of both: keyword + semantic with RRF fusion |
embedding_status() | Embedding coverage and model info |
| Tool | What it does |
|---|---|
index_status() | Index freshness and stats |
reindex() | Trigger incremental re-index |
embedding_health() | Check if the embedding provider (Ollama, etc.) is reachable |
setup_guide() | Structured setup instructions for agents and users |
server_stats() | Server uptime and process info |
restart_server() | Request server restart (SSE only) |
In workspace mode, search_symbols, get_symbol, codebase_map, and hybrid_search accept an optional project filter. Graph/git/build/community tools require project in workspace mode.
Since v0.20.2, srclight refuses unknown tool arguments instead of silently discarding them. This is a deliberate behaviour change and it can break callers that were previously sending extra keys without noticing.
The MCP Python SDK's FastMCP drops arguments that are not in a tool's signature, and it does so
before the tool function runs. Combined with an inputSchema that omitted
additionalProperties: false, a mistyped argument produced a confident wrong answer rather than an
error. Measured on this server:
One added letter. No error, identical hit count, identical result shape, real symbols — from repos the caller never asked about. That is not a lossy call, it is a wrong one, and the caller has no way to learn their filter was ignored.
additionalProperties: false in tools/list, so the catalog matches
what the runtime enforces. Previously the runtime and the advertised schema disagreed.index_status, codebase_map, and three others). An
empty property set means "this tool takes no arguments", not "anything goes".This validates the top-level argument object. An argument that is itself a structured object is
validated by its own model, which this layer does not descend into. No srclight tool currently takes
an object argument, so the distinction is not reachable here today — but the guarantee is
"top-level", and a future tool taking a typed nested model would need extra="forbid" on that model
to get the same protection.
The error names exactly what it received and what the tool accepts:
Fix the argument name. If you believe the argument should exist, the server may be running older code than you expect — check its reported revision and reconnect.
If you cannot update your caller right now, pin the previous behaviour and update when you can:
That is a deliberate escape hatch, not an endorsement — the older versions still return wrong answers for mistyped filters, silently. Prefer fixing the argument name.
The policy lives in src/srclight/_mcpkit.py, a generated single-file build of
mcpkit, shared across this estate's MCP servers so one policy
is not reimplemented per repo. Do not hand-edit it — it carries a sha256 of its own body and
a verifier will reject a modified copy.
It adds no runtime dependency — the file is vendored, not installed, so pip install srclight
is unaffected. mcpkit is only needed to regenerate it.
tests/test_strict_args.py is a smoke test asserting that srclight.server.mcp itself enforces
the policy — not a freshly constructed lookalike. If server.py were reverted to a bare FastMCP
while _mcpkit.py sat unused in the tree, that test is the only one that would fail.
See docs/usage-guide.md for the full deployment and usage guide, including:
Keep indexes fresh automatically:
The hooks run srclight index in the background after each commit and branch switch.
camelCase, handles ::, ->).npy sidecar snapshot is built and loaded to GPU VRAM (cupy) or CPU RAM (numpy) for fast searchEach repo is indexed independently. At query time, SQLite's ATTACH mechanism joins them into a single searchable namespace. Handles >10 repos via automatic batching (SQLite's ATTACH limit).
A survey of 50+ MCP code intelligence servers across all major registries (Official MCP Registry, Smithery, Glama, mcp.so, awesome-mcp-servers) found that no other single server combines srclight's full capabilities:
| Capability | srclight | grep/glob (default) | CodeMCP (SCIP) | Claude Context (Zilliz) |
|---|---|---|---|---|
| Symbol search (FTS5) | 3 indexes (name, content, docs) | None | SCIP-based | BM25 |
| Semantic search (embeddings) | GPU-accelerated, ~3ms | None | None | OpenAI API + Milvus |
| Hybrid search (keyword + semantic) | RRF fusion | None | None | BM25 + vector |
| Relationship graph (callers, callees) | tree-sitter edges | None | SCIP edges | None |
| Community detection (module clusters) | Louvain on call graph | None | None | None |
| Impact analysis (blast radius + risk) | Per-symbol + diff-level | None | None | None |
| Git change intelligence | blame, hotspots, WIP, detect_changes | None | None | None |
| Build system awareness | CMake, .csproj, #ifdef | None | None | None |
| Multi-repo workspace | ATTACH+UNION | None | None | None |
| Infrastructure required | pip install, SQLite | None | SCIP indexer | Docker, Milvus, OpenAI API |
| Fully local / private | Yes, zero API calls | Yes | Yes | No (needs OpenAI) |
| Languages | 11 | Any (regex) | 5 (SCIP) | Any (chunking) |
| MCP tools | 42 | 2 (grep, glob) | 80+ | ~10 |
Unlike grep-based tools, srclight builds a persistent index with structured lookups. Unlike cloud-based solutions, everything runs locally — your code never leaves your machine. Unlike IDE plugins, srclight works with any MCP client.
.npy sidecar, cupy/numpy vectorized mathdetect_changes: map git diff to affected symbols and aggregate blast radiusMIT — Gig8 LLC