Repository navigation
0.10.0: two silent empty-result paths — tree format returns {} over MCP (default), and config get returns empty for all keys but auto_index #1522
Description
Two independent v0.10.0 bugs that share a failure shape: both return an empty result with a success status instead of either data or an error. Filing together because that shape is the actionable part — for an LLM client, "empty" and "nothing found" are indistinguishable, so both produce silent false conclusions rather than visible failures. Happy to split into two issues if you'd prefer.
Environment
codebase-memory-mcp 0.10.0,windows-amd64release zip- Windows 11 (26100), installed to a custom
--dir - MCP client: Claude Code (stdio)
- Project indexed with
--mode full,status: ready, 4770 nodes / 21837 edges,parse_partial: 0,skipped: 0
Bug 1 — format: "tree" returns bare {} over MCP (default format, so every naive call is affected)
search_graph and trace_path return an empty JSON object {} over the MCP transport whenever the output format is tree. Since tree is the default, an ordinary call with no format argument silently yields nothing. The identical query with format: "json" returns full, correct results, so the query engine and the index are fine — it looks isolated to the MCP-side tree encoder.
Critically, the same tree format renders correctly over the CLI, which is what localizes this to the MCP response path rather than the formatter itself.
Reproduction
Same binary, same index, same project, four consecutive calls:
| # | Call | Result |
|---|---|---|
| 1 | search_graph(project=P, name_pattern="_build_and_push_graph") — no format |
{} |
| 2 | search_graph(project=P, name_pattern="_build_and_push_graph", format="tree") |
{} |
| 3 | search_graph(project=P, name_pattern="_build_and_push_graph", format="json") |
correct, total: 2 |
| 4 | trace_path(project=P, function_name="similarity_edge_key", mode="calls", direction="inbound") — no format |
{} |
| 5 | same as 4 with format="json" |
correct, callers_total: 3 |
Call 3 output (abridged):
{"total":2,"count":2,"cols":["name","label","lines","in","out"],
"groups":[{"qn_prefix":"<project>.<pkg>.main","file":"<pkg>/main.py",
"rows":[["_build_and_push_graph","Function","1457-1936",6,66]]}],
"has_more":false}Call 5 output:
{"function":"similarity_edge_key","direction":"inbound","mode":"calls",
"callers_total":3,
"callers":{"cols":["name","hop"],"groups":[
{"qn_prefix":"<project>.<pkg>.graph.builder","rows":[["to_graphology_json",1]]},
{"qn_prefix":"<project>.<pkg>.main","rows":[["_build_and_push_graph",2]]}]}}CLI contrast — tree works here
$ codebase-memory-mcp cli search_graph --project <P> --name-pattern "_build_and_push_graph"
total: 2
results: 2 (rows: name label lines in out; qn = group prefix + "." + name)
<project>.<pkg>.main (<pkg>/main.py):
_build_and_push_graph Function 1457-1936 6 66
<project>.<pkg>.tests.test_exceptions (<pkg>/tests/test_exceptions.py):
test_r3_cache_key_construction_matches_build_and_push_graph_source Function 356-370 0 1
has_more: false
Explicit --format tree over the CLI is identical. So: CLI tree ✅, MCP tree ❌, MCP json ✅.
Why this one is worse than it looks
{} is indistinguishable from a genuine zero-result search. An agent following the server's own instructions ("use graph tools first for structural code discovery") will conclude a symbol has no callers, or does not exist, and fall back to grep or to an assumption — with no error anywhere to signal that the answer was wrong. The failure is silent, and it hits the default code path.
Suggested fix, in preference order: fix the MCP tree encoder; failing that, return an explicit error rather than {} when encoding yields nothing, so callers can distinguish "no matches" from "could not encode".
Bug 2 — config get returns empty with exit 0 for every key except auto_index
config get <key> prints a value only for auto_index. Every other valid key returns an empty string and exit code 0 — as does a deliberately invalid key, so a typo is indistinguishable from a correctly-read setting.
Reproduction
$ for k in auto_index auto_watch auto_index_limit ui-lang totally_bogus_key; do
printf '%-20s -> [%s] exit=%s\n' "$k" "$(codebase-memory-mcp config get $k)" "$?"
done
auto_index -> [true] exit=0
auto_watch -> [] exit=0
auto_index_limit -> [] exit=0
ui-lang -> [] exit=0
totally_bogus_key -> [] exit=0
config list reports all four correctly in the same session, so the values are stored and readable — it is the get path that drops them:
Configuration:
auto_index = true
auto_index_limit = 50000
auto_watch = true
ui-lang = auto
Expected: config get auto_watch prints true; an unknown key exits non-zero with an error naming the key.
Note on how these were found
Surfaced while verifying an 0.8.1 → 0.10.0 upgrade. Unrelated to both, but worth flagging in case others hit it during the same upgrade: every .db in the data dir had been left with an empty DACL on Windows (D:AI, zero ACEs), which made the daemon fail at startup with
level=error msg=daemon.runtime_config_open_failed reason=config_db_unavailable
level=error msg=daemon.start_failed component=application
while every client reported the misleading CBM daemon is active or starting but could not accept this client within 30000 ms — because the dead daemon left its lock files behind. I could not determine what stripped the ACLs and cannot attribute it to this project; files recreated by 0.10.0 get correct ACEs (SYSTEM full, logon-session read/execute, owner full), so this is not a reproducible bug report. The only suggestion worth making is that config_db_unavailable would be far easier to diagnose if it distinguished "permission denied" from "locked" and included the path.
Activity
DeusData commentedon Aug 10, 2026
Thank you again for the exceptionally clear report. We are treating this as critical because the default MCP path can return a silent empty success result. A fix is already actively in progress for the
0.10.1release, and we will update this thread once the regression tests and implementation are ready.fix(mcp): make every tool reply client-usable — structuredContent, pi…
fix(mcp): make every tool reply client-usable — structuredContent, pi…
Merge pull request #1523 from DeusData/fix/1522-silent-empty-results
DeusData commentedon Aug 11, 2026
Fixed on main in f59d24f (PR #1523, merge 367ba25) — shipping in v0.10.1, releasing now.
Thank you for an outstanding report, @Navier8. The format-by-format call tables localized the fault to the MCP response path before we had read a line of code, and both bugs reproduced exactly as described — plus your framing of the failure shape ("empty and success-status, indistinguishable from nothing-found") turned out to be the right lens: a verification sweep guided by it found a third bug of the same class (7+ pipelined requests killed the server with all buffered responses lost; fixed in the same PR).
What shipped for each of your findings:
outputSchema: tree-format replies carriedstructuredContent: {}while a declared schema tells spec-honoring clients thatstructuredContentis the result. It reproduced on every platform, not just Windows — your CLI-tree-works observation was the discriminating clue. Tools no longer declare anoutputSchema, object payloads keep their parsedstructuredContent, text payloads omit the key entirely, and both the unit suite and the shipped-binary smoke suite now assert a default-format reply can never render as{}.config getnow prints the stored value or the key's real runtime default, and unknown keys exit non-zero naming the known keys, onget,set, andresetalike.On the DACL note: not reproducible from our side either, but the misattributed
config_db_unavailablediagnosis you suggested is a good one — distinguishing permission-denied from locked, with the path included, is on the follow-up list.The v0.10.1 release notes credit this report prominently. Thanks again — reports of this quality are rare and genuinely move the project.
DeusData commentedon Aug 11, 2026
v0.10.1 is released with all fixes — https://github.com/DeusData/codebase-memory-mcp/releases/tag/v0.10.1 (GitHub archives, npm, and PyPI are all serving it).
Verified end-to-end on the shipped binaries, from the seat of a real MCP client (Claude Code):
search_graph/trace_path/query_graph/get_architecture/search_code/detect_changeson the default tree format all render full results — no more{}. No tool declares anoutputSchemaanymore; text payloads carry nostructuredContentkey at all, object payloads keep the parsed form.config getreturns stored-or-default values, and unknown keys exit 1 naming the known keys, onget/set/resetalike.All three contracts are pinned by unit tests, a frontend-queue test, a CLI contract test, and shipped-binary smoke phases that drive the real artifact the way a schema-honoring client does — each verified red against v0.10.0 before the fix.
@Navier8 — if v0.10.1 behaves in your setup, feel free to close this out (or tell us what still looks off and we'll jump on it). Thanks again for the report that started all of this; the release notes credit it in full.
github-actions commentedon Aug 11, 2026
Thanks for the report! To move this forward we need a bit more so we can reproduce it ourselves:
codebase-memory-mcp --versionyou're onOnce that's here we'll pick it straight back up. Heads-up: issues left
awaiting-reporterare automatically closed after a few weeks of silence, but a comment reopens the door anytime.DeusData commentedon Aug 11, 2026
Small housekeeping note: please ignore the bot's boilerplate above asking for version/steps — that's our label automation misfiring on this thread (a process bug on our side, noted). Nothing more is needed from you unless v0.10.1 misbehaves in your setup.
feat(config): add watcher_enabled master switch for the background wa…
feat(config): add watcher_enabled master switch for the background wa…