fix(mcp): Run bd commands in user's working directory
The MCP server was running bd commands from the plugin installation directory, causing the database to be created in the wrong place. Added BEADS_WORKING_DIR config option and modified BdClient to use working directory for subprocess calls. Falls back to PWD environment variable. This ensures bd commands run from the user's actual project directory. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,7 @@ Then use in Claude Desktop config:
|
||||
**Environment Variables** (all optional):
|
||||
- `BEADS_PATH` - Path to bd executable (default: `~/.local/bin/bd`)
|
||||
- `BEADS_DB` - Path to beads database file (default: auto-discover from cwd)
|
||||
- `BEADS_WORKING_DIR` - Working directory for bd commands (default: `$PWD` or current directory)
|
||||
- `BEADS_ACTOR` - Actor name for audit trail (default: `$USER`)
|
||||
- `BEADS_NO_AUTO_FLUSH` - Disable automatic JSONL sync (default: `false`)
|
||||
- `BEADS_NO_AUTO_IMPORT` - Disable automatic JSONL import (default: `false`)
|
||||
|
||||
@@ -76,6 +76,7 @@ class BdClient:
|
||||
actor: str | None
|
||||
no_auto_flush: bool
|
||||
no_auto_import: bool
|
||||
working_dir: str | None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -84,6 +85,7 @@ class BdClient:
|
||||
actor: str | None = None,
|
||||
no_auto_flush: bool | None = None,
|
||||
no_auto_import: bool | None = None,
|
||||
working_dir: str | None = None,
|
||||
):
|
||||
"""Initialize bd client.
|
||||
|
||||
@@ -93,6 +95,7 @@ class BdClient:
|
||||
actor: Actor name for audit trail (optional, loads from config if not provided)
|
||||
no_auto_flush: Disable automatic JSONL sync (optional, loads from config if not provided)
|
||||
no_auto_import: Disable automatic JSONL import (optional, loads from config if not provided)
|
||||
working_dir: Working directory for bd commands (optional, loads from config/env if not provided)
|
||||
"""
|
||||
config = load_config()
|
||||
self.bd_path = bd_path if bd_path is not None else config.beads_path
|
||||
@@ -104,6 +107,18 @@ class BdClient:
|
||||
self.no_auto_import = (
|
||||
no_auto_import if no_auto_import is not None else config.beads_no_auto_import
|
||||
)
|
||||
self.working_dir = working_dir if working_dir is not None else config.beads_working_dir
|
||||
|
||||
def _get_working_dir(self) -> str:
|
||||
"""Get working directory for bd commands.
|
||||
|
||||
Returns:
|
||||
Working directory path, falls back to current directory if not configured
|
||||
"""
|
||||
if self.working_dir:
|
||||
return self.working_dir
|
||||
# Fall back to PWD environment variable or current directory
|
||||
return os.environ.get("PWD", os.getcwd())
|
||||
|
||||
def _global_flags(self) -> list[str]:
|
||||
"""Build list of global flags for bd commands.
|
||||
@@ -142,7 +157,7 @@ class BdClient:
|
||||
*cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
cwd=os.getcwd(),
|
||||
cwd=self._get_working_dir(),
|
||||
)
|
||||
stdout, stderr = await process.communicate()
|
||||
except FileNotFoundError as e:
|
||||
@@ -186,7 +201,7 @@ class BdClient:
|
||||
"version",
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
cwd=os.getcwd(),
|
||||
cwd=self._get_working_dir(),
|
||||
)
|
||||
stdout, stderr = await process.communicate()
|
||||
except FileNotFoundError as e:
|
||||
@@ -399,7 +414,7 @@ class BdClient:
|
||||
*cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
cwd=os.getcwd(),
|
||||
cwd=self._get_working_dir(),
|
||||
)
|
||||
_stdout, stderr = await process.communicate()
|
||||
except FileNotFoundError as e:
|
||||
@@ -427,7 +442,7 @@ class BdClient:
|
||||
*cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
cwd=os.getcwd(),
|
||||
cwd=self._get_working_dir(),
|
||||
)
|
||||
stdout, stderr = await process.communicate()
|
||||
except FileNotFoundError as e:
|
||||
@@ -494,7 +509,7 @@ class BdClient:
|
||||
*cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
cwd=os.getcwd(),
|
||||
cwd=self._get_working_dir(),
|
||||
)
|
||||
stdout, stderr = await process.communicate()
|
||||
except FileNotFoundError as e:
|
||||
|
||||
@@ -36,6 +36,7 @@ class Config(BaseSettings):
|
||||
beads_actor: str | None = None
|
||||
beads_no_auto_flush: bool = False
|
||||
beads_no_auto_import: bool = False
|
||||
beads_working_dir: str | None = None
|
||||
|
||||
@field_validator("beads_path")
|
||||
@classmethod
|
||||
@@ -132,6 +133,7 @@ def load_config() -> Config:
|
||||
+ "Advanced configuration (optional):\n"
|
||||
+ f" BEADS_PATH - Path to bd executable (default: {default_path})\n"
|
||||
+ " BEADS_DB - Path to beads database file (default: auto-discover)\n"
|
||||
+ " BEADS_WORKING_DIR - Working directory for bd commands (default: $PWD or cwd)\n"
|
||||
+ " BEADS_ACTOR - Actor name for audit trail (default: $USER)\n"
|
||||
+ " BEADS_NO_AUTO_FLUSH - Disable automatic JSONL sync (default: false)\n"
|
||||
+ " BEADS_NO_AUTO_IMPORT - Disable automatic JSONL import (default: false)"
|
||||
|
||||
Reference in New Issue
Block a user