Skip to content

Repository files navigation

bb - Bitbucket CLI

bb — Bitbucket Cloud CLI

License: MIT CI Bash Python GitHub release

A lightweight command-line interface for Bitbucket Cloud. Wraps the Bitbucket REST API for common operations like managing pipelines, pull requests, and repositories. Ships with a Python MCP server so any Claude Code session (or any other MCP-aware client) can drive Bitbucket Cloud as native tools.

The bash CLI has no dependencies beyond curl and jq. The MCP server adds Python 3.10+. Works on macOS, Linux, and WSL.

Features

  • Pipelines: List, view, watch, trigger, and stop pipeline builds
  • Pull Requests: Create, view, approve, unapprove, merge, decline, diff, comment
  • Repositories: List repos, view details, list/show branches, list recent commits
  • Browser Integration: Quick-open any resource in your browser
  • MCP server: 43 tools covering the full surface, plus git-context wrappers (current branch, status, recent commits, uncommitted changes) for agent workflows

Requirements

  • bash (3.2+) — works with macOS system bash; bash 4+ also fine
  • curl - usually pre-installed on macOS/Linux
  • jq (1.6+) - JSON processor (install instructions); bb trigger builds its variables payload via $ARGS.positional, a jq 1.6 feature
  • Python 3.10+ (only required for the MCP server)

Installing jq

macOS (Homebrew):

brew install jq

Ubuntu/Debian:

sudo apt-get install jq

Fedora/RHEL:

sudo dnf install jq

Windows (via Chocolatey):

choco install jq

Installation

  1. Clone this repository:

    git clone https://github.com/daniel-pittman/bitbucket-cli.git
    cd bitbucket-cli
  2. Make the script executable:

    chmod +x bb
  3. Symlink to your PATH. Pick the directory that's on your PATH and that you own:

    # macOS with Homebrew (no sudo needed; resolves to /opt/homebrew on
    # Apple Silicon, /usr/local on Intel Macs):
    ln -s "$(pwd)/bb" "$(brew --prefix)/bin/bb"
    
    # macOS without Homebrew, or Linux (needs sudo on most setups):
    sudo ln -s "$(pwd)/bb" /usr/local/bin/bb

    Or add the directory to your PATH (pick the rc file your shell uses; macOS defaults to zsh since Catalina):

    # bash:
    echo 'export PATH="$PATH:/path/to/bitbucket-cli"' >> ~/.bashrc
    # zsh (default on macOS):
    echo 'export PATH="$PATH:/path/to/bitbucket-cli"' >> ~/.zshrc

Configuration

Create a config file at ~/.config/bb/config:

mkdir -p ~/.config/bb
cat > ~/.config/bb/config <<EOF
BB_USER=your-email@example.com
BB_TOKEN=your-api-token
BB_WORKSPACE=your-workspace   # optional — see "How the workspace is resolved"
EOF

BB_USER and BB_TOKEN are required. BB_WORKSPACE is optional: when you run bb inside a Bitbucket git checkout, the workspace is auto-detected from the origin remote, so you only need BB_WORKSPACE as a fallback for commands run outside a repo (e.g. bb repos from an arbitrary directory).

How the workspace is resolved

For any command that needs a workspace, bb resolves it in this order (highest priority first):

  1. -w/--workspace <name> flag — explicit, per-invocation override.
  2. workspace/slug argument — e.g. bb pipelines acme/widget targets the acme workspace regardless of git context or config.
  3. git origin auto-detect — when you're inside a Bitbucket checkout, the workspace comes from the remote URL. This is why cd-ing into any repo and running bb prs / bb pipelines Just Works across multiple workspaces.
  4. BB_WORKSPACE — your configured default, used when none of the above apply (notably for repo-less commands like bb repos run outside a checkout).
  5. If none resolve a workspace, the command fails with a message naming all three ways to supply one.

This mirrors the MCP server's _resolve_repo behavior, so the bash CLI and the Python tools agree on which workspace a given invocation targets.

