Skip to main content
Glama
harshithsunku

mcp-gtags-server

mcp-gtags-server

Stop letting your AI agent grep. Give it an index.

PyPI CI Kernel eval Python 3.10+ License: MIT MCP Powered by GNU Global Install in Cursor

mcp-name: io.github.harshithsunku/mcp-gtags-server

# If you don't have uv yet (one-time, no sudo):
curl -LsSf https://astral.sh/uv/install.sh | sh
{ "mcpServers": { "gtags": { "command": "uvx", "args": ["mcp-gtags-server"] } } }

One user-level config entry, no sudo, no pre-installed anything — the whole toolchain installs itself into user space on first use, and every repo you open is served automatically.

Every AI coding agent — Claude Code, Cursor, Codex, you name it — answers "where is this function defined?" the same way: grep the entire tree. On a million-line C/C++ codebase that's a full scan per question, and the output is a firehose: every comment, string literal, and unrelated match, dumped straight into the model's context window.

mcp-gtags-server replaces those scans with indexed lookups powered by GNU Global (gtags) — the same tags engine kernel and systems developers have trusted for decades — exposed to agents over the Model Context Protocol. Built for the codebases LSP-based tools can't handle: kernel-scale C/C++, trees that don't currently compile, machines you can't sudo on.

  • ~100× faster per query — milliseconds instead of seconds, at any codebase size

  • Radically less noise — the definition, not 7,873 lines of matches

  • Speaks kernel#ifdef guard stacks with .config filtering, macro-generated symbols (sys_read → its SYSCALL_DEFINE3 site) that no other tagging tool resolves, and definitions the parser misses recovered from their EXPORT_SYMBOL site via ctags

  • Zero index management — first query builds the index, every query auto-refreshes it

  • Correctness measured in CI — a 65-case golden eval covering all 11 tools against a pinned kernel: 100% recall, 100% precision@1 (docs/capability.md)

  • Works everywhere MCP does — Claude Code, Claude Desktop, Cursor, any MCP client

The numbers (real Linux kernel, not a toy)

Measured on a full Linux kernel checkout — 65,163 C/C++ files, 37.1 million lines — warm page cache:

Question an agent asks

grep -rn

gtags (this server)

Context consumed

Where is tcp_v4_rcv defined?

1.40 s

0.01 s

8 lines → 1 line

Where is kmalloc defined?

1.62 s

0.01 s

7,873 lines → 5 lines

Who references kmalloc?

1.62 s

0.10 s

7,873 noisy lines → 2,744 real sites (or a ranked per-file summary)

Show me tcp_v4_rcv's implementation

read a 3,500-line file

get_symbol_body

exactly the 271-line function

Who calls ext4_mark_inode_dirty?

245 raw match lines

find_callers

62 deduped caller functions, with counts

Where is sys_read really defined?

no answer — the name is macro-generated

0.03 s

fs/read_write.c SYSCALL_DEFINE3(read, ...), flagged resolved_via

Where is mutex_lock defined?

24,774 noisy match lines

0.2 s

kernel/locking/mutex.c:314 — recovered via EXPORT_SYMBOL + ctags after gtags' parser derails on it

Does ksys_read ever reach rw_verify_area?

N rounds of grep + reading

0.6 s

the shortest call chain, with every call site's file:line

What does my uncommitted diff impact?

not answerable

0.1 s

blast_radius: changed functions + callers, ranked by distance

One-time index build: 66 s for the whole kernel. Incremental refresh after edits: well under a second. Reproduce it yourself with scripts/benchmark.sh:

./scripts/benchmark.sh /path/to/linux tcp_v4_rcv kmalloc ext4_readdir

The speed is nice. The real win is precision: an agent that gets 5 exact lines instead of 7,873 noisy ones keeps its context window for actual reasoning.

And the answers are measured, not assumed: CI runs a 65-case golden eval against pinned kernel v6.16 on every push — currently 100% recall, 100% precision@1 across definitions, macro resolution, export recovery, references, callers, callees, definition bodies, #ifdef guards, and reachability, covering all 11 tools. The full methodology, numbers, and honest limitations live in docs/capability.md.

Related MCP server: Sigil MCP Server

Quick start (60 seconds)

Option A — one config entry (recommended)

Add the server once, at user level, and you're done — no installer, no pre-installed gtags, no per-repo setup. The only prerequisite is uv (or use Option B, which installs it for you).

# Claude Code (once per device, all repos):
claude mcp add --scope user gtags -- uvx mcp-gtags-server
// Cursor (~/.cursor/mcp.json), or any MCP client's global settings:
{
  "mcpServers": {
    "gtags": { "command": "uvx", "args": ["mcp-gtags-server"] }
  }
}

Or click the Cursor one-click install badge at the top of this page.

On the very first tool call the server bootstraps everything else by itself: GNU Global (prebuilt user-space binaries — no compiler, no sudo), universal-ctags, and Pygments, all into ~/.gtags-mcp. While that one-time install runs (a few seconds on most platforms), tool calls return a "toolchain is being installed — retry shortly" status instead of failing. Opt out with --no-auto-setup or GTAGS_MCP_AUTO_SETUP=0.

The prebuilt Linux binaries run on any distro with glibc ≥ 2.28 (RHEL/Rocky 8+, Ubuntu 18.10+, Debian 10+). On older hosts — or if a downloaded binary fails its post-install execution check — setup automatically compiles GNU Global from source instead, which only needs make and a C compiler.

Option B — one-line installer (shared background server)

One command. No sudo. Works everywhere — restricted corporate machines, containers, build servers:

curl -fsSL https://raw.githubusercontent.com/harshithsunku/mcp-gtags-server/main/scripts/install.sh | bash

