Metadata-Version: 2.4
Name: bitbucket-mcp
Version: 0.4.2
Summary: MCP server for managing Bitbucket Cloud Pull Requests
Author: Acendas
License-Expression: MIT
License-File: LICENSE
Keywords: anthropic,bitbucket,claude,mcp,model-context-protocol,pull-request
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Requires-Dist: fastmcp>=0.1.0
Requires-Dist: httpx>=0.25.0
Description-Content-Type: text/markdown

# Bitbucket MCP Server

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

## Features

- **Repository Management**: List repositories, get repo details, list branches
- **Pull Request Lifecycle**: Create, update, merge, and decline PRs
- **Code Review**: Approve, request changes, add/remove reviewers
- **Comments**: Add, read, reply to, and delete comments (including inline code comments)
- **Diff & Code**: View diffs, file changes, commits, and file contents
- **Merge Status**: Check if PR can be merged, view conflicts and blockers

## 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 & Repository

#### `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": "..." }] }
```

#### `list_repositories`
List repositories in a workspace.

```python
list_repositories(
    workspace="your-workspace",  # optional if configured
    page=1,
    pagelen=25,
    query="search-term"          # optional, filter by name
)
# Returns: { "repositories": [{ "slug": "...", "name": "...", "default_branch": "main", ... }] }
```

#### `get_repository`
Get detailed information about a specific repository.

```python
get_repository(
    repo_slug="my-repo",
    workspace="your-workspace"   # optional if configured
)
# Returns: { "slug": "...", "name": "...", "clone_ssh": "...", "clone_https": "...", ... }
```

#### `list_branches`
List branches in a repository.

```python
list_branches(
    repo_slug="my-repo",
    workspace="your-workspace",  # optional if configured
    page=1,
    pagelen=25,
    query="feature"              # optional, filter by name
)
# Returns: { "branches": [{ "name": "main", "commit_hash": "...", "commit_message": "..." }] }
```

#### `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
)
```

#### `merge_pull_request`
Merge a Pull Request.

```python
merge_pull_request(
    repo_slug="my-repo",
    pr_id=123,
    merge_strategy="squash",             # "merge_commit", "squash", or "fast_forward"
    close_source_branch=True,            # optional, delete source branch after merge
    message="Custom merge message",      # optional
    workspace="your-workspace"           # optional if configured
)
# Returns: { "success": true, "merge_commit": "abc123...", "state": "MERGED" }
```

#### `decline_pull_request`
Decline/close a PR without merging.

```python
decline_pull_request(
    repo_slug="my-repo",
    pr_id=123,
    reason="Superseded by PR #456",      # optional, adds as comment
    workspace="your-workspace"           # optional if configured
)
```

#### `get_pull_request_merge_status`
Check if a PR can be merged and view any blockers.

```python
get_pull_request_merge_status(
    repo_slug="my-repo",
    pr_id=123,
    workspace="your-workspace"           # optional if configured
)
# Returns: { "can_merge": true/false, "has_conflicts": false, "approvals": [...], "blockers": [...] }
```

### 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_reviewer`
Add a reviewer to a PR without removing existing reviewers.

```python
add_reviewer(
    repo_slug="my-repo",
    pr_id=123,
    reviewer="{uuid}",                   # UUID or account_id
    workspace="your-workspace"           # optional if configured
)
```

#### `remove_reviewer`
Remove a reviewer from a PR.

```python
remove_reviewer(
    repo_slug="my-repo",
    pr_id=123,
    reviewer="{uuid}",                   # UUID or account_id
    workspace="your-workspace"           # optional if configured
)
```

### Comments

#### `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
)
```

#### `get_pull_request_comments`
Get all comments from a PR, including inline code comments.

```python
get_pull_request_comments(
    repo_slug="my-repo",
    pr_id=123,
    workspace="your-workspace",          # optional if configured
    page=1,
    pagelen=50
)
# Returns: { "comments": [{ "id": 123, "content": "...", "author": "...", "inline": { "path": "...", "to_line": 15 } }] }
```

#### `reply_to_comment`
Reply to a specific comment (threaded replies).

```python
reply_to_comment(
    repo_slug="my-repo",
    pr_id=123,
    comment_id=456,
    content="Good point, I'll fix that.",
    workspace="your-workspace"           # optional if configured
)
```

#### `add_inline_comment`
Add an inline comment on a specific line of code.

```python
add_inline_comment(
    repo_slug="my-repo",
    pr_id=123,
    file_path="src/main.py",
    line=42,
    content="Consider using a constant here.",
    workspace="your-workspace"           # optional if configured
)
```

#### `delete_comment`
Delete a comment (only your own comments).

```python
delete_comment(
    repo_slug="my-repo",
    pr_id=123,
    comment_id=456,
    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": "...", ... }
```

#### `get_pull_request_commits`
List all commits in a PR.

```python
get_pull_request_commits(
    repo_slug="my-repo",
    pr_id=123,
    workspace="your-workspace",          # optional if configured
    page=1,
    pagelen=50
)
# Returns: { "commits": [{ "hash": "...", "message": "...", "author": "...", "date": "..." }] }
```

#### `get_pull_request_activity`
Get the full activity timeline of a PR (comments, approvals, updates).

```python
get_pull_request_activity(
    repo_slug="my-repo",
    pr_id=123,
    workspace="your-workspace",          # optional if configured
    page=1,
    pagelen=50
)
# Returns: { "activities": [{ "type": "approval", "user": "...", "date": "..." }, ...] }
```

## Example Usage with Claude

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

2. **List repositories:**
   > "Show me all repositories in my workspace"

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

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

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

6. **Check merge status:**
   > "Can PR #42 be merged? Are there any conflicts?"

7. **Merge a PR:**
   > "Squash merge PR #42 and delete the source branch"

8. **Add an inline comment:**
   > "Add a comment on line 25 of src/main.py in PR #42 saying 'Consider using a constant here'"

9. **View PR activity:**
   > "Show me the activity timeline for PR #42"

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

11. **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.