Getting an API Token

  1. Go to Atlassian API Tokens
  2. Click "Create API token"
  3. Copy the token and set it as BB_TOKEN
  4. Set BB_USER to your Bitbucket account email address

Required Bitbucket Permissions

Creating or rotating a token? Tick these nine. Scopes are fixed when a token is issued, so a rotation must re-select the whole set: ticking only the one you were missing leaves you with a token that has only that one.

read:repository:bitbucket      read:pullrequest:bitbucket
admin:repository:bitbucket     write:pullrequest:bitbucket

read:pipeline:bitbucket        read:workspace:bitbucket
write:pipeline:bitbucket       read:project:bitbucket
admin:pipeline:bitbucket

write:repository:bitbucket is deliberately absent: no bb command needs it. The only writes to the repository resource itself are bb repo-create and bb repo-update, which need admin:repository:bitbucket; every other write targets a sub-resource (pipelines, pull requests) covered by its own scope. Atlassian's token UI may include it alongside the admin tier, which is harmless.

After rotating, bb projects is a good single check: it needs read:project:bitbucket, the scope most often left off. Any command that fails now prints the exact scope it needed and the ones the token carries, so a gap names itself rather than needing a guess.

The per-feature breakdown:

Feature Required Permission
View pipelines, PRs, repos Read access to repositories (read:repository:bitbucket)
Trigger/stop pipelines Read + Write access to Pipelines (read:pipeline:bitbucket, write:pipeline:bitbucket)
Create/approve/merge PRs Read + Write access to Pull Requests (read:pullrequest:bitbucket, write:pullrequest:bitbucket)
List workspaces (bb workspaces) read:workspace:bitbucket (new in v1.2.0 — Atlassian API token scope, opt-in when creating the token)
List projects (bb projects) read:project:bitbucket (Atlassian API token scope, opt-in when creating the token). Verified against the live 403 envelope: the missing scope is named under error.detail.required.
List workspace members (bb members) read:workspace:bitbucket — membership is a workspace resource, so the same scope bb workspaces needs covers it. Verified live against a token carrying read:workspace:bitbucket and NOT read:project:bitbucket: the listing succeeds, so it does not depend on the project scope.
Create a repository (bb repo-create) Admin access to repositories (admin:repository:bitbucket). write:repository:bitbucket alone is not sufficient.
Update a repository (bb repo-update, e.g. move its project) Admin access to repositories (admin:repository:bitbucket). write:repository:bitbucket alone is not sufficient (same scope as bb repo-create).
Read Pipelines status (bb pipelines-status) Read access to Pipelines (read:pipeline:bitbucket).
Enable/disable Pipelines (bb pipelines-enable, bb pipelines-disable) Admin access to Pipelines (admin:pipeline:bitbucket). write:pipeline:bitbucket alone is not sufficient.
List deployment environments (bb environments) Read access to Pipelines (read:pipeline:bitbucket).
Create/delete deployment environments (bb environment-create, bb environment-delete) Admin access to Pipelines (admin:pipeline:bitbucket). write:pipeline:bitbucket alone is not sufficient.
Set or delete pipeline variables, any scope (bb vars set, bb vars delete, with --workspace / --deployment <env>) Admin access to Pipelines (admin:pipeline:bitbucket). write:pipeline:bitbucket alone is not sufficient. This one scope covers set and delete at all three variable scopes (repo, workspace, deployment-environment); verified against the live 403 envelope.

Note: Atlassian API tokens inherit your account's workspace permissions. If you can perform an action in the Bitbucket UI, the CLI can do it too — provided the token carries the scope. The cross-workspace listing endpoints (/2.0/workspaces, /2.0/repositories?role=member) were removed under Atlassian's CHANGE-2770 on 2026-04-14; bb workspaces uses the replacement /2.0/user/workspaces endpoint (CHANGE-3022) which requires the read:workspace:bitbucket scope. Rotating the token to add it leaves existing tokens unchanged.