Everything lands in your home directory — the server (via uv), GNU Global, universal-ctags, and Pygments (in ~/.gtags-mcp). When it finishes, a shared background HTTP server is running that every client and IDE window on the machine can point at (http://127.0.0.1:8383/mcp), and the exact client configuration is printed to your console.

Re-run the same command any time:

  • Up to date? → "Already installed and up to date — nothing to install", and the config is printed again.

  • New release on GitHub/PyPI? → the package updates, an outdated gtags toolchain is wiped and reinstalled automatically, and the background server restarts on the new version.

One config, many repos

However you install it, one user-level entry serves every repo you open — 20 repos need zero extra installs and zero extra config. Each tool call resolves its project root down this ladder:

  1. project_root argument on the tool call (agents pass this to target any tree)

  2. --root flag / GTAGS_MCP_ROOT env var

  3. root in a config file (note: pinning a root here defeats multi-repo)

  4. The client's workspace roots (MCP roots protocol) — IDEs that advertise their open folders get the right repo automatically, even on the shared HTTP server; with several folders open, agents are asked to pass project_root

  5. Walk up from the server's working directory to the nearest .git/GTAGS — this is why stdio servers spawned by Claude Code/Cursor inside a repo just work

That's it. No indexing step, no configuration. Ask your agent "who calls tcp_v4_rcv?" — the first query in any repo builds that repo's index automatically, and every query after that is answered in milliseconds. Run mcp-gtags-server doctor any time to see what the server detects, or mcp-gtags-server config to re-print the client configuration.

The installer runs mcp-gtags-server --transport http --host 127.0.0.1 --port 8383 in the background (pid: ~/.gtags-mcp/server.pid, log: ~/.gtags-mcp/server.log). Environment overrides for the installer:

Variable

Default

Meaning

GTAGS_MCP_PORT

8383

HTTP port

GTAGS_MCP_HOST

127.0.0.1

Bind address — set 0.0.0.0 to reach the server from other devices at http://<machine-ip>:8383/mcp

GTAGS_MCP_NO_SERVER

unset

1 = don't start a background server

Security note: the HTTP endpoint is unauthenticated. It binds localhost by default; only bind 0.0.0.0 on networks you trust.

# 1. GNU Global — EITHER user-space (no sudo):
mcp-gtags-server setup
#    OR a system package:
sudo apt install global      # Debian/Ubuntu
sudo dnf install global      # Fedora
brew install global          # macOS

# 2. The server:
uv tool install mcp-gtags-server        # or: pip install mcp-gtags-server

The server finds binaries in this order: --bin-dir/GTAGS_MCP_BIN_DIR/config bin_dir~/.gtags-mcp/binPATH~/.local/bin.

Easiest: download mcp-gtags-server.mcpb from the latest release, drag it into Claude Desktop's Settings → Extensions, and pick your project folder in the setup screen. The gtags toolchain installs itself on first use.

Or add to claude_desktop_config.json manually (pin the project since Desktop doesn't launch in your repo):

{
  "mcpServers": {
    "gtags": {
      "command": "uvx",
      "args": ["mcp-gtags-server", "--root", "/absolute/path/to/your/project"]
    }
  }
}

By default the server uses the client's advertised workspace root (MCP roots protocol) or auto-detects the project root by walking up from its working directory to the nearest .git or existing GTAGS — so queries from anywhere inside a monorepo resolve to the repo root. Override with --root /path, the GTAGS_MCP_ROOT env var, or root in a config file — or pass project_root on any individual tool call to query a different tree. (See "One config, many repos" for the full resolution order.)

Every setting can also live in a TOML file, so teams share defaults through the repo (like .editorconfig):

  • Project: .gtags-mcp.toml at the project root

  • User: ~/.config/gtags-mcp/config.toml

# .gtags-mcp.toml
label = "native-pygments"     # force a GTAGSLABEL parser label
bin_dir = "/opt/tools/bin"    # extra directory searched for gtags/global/ctags
skip_globs = ["*.gen.c"]      # never index paths/basenames matching these globs
respect_gitignore = true      # default: index only what `git ls-files` reports
enrich = true                 # default: ctags kind/signature/scope on results
guards = true                 # default: #ifdef guard stacks on results
macro_resolve = true          # default: resolve macro-generated symbols (sys_*, ...)
# root = "/abs/path"          # default project root (user config)

Precedence: tool-call argument > CLI flag > environment variable > project config > user config > built-in default.

The tools

Symbol-level tools — the noise killers

Give the agent the symbol, not the file.

Tool

What the agent gets

symbol_info

A one-shot overview card — definitions (with kind, signature, scope, and #ifdef guard), reference count, hottest files, EXPORT_SYMBOL* status, and which tool to use next. Multiply-defined symbols are explained as "N definitions under M distinct guards"; macro-generated ones resolve with a resolved_via flag. The best first query for any unfamiliar symbol.

get_symbol_body

Just the source of a definition. The 271-line tcp_v4_rcv function — not the 3,500-line file it lives in. Handles functions, structs, and multi-line macros.

find_callers

The call graph, deduplicated. Every reference mapped to its enclosing function with call counts: 245 raw lines for ext4_mark_inode_dirty collapse to 62 callers. Iterate it to walk the caller graph as deep as you need.

find_callees

The outgoing call graph. What does this function call? Body-extracted call sites, each verified against the index, split into in-tree (with locations) and external.

reachability

"Can this function end up in that one?" — BFS over the caller graph returns the shortest call chain from A to B with the file:line of every call site (ksys_read → vfs_read → rw_verify_area), or an honest "no static path" that names the function-pointer caveat. One call instead of a dozen find_callers rounds.

blast_radius

What does my diff impact? Takes git diff <ref>, maps changed lines to their enclosing functions via the index, then walks callers outward — results ranked by distance (changed functions first, direct callers next). The pre-merge "what else must I re-check" answer, tied to real git state.

summarize_references

A ranked per-file count. The cheap first move for hot symbols — kmalloc's 2,744 references become one screen of "where usage concentrates".

Core lookups

Tool

What it does

Underlying command

find_definition

Where is this symbol defined? Falls back to macro-family resolution (sys_*, trace_*, DEFINE_* names) when there's no literal definition, and suggests prefix matches when nothing matches at all

global -x + macro resolution

find_references

Raw reference lines for a symbol — falls back to symbol-usage records (libc calls, some variables) when the index has no in-tree references, flagged fallback

global -rx, fallback global -sx

list_file_symbols

A file's API surface — every symbol it defines

global -fx

update_index

Synchronous freshness barrier after edits; full=true rebuilds from scratch (rarely needed — indexing is automatic)

gtags -i / gtags

Every query tool supports limit/offset pagination, long-line truncation, and (where it makes sense) case_insensitive — output is engineered to never flood a context window.

Structured output (JSON by default)

Since v0.8.0 every tool returns a machine-readable JSON envelope by default (pass format="text" for the previous human-readable rendering — a breaking change if you parsed the old text):

{
  "tool": "find_definition",
  "root": "/abs/project/root",
  "results": [
    {"symbol": "kmap", "path": "include/linux/highmem-internal.h", "line": 40,
     "col": 22, "kind": "function", "typeref": "void *", "scope": null,
     "signature": "(struct page * page)", "guard": ["CONFIG_HIGHMEM"],
     "snippet": "static inline void *kmap(struct page *page)"}
  ],
  "total": 2, "offset": 0, "truncated": false,
  "next_tools": ["get_symbol_body", "find_callers", "symbol_info"],
  "warning": null
}
  • Symbol locations always use the stable record schema {symbol, path, line, col, kind, typeref, scope, signature, guard, snippet} with repo-relative paths. Keys are only ever added, never renamed or removed — parsers never need to change shape.

  • kind / typeref / scope / signature say what a symbol is (since v0.8.1): function vs. macro vs. struct vs. typedef vs. enum constant, its return/target type, its enclosing scope (enum:color, struct:item), and its parameter list — extracted per file by universal-ctags with no build and no compile database, cached, and filled on definition-shaped results (find_definition, symbol_info, list_file_symbols). When universal-ctags isn't available the fields are simply null; disable explicitly with --no-enrich, GTAGS_MCP_ENRICH=0, or enrich = false in .gtags-mcp.toml.

  • guard says when a symbol exists (since v0.9.0): the enclosing #if/#ifdef stack, outermost first ([] = unconditional, null = scanning disabled or file unreadable). See the next section — this is the headline feature.

  • resolved_via says how a symbol was found when it took macro-family resolution rather than a literal index match ("macro:SYSCALL_DEFINE", "fuzzy:vfs_read") — see Macro-generated symbols.

  • next_tools tells the agent the highest-value follow-up call for what was (or wasn't) found.

  • total/offset/truncated replace the text continuation footer; errors keep the envelope with an error field.

  • Composite tools return tool-shaped results (e.g. find_callees {in_tree, external}, symbol_info an overview object, reachability a hop chain) inside the same envelope.

#ifdef-aware: know which definition your config actually compiles

Kernel and firmware code defines the same symbol multiple times and lets the build configuration pick one. Every other no-build tool returns a flat, unexplained list — an agent happily reads the no-op stub of kmap and reasons its way to a wrong answer. This server reads the preprocessor conditionals (pure scanning — still no build, no compile_commands.json):

Symbol: kmap
  2 definitions under 2 distinct guards:
  [CONFIG_HIGHMEM] defined at include/linux/highmem-internal.h:40 — function kmap(struct page * page) -> void *
  [!CONFIG_HIGHMEM] defined at include/linux/highmem-internal.h:170 — function kmap(struct page * page) -> void *

Pass active_config — a kernel .config path or a macro list like "CONFIG_SMP,BITS_PER_LONG=64,!CONFIG_DEBUG" — to find_definition, find_references, or symbol_info, and definitions whose guard stack is definitely false under it are dropped (the envelope reports the count as config_filtered). Filtering is deliberately conservative: a .config is a closed world for CONFIG_* macros (kbuild semantics, including =mCONFIG_X_MODULE and IS_ENABLED/IS_BUILTIN/IS_MODULE), but anything unknown (__ASSEMBLY__, ARCH_HAS_*, arithmetic it can't decide) never drops a result.

The details are handled so the output stays clean: classic include guards (#ifndef FOO_H) are detected and suppressed, #elif chains compose into explicit conditions (!CONFIG_X86_64 && CONFIG_X86_32), comments on directives are ignored (they lie), and broken/partial files never fail a query. Disable with --no-guards, GTAGS_MCP_GUARDS=0, or guards = false in .gtags-mcp.toml.

Macro-generated symbols resolve too (sys_readSYSCALL_DEFINE3)

The best-known gap of every tagging tool on the kernel: sys_read, trace_sched_switch, and css_set_lock have no literal definition anywhere — they are minted by token-pasting macros, and a plain lookup comes back empty (or worse, returns a same-named test helper). This server resolves them from the index alone, no preprocessor and no build:

find_definition("sys_read")        → fs/read_write.c:723  SYSCALL_DEFINE3(read, ...)   resolved_via: "macro:SYSCALL_DEFINE"
find_definition("__x64_sys_openat")→ fs/open.c:1385       SYSCALL_DEFINE4(openat, ...) (arch entry-point wrappers map back)
find_definition("trace_sched_switch") → include/trace/events/sched.h:220  TRACE_EVENT(sched_switch, ...)
find_definition("css_set_lock")    → kernel/cgroup/cgroup.c:82  DEFINE_SPINLOCK(css_set_lock);

Covered families: SYSCALL_DEFINE0..6 / COMPAT_SYSCALL_DEFINE* (incl. __x64_/__ia32_/__arm64_/__se_/__do_ wrapper spellings), tracepoints (TRACE_EVENT, DEFINE_EVENT, DECLARE_TRACE, ...), and the bare-name definers (DEFINE_SPINLOCK, DEFINE_MUTEX, DEFINE_PER_CPU*, DECLARE_BITMAP, module_param*, any DEFINE_/DECLARE_-shaped macro) — plus a last-resort fuzzy tier that tries underscore-variant spellings. Resolved results are flagged with resolved_via in the envelope and ranked ahead of same-named textual shadows; DEFINE_* sites rank above their DECLARE_* counterparts. symbol_info additionally reports the EXPORT_SYMBOL / EXPORT_SYMBOL_GPL variant a kernel symbol is exported with, in an exported field. Costs nothing when a symbol resolves normally (only family-shaped names like sys_*/trace_* get the extra indexed lookups); disable with --no-macro-resolve, GTAGS_MCP_MACRO_RESOLVE=0, or macro_resolve = false.

What gets indexed (junk stays out)

Indexing feeds gtags an explicit file list instead of letting it walk the tree:

  • In a git repository the list comes from git ls-files.gitignore is respected exactly, so build output, vendored blobs, and generated files never pollute the index. Disable with respect_gitignore = false in .gtags-mcp.toml.

  • Outside git, the tree is walked minus well-known junk directories (.git, node_modules, build, dist, .venv, ...).

  • skip_globs in .gtags-mcp.toml drops anything else you never want indexed.

Incremental refreshes recollect the list, so newly ignored files drop out of the index and new files appear — automatically.

The flow that saves your context window

1. symbol_info("kmalloc")                    → definitions + usage spread + next step (12 lines)
2. find_callers("ext4_mark_inode_dirty")     → deduped callers with counts (1 line/caller)
3. get_symbol_body("tcp_v4_rcv")             → read the ONE function that matters
4. find_callees("tcp_v4_rcv")                → what it depends on, with locations
5. reachability("ksys_read", "rw_verify_area") → the call chain, one line per hop
6. blast_radius("HEAD")                      → what my edit impacts, ranked by distance

A few hundred lines of context total — versus tens of thousands for the grep-and-read-files equivalent.

Multi-language projects (C + Python + more)

Real projects mix languages — a C core with Python tooling, JS frontends, Go services. The server handles this automatically:

  • Native languages (C, C++, Java, PHP, Yacc, assembly) use GNU Global's fast built-in parser.

  • Everything else (Python, Go, Rust, JavaScript, TypeScript, Ruby, ... ~150 languages) is indexed through Global's ctags + Pygments plugin parsers — same index, same tools, same queries.

The one-line installer (and mcp-gtags-server setup) enables this automatically — it installs universal-ctags and Pygments into user space, and the server switches to the native-pygments parser label on its own. Prefer system packages? Those work too:

sudo apt install exuberant-ctags python3-pygments   # Debian/Ubuntu
sudo dnf install ctags python3-pygments             # Fedora
brew install ctags && pip install pygments          # macOS

Now find_definition("py_util"), get_symbol_body (indentation-aware for Python), find_callees, find_callers — all work across every language in the tree, in one index.

Force a specific parser label with --label, GTAGS_MCP_LABEL, or label in .gtags-mcp.toml (e.g. default for native-only, pygments for plugin-everything).

Honest caveats: for plugin-parsed languages, definitions are as accurate as ctags, but references are token-based — every occurrence of the name counts, without C-grade semantic reference tracking or local-scope awareness. For C/C++ nothing changes: the native parser still does that part.

How it works

Architecture

One long-lived server process per IDE window (stdio) — or one shared HTTP server for the whole machine. Everything heavy lives on disk and is shared: the toolchain installs itself once per machine, the index builds itself once per repo.

flowchart LR
    subgraph clients["MCP clients"]
        CC["Claude Code / Cursor / VS Code"]
        CD["Claude Desktop (.mcpb)"]
    end

    subgraph proc["mcp-gtags-server — spawned once per window, lives for the session"]
        T["11 navigation tools"]
        RR["root resolution<br/>project_root → env → config → client roots → cwd"]
    end

    subgraph disk["your machine, user space (no sudo)"]
        TC["~/.gtags-mcp<br/>global · gtags · ctags · Pygments<br/>self-installs on first use"]
        IX["&lt;repo&gt;/.gtags-mcp/GTAGS<br/>one index per repo, auto-built"]
    end

    CC -- "stdio (uvx)" --> T
    CD -- "stdio" --> T
    T --> RR
    RR -- "runs global (ms, indexed)" --> TC
    TC -- "B-tree lookup" --> IX

A tool call, end to end

The binary is not re-executed per call — the server process stays alive; each call is one JSON-RPC message plus one millisecond-scale global subprocess:

sequenceDiagram
    participant A as Agent
    participant S as server (long-lived process)
    participant G as global (GTAGS index)

    A->>S: find_definition("tcp_v4_rcv")
    Note over S: first call on this machine?<br/>toolchain installs itself in the background,<br/>calls answer "installing — retry shortly"
    Note over S: first query in this repo?<br/>index auto-builds once (~66 s for the kernel)
    S->>G: global -dx tcp_v4_rcv
    G-->>S: net/ipv4/tcp_ipv4.c:2067 (milliseconds)
    S-->>A: narrow JSON answer — no grep firehose
  • First query on a tree? The index is built automatically (the only operation that ever blocks — and only once).

  • Where do the index files go? Into a single .gtags-mcp/ folder at the project root — never loose files next to your code. The folder ships its own .gitignore, so git status stays clean without touching yours. A pre-existing root-level GTAGS (from older versions, or your own gtags runs) keeps being used as-is. mcp-gtags-server doctor shows the location.

  • Files changed? A debounced incremental refresh runs in the background: queries always answer instantly from the current index while gtags -i catches up behind the scenes. Measured on the kernel: queries return in 0.02s while the 25s freshness check runs invisibly. Staleness is bounded by the debounce window; call update_index for a synchronous, guaranteed-fresh barrier right after edits.

  • Huge result? Pagination footers tell the agent exactly how to fetch the next page — or the tool itself suggests a narrower one (find_callers on a symbol used in 500+ files points to summarize_references).

FAQ

Why gtags instead of a language server (LSP)? LSP servers give richer semantics but need a working build configuration, per-editor setup, and serious warm-up time on large trees. gtags indexes 37M lines in about a minute with zero configuration, handles the kernel-scale codebases LSPs choke on, and its fuzzy parser doesn't care whether the code currently compiles. For C/C++ navigation questions — definition, references, callers — it's the pragmatic sweet spot. (Wrapping clangd for the compile-DB case was considered and deliberately rejected: users who have a working compile_commands.json already have clangd and its ecosystem — see ROADMAP.md.)

What languages? C, C++, Yacc, Java, PHP, and assembly natively — plus Python, Go, Rust, JS/TS, Ruby, and ~150 others via the ctags/Pygments plugin parsers (see Multi-language projects).

Does the agent have to manage the index? No. That's the point. Build-on-first-query, background refresh with adaptive debounce, zero blocking — queries never wait for index maintenance. The explicit update_index tool exists only as an escape hatch: a synchronous freshness barrier after edits, and a from-scratch rebuild with full=true.

Where does the index live? Can I delete it? In .gtags-mcp/ at the project root (self-gitignored). Delete it freely any time — the next query rebuilds it from scratch.

Will it fight my agent's built-in tools? The tool descriptions are written to steer the model: they say when to use indexed lookups instead of grep. In practice agents pick the faster, narrower tool naturally.

Development

git clone https://github.com/harshithsunku/mcp-gtags-server
cd mcp-gtags-server
uv run --extra dev pytest       # 229 tests; e2e tests auto-skip if GNU Global is absent
npx @modelcontextprotocol/inspector mcp-gtags-server    # poke at it interactively

Tests build a real C project in a temp dir and exercise auto-indexing, auto-refresh, caller mapping, body extraction, pagination, user-space binary discovery, and config layering end-to-end.

Correctness is also measured, not assumed: mcp-gtags-server eval --golden evals/golden.jsonl --root <kernel-tree> runs a 65-case golden set covering all 11 tools (definitions, macro resolution, references, callers, callees, bodies, guards, reachability, maintenance) against a real kernel and prints recall / precision@1 — CI does this weekly against a pinned tag. See docs/capability.md for the current numbers.

Release flow: bump version in pyproject.toml, tag vX.Y.Z, push — CI publishes to PyPI and users pick the update up on their next installer re-run. Prebuilt GNU Global binaries are rebuilt by tagging global-v<version> (or gh workflow run release-binaries.yml -f version=<version> to replace the assets of an existing release in place); Linux builds run inside manylinux_2_28 containers so they work on any glibc ≥ 2.28 host, enforced by a CI symbol-ceiling check.

Roadmap

See ROADMAP.md — structured JSON output landed in v0.8.0, ctags metadata enrichment (kind/signature/scope) in v0.8.1, #ifdef/config-guard awareness (the headline capability for kernel and firmware trees) in v0.9.0, then, all shipped in v1.0.0: macro-family symbol resolution (sys_read → its SYSCALL_DEFINE3 site), the agent workflow tools (reachability, blast_radius), automatic recovery from corrupted index databases, and the correctness eval harness — a 65-case golden set against pinned kernel v6.16 scoring 100% recall / 100% precision@1 in CI, with the measured writeup in docs/capability.md. Every technical milestone is done; what remains is distribution (MCP registry, directories, the writeup post).

Contributions welcome — open an issue or PR.

License

MIT © Harshith Sunku

Available Tools

11 tools
blast_radiusA

Which functions are impacted by a change? (refactoring blast radius)

Use this after editing or before merging: maps every line of git diff <git_ref> to its enclosing function via the index, then walks the caller graph outward. Ranked by distance — changed functions first, direct callers next. JSON results: {symbol, path, line, distance, via, call_sites} records.

Args: git_ref: Diff base for git diff (default HEAD = uncommitted changes; "HEAD~1" for the last commit, "main..." for a branch). depth: Caller levels to expand beyond the changed functions (0-3, default 1; 0 = just list the changed functions).

ParametersJSON Schema
NameRequiredDescriptionDefault
depthNo
limitNo
formatNojson
offsetNo
git_refNoHEAD
project_rootNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses the tool's behavior: it computes blast radius by analyzing git diff, mapping to functions, and walking the caller graph. It explains the ranked output structure (JSON fields). No side effects or destructive actions are implied. A score of 5 would require mention of auth needs or rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise (a few sentences and a bullet list) and front-loaded with the core question. Every sentence adds value, and the structure is easy to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 6 parameters and an output schema, the description explains the algorithm and two key parameters but omits details for format, limit, offset, and project_root. The output schema exists but is not detailed in the description, though the tool's JSON fields are partially listed. Completeness is adequate but has significant gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains git_ref (with examples) and depth (range and default), but does not describe limit, format, offset, or project_root. Thus, it adds meaning for only 2 of 6 parameters, leaving gaps.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Which functions are impacted by a change?' and explains it maps git diff to enclosing functions and walks the caller graph. This distinguishes it from sibling tools like find_callees and find_callers which are more direct without the diff analysis.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says 'Use this after editing or before merging', providing clear context. It also gives examples for the git_ref parameter, but does not explicitly exclude when not to use it or mention alternatives beyond the sibling tool list.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_calleesA

What functions does this function CALL? (the outgoing call graph)

Use this to see a function's dependencies without reading any file: call sites are detected in its body and verified against the index. Macro-generated and parser-missed (EXPORT_SYMBOL-recovered) definitions resolve too, flagged resolved_via. JSON results: {in_tree: [{symbol, path, line}], external: [names]}.

Args: symbol: Exact name of the function to analyze.

ParametersJSON Schema
NameRequiredDescriptionDefault
formatNojson
symbolYes
project_rootNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses that call sites are detected and verified against the index, that macro-generated and parser-missed definitions resolve (flagged as resolved_via), and provides the JSON output structure. However, it does not mention any side effects or potential failure modes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is relatively concise, front-loading the core purpose, and includes technical details efficiently. A minor trim could be made, but it is effective overall.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is complex, but the description covers the main behavioral aspects (resolution of macro-generated definitions) and output structure. An output schema exists, reducing the need to explain return values. However, it lacks information on prerequisites or error conditions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description only explains the 'symbol' parameter ('Exact name of the function to analyze'). It does not describe 'format' (enum with default) or 'project_root' (nullable), which are needed for full understanding. The description should compensate for the low schema coverage by explaining all parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'What functions does this function CALL? (the outgoing call graph)'. It also explicitly positions it as a way to see dependencies without reading files, differentiating it from siblings like 'find_callers' (incoming calls) and 'find_references'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a clear use case ('Use this to see a function's dependencies without reading any file') and notes that macro-generated definitions resolve, but it does not explicitly state when not to use this tool or compare it to alternatives like 'blast_radius' or 'reachability'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_callersA

Find the FUNCTIONS that call a symbol, deduplicated, with call counts.

Use this INSTEAD of find_references when you want the call graph rather than raw match lines: each reference is mapped to its enclosing function. The highest signal-to-noise "who uses this?" view; iterate it to walk the caller graph upward. JSON results: {caller, path, sites} items.

Args: symbol: Exact symbol name whose callers you want.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
formatNojson
offsetNo
symbolYes
project_rootNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Describes deduplication, call counts, and JSON result structure. No annotations exist, so the description effectively communicates read-only behavior. Mentions iterative use for walking the caller graph.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the main purpose, followed by usage note and parameter description. Two concise paragraphs with no irrelevant text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations and presence of siblings, the description covers key aspects: purpose, differentiation, and output format. Lacks details on error handling or performance, but adequate for a read-only query tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The 'symbol' parameter is well-defined ('Exact symbol name whose callers you want'). Other parameters (limit, format, etc.) are not described but have clear names and defaults in the schema. Schema coverage is 0%, so the description adds some value for the core parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description specifies the exact action: find functions that call a symbol, deduplicated with call counts. It clearly distinguishes from siblings like find_references and find_callees.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states to use this instead of find_references for call graph vs. raw match lines. Provides context on when it is appropriate, but does not explicitly mention when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_definitionA

Find where a C/C++ symbol (function, struct, macro, typedef, enum) is defined.

Use this INSTEAD of grep whenever you need a symbol's definition: an indexed lookup that returns only the definition site(s). Multiply-defined symbols (#ifdef alternates) carry each definition's guard stack. Macro-generated symbols resolve too: "sys_read", "trace_sched_switch", or a DEFINE_SPINLOCK/module_param name returns the generator invocation site (SYSCALL_DEFINE3(read, ...)), flagged resolved_via — no build needed. Definitions the index parser missed are recovered from their EXPORT_SYMBOL* site via ctags, flagged resolved_via "ctags:...". On a miss the envelope carries "suggestions": defined symbols starting with the queried name.

JSON records: {symbol, path, line, col, kind, typeref, scope, signature, guard, snippet} — kind/typeref/scope/signature are ctags metadata when available; guard is the enclosing #if/#ifdef stack, outermost first, [] = unconditional.

Args: symbol: Exact symbol name, e.g. "tcp_v4_rcv". case_insensitive: Match ignoring case. active_config: Kernel .config path or macro list like "CONFIG_SMP,BITS_PER_LONG=64,!CONFIG_DEBUG"; drops definitions whose guard stack is definitely false under it (count reported as config_filtered). Unknown macros never drop anything.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
formatNojson
offsetNo
symbolYes
project_rootNo
active_configNo
case_insensitiveNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description fully discloses behavioral traits: indexed lookup with fallback to ctags, handling of macros, multiple definitions with guard stacks, config filtering, and miss suggestions. It also explains the resolved_via flag and the JSON record structure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections (primary use, edge cases, output format, arguments). While comprehensive, it is slightly long but every sentence contributes value. Front-loaded with main purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of symbol lookup with multiple resolution strategies and edge cases, the description covers all necessary aspects: what tool does, what it returns (JSON fields), how it handles special cases (macros, multiple definitions, misses), and configuration filtering. The output schema is not provided externally but is fully described in text.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds significant meaning for three of seven parameters (symbol, case_insensitive, active_config) with examples and details. However, limit, format, offset, and project_root are not described, and the schema itself has 0% description coverage, so the description only partially compensates.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool 'Find where a C/C++ symbol is defined', specifying the verb (find), resource (definition of a C/C++ symbol), and lists supported symbol types (function, struct, macro, typedef, enum). It distinguishes itself from sibling tools like find_references by focusing exclusively on definitions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly advises to use this tool instead of grep for definitions, and explains behavior for multiply-defined symbols, macro-generated symbols, and miss handling with suggestions. It provides clear context on when to use the tool versus alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_referencesA

Find all call/usage sites of a C/C++ symbol.

Use this INSTEAD of grep for "who calls/uses this?": only real reference sites from the index, each with its #if/#ifdef guard stack. Symbols with no in-tree definition (libc calls, some variables) work too — the query falls back to symbol-usage records, flagged "fallback": "symbol_usages".

Args: symbol: Exact symbol name. case_insensitive: Match ignoring case. active_config: Kernel .config path or macro list; drops references whose guard stack is definitely false under it (config_filtered).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
formatNojson
offsetNo
symbolYes
project_rootNo
active_configNo
case_insensitiveNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses that results come from an index with #if guard stacks, and explains the fallback mechanism for symbols without definitions ('flagged as fallback'). This is detailed and honest.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and well-structured: a one-line purpose, a usage directive, technical behavior details, and a bullet-like parameter list. Every sentence adds value without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

While the description covers core functionality and uses the output schema (not needing return details), it omits several parameters and does not address sibling tool differentiation. For a tool with 7 parameters and 10 siblings, more completeness is expected.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 7 parameters, but the description only documents 3 (symbol, case_insensitive, active_config) with minimal detail. Parameters like limit, offset, format, and project_root are omitted entirely. Since schema coverage is 0%, the description should compensate but falls short.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the purpose: 'Find all call/usage sites of a C/C++ symbol.' It provides a specific verb and resource, and distinguishes from grep by saying 'Use this INSTEAD of grep'. This makes the tool's role unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit guidance on when to use this tool ('who calls/uses this?') and contrasts with grep. However, it does not address when to prefer sibling tools like find_callees or find_callers, which are listed in the context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_symbol_bodyA

Return the full source of a symbol's definition — just the body.

Use this INSTEAD of reading a whole file to see how a function, struct, or macro is implemented: it extracts only the definition's lines, so a one-screen function never costs a 5000-line file read. Macro-generated and parser-missed (EXPORT_SYMBOL-recovered) definitions resolve too, flagged resolved_via. JSON results: {path, line, body} items.

Args: symbol: Exact symbol name. max_definitions: Return at most this many bodies when the symbol is multiply defined (default 3).

ParametersJSON Schema
NameRequiredDescriptionDefault
formatNojson
symbolYes
project_rootNo
max_definitionsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses behavior: it extracts only definition lines, handles macro-generated and parser-missed definitions, flags them via 'resolved_via', and describes the JSON result structure. This provides rich context beyond what annotations typically cover.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise (5-6 sentences), front-loaded with the main purpose, and every sentence adds value: use case, behavior, edge cases, and result structure. No redundant or vague statements.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that there is an output schema (making return values partly documented), the description covers key behavioral traits and use cases adequately. However, it omits description for two parameters ('format' and 'project_root'), which slightly reduces completeness for an agent relying solely on the description.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It adds meaning for 'symbol' and 'max_definitions' (e.g., exact name, default 3), but does not explain 'format' or 'project_root', leaving them ambiguous. The description provides partial but not complete parameter information.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool returns the full source of a symbol's definition body, distinguishing it from reading entire files. The verb 'return' and resource 'symbol's definition body' are specific and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly advises using this tool instead of reading whole files, providing a clear use case (e.g., seeing implementation without cost). It implies when to use but does not contrast with sibling tools like find_definition or symbol_info, which could also serve related purposes.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_file_symbolsA

List every symbol defined in one source file.

Use this INSTEAD of reading a file when you only need its API surface — the functions, structs, and macros it defines — as a compact list with ctags metadata and #ifdef guard stacks when available.

Args: file_path: Source file, relative to the project root or absolute.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
formatNojson
offsetNo
file_pathYes
project_rootNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It discloses the output nature (compact list with ctags metadata and #ifdef guard stacks) and implies a read-only operation without side effects. However, it does not explicitly state that it is non-destructive or safe.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise (a few sentences) with the main purpose front-loaded. However, it could be more structured by grouping parameter details separately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Although an output schema exists, the description does not mention pagination parameters (limit, offset) or the format parameter, which are important for controlling the tool's behavior. The description only covers one of five parameters, leaving significant gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so description must compensate. Only the required 'file_path' is described in the Args section; optional parameters like limit, format, offset, and project_root are not explained. Their meaning and defaults are left to the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'List every symbol defined in one source file,' specifying a concrete verb and resource, and distinguishes the tool from reading the whole file by emphasizing the API surface aspect.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Use this INSTEAD of reading a file when you only need its API surface,' providing clear when-to-use guidance and contrasting with an alternative action.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

reachabilityA

Does FROM transitively call TO — and through which call chain?

Use this instead of chaining find_callers rounds when the question is "can this function end up in that one?". BFS over the caller graph returns the SHORTEST chain, each hop with the call site's file:line. JSON results: {path_found, hops, depth, nodes_explored}; hops run from from_symbol to to_symbol. Static analysis cannot follow function pointers (ops structs, callbacks).

Args: from_symbol: The caller end ("can this reach ..."). to_symbol: The callee end ("... this function?"). max_depth: Longest chain to consider, in calls (1-12, default 8).

ParametersJSON Schema
NameRequiredDescriptionDefault
formatNojson
max_depthNo
to_symbolYes
from_symbolYes
project_rootNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description fully describes the tool's behavior: BFS over caller graph, returns shortest chain, output structure, and static analysis limitations. It adds value beyond structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and front-loaded with the core question. Each sentence adds value, but the parameter list could be integrated more seamlessly. It is appropriately sized for a tool with 5 parameters.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the tool's purpose, usage, algorithm, output format, and limitations. Given the complexity (5 parameters, no annotations), it is fairly complete. The output schema is partially described, compensating for its absence.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds meaning to three key parameters (from_symbol, to_symbol, max_depth) beyond the schema. However, it does not describe the 'format' and 'project_root' parameters, which are also present. Schema coverage is 0%, so description partially compensates.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: checking if one symbol transitively calls another and finding the call chain. It explicitly distinguishes itself from sibling tools like find_callers by stating when to use it instead.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear guidance on when to use this tool ('instead of chaining find_callers rounds') and mentions a limitation (cannot follow function pointers). However, it does not explicitly list when not to use it or compare to all siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

summarize_referencesA

Per-file reference counts for a symbol — the cheapest wide view.

Use this FIRST for very widely used symbols (thousands of references): one line per file, sorted by count, shows where usage concentrates; then drill in with find_references or find_callers. JSON results: {path, count} items plus total_references.

Args: symbol: Exact symbol name.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
formatNojson
offsetNo
symbolYes
project_rootNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses it is a cheap, aggregated view and outlines the JSON result structure. However, with no annotations, it could further detail whether it is read-only or any side effects, but the description is reasonably transparent for a query tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise with two paragraphs; the first sentence captures the core purpose. The 'Args' line is slightly redundant with the schema, but the overall structure is effective and front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has no annotations but has an output schema, the description covers the output structure and usage context. However, parameter explanations are lacking for 4 of 5 parameters, and pagination behavior (offset/limit) is not clarified, leaving moderate gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%. The description only explains the required 'symbol' parameter ('Exact symbol name'). Other parameters (limit, offset, format, project_root) are not described, leaving significant gaps despite the tool having 5 parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it provides 'Per-file reference counts for a symbol' and positions itself as 'the cheapest wide view,' distinguishing it from sibling tools like find_references and find_callers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly advises to 'Use this FIRST for very widely used symbols' and then 'drill in with find_references or find_callers,' providing clear context and alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

symbol_infoA

One-shot overview card for a symbol — the best FIRST query.

One call returns where a symbol is defined, WHAT it is (kind, signature, scope), under WHICH #ifdef guards each definition lives (guard_variants

1 means the flat list is really a config choice), how widely it's used and where, plus the tool to use next. Macro-generated symbols resolve (resolved_via); definitions the index parser missed are recovered from their EXPORT_SYMBOL* site via ctags; kernel symbols report their EXPORT_SYMBOL* variant in "exported". JSON results: {definitions, definition_count, guard_variants, resolved_via, exported, reference_count, file_count, top_files}.

Args: symbol: Exact symbol name. active_config: Kernel .config path or macro list; definitions whose guard stack is definitely false under it are dropped (config_filtered).

ParametersJSON Schema
NameRequiredDescriptionDefault
formatNojson
symbolYes
project_rootNo
active_configNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so the description carries full burden. It discloses macro resolution, EXPORT_SYMBOL recovery, config filtering, and result structure. It does not mention side effects or rate limits but covers core behavior well.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single focused paragraph with key facts front-loaded. It is concise, but could benefit from clearer bullet structure for parameters.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (kernel symbols, macros, config filtering), the description covers essential behavior and output structure. However, it misses handling of missing symbols, error cases, and two parameters, leaving gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%; the description only explains 'symbol' and 'active_config' in detail, omitting 'format' (despite having an enum) and 'project_root'. This leaves half the parameters undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it is a 'one-shot overview card for a symbol — the best FIRST query,' specifying exactly what it returns (definitions, kind, guards, usage) and distinguishes it from sibling tools by recommending it as the initial query.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly positions itself as the 'best FIRST query' and mentions 'the tool to use next,' implying it precedes more specific tools like find_callees or find_callers. It lacks explicit when-not-to-use guidance but provides clear context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_indexA

Synchronously refresh the index — the guaranteed-freshness barrier.

Query tools refresh the index automatically in the background, so results can lag very recent edits by a few seconds. Call this right after editing files when the very next query must see the changes.

Args: full: Rebuild the index from scratch instead of refreshing it incrementally (rarely needed — large branch switch, suspected corruption).

ParametersJSON Schema
NameRequiredDescriptionDefault
fullNo
formatNojson
project_rootNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, description carries full burden. It discloses synchronous nature and the 'full' rebuild parameter, but lacks details on side effects, performance impact, or required permissions. Provides useful context about background refreshing but incomplete.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Description is relatively concise with 5 sentences and an Args section. Some metaphorical language ('guaranteed-freshness barrier') but overall efficient and well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given complexity and existence of output schema, description explains main purpose and one parameter. However, two parameters are undocumented, and no annotations exist. It is moderately complete for a simple tool but could be improved.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so description must compensate. Only the 'full' parameter is explained. The 'format' and 'project_root' parameters have no description, leaving their purpose unclear. Significant gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the tool synchronously refreshes the index for guaranteed freshness, contrasting with query tools that auto-refresh with lag. This distinct purpose is well-articulated and differentiates from all sibling query tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to call it right after editing files when the next query must see changes. It implies not to use when lag is acceptable, but doesn't explicitly state when not to use or provide alternative strategies.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 10 tool updatesv1.4.1
    • Removedcall_hierarchy
    • Removedcomplete_symbol
    • Removedfind_dead_symbols
    • Removedfind_files
    • Removedfind_includers
    • Removedfind_symbol_usages
    • Removedgrep_project
    • Removedindex_project
    • Removedproject_overview
    • Changedupdate_index1 field changed
      • addedInput schema / properties / full
        Added value: +{
        +  "default": false,
        +  "title": "Full",
        +  "type": "boolean"
        +}
  2. 5 tool updatesv1.1.0
    • Addedblast_radius
    • Changedfind_definition1 field changed
      • addedInput schema / properties / active_config
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Active Config"
        +}
    • Changedfind_references1 field changed
      • addedInput schema / properties / active_config
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Active Config"
        +}
    • Addedreachability
    • Changedsymbol_info1 field changed
      • addedInput schema / properties / active_config
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Active Config"
        +}
  3. 18 tool updatesv0.8.2
    • Changedcall_hierarchy1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedcomplete_symbol1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedfind_callees1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedfind_callers1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedfind_dead_symbols1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedfind_definition1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedfind_files1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedfind_includers1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedfind_references1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedfind_symbol_usages1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedget_symbol_body1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedgrep_project1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedindex_project1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedlist_file_symbols1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedproject_overview1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedsummarize_references1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedsymbol_info1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
    • Changedupdate_index1 field changed
      • addedInput schema / properties / format
        Added value: +{
        +  "default": "json",
        +  "enum": [
        +    "json",
        +    "text"
        +  ],
        +  "title": "Format",
        +  "type": "string"
        +}
  4. 18 tool updatesv0.4.0
    • First observedcall_hierarchy
    • First observedcomplete_symbol
    • First observedfind_callees
    • First observedfind_callers
    • First observedfind_dead_symbols
    • First observedfind_definition
    • First observedfind_files
    • First observedfind_includers
    • First observedfind_references
    • First observedfind_symbol_usages
    • First observedget_symbol_body
    • First observedgrep_project
    • First observedindex_project
    • First observedlist_file_symbols
    • First observedproject_overview
    • First observedsummarize_references
    • First observedsymbol_info
    • First observedupdate_index

TDQS

A4/5.0

Scored across 11 tools

Disambiguation4/5

Each tool has a clearly defined purpose, with distinct focuses: blast_radius on change impact, find_callees/find_callers on call graph, find_definition on definition sites, etc. Some slight overlap exists between blast_radius and reachability, but descriptions adequately differentiate them.

Naming Consistency4/5

All tool names use lowercase with underscores, predominantly following a verb_noun pattern (e.g., find_definition, list_file_symbols). A few names like blast_radius and reachability are noun phrases but still consistent with the underscore style.

Tool Count5/5

11 tools is well-suited for a code analysis server. Each tool serves a specific, non-redundant purpose, covering search, definitions, references, call graphs, impact analysis, and index management without being overwhelming.

Completeness4/5

The tool surface covers the core needs of static C/C++ analysis: definitions, references, callers/callees, symbol info, file symbols, and impact analysis. Missing features like direct file reading or documentation retrieval are minor gaps for the intended use case.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    A minimalist indexing tool that provides AI agents with semantic search and structural AST parsing for deep codebase understanding. It enables autonomous agents to navigate large codebases predictably using vector embeddings and native language server capabilities like definition and reference tracking.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides IDE-like code navigation and search for local repositories, enabling AI assistants to perform symbol search, trigram indexing, and semantic navigation.
    AGPL 3.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    Exposes type-aware code navigation and fast file search to AI agents via language servers, enabling definitions, references, symbols, and file lookup without reading entire codebases.
    1,301
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables LLM agents to efficiently understand and navigate a codebase by providing semantic search over symbols and a reference graph, replacing expensive grep/glob calls with structured tools like definition lookup, caller/callee queries, and change-impact analysis.
    2
    MIT