fix(mcp): detect Dolt-backed projects in workspace discovery (GH#2997)#3207
fix(mcp): detect Dolt-backed projects in workspace discovery (GH#2997)#3207maphew wants to merge 2 commits intogastownhall:mainfrom
Conversation
The MCP `context()` tool reported "Database: Not found" for embedded Dolt projects because `_find_beads_db()` and `_find_beads_db_in_tree()` only globbed for `*.db` files. Embedded Dolt projects keep their data under `.beads/embeddeddolt/` and declare the backend in `.beads/metadata.json` — there is no `*.db` file to find. Adds `_has_beads_project_files()` mirroring Go's `hasBeadsProjectFiles` (metadata.json, config.yaml, dolt/, embeddeddolt/, or non-backup *.db). Both Python discovery functions (and `.beads/redirect` validation) now use this check, so SQLite, embedded Dolt, and server Dolt projects are all recognized. `context()` now reports the project root and backend when no SQLite db is present, instead of the misleading "Not found".
maphew
left a comment
There was a problem hiding this comment.
Code Review: fix(mcp): detect Dolt-backed projects in workspace discovery
Good work — _has_beads_project_files correctly mirrors Go's hasBeadsProjectFiles, the tools.py refactoring is clean, and the 5 new tests are thorough. Three bugs to address:
1. 🔴 Bug (high) — _detect_backend crashes on malformed metadata.json
File: server.py L290-300
json.load() can return any JSON type ([], "string", 42). The subsequent meta.get("backend") throws AttributeError which is not caught by the except (OSError, ValueError, json.JSONDecodeError) clause, crashing the MCP server.
Fix:
try:
with open(metadata_path) as f:
meta = json.load(f)
if not isinstance(meta, dict):
meta = {}
backend = (meta.get("backend") or meta.get("database") or "").lower()2. 🟡 Bug (medium) — _find_beads_project doesn't follow .beads/redirect
File: server.py L256-278
This function duplicates the upward directory walk from _find_beads_db_in_tree (in tools.py) but skips redirect handling. Worktree setups that rely on .beads/redirect will fail — _context_set won't find the project even though the existing _find_beads_db_in_tree would.
Fix: Remove _find_beads_project entirely. In _context_set, call the already-robust _find_beads_db_in_tree(resolved_root) to get the project root, then derive the backend:
project_root = _find_beads_db_in_tree(resolved_root)
if project_root is None:
# ... "Not found" path ...
backend = _detect_backend(os.path.join(project_root, ".beads"))This eliminates the duplicated walk and inherits redirect + symlink support for free.
3. 🟡 Bug (medium) — SQLite fallthrough when .db file is missing
File: server.py L703-721
When _detect_backend returns "sqlite" (e.g. metadata.json declares it) but no .db file exists yet, _find_beads_db(project_root) returns None. The code falls out of the if db_path: block and into the Dolt/unknown path, reporting:
Context set successfully:
Project: /path/.beads (backend: sqlite)
…instead of the expected "Database: Not found (run context(action='init') to create)" message.
Fix: Add an else clause:
if backend == "sqlite":
db_path = _find_beads_db(project_root)
if db_path:
_workspace_context["BEADS_DB"] = db_path
os.environ["BEADS_DB"] = db_path
return (
f"Context set successfully:\n"
f" Workspace root: {resolved_root}\n"
f" Database: {db_path}"
)
else:
_workspace_context.pop("BEADS_DB", None)
os.environ.pop("BEADS_DB", None)
return (
f"Context set successfully:\n"
f" Workspace root: {resolved_root}\n"
f" Database: Not found (run context(action='init') to create)"
)Note (pre-existing, not from this PR)
test_compaction_config.py has hardcoded macOS paths (/Users/stevey/src/dave/beads/...) that fail on non-macOS environments.
Tests and _has_beads_project_files logic look solid. With these three fixes the PR should be good to merge. 👍
…ect support Addresses review item #2: _find_beads_project duplicated the upward directory walk but skipped .beads/redirect handling. Now delegates to _find_beads_db_in_tree, inheriting redirect, symlink, and all backend detection for free. Amp-Thread-ID: https://ampcode.com/threads/T-019d84e2-3a96-7263-a399-c3b2cc0ba6bb Co-authored-by: Amp <amp@ampcode.com>
Summary
Fixes #2997 — MCP
context()tool reported "Database: Not found" for embedded Dolt projects because workspace discovery only globbed for*.dbfiles. Embedded Dolt has no*.db; data lives at.beads/embeddeddolt/and the backend is declared in.beads/metadata.json._has_beads_project_files()mirroring Go'shasBeadsProjectFiles(checksmetadata.json,config.yaml,dolt/,embeddeddolt/, or non-backup*.db)_find_beads_db_in_tree()and.beads/redirectvalidation now recognise SQLite, embedded Dolt, and server Dolt_find_beads_project()+_detect_backend()inserver.py;context()reportsProject: ... (backend: dolt-embedded)instead of the misleading "Not found" for Dolt projectsTest plan
test_workspace_auto_detect.pytests passtest_workspace_auto_detect,test_multi_project_switching,test_lifecycle,test_tools,test_worktree_separate_dbs)context_set()returns correct output for both Dolt-embedded and SQLite workspaces🤖 Generated with Claude Code