The bb repo-create and bb vars set admin scopes are the most common to be missing, because most day-to-day tokens are scoped read + write only. A token's scopes are fixed at creation: adding a scope does not apply to an already-issued token. To use these two commands you must create a new token (or rotate the existing one) with the admin scope included. A token without the scope returns a 403 whose body names the exact missing scope under error.detail.required, so the failure is self-diagnosing.

Environment Variables

You can also set configuration via environment variables:

export BB_USER="your-email@example.com"
export BB_TOKEN="your-api-token"
export BB_WORKSPACE="your-workspace"

Two optional variables affect diagnostics rather than auth:

Variable Effect
BB_DEBUG=1 Traces every request to stderr as [bb] GET /path -> 200. The token is never part of a URL, so nothing sensitive is traced.
BB_API_BASE Overrides the API root (default https://api.bitbucket.org/2.0). Honoured by both the CLI and the MCP server.

When a request fails

A failed request prints Bitbucket's own explanation, not a guess. The most useful case is a missing token scope, where the API names both the scope it needs and the scopes the token actually carries:

$ bb workspaces
Error: HTTP 403 on GET /user/workspaces
  Your credentials lack one or more required privilege scopes.
  required scopes: read:workspace:bitbucket
  granted scopes:  read:repository:bitbucket, read:pullrequest:bitbucket
  A token's scopes are fixed at creation. To add one, create or
  rotate the token at
  https://id.atlassian.com/manage-profile/security/api-tokens

Exit codes are unchanged: 22 for any HTTP status >= 400, curl's own exit code for a connectivity failure (which is reported as such, never as an API rejection).

Usage

bb <command> [options]

Pipelines

bb pipelines [repo] [count]           # List recent pipelines (default: 10)
bb pipeline [repo] <number>           # Show pipeline details and steps
bb watch [repo] [number] [interval]   # Poll pipeline until done (default: 15s)
bb logs [repo] <number> [step]        # Show step logs
bb trigger [repo] [branch] [pattern] [--var KEY=VALUE ...]
                                      # Trigger a pipeline run
bb stop [repo] <number>               # Stop a running pipeline
bb approve [repo] <number>            # Open pipeline in browser (manual steps require UI)
bb pipelines-status [repo]            # Show whether Pipelines (CI) is enabled
bb pipelines-enable [repo]            # Enable Pipelines (CI) on a repo
bb pipelines-disable [repo]           # Disable Pipelines (CI) on a repo

Pipelines must be enabled on a repo before pipeline variables, custom pipelines, or builds work at all. bb pipelines-status reports the current state (it reads as "disabled (never configured)" when Pipelines has never been set up, which the API signals with a 404). bb pipelines-enable / bb pipelines-disable toggle it and need admin:pipeline:bitbucket scope.

bb trigger runs the branch's default pipeline, or a custom: pipeline when [pattern] is given. Per-run pipeline variables are passed with the repeatable --var KEY=VALUE flag (short form -v, or --var=KEY=VALUE); trailing positional KEY=VALUE pairs after [pattern] are also accepted. The variables do not have to be declared in bitbucket-pipelines.yml; Bitbucket accepts arbitrary per-run keys. Malformed pairs (no =, or a key that isn't letters/digits/underscores starting with a non-digit) fail loudly before any API call, and the confirmation echo masks values as KEY=*** because they may be secrets:

bb trigger ryan-repo develop build-installer --var GOLD_VERSION=v1.0.1

Pull Requests

bb prs [repo] [state]                 # List PRs (default: OPEN)
bb pr [repo] <id>                     # View PR details
bb pr-create [--repo R] <title> [dest]  # Create PR from current branch
                                      #   <title> is the FIRST positional; repo is
                                      #   --repo (slug or ws/slug) or auto-detected
                                      #   opt: --close-source-branch
                                      #   opt: --description TEXT | --description-file PATH
                                      #        (or pipe a body: pr-create ... < body.md)
                                      #   opt: --reviewer UUID (repeatable; bb members)
bb pr-update [repo] <id> [--title T] [--description D | --description-file F]
                                      # Update a PR title and/or description
                                      #   opt: --reviewer UUID (repeatable; adds)
                                      #   opt: --remove-reviewer UUID (repeatable)
                                      #   opt: --drop-approvals
