You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
v0.9.0: #ifdef/config-guard awareness — the headline capability
Roadmap milestone 3. Kernel and firmware code defines the same symbol
multiple times under #if/#ifdef and lets the build config pick one; no
other no-build tool tells an agent which definition is live. Now every
definition-shaped result carries its enclosing conditional stack, and
results can be filtered by an actual kernel .config.
- New gtags_mcp.guards module: pure-Python preprocessor-directive
scanner (comment-aware, continuation-aware, include-guard
suppression, #elif chains composed into explicit conditions), a
kernel .config / macro-list parser with kbuild autoconf semantics
(=m defines CONFIG_X_MODULE; IS_ENABLED/IS_BUILTIN/IS_MODULE), and a
tri-state expression evaluator. Stat-validated LRU cache (4096
entries — active_config scans every file a hot symbol touches).
- The guard record field reserved in v0.8.0 is now live: a list of
conditions outermost-first ([] = unconditional, null = disabled).
Attached on find_definition, find_references, list_file_symbols, and
symbol_info.
- symbol_info explains multiply-defined symbols: "N definitions under
M distinct guards", each with a [CONFIG_X] prefix; new guard_variants
JSON key.
- active_config on find_definition/find_references/symbol_info: a
.config path or macro list ("CONFIG_SMP,!CONFIG_DEBUG") drops results
whose guard stack is DEFINITELY false — unknown macros never drop
anything; drop count reported as config_filtered (filtering runs
pre-pagination so totals stay honest).
- Opt out with --no-guards, GTAGS_MCP_GUARDS=0, or guards = false;
doctor reports guard-scanning status.
Verified on the Linux kernel: kmap resolves to its CONFIG_HIGHMEM /
!CONFIG_HIGHMEM alternates, __efiapi's 3-way #elif chain composes
correctly, a mini .config narrows both to the live definition, and
include-guard suppression keeps ordinary headers noise-free.
81 new tests (178 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|`symbol_info`|**A one-shot overview card** — definitions (with kind, signature, and scope), reference count, hottest files, and which tool to use next. The best first query for any unfamiliar symbol. |
182
+
|`symbol_info`|**A one-shot overview card** — definitions (with kind, signature, scope, and `#ifdef` guard), reference count, hottest files, and which tool to use next. Multiply-defined symbols are explained as "N definitions under M distinct guards". The best first query for any unfamiliar symbol. |
182
183
|`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. |
183
184
|`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. |
184
185
|`call_hierarchy`|**Multi-level impact analysis.** Who calls X, who calls *those*, up to 5 levels — a cycle-safe, capped tree instead of N rounds of grep. |
@@ -225,19 +226,52 @@ Since v0.8.0 every tool returns a **machine-readable JSON envelope by default**
- 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.`guard` (`#ifdef` stack) is reserved for an upcoming milestone and currently `null`.
240
+
- 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.
240
241
-**`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`.
242
+
-**`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.
243
+
244
+
### `#ifdef`-aware: know which definition your config actually compiles
245
+
246
+
Kernel and firmware code defines the same symbol multiple times and lets the
247
+
build configuration pick one. Every other no-build tool returns a flat,
248
+
unexplained list — an agent happily reads the no-op stub of `kmap` and
249
+
reasons its way to a wrong answer. This server reads the preprocessor
250
+
conditionals (pure scanning — still no build, no `compile_commands.json`):
251
+
252
+
```text
253
+
Symbol: kmap
254
+
2 definitions under 2 distinct guards:
255
+
[CONFIG_HIGHMEM] defined at include/linux/highmem-internal.h:40 — function kmap(struct page * page) -> void *
256
+
[!CONFIG_HIGHMEM] defined at include/linux/highmem-internal.h:170 — function kmap(struct page * page) -> void *
257
+
```
258
+
259
+
Pass `active_config` — a kernel `.config` path or a macro list like
260
+
`"CONFIG_SMP,BITS_PER_LONG=64,!CONFIG_DEBUG"` — to `find_definition`,
261
+
`find_references`, or `symbol_info`, and definitions whose guard stack is
262
+
**definitely false** under it are dropped (the envelope reports the count as
263
+
`config_filtered`). Filtering is deliberately conservative: a `.config` is a
264
+
closed world for `CONFIG_*` macros (kbuild semantics, including
265
+
`=m` → `CONFIG_X_MODULE` and `IS_ENABLED`/`IS_BUILTIN`/`IS_MODULE`), but
266
+
anything unknown (`__ASSEMBLY__`, `ARCH_HAS_*`, arithmetic it can't decide)
267
+
never drops a result.
268
+
269
+
The details are handled so the output stays clean: classic include guards
270
+
(`#ifndef FOO_H`) are detected and suppressed, `#elif` chains compose into
271
+
explicit conditions (`!CONFIG_X86_64 && CONFIG_X86_32`), comments on
272
+
directives are ignored (they lie), and broken/partial files never fail a
273
+
query. Disable with `--no-guards`, `GTAGS_MCP_GUARDS=0`, or `guards = false`
274
+
in `.gtags-mcp.toml`.
241
275
-`next_tools` tells the agent the highest-value follow-up call for what was (or wasn't) found.
242
276
-`total`/`offset`/`truncated` replace the text continuation footer; errors keep the envelope with an `error` field.
243
277
- Composite tools return tool-shaped `results` (e.g. `call_hierarchy` a nested caller tree, `find_callees``{in_tree, external}`, `symbol_info` an overview object) inside the same envelope.
@@ -328,10 +362,11 @@ Release flow: bump `version` in `pyproject.toml`, tag `vX.Y.Z`, push — CI publ
328
362
329
363
## Roadmap
330
364
331
-
See [ROADMAP.md](ROADMAP.md) — structured JSON output landed in v0.8.0 and ctags
332
-
metadata enrichment (kind/signature/scope on every definition) in v0.8.1; next up are
333
-
`#ifdef`/config-guard awareness (the headline capability for kernel and firmware
334
-
trees), macro-family symbol resolution, and a correctness eval harness.
365
+
See [ROADMAP.md](ROADMAP.md) — structured JSON output landed in v0.8.0, ctags
366
+
metadata enrichment (kind/signature/scope) in v0.8.1, and `#ifdef`/config-guard
367
+
awareness (the headline capability for kernel and firmware trees) in v0.9.0;
368
+
next up are macro-family symbol resolution, agent workflow tools
369
+
(`reachability`, `blast_radius`), and a correctness eval harness.
Copy file name to clipboardExpand all lines: pyproject.toml
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
[project]
2
2
name = "mcp-gtags-server"
3
-
version = "0.8.2"
3
+
version = "0.9.0"
4
4
description = "Indexed code navigation for AI coding agents — replace grep scans with GNU Global (gtags) lookups over MCP. ~100x faster and radically less noise on million-line C/C++ codebases."
0 commit comments