Stop reading
whole files.

code-kb is an MCP server that answers a coding agent's questions about a repository with the smallest slice of code that answers them. Skeletons instead of files. One function instead of one module. The callers that matter instead of a grep dump.

80–98% fewer prompt tokens 0–5 ms per query under 15 MB of memory 40+ languages

Install code-kb See the eleven tools

Works with Claude Code, Grok CLI, Antigravity, Codex CLI, and Cursor. Ships binaries for Windows, Linux, and macOS.

crates/code-kb-core/src/queries.rs 2,473 lines
≈ 25,900 tokens
/// Search symbols by name query, kind filter, and test flag.pub fn search_symbols(    conn: &Connection,    query: &str,    kind_filter: Option<&str>,    include_tests: bool,    limit: usize,) -> Result<Vec<Symbol>, QueryError> {{ /* 3 lines hidden: L313-L315 */ }
search_symbols_scoped(conn, query, kind_filter, None, include_tests, limit)}
/// Search symbols with optional path scoping filter.pub fn search_symbols_scoped( conn: &Connection, query: &str, kind_filter: Option<&str>, path_filter: Option<&str>, include_tests: bool, limit: usize,) -> Result<Vec<Symbol>, QueryError> {{ /* 65 lines hidden: L325-L389 */ }
// Try get_symbol_by_name first for qualified queries (e.g. McpServer::new, Class.method) if (query.contains("::") || query.contains('.')) && let Ok(Some(sym)) = get_symbol_by_name(conn, query, path_filter) { return Ok(vec![sym]); } let kind_filter = kind_filter.map(normalize_kind); let like_query = format!("{}%", escape_like(query)); let mut sql = String::from( "SELECT s.id, s.name, s.kind, s.file_path, s.start_line, s.end_line, s.signature FROM symbols s WHERE s.name LIKE ?1 ESCAPE '\\'", ); let mut params: Vec<Box<dyn ToSql>> = vec![Box::new(like_query)]; if let Some(kind) = kind_filter { sql.push_str(" AND s.kind = ?2"); params.push(Box::new(kind)); } ⋮ 45 more lines}
/// Sanitizes a free-form user query into `(and_query, or_query)` formatted for SQLite FTS5./// Each alphanumeric/underscore token is quoted and given a prefix wildcard: `"token"*`.pub fn sanitize_fts5_query(query: &str) -> (String, String) {{ /* 15 lines hidden: L393-L407 */ }
let words: Vec<String> = query .split(|c: char| !c.is_alphanumeric() && c != '_') .filter(|s| !s.is_empty()) .map(|s| format!("\"{s}\"*")) .collect(); if words.is_empty() { return (String::new(), String::new()); } let and_query = words.join(" "); let or_query = words.join(" OR "); (and_query, or_query)}
⋮ 2,066 more lines to the end of the file

Real output from this repository. Token counts are bytes divided by four.

Why

Where the tokens go

An agent that wants one signature usually reads the whole file to get it. A 2,500-line file costs about 26,000 tokens. Over a ten-turn session that adds up to more than the context window holds, so the harness compacts the conversation and the agent forgets the rules it was given.

Read the file

cat crates/code-kb-core/src/queries.rs
Lines
2,473
Tokens
≈ 25,900
Needed
one signature

Ask code-kb

file_skeleton("queries.rs")
get_symbol_context("search_symbols_scoped")
Skeleton
≈ 1,800 tokens, 93% less
Context slice
≈ 780 tokens, 97% less
Query time
2 ms

What it does

Seven capabilities for AI coding agents

Skeletons
file_skeleton returns every type, trait, signature, and docstring in a file with the bodies removed. codebase_outline does the same for a directory in about 200 tokens.
Context slices
get_symbol_context returns one function's body, the signatures of the functions it calls, its parameter types, and its tests. One call replaces four to six searches.
Blast radius
blast_radius walks the callers of a symbol across several hops with a recursive SQLite query and names the tests to run. With no target, it reads the uncommitted git changes.
Atomic edits
replace_symbol_body validates the edited file through julie-extract check for every language the extractor parses, about 40; other paths report validation skipped. It then verifies a hash, writes the file, and re-indexes it in one turn.
Token telemetry
telemetry_summary tracks tokens saved, call counts, and error rates across sessions in a central SQLite database. code-kb stats prints the report from the terminal.
Windows first
Every release ships a Windows binary tested on NTFS. Paths use forward slashes, verbatim prefixes are stripped, and file handles close before any rename.
Native hooks
code-kb hook SessionStart prints routing instructions for the agent from the binary itself. No Node.js, Python, or shell in the path.

Compared

code-kb against a bare agent

Task With code-kb With grep, cat, and read
Prompt tokens per lookup 85–98% fewer 5,000–15,000 per file read
Find a signature file_skeleton, bodies removed Whole file in the prompt
Search by concept BM25 full-text search in under 3 ms Text grep that also matches comments, strings, and logs
Prepare an edit get_symbol_context, one call Four to six searches across turns
Callee noise Standard library calls filtered in 40+ languages Every runtime call listed
Predict which tests to run blast_radius, recursive SQL Guess, or run the whole suite
Replace a function Syntax checked before the write by julie-extract for about 40 languages; skipped otherwise Text or regex replacement
Query time 0–5 ms median 10–50 ms of disk reads, then the model reads it all
Memory held by the server Under 15 MB None, paid for in prompt size instead
Context left for the task Instructions survive the session Compaction, forgotten constraints

Steps

From a cold start to a verified edit

The order an agent follows on a repository it has never seen. Each step costs less than the file read it replaces.

  1. Orient

    Directory tree and the main exports, about 200 tokens.

    codebase_outline(depth=2)
  2. Find the interface

    Signatures and traits with bodies removed. Search by concept when the name is unknown.

    file_skeleton("src/server.rs")
    search_symbols("auth token validation")
  3. Get the context

    The target body, its callees' signatures, parameter types, and tests in one call.

    get_symbol_context("handle_request")
  4. Check the impact

    Callers across several hops and the tests that cover them.

    blast_radius(symbol="compute_hash")
  5. Edit

    Syntax validation by julie-extract for about 40 languages; other paths report it skipped. Hash check, atomic write, re-index.

    replace_symbol_body(
      symbol_name="calculate",
      file_path="calc.rs",
      new_body="{ a + b }"
    )
  6. Verify

    Run the predicted tests, then read the tool telemetry.

    cargo test compute_hash
    code-kb stats

Tools

Eleven tools, each with a matching command

Every MCP tool has a one-to-one CLI command, so you can check any answer from the terminal.

MCP tool CLI command Returns Accepts
codebase_outlinecode-kb outline [path]Directory tree and main symbolspath, depth
file_skeletoncode-kb skeleton <file>File outline, bodies removedfile_path
lookup_symbolcode-kb lookup <query>Exact or prefix symbol matchquery, path
search_symbolscode-kb search <query>Full-text search over docstrings and signaturesquery, path
get_symbol_bodycode-kb body <symbol>Source of one symbolsymbol_name, file_path
get_symbol_contextcode-kb context <symbol>Body, callee signatures, types, testssymbol_name, file_path
find_referencescode-kb refs <symbol>Callers or callees, stdlib filteredsymbol_name, direction (default callers)
blast_radiuscode-kb blast-radius [target]Multi-hop callers and tests to runsymbol, file; omitted target reads git changes
find_structural_factscode-kb facts [category]Routes, queries, models, config keysno category lists all
replace_symbol_bodycode-kb edit <symbol>Atomic replacement; syntax validation for supported languagessymbol_name, file_path, new_body, expected_body_hash
telemetry_summarycode-kb statsToken savings, call counts, error ratestime_window, workspace_only

Install

Connect it to your agent

Install the plugin for your agent. It needs Node.js 18 or newer; on first run it downloads the release archive for your platform, which holds code-kb and the matching julie-extract side by side. Or download the archive yourself, put both binaries on PATH, and register the server by hand. GUI apps such as Cursor start the server from their own install directory, so their config passes --root with the project path; terminal agents need no flag. The README has every harness.

As a plugin, which also installs the skill and hooks (two separate prompts):

/plugin marketplace add anortham/code-kb
/plugin install code-kb@code-kb

Or by hand, for every project on this machine:

claude mcp add --scope user code-kb -- code-kb serve

For one project, in .mcp.json:

{
  "mcpServers": {
    "code-kb": {
      "command": "code-kb",
      "args": ["serve"]
    }
  }
}