mcp-beads 0.30.3
MCP server for beads issue tracker.
Requires Python: >=3.10
Keywords: beads, mcp, claude, issue-tracker, ai-agent, model-context-protocol

# mcp-beads

MCP server for [beads](https://github.com/shaneholloman/beads) issue tracker and agentic memory system.
Enables AI agents to manage tasks using beads CLI through Model Context Protocol.

## Installing

### Option 1: Using uvx (Recommended)

No installation required - UV runs it on-demand:

```json
{
  "mcpServers": {
    "beads": {
      "command": "uvx",
      "args": ["mcp-beads"]
    }
  }
}
```

**Benefits:**

- No global installation needed
- Always uses latest version (or pin with `uvx mcp-beads@0.30.0`)
- UV handles caching automatically

### Option 2: Using uv tool install

Install permanently to PATH:

```sh
uv tool install mcp-beads
```

Then configure Claude Desktop:

```json
{
  "mcpServers": {
    "beads": {
      "command": "mcp-beads"
    }
  }
}
```

### Option 3: Development Installation

For development, clone the repository:

```sh
git clone https://github.com/shaneholloman/beads
cd beads/adapters/mcp
uv sync
```

Then use in Claude Desktop config:

```json
{
  "mcpServers": {
    "beads": {
      "command": "uv",
      "args": [
        "--directory",
        "/path/to/mcp-beads",
        "run",
        "mcp-beads"
      ]
    }
  }
}
```

**Environment Variables** (all optional):

- `BEADS_USE_DAEMON` - Use daemon RPC instead of CLI (default: `1`, set to `0` to disable)
- `BEADS_PATH` - Path to beads executable (default: `~/.local/bin/beads`)
- `BEADS_DB` - Path to beads database file (default: auto-discover from cwd)
- `BEADS_WORKING_DIR` - Working directory for beads commands (default: `$PWD` or current directory). Used for multi-repo setups - see below
- `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`)

## Multi-Repository Setup

**Recommended:** Use a single MCP server instance for all beads projects - it automatically routes to per-project local daemons.

### Single MCP Server (Recommended)

**Simple config - works for all projects:**

```json
{
  "mcpServers": {
    "beads": {
      "command": "mcp-beads"
    }
  }
}
```

**How it works (LSP model):**

1. MCP server checks for local daemon socket (`.beads/beads.sock`) in your current workspace
2. Routes requests to the **per-project daemon** based on working directory
3. Auto-starts the local daemon if not running
4. **Each project gets its own isolated daemon** serving only its database

**Architecture:**

```txt
MCP Server (one instance)
    ↓
Per-Project Daemons (one per workspace)
    ↓
SQLite Databases (complete isolation)
```

**Why per-project daemons?**

- ✔ Complete database isolation between projects
- ✔ No cross-project pollution or git worktree conflicts
- ✔ Simpler mental model: one project = one database = one daemon
- ✔ Follows LSP (Language Server Protocol) architecture
- ✔ One MCP config works for unlimited projects

**Note:** Global daemon support was removed in v0.16.0 to prevent cross-project database pollution.

### Alternative: Per-Project MCP Instances (Not Recommended)

Configure separate MCP servers for specific projects using `BEADS_WORKING_DIR`:

```json
{
  "mcpServers": {
    "beads-webapp": {
      "command": "mcp-beads",
      "env": {
        "BEADS_WORKING_DIR": "/Users/yourname/projects/webapp"
      }
    },
    "beads-api": {
      "command": "mcp-beads",
      "env": {
        "BEADS_WORKING_DIR": "/Users/yourname/projects/api"
      }
    }
  }
}
```

**WARNING: Problem**: AI may select the wrong MCP server for your workspace, causing commands to operate on the wrong database. Use single MCP server instead.

## Multi-Project Support

The MCP server supports managing multiple beads projects in a single session using per-request workspace routing.

### Using `workspace_root` Parameter

Every tool accepts an optional `workspace_root` parameter for explicit project targeting:

```python
# Query issues from different projects concurrently
results = await asyncio.gather(
    beads_ready_work(workspace_root="/Users/you/project-a"),
    beads_ready_work(workspace_root="/Users/you/project-b"),
)

# Create issue in specific project
await beads_create_issue(
    title="Fix auth bug",
    priority=1,
    workspace_root="/Users/you/project-a"
)
```

### Architecture

**Connection Pool**: The MCP server maintains a connection pool keyed by canonical workspace path:

- Each workspace gets its own daemon socket connection
- Paths are canonicalized (symlinks resolved, git toplevel detected)
- Concurrent requests use `asyncio.Lock` to prevent race conditions
- No LRU eviction (keeps all connections open for session)

**ContextVar Routing**: Per-request workspace context is managed via Python's `ContextVar`:

- Each tool call sets the workspace for its duration
- Properly isolated for concurrent calls (no cross-contamination)
- Falls back to `BEADS_WORKING_DIR` if `workspace_root` not provided

**Path Canonicalization**:

- Symlinks are resolved to physical paths (prevents duplicate connections)
- Git submodules with `.beads` directories use local context
- Git toplevel is used for non-initialized directories
- Results are cached for performance

### Backward Compatibility

The `set_context()` tool still works and sets a default workspace:

```python
# Old way (still supported)
await set_context(workspace_root="/Users/you/project-a")
await beads_ready_work()  # Uses project-a

# New way (more flexible)
await beads_ready_work(workspace_root="/Users/you/project-a")
```

### Concurrency Gotchas

**WARNING: IMPORTANT**: Tool implementations must NOT spawn background tasks using `asyncio.create_task()`.

**Why?** ContextVar doesn't propagate to spawned tasks, which can cause cross-project data leakage.

**Solution**: Keep all tool logic synchronous or use sequential `await` calls.

### Troubleshooting

**Symlink aliasing**: Different paths to same project are deduplicated automatically via `realpath`.

**Submodule handling**: Submodules with their own `.beads` directory are treated as separate projects.

**Stale sockets**: Currently no health checks. Phase 2 will add retry-on-failure if monitoring shows need.

**Version mismatches**: Daemon version is auto-checked since v0.16.0. Mismatched daemons are automatically restarted.

## Features

**Resource:**

- `beads://quickstart` - Quickstart guide for using beads

**Tools (all support `workspace_root` parameter):**

- `init` - Initialize beads in current directory
- `create` - Create new issue (bug, feature, task, epic, chore)
- `list` - List issues with filters (status, priority, type, assignee)
- `ready` - Find tasks with no blockers ready to work on
- `show` - Show detailed issue info including dependencies
- `update` - Update issue (status, priority, design, notes, etc). Note: `status="closed"` or `status="open"` automatically route to `close` or `reopen` tools to respect approval workflows
- `close` - Close completed issue
- `dep` - Add dependency (blocks, related, parent-child, discovered-from)
- `blocked` - Get blocked issues
- `stats` - Get project statistics
- `reopen` - Reopen a closed issue with optional reason
- `set_context` - Set default workspace for subsequent calls (backward compatibility)
- `where_am_i` - Show current workspace context and database path
- `debug_env` - Debug tool to show environment and working directory information

## Development

Run MCP inspector:

```sh
# inside mcp-beads dir
uv run fastmcp dev src/beads_mcp/server.py
```

Type checking:

```sh
uv run ty check src/
```

Linting and formatting:

```sh
uv run ruff check src/beads_mcp
uv run ruff format src/beads_mcp
```

## Testing

Run all tests:

```sh
uv run pytest
```

With coverage:

```sh
uv run pytest --cov=beads_mcp tests/
```

Test suite includes both mocked unit tests and integration tests with real `beads` CLI.

### Multi-Repo Integration Test

Test daemon RPC with multiple repositories:

```sh
# Start the daemon first
cd /path/to/beads
./beads daemon start

# Run multi-repo test
cd adapters/mcp
uv run test_multi_repo.py
```

This test verifies that the daemon can handle operations across multiple repositories simultaneously using per-request context routing.