bb pr-approve [repo] <id>             # Approve a PR
bb pr-merge [repo] <id> [strategy]    # Merge a PR (merge_commit|squash|fast_forward)
                                      #   opt: --close-source-branch
bb pr-decline [repo] <id>             # Decline a PR
bb pr-diff [repo] <id>                # Show PR diff
bb pr-comments [repo] <id>            # Show PR comments

Creating a PR: title first, repo via --repo. <title> is the first positional and dest the second, so bb pr-create "<title>" <dest> works with the repo auto-detected from the git origin. Select a different repo with --repo (slug or workspace/slug). A leading workspace/slug positional is still accepted for back-compat; a single-token title shaped like ws/slug (e.g. fix/typo, one slash, no spaces) is taken as the repo, so pass --repo to disambiguate in that rare case.

Requesting review. Bitbucket identifies reviewers only by account UUID, so bb members is the lookup and --reviewer is the consumer:

bb members                                    # DISPLAY NAME / NICKNAME / UUID
bb pr-create "Add widget cache" develop \
    --reviewer "{11111111-2222-3333-4444-555555555555}" \
    --reviewer "{66666666-7777-8888-9999-000000000000}"

Reviewers can also be changed after the PR exists, which is how review actually gets assigned:

bb pr-update 42 --reviewer "{6666...}"          # add, keeping the existing ones
bb pr-update 42 --remove-reviewer "{1111...}"   # remove, keeping everyone else

Bitbucket's PR update replaces the whole reviewer array, so both flags read the PR first and send the full resulting list; sending only the person being added would silently unassign everyone else. Adding someone already on the PR is a no-op, not a duplicate.

There is deliberately no "set the reviewers to exactly this" flag. Replace is the operation that silently discards other people's approvals, and add/remove composes to the same result with each change stated explicitly. Relatedly, removing a reviewer who has already approved discards that approval and re-adding them does not restore it, so it is refused unless you pass --drop-approvals. Removing a reviewer who has not approved needs no opt-in.

--reviewer is repeatable and takes the UUID column verbatim (braces optional). A name or nickname is rejected locally, before any request, with a pointer back to bb members — Bitbucket would only answer that with a 400. bb members lists the first 100 members and says so when there are more; the MCP members_list tool paginates. Deactivated accounts are marked (inactive), and bb members warns when two accounts share a display name and nickname, which happens and leaves the UUID as the only thing telling them apart.

PR body. Supply it with --description "...", --description-file PATH, or a file redirect bb pr-create "<title>" <dest> < body.md. pr-create never blocks reading stdin: the implicit redirect path reads a regular file only, so an interactive or piped invocation with no body never hangs. On any platform where the < body.md convenience read is not detected, use --description-file (the portable path).

Source-branch deletion on merge. The source branch is kept by default. Deleting a branch on merge is destructive, so it is opt-in, never automatic, the same stance gh pr merge takes with --delete-branch. Pass --close-source-branch on either pr-create or pr-merge to have the source branch deleted when the PR merges. pr-merge sends the choice explicitly, so it overrides whatever a PR was stored with at creation (the merge API's value wins over the PR's): a PR created by an older bb or the Bitbucket UI with the box checked still keeps its source branch unless you pass --close-source-branch.

Branches & Repositories

bb branches [repo]                    # List branches
bb projects [workspace]               # List workspace projects
bb members [workspace]                # List workspace members + their UUIDs
bb repos                              # List workspace repos
bb repo [repo]                        # Show repo details
bb repo-create <name> [opts]          # Create a repo (default PRIVATE)
bb repo-update [repo] <opts>          # Update a repo (move project, change description)
bb downloads [repo]                   # List repo downloads
bb environments [repo]                # List deployment environments
bb environment-create [repo] <name> [--type T]  # Create a deployment environment
bb environment-delete [repo] <name>   # Delete a deployment environment
bb vars [scope] [repo]                # List pipeline variables (repo|workspace|deployment)
bb vars set [scope] [repo] <KEY> [opts]  # Create or update a pipeline variable
bb vars delete [scope] [repo] <KEY>   # Delete a pipeline variable (destructive)

bb environments lists a repo's deployment environments (the named targets a pipeline deploys to: Test / Staging / Production). bb environment-create <name> [--type Test|Staging|Production] adds one (default type Test); bb environment-delete <name> removes it by name. Each environment carries its own deployment variables, managed via bb vars [set] --deployment <env>. Create and delete need admin:pipeline:bitbucket scope.

bb repo shows a repository's project as Project: KEY (Name), and bb repos carries a PROJECT column of keys. Both read the field from the response they already fetch, so neither costs an extra call, and both answer "which project is this repo in?" without a detour to the API. A repo in a workspace that does not use projects reads (none) / -. This matters because bb repo-update --project KEY can change a repo's project: without a way to read the value back, setting the wrong key looks exactly like setting the right one.

bb projects lists a workspace's projects (KEY and NAME). The KEY is what --project expects on bb repo-create and bb repo-update. The workspace defaults to the resolved one (-w / git origin / BB_WORKSPACE); pass an explicit [workspace] to list another's. Needs read:project:bitbucket scope, which bb repo does NOT (a repo's own project comes back on the repository record). See Required Bitbucket Permissions.

bb projects                # projects in the resolved workspace
bb projects acme           # projects in workspace "acme"

bb repo-create defaults to a private repo so a forgotten flag never publishes one. Flags: --public / --private, --project KEY (required on workspaces that use projects), --description TEXT.

bb repo-create widget-service                          # private, default project
bb repo-create widget-service --project WID            # private, in project WID
bb repo-create docs-site --public --description "Docs" # public

bb repo-update changes an existing repo's settings. The dominant use is moving a repo between projects (bb repo-create takes a project but nothing else could change it afterward). At least one of --project KEY / --description TEXT is required; [repo] accepts the same shapes as every other repo command (bare slug, ws/slug, or omitted to auto-detect from the git origin).

bb repo-update widget-service --project WID            # move into project WID
bb repo-update acme/widget-service --description "..."  # change description
bb repo-update --project WID                            # current checkout, move project

Both bb repo-create and bb repo-update need admin:repository:bitbucket scope on the token. A read/write-only token must be rotated to add it (adding a scope does not apply to an already-issued token). See Required Bitbucket Permissions.

bb vars, bb vars set, and bb vars delete operate at three scopes, selected by a flag (default is repo):

  • repo (default): no flag.
  • workspace: --workspace (no repo argument; variables are shared across the workspace).
  • deployment-environment: --deployment <env>. <env> is the environment NAME or slug (for example Development or production), which the command resolves to its environment UUID by listing the repo's environments first. An unknown name fails with the list of available environments and writes nothing.

The scope endpoints are pipelines_config (repo, underscore), pipelines-config (workspace, hyphen), and deployments_config/environments/{uuid} (deployment); the hyphen-vs-underscore difference is a Bitbucket API quirk, handled for you.

bb vars set creates the variable if its key is new at that scope, or updates the existing one. Provide the value via exactly one of --value, --value-file, or --value-env. For secrets prefer --value-file or --value-env so the secret never appears in argv / the process list / shell history, and pass --secured so Bitbucket masks it. The command never echoes a value back, at any scope.

# Repo scope (default)
bb vars set widget-service AWS_REGION --value us-east-1            # non-secret
bb vars set widget-service AWS_SECRET --secured --value-file ./secret.txt
bb vars set widget-service AWS_KEY --secured --value-env AWS_KEY   # read from env

# Workspace scope (shared across the workspace; no repo argument)
bb vars --workspace
bb vars set --workspace DOCKERHUB_TOKEN --secured --value-env DOCKERHUB_TOKEN

# Deployment-environment scope (env name resolves to its UUID)
bb vars --deployment Production widget-service
bb vars set --deployment Production widget-service DB_URL --secured --value-file ./db_url.txt

bb vars delete <KEY> removes a variable by key at the chosen scope (it resolves the key to its UUID first, walking all pages). A key that does not exist at the scope fails with a clean not-found error and issues no delete. This is destructive (a secured value can't be recovered after deletion), so confirm the key and scope before running it.

bb vars delete widget-service AWS_ACCESS_KEY_ID            # repo scope
bb vars delete --workspace DOCKERHUB_TOKEN                 # workspace scope
bb vars delete --deployment Production widget-service DB_URL  # deployment scope

All three scopes, for bb vars, bb vars set, and bb vars delete, need admin:pipeline:bitbucket scope on the token (write:pipeline:bitbucket alone is not enough). A read/write-only token must be rotated to add it. See Required Bitbucket Permissions.

Utilities

bb open [repo] [section]              # Open in browser (pr|pipelines|branches|settings|commits)
bb help                               # Show help

Global Flags

-w, --workspace <name>                # Override workspace for this command

Auto-Detection

When inside a git repository with a Bitbucket remote, the [repo] argument is optional — both the repo slug AND the workspace are auto-detected from the origin remote URL. This is what lets you cd between repos in different workspaces and have commands target the right one without a -w flag. To override, pass -w <workspace>, a workspace/slug argument, or set BB_WORKSPACE as a default (see How the workspace is resolved).

Examples

# Watch the latest pipeline on current repo
bb watch

# List open PRs
bb prs

# Create a PR from current branch to develop (repo auto-detected from git origin)
bb pr-create "Add new feature" develop

# Target a specific repo with --repo (slug or workspace/slug)
bb pr-create --repo my-repo "Add new feature" develop

# Trigger a custom pipeline with per-run variables
bb trigger my-repo main manual-deploy-prod --var LAMBDA_NAMES=mci --var REGION=us-west-2

# View pipeline logs for step 1
bb logs my-repo 42 1

# Open repo settings in browser
bb open my-repo settings

MCP server (for Claude Code / AI agents)

A Python Model Context Protocol server (mcp_server.py) ships as a peer to the bb bash script. Both implement the same Bitbucket Cloud REST contract independently — the MCP server does not shell out to bb; it speaks HTTP directly via Python stdlib (no requests etc.). Any Claude Code session — or any other MCP-aware client — can drive Bitbucket Cloud as native tools without invoking the CLI.

What it exposes

41 tools covering pipelines, pull requests, workspaces, projects, repos, branches, commits, pipeline config + variables, deployment environments, and git-context helpers:

Category Tools
Pipelines (read) pipelines_list, pipeline_show, pipeline_steps, pipeline_logs, pipelines_config_show
Pipelines (write) pipeline_trigger, pipeline_stop, pipelines_config_set (enable/disable; needs admin:pipeline:bitbucket)
Pull requests (read) prs_list, pr_show, pr_activity, pr_diff, pr_comments_list
Pull requests (write) pr_create, pr_approve, pr_unapprove, pr_merge, pr_decline, pr_comment_add
Workspaces / projects / members workspaces_list (needs read:workspace:bitbucket scope), projects_list (needs read:project:bitbucket scope), members_list (resolves a person to the account UUID pr_create(reviewers=...) needs) — see Required Bitbucket Permissions
Repos / metadata repos_list, repo_show, repo_create, repo_update, branches_list, branch_show, commits_list, vars_list, vars_set, vars_delete, downloads_list
Deployment environments environments_list, environment_create, environment_delete (create/delete need admin:pipeline:bitbucket)
Git context git_current_branch, git_status, git_remote_repo, git_recent_commits, git_uncommitted_changes
Meta whoami (see note below)

Note on whoami: resolves config + git context + a workspace-reachability probe (single low-cost GET /repositories/{workspace}?pagelen=1, 10 s timeout). Never echoes BB_TOKEN. The probe requires repository:read scope — a workspace-scoped token granting only pipelines:read or pullrequest:read will report auth.ok=False even though pipeline/PR tools still work, so treat the probe as a scope hint rather than a global credential verdict.

Every tool that takes a repo argument supports auto-detection (omit repo to resolve from the current git checkout's origin remote — or from BB_DEFAULT_REPO_PATH if set; see Environment overrides below) and workspace override (workspace/repo shape).

MCP server requirements

  • Python 3.10+ available on PATH (the bash CLI doesn't need Python — only the MCP server does).
  • The same ~/.config/bb/config (or BB_USER / BB_TOKEN / BB_WORKSPACE env vars) as the CLI — see Configuration above.

MCP server install

# 1. Make sure bb itself is installed and configured (see Configuration above).

# 2. Register the MCP server with Claude Code (user scope = all sessions on this machine):
claude mcp add --scope user bitbucket \
    -- python3 /absolute/path/to/bitbucket-cli/mcp_server.py  # ← replace with your clone path

# `python3` is intentionally bare — `claude mcp add` inherits PATH, so a
# Homebrew or pyenv Python 3.10+ resolves naturally. Do NOT hardcode
# /usr/bin/python3 on macOS: Apple's bundled Python at that path is 3.9,
# which is below the MCP server's 3.10 minimum. The `--` separator before
# `python3` keeps the command robust if you later add `--env` flags
# (see "Multiple workspaces" below).

# 3. On first invocation, the server self-bootstraps a durable venv at
#    $XDG_DATA_HOME/bitbucket-cli/venv (default: ~/.local/share/bitbucket-cli/venv)
#    and installs the `mcp` package into it. Subsequent launches reuse the venv.
#
#    To force a clean rebuild:
#      rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/bitbucket-cli/venv"
#    and relaunch the MCP server.

# 4. Verify the connection (handshake only — does NOT validate credentials):
claude mcp list
# Should show: bitbucket: ... - ✓ Connected
#
# First invocation may briefly show "✗ Failed to connect" while the venv
# bootstraps (pip-installs `mcp`, 5-30 s depending on network). Retry once.

# 5. Verify credentials in a Claude Code session by asking it to run the
#    `whoami` tool — `Connected` above only confirms the stdio handshake;
#    `whoami` confirms BB_USER/BB_TOKEN/BB_WORKSPACE actually resolve AND
#    the token reaches your configured workspace.

Multiple workspaces: to register more than one server (e.g. bitbucket-work and bitbucket-personal pointing at different workspaces), use --env flags per registration so each server entry carries its own credentials:

claude mcp add --scope user bitbucket-work \
    --env BB_USER=you@work.com \
    --env BB_TOKEN=... \
    --env BB_WORKSPACE=acme \
    -- python3 /absolute/path/to/bitbucket-cli/mcp_server.py  # ← replace with your clone path

Other MCP clients

mcp_server.py is a stdio MCP server, so any client that speaks MCP-over-stdio can use it. The command is python3 /absolute/path/to/bitbucket-cli/mcp_server.py — same Python-version constraint as above. Credentials come from ~/.config/bb/config or environment variables; clients that strip HOME from the subprocess environment need to pass BB_USER / BB_TOKEN / BB_WORKSPACE explicitly instead.

Environment overrides

Variable Purpose
BB_API_BASE Override the Bitbucket REST base URL (default https://api.bitbucket.org/2.0). Useful for a test / proxied / staging mirror.
BB_DEFAULT_REPO_PATH Default working directory for repo auto-detection (when a Bitbucket tool is called with repo="") AND for the git_* tools' default path="" resolution. Defaults to the MCP server's launch cwd.
XDG_DATA_HOME Standard XDG override for the data root. The venv lives at $XDG_DATA_HOME/bitbucket-cli/venv (default ~/.local/share/bitbucket-cli/venv).

Optional: install the bundled bitbucket agent for delegated use

The MCP server exposes the tools; the bundled agent (agents/bitbucket.md in this repo) is the behavioral layer that makes a Claude Code session use those tools intelligently — propose-first protocol for destructive ops (pr_merge, pr_decline, pipeline_stop, pr_unapprove), resolve-git-context-first before any Bitbucket call, show-diffs-before-merge discipline, bash/Python parity rule for delegated CLI maintenance, and the per-workspace conventions block for tracking each workspace's defaults.

The bundled agents/bitbucket.md is a deliberately-generic template — it ships with placeholder examples (acme/widget-service, fictional reviewers, generic custom-pipeline patterns like deploy-prod) and an explicitly-blank "Per-workspace conventions" section at the bottom. After copying it to ~/.claude/agents/bitbucket.md, personalize your local copy with your default workspace, required reviewers, custom pipeline patterns, branch naming conventions, and any other non-generic context. Anything you contribute back to this repo via PR should be re-genericized first — real workspace slugs, real ticket titles, real reviewer handles, and project-specific custom-pipeline patterns belong only in your personal ~/.claude/agents/ copy, never in the upstream-tracked version.

The agent is a single Markdown file with frontmatter. To install:

# 1. Copy the agent definition into user-scope agents.
mkdir -p ~/.claude/agents
cp agents/bitbucket.md ~/.claude/agents/bitbucket.md

# 2. Populate the "Per-workspace conventions" section using bb itself —
#    don't type defaults from memory, let the CLI discover them:
#      bb workspaces                # which workspaces you belong to
#      bb -w <ws> repos             # what's in each
#      bb repo <ws>/<repo>          # → Main branch (verify PR base; GitFlow repos target develop)
#      bb pipelines <ws>/<repo>     # → TRIGGER column = custom pipelines
#      bb branches <ws>/<repo>      # → branch-naming convention
#      bb vars <ws>/<repo>          # → SECURED=true = sensitive vars to mask
#    Add one block per workspace (the template at the bottom of the agent
#    file shows the shape). The bundled agent can run this survey for you.

# 3. Newly-started Claude Code sessions pick up the agent automatically.
#    Existing sessions need a restart. In any new session you can then
#    delegate to it:
#
#    "Use the bitbucket agent to merge PR 42"
#    "Have the bitbucket agent watch pipeline 142"
#    "Ask the bitbucket agent to trigger a deploy-prod run on main"

The agent description tells Claude Code's orchestrator when to delegate to it automatically (e.g. when the user mentions Bitbucket pipeline / PR / repo operations). You don't have to invoke it by name.

What the agent enforces on top of the raw tools:

The MCP tools already do per-call auto-detection on their own (source-branch auto-detect on pr_create, repo auto-detect on every Bitbucket tool given repo="") — the agent doesn't re-implement those. What the agent adds:

Behavior Raw MCP tools With bundled bitbucket subagent
Destructive ops (pr_merge, pr_decline, pipeline_stop, pr_unapprove) Fired immediately when invoked Propose-first: show diff / activity / current state, confirm with user, then act
Pipeline failure investigation Caller must navigate pipeline_showpipeline_stepspipeline_logs manually Triages in that order, surfaces the relevant log tail (last ~50 lines around the failure) instead of dumping the whole stream
Avoiding redundant probes Caller may re-fetch git_current_branch / git_remote_repo per call even when the tool would auto-detect Lets tool-level auto-detect carry the call (passes repo="" and omits source_branch= instead of pre-fetching git context just to echo it back)
bb-CLI maintenance (delegated) Re-discovers the parity rule, naming conventions, redaction patterns per session Owns the design → implement → test → docs → PR cycle with the rules already baked in
Per-workspace conventions Re-discovered each session Reads (or bb-discovers and proposes) the agent file's "Per-workspace conventions" block for the active workspace before any write op

Security

  • BB_TOKEN is never echoed (whoami, error envelopes, log lines).
  • URL credentials (https://user:token@host/...) and signed-URL query parameters (AWS / Azure / GCP / bearer / access_token / api_key) are stripped from every error message.
  • Cross-host Authorization headers are stripped on redirect so the Bitbucket Basic header never reaches S3 when fetching pipeline logs.
  • Pipeline variable values are masked as KEY=*** when echoed back.

The agent file is genuinely portable — strip the example "Per-workspace conventions" section and you have a clean template that works for any Bitbucket Cloud workspace.

License

MIT License - see LICENSE for details.

About

Lightweight CLI for Bitbucket Cloud - manage pipelines, PRs, and repos from your terminal

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages