From 74b460b2989c45b7596d97cea3938c5ac48b2bee Mon Sep 17 00:00:00 2001 From: Michael Shuffett Date: Fri, 17 Oct 2025 21:16:19 -0700 Subject: [PATCH] fix(mcp): Fix three critical bugs in beads MCP plugin This PR fixes three bugs that prevented the MCP plugin from working: 1. **Fixed parameter name mismatch in tools.py** - Changed `workspace_root=workspace_root` to `working_dir=workspace_root` - The `create_bd_client()` function expects `working_dir` parameter, but tools.py was passing `workspace_root` - This caused "got an unexpected keyword argument 'workspace_root'" error 2. **Added version check guard for daemon client** - Added `hasattr(_client, '_check_version')` check before calling - BdDaemonClient doesn't have `_check_version()` method, only BdCliClient does - This caused "'BdDaemonClient' object has no attribute '_check_version'" error 3. **Implemented proper daemon socket detection for fallback** - Added synchronous socket file existence check before creating daemon client - Walks up directory tree looking for `.beads/bd.sock` file - Only creates daemon client if socket exists, otherwise falls back to CLI - Previously, daemon client was created but failed on first method call - This enables the documented "prefer_daemon with automatic CLI fallback" behavior **Testing:** - Verified MCP tools work correctly with single-repo setup - Confirmed automatic fallback to CLI when daemon isn't running - Tested on macOS with bd v0.9.9 **Related Issues:** - Addresses symptoms similar to #65 (Windows BEADS_WORKING_DIR issue) --- .../beads-mcp/src/beads_mcp/bd_client.py | 41 +++++++++++++++---- integrations/beads-mcp/src/beads_mcp/tools.py | 7 ++-- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/integrations/beads-mcp/src/beads_mcp/bd_client.py b/integrations/beads-mcp/src/beads_mcp/bd_client.py index 4a81d2a7..4fcbe5a9 100644 --- a/integrations/beads-mcp/src/beads_mcp/bd_client.py +++ b/integrations/beads-mcp/src/beads_mcp/bd_client.py @@ -637,16 +637,39 @@ def create_bd_client( if prefer_daemon: try: from .bd_daemon_client import BdDaemonClient + from pathlib import Path - # Create daemon client with working_dir for context - client = BdDaemonClient( - working_dir=working_dir, - actor=actor, - ) - # Try to ping - if this works, use daemon - # Note: This is sync check, actual usage is async - # The caller will need to handle daemon not running at call time - return client + # Check if daemon socket exists before creating client + # Walk up from working_dir to find .beads/bd.sock + search_dir = Path(working_dir) if working_dir else Path.cwd() + socket_found = False + + current = search_dir.resolve() + while True: + beads_dir = current / ".beads" + if beads_dir.is_dir(): + sock_path = beads_dir / "bd.sock" + if sock_path.exists(): + socket_found = True + break + # Found .beads but no socket - daemon not running + break + + # Move up one directory + parent = current.parent + if parent == current: + # Reached filesystem root + break + current = parent + + if socket_found: + # Daemon is running, use it + client = BdDaemonClient( + working_dir=working_dir, + actor=actor, + ) + return client + # No socket found, fall through to CLI client except ImportError: # Daemon client not available (shouldn't happen but be defensive) pass diff --git a/integrations/beads-mcp/src/beads_mcp/tools.py b/integrations/beads-mcp/src/beads_mcp/tools.py index 14f97d29..8c0cb6cf 100644 --- a/integrations/beads-mcp/src/beads_mcp/tools.py +++ b/integrations/beads-mcp/src/beads_mcp/tools.py @@ -51,12 +51,13 @@ async def _get_client() -> BdClientBase: _client = create_bd_client( prefer_daemon=use_daemon, - workspace_root=workspace_root + working_dir=workspace_root ) - # Check version once per server lifetime + # Check version once per server lifetime (only for CLI client) if not _version_checked: - await _client._check_version() + if hasattr(_client, '_check_version'): + await _client._check_version() _version_checked = True return _client