# Bitbucket MCP Server **A Model Context Protocol server for AI agents to interact with Bitbucket Cloud Pull Requests** [![Node.js](https://img.shields.io/badge/Node.js-24.13-339933?logo=node.js&logoColor=white)](https://nodejs.org/) [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) [![MCP](https://img.shields.io/badge/MCP-1.29-blueviolet)](https://modelcontextprotocol.io/) [![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
--- ## Overview This MCP server exposes Bitbucket Cloud operations as tools that AI agents (Claude, etc.) can invoke over stdio. It connects your AI workflow directly to your Bitbucket repositories — covering everything from read-only PR inspection to full write operations. ### Capabilities | Category | Operations | |----------|-----------| | **Workspaces & Repos** | List workspaces, list/get repositories, list branches | | **Pull Requests (read)** | List, get details, get full expanded PR, status | | **Pull Requests (write)** | Create, update, merge, decline | | **Code Review** | Diff, patch, file changes, commits | | **Collaboration** | Comments (read/add/edit/delete), activities, participants, reviewers | | **Review Workflow** | Approve, unapprove, request changes, remove request-changes | | **Tasks** | Get tasks, task count, create/update/delete tasks | | **Auth** | Token validation | --- ## Quick Start Get up and running in 4 steps: ### 1. Prerequisites - Node.js **24.13+** (see `.nvmrc`) - A Bitbucket Cloud [API Token](https://id.atlassian.com/manage-profile/security/api-tokens) with **repository read** permissions (note: App Passwords are no longer supported by Bitbucket) ### 2. Install & Build ```bash git clone cd bitbucket-mcp npm install npm run build ``` ### 3. Configure in Claude Add the MCP server to your Claude configuration: **Claude Code** — edit `~/.claude.json` (global) or `.claude/settings.json` (per-project): ```json { "mcpServers": { "bitbucket": { "command": "node", "args": ["/absolute/path/to/bitbucket-mcp/dist/index.js"], "env": { "BITBUCKET_MCP_EMAIL": "your_email@example.com", "BITBUCKET_MCP_TOKEN": "your_api_token", "DEFAULT_WORKSPACE": "your-workspace", "DEFAULT_REPO": "your-repo" } } } } ``` **Claude Desktop** — edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows): ```json { "mcpServers": { "bitbucket": { "command": "node", "args": ["/absolute/path/to/bitbucket-mcp/dist/index.js"], "env": { "BITBUCKET_MCP_EMAIL": "your_email@example.com", "BITBUCKET_MCP_TOKEN": "your_api_token", "DEFAULT_WORKSPACE": "your-workspace", "DEFAULT_REPO": "your-repo" } } } } ``` > **Important:** > - Replace `/absolute/path/to/bitbucket-mcp` with the actual absolute path where you cloned the repo. > - `DEFAULT_WORKSPACE` and `DEFAULT_REPO` are optional but convenient — they let you omit those parameters from every tool call. > - Get your API token from [Atlassian API Tokens](https://id.atlassian.com/manage-profile/security/api-tokens). ### 4. Verify Restart Claude (or reload MCP servers), then ask Claude to run the `validate_token` tool. If credentials are correct, it will confirm the connection is working. --- ## Available Tools ### Authentication | Tool | Description | |------|-------------| | `validate_token` | Verify credentials are valid | ### Workspaces & Repositories | Tool | Description | Key Parameters | |------|-------------|----------------| | `list_workspaces` | List all workspaces the authenticated user belongs to | `page?`, `pagelen?` | | `list_repositories` | List repositories in a workspace | `workspace`, `role?`, `page?`, `pagelen?` | | `get_repository` | Get metadata for a specific repository | `workspace`, `repository` | | `list_branches` | List branches in a repository | `workspace`, `repository`, `filter_by_name?`, `page?`, `pagelen?` | ### Pull Request Discovery | Tool | Description | Key Parameters | |------|-------------|----------------| | `list_pull_requests` | List PRs in a repository | `workspace`, `repository`, `state?`, `author?` | | `get_pull_request` | Get PR summary | `workspace`, `repository`, `pullRequestId` | | `get_full_pull_request` | Get PR with all fields expanded | `workspace`, `repository`, `pullRequestId` | | `get_pull_request_status` | Get PR state (open/merged/declined) | `workspace`, `repository`, `pullRequestId` | ### Pull Request Write Operations | Tool | Description | Key Parameters | |------|-------------|----------------| | `create_pull_request` | Create a new pull request | `workspace`, `repository`, `title`, `source_branch`, `destination_branch`, `description?`, `reviewers?`, `close_source_branch?` | | `update_pull_request` | Update title, description, reviewers, or destination branch | `workspace`, `repository`, `pullRequestId`, `title?`, `description?`, `reviewers?`, `destination_branch?` | | `merge_pull_request` | Merge an open pull request | `workspace`, `repository`, `pullRequestId`, `merge_strategy?`, `commit_message?`, `close_source_branch?` | | `decline_pull_request` | Decline (close) an open pull request | `workspace`, `repository`, `pullRequestId` | ### Review Workflow | Tool | Description | Key Parameters | |------|-------------|----------------| | `approve_pull_request` | Approve a pull request | `workspace`, `repository`, `pullRequestId` | | `unapprove_pull_request` | Remove your approval | `workspace`, `repository`, `pullRequestId` | | `request_changes_pull_request` | Request changes on a pull request | `workspace`, `repository`, `pullRequestId` | | `remove_request_changes_pull_request` | Remove a request-changes vote | `workspace`, `repository`, `pullRequestId` | ### Code Changes | Tool | Description | Key Parameters | |------|-------------|----------------| | `get_pull_request_diff` | Get unified diff | `workspace`, `repository`, `pullRequestId`, `path?`, `context?` | | `get_pull_request_patch` | Get raw patch file | `workspace`, `repository`, `pullRequestId` | | `get_pull_request_changes` | List modified files | `workspace`, `repository`, `pullRequestId` | | `get_pull_request_commits` | List commits in PR | `workspace`, `repository`, `pullRequestId` | ### Comments | Tool | Description | Key Parameters | |------|-------------|----------------| | `get_pull_request_comments` | Get all comments | `workspace`, `repository`, `pullRequestId` | | `get_pull_request_comment` | Get a specific comment | `workspace`, `repository`, `pullRequestId`, `commentId` | | `add_pull_request_comment` | Add a general or inline comment | `workspace`, `repository`, `pullRequestId`, `content`, `inline_path?`, `inline_line?`, `parent_comment_id?` | | `update_pull_request_comment` | Edit an existing comment | `workspace`, `repository`, `pullRequestId`, `commentId`, `content` | | `delete_pull_request_comment` | Delete a comment | `workspace`, `repository`, `pullRequestId`, `commentId` | ### Activities & Participants | Tool | Description | Key Parameters | |------|-------------|----------------| | `get_pull_request_activities` | Get activity feed | `workspace`, `repository`, `pullRequestId` | | `get_pull_request_participants` | Get all participants | `workspace`, `repository`, `pullRequestId` | | `get_pull_request_reviewers` | Get assigned reviewers | `workspace`, `repository`, `pullRequestId` | ### Tasks | Tool | Description | Key Parameters | |------|-------------|----------------| | `get_pull_request_tasks` | Get PR tasks | `workspace`, `repository`, `pullRequestId` | | `get_pull_request_task_count` | Get task count | `workspace`, `repository`, `pullRequestId` | | `create_pull_request_task` | Create a review task | `workspace`, `repository`, `pullRequestId`, `content`, `comment_id?` | | `update_pull_request_task` | Update or resolve/unresolve a task | `workspace`, `repository`, `pullRequestId`, `taskId`, `content?`, `state?` | | `delete_pull_request_task` | Delete a task | `workspace`, `repository`, `pullRequestId`, `taskId` | > **Pagination:** Tools that return lists support `page` and `pagelen` parameters. --- ## Example ```json { "name": "list_pull_requests", "arguments": { "workspace": "my-team", "repository": "backend-api", "state": "open" } } ``` Response: ```json { "pull_requests": [ { "id": 42, "title": "feat: add user authentication", "state": "OPEN", "author": { "display_name": "Jane Doe" }, "source": { "branch": { "name": "feature/auth" } }, "destination": { "branch": { "name": "main" } } } ], "count": 1 } ``` --- ## Development ### Running Locally For development, you can use a `.env` file instead of configuring credentials in the MCP client. Copy `.env.template` to `.env` and fill in your values: ```env BITBUCKET_MCP_EMAIL=your_email@example.com BITBUCKET_MCP_TOKEN=your_api_token DEFAULT_WORKSPACE=my-workspace DEFAULT_REPO=my-repo # Only needed when running write integration tests (see Testing below) # RUN_WRITE_TESTS=true # TEST_PR_ID=123 ``` ```bash # Run with hot reload npm run dev # Or run directly npm start ``` ### Testing ```bash # Run all tests (unit only by default) npm test # Run tests in watch mode npm run test:watch # Integration tests — read-only, requires valid credentials in .env npm run test:integration # Type check npx tsc --noEmit # Coverage report npm run test:coverage ``` **Write operation tests** (approve/unapprove, comments, tasks) are disabled by default and require two additional variables in your `.env`: | Variable | Description | |----------|-------------| | `RUN_WRITE_TESTS=true` | Opt in to running write tests | | `TEST_PR_ID=` | ID of a PR you own and can safely modify | `TEST_PR_ID` is mandatory — write tests will never fall back to a random PR from the repository. If it is not set, each write test is skipped with a warning. This prevents accidental modifications to PRs you don't intend to touch. ### Project Structure ``` src/ ├── index.ts # MCP server & tool schema definitions ├── router.ts # Tool name → API method dispatcher ├── bitbucket-client.ts # Axios HTTP client for Bitbucket Cloud API └── config.ts # Credential & default config loading tests/ ├── unit/ # Mocked unit tests └── integration/ # Live API tests ``` --- ## Authentication Details This server uses **HTTP Basic Authentication** with the Bitbucket Cloud REST API v2.0: - **Username** = your Bitbucket email - **Password** = an [API Token](https://id.atlassian.com/manage-profile/security/api-tokens) > **Note:** Bitbucket no longer supports App Passwords. You must use an API Token instead. Credential resolution order: 1. Environment variables (`BITBUCKET_MCP_EMAIL` + `BITBUCKET_MCP_TOKEN`) 2. `.env` file in project root 3. Interactive prompt (development only) --- ## License [MIT](LICENSE)