# Bitbucket MCP Server

A FastMCP server for managing Pull Requests on Bitbucket Cloud. Create, list, view, update, and review PRs directly from Claude.

## Features

- Create PRs with automatic default reviewer support
- List and view PR details
- Update PR title, description, destination branch, and reviewers
- Approve, unapprove, or request changes on PRs
- Add comments to PRs
- List workspace members for reviewer selection

## Installation

### From PyPI (Recommended)

```bash
pip install bitbucket-mcp
```

Or run directly with uvx (no install needed):

```bash
uvx bitbucket-mcp
```

## Getting an API Token

1. Go to [Atlassian API Tokens](https://id.atlassian.com/manage-profile/security/api-tokens)
2. Click **Create API token**
3. Give it a name (e.g., "Bitbucket MCP")
4. Copy the generated token

## Configuration

### Option 1: Interactive Setup (Recommended)

Use the `setup_bitbucket` tool:

```
setup_bitbucket(
    workspace="your-workspace",
    username="your-email@example.com",
    api_token="your-api-token"
)
```

This stores credentials securely in `~/.bitbucket-mcp/config.json` with 600 permissions.

### Option 2: Environment Variables

```bash
export BITBUCKET_API_TOKEN="your-api-token"
export BITBUCKET_USERNAME="your-email@example.com"
export BITBUCKET_WORKSPACE="your-workspace"  # optional default
```

## Claude Desktop Configuration

Add to your `claude_desktop_config.json`:

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

Or if installed with pip:

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

## Available Tools

### Configuration

#### `setup_bitbucket`
Configure Bitbucket credentials.

```python
setup_bitbucket(
    workspace="your-workspace",
    username="your-email@example.com",
    api_token="your-api-token"
)
```

#### `get_config_status`
Check if Bitbucket is configured.

```python
get_config_status()
# Returns: { "configured": true, "workspace": "...", "username": "..." }
```

### Workspace

#### `list_workspace_members`
List members of a workspace. Useful for finding reviewers.

```python
list_workspace_members(
    workspace="your-workspace",  # optional if configured
    page=1,
    pagelen=50
)
# Returns: { "members": [{ "uuid": "...", "display_name": "...", "account_id": "..." }] }
```

#### `get_default_reviewers`
Get the default reviewers configured for a repository.

```python
get_default_reviewers(
    repo_slug="my-repo",
    workspace="your-workspace"  # optional if configured
)
# Returns: { "default_reviewers": [{ "uuid": "...", "display_name": "..." }] }
```

### Pull Requests

#### `create_pull_request`
Create a new Pull Request. Automatically includes default reviewers.

```python
create_pull_request(
    repo_slug="my-repo",
    title="Feature: Add new functionality",
    source_branch="feature/my-feature",
    destination_branch="main",           # optional, defaults to "main"
    description="This PR adds...",       # optional
    reviewers=["uuid-1", "uuid-2"],      # optional, additional reviewers
    use_default_reviewers=True,          # optional, defaults to True
    workspace="your-workspace"           # optional if configured
)
```

#### `list_pull_requests`
List PRs for a repository.

```python
list_pull_requests(
    repo_slug="my-repo",
    state="OPEN",                        # OPEN, MERGED, DECLINED, SUPERSEDED, or ALL
    workspace="your-workspace",          # optional if configured
    page=1,
    pagelen=25
)
```

#### `get_pull_request`
Get details of a specific PR.

```python
get_pull_request(
    repo_slug="my-repo",
    pr_id=123,
    workspace="your-workspace"           # optional if configured
)
```

#### `update_pull_request`
Update an existing PR.

```python
update_pull_request(
    repo_slug="my-repo",
    pr_id=123,
    title="New title",                   # optional
    description="New description",       # optional
    destination_branch="develop",        # optional
    reviewers=["uuid-1", "uuid-2"],      # optional, replaces current reviewers
    close_source_branch=True,            # optional
    workspace="your-workspace"           # optional if configured
)
```

### Reviews

#### `approve_pull_request`
Approve a PR.

```python
approve_pull_request(
    repo_slug="my-repo",
    pr_id=123,
    workspace="your-workspace"           # optional if configured
)
```

#### `unapprove_pull_request`
Remove your approval from a PR.

```python
unapprove_pull_request(
    repo_slug="my-repo",
    pr_id=123,
    workspace="your-workspace"           # optional if configured
)
```

#### `request_changes_pull_request`
Request changes on a PR.

```python
request_changes_pull_request(
    repo_slug="my-repo",
    pr_id=123,
    workspace="your-workspace"           # optional if configured
)
```

#### `add_pull_request_comment`
Add a comment to a PR (supports markdown).

```python
add_pull_request_comment(
    repo_slug="my-repo",
    pr_id=123,
    comment="Looks good! Just one suggestion...",
    workspace="your-workspace"           # optional if configured
)
```

### Code Review (Diffs & Files)

#### `get_pull_request_diffstat`
Get a summary of files changed in a PR with line counts.

```python
get_pull_request_diffstat(
    repo_slug="my-repo",
    pr_id=123,
    workspace="your-workspace"           # optional if configured
)
# Returns: { "files": [{ "path": "...", "status": "modified", "lines_added": 10, "lines_removed": 5 }], ... }
```

#### `get_pull_request_diff`
Get the code diff for a PR. Can fetch full diff or specific file.

```python
get_pull_request_diff(
    repo_slug="my-repo",
    pr_id=123,
    file_path="src/main.py",             # optional, recommended for large PRs
    workspace="your-workspace"           # optional if configured
)
# Returns: { "diff": "--- a/src/main.py\n+++ b/src/main.py\n...", ... }
```

#### `get_file_contents`
Get contents of a file from a specific branch or commit.

```python
get_file_contents(
    repo_slug="my-repo",
    file_path="src/main.py",
    ref="feature/my-branch",             # branch, tag, or commit hash
    workspace="your-workspace"           # optional if configured
)
# Returns: { "content": "...", ... }
```

## Example Usage with Claude

1. **First time setup:**
   > "Set up Bitbucket with my workspace 'mycompany', username 'me@example.com', and API token 'abc123'"

2. **Create a PR:**
   > "Create a PR in my-repo from feature/login to main titled 'Add user login'"

3. **List open PRs:**
   > "Show me all open PRs in my-repo"

4. **Review a PR:**
   > "Approve PR #42 in my-repo"

5. **Add a comment:**
   > "Add a comment to PR #42 saying 'LGTM!'"

6. **Find reviewers:**
   > "List all members in my workspace so I can add them as reviewers"

7. **Review PR code:**
   > "Show me what files changed in PR #42"
   > "Review the diff for src/main.py in PR #42"

## Security

- Credentials are stored in `~/.bitbucket-mcp/config.json` with 600 permissions (owner-only access)
- API tokens are never logged or exposed in error messages
- Environment variables are supported for CI/CD scenarios

## License

MIT License - see [LICENSE](LICENSE) for details.
