
Company News
Free Business Plan Upgrades for Open Source Maintainers
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.
bitbucket-mcp-py
Advanced tools
MCP Server for Bitbucket API - Container optimized with configurable tools, structured output and slim responses
Connect Claude Code, OpenAI Codex, Cursor, VS Code (GitHub Copilot), and any MCP-compatible AI assistant to your Bitbucket Cloud repositories. Review pull requests, monitor pipelines, and manage your code — all through natural language.
readOnlyHint / destructiveHint / idempotentHint / openWorldHint + a human-readable title, so clients (Claude Code, Cursor) auto-include read-only tools and warn before destructive operationsconfigs/tools.json or BITBUCKET_TOOLS_CONFIG env varThe recommended way to run the server is via uvx (zero install, isolated environment):
# Always latest version
uvx --from bitbucket-mcp-py bitbucket-mcp
# Pin a specific version
uvx --from bitbucket-mcp-py==1.8.1 bitbucket-mcp
Why
--from? The PyPI package isbitbucket-mcp-pybut the command entry point isbitbucket-mcp. The--fromflag tells uvx which package to install.
| Mode | Command | Best for |
|---|---|---|
| pip global | pip install bitbucket-mcp-py | Simple, persistent install |
| Local dev | pip install -e . in project dir | Contributing to the project |
| Docker | See Docker section | Container-based workflows |
Set the following environment variables (or use a .env file — see Credentials):
| Variable | Description |
|---|---|
BITBUCKET_USERNAME | Your Bitbucket email |
BITBUCKET_TOKEN | Your Bitbucket API token |
BITBUCKET_WORKSPACE | Your workspace slug |
Get your API token at: https://id.atlassian.com/manage-profile/security/api-tokens
⚠️ Use a scoped token, not a global one. When creating the token, select specific scopes (e.g.
Repositories: Read,Pull requests: Read/Write). Global tokens without explicit scopes do not work with this MCP server.
Option A — CLI (fastest):
claude mcp add bitbucket-mcp \
-e BITBUCKET_USERNAME=your-email@example.com \
-e BITBUCKET_TOKEN=your-api-token \
-e BITBUCKET_WORKSPACE=your-workspace \
-- uvx --from bitbucket-mcp-py bitbucket-mcp
Option B — JSON config (~/.claude.json or project .mcp.json):
{
"mcpServers": {
"bitbucket-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["--from", "bitbucket-mcp-py", "bitbucket-mcp"],
"env": {
"BITBUCKET_USERNAME": "your-email@example.com",
"BITBUCKET_TOKEN": "your-api-token",
"BITBUCKET_WORKSPACE": "your-workspace"
}
}
}
}
Option A — CLI (fastest):
codex mcp add bitbucket-mcp \
--env BITBUCKET_USERNAME=your-email@example.com \
--env BITBUCKET_TOKEN=your-api-token \
--env BITBUCKET_WORKSPACE=your-workspace \
-- uvx --from bitbucket-mcp-py bitbucket-mcp
Option B — TOML config (~/.codex/config.toml):
[mcp_servers.bitbucket-mcp]
command = "uvx"
args = ["--from", "bitbucket-mcp-py", "bitbucket-mcp"]
env = { BITBUCKET_USERNAME = "your-email@example.com", BITBUCKET_TOKEN = "your-api-token", BITBUCKET_WORKSPACE = "your-workspace" }
Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"bitbucket-mcp": {
"command": "uvx",
"args": ["--from", "bitbucket-mcp-py", "bitbucket-mcp"],
"env": {
"BITBUCKET_USERNAME": "your-email@example.com",
"BITBUCKET_TOKEN": "your-api-token",
"BITBUCKET_WORKSPACE": "your-workspace"
}
}
}
}
Add to .vscode/mcp.json (workspace) or ~/Library/Application Support/Code/User/mcp.json (global, macOS):
{
"servers": {
"bitbucket-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["--from", "bitbucket-mcp-py", "bitbucket-mcp"],
"env": {
"BITBUCKET_USERNAME": "your-email@example.com",
"BITBUCKET_TOKEN": "your-api-token",
"BITBUCKET_WORKSPACE": "your-workspace"
}
}
}
}
| Category | Tools |
|---|---|
| Repositories | list_repositories, get_repository, get_repository_tags |
| Pull Requests | get_pull_requests, get_pull_request, create_pull_request, update_pull_request, approve_pull_request, unapprove_pull_request, request_changes_pull_request, unrequest_changes_pull_request, decline_pull_request, merge_pull_request |
| Comments | get_pull_request_comments, add_pull_request_comment, get_pull_request_comment, update_pull_request_comment, delete_pull_request_comment, resolve_pull_request_comment, reopen_pull_request_comment, get_pull_request_activity |
| Tasks PR | get_pull_request_tasks, get_pull_request_task, create_pull_request_task, update_pull_request_task, delete_pull_request_task |
| Diff / Review | get_pull_request_diff, get_pull_request_patch, get_pull_request_diffstat, get_pull_request_commits |
| PR Discovery | get_pull_requests_pending_review |
| Build / CI | get_pull_request_statuses, get_commit_statuses |
| Pipelines | list_pipeline_runs, get_pipeline_run, get_pipeline_steps, get_pipeline_step_logs, run_pipeline, stop_pipeline |
| Pipelines Config | get_pipeline_config, list_pipeline_variables, get_pipeline_variable, create_pipeline_variable, update_pipeline_variable, delete_pipeline_variable, list_pipeline_schedules, get_pipeline_schedule, list_pipeline_schedule_executions, create_pipeline_schedule, update_pipeline_schedule, delete_pipeline_schedule, list_pipeline_caches, delete_pipeline_cache |
| Reviewers | get_effective_default_reviewers, suggest_pull_request_reviewers |
| Draft PR | create_draft_pull_request, publish_draft_pull_request, convert_pull_request_to_draft |
| Batch Review | submit_pull_request_batch_review |
| Review Summary | get_pull_request_review_summary |
| Issues | list_issues, get_issue, create_issue, update_issue, delete_issue, get_issue_comments, get_issue_comment, add_issue_comment, update_issue_comment, delete_issue_comment |
| Commits | list_commits, get_commit, get_commit_comments, get_commit_comment, add_commit_comment |
| Source | get_file_content, list_directory |
| Deployments | list_environments, get_environment, create_environment, delete_environment, list_deployments, get_deployment, list_deployment_variables, create_deployment_variable, update_deployment_variable, delete_deployment_variable |
| Branch Restrictions | list_branch_restrictions, get_branch_restriction, create_branch_restriction, update_branch_restriction, delete_branch_restriction |
| Workspace | list_workspace_members, get_workspace_member, list_workspace_permissions, list_repository_permissions |
Disabled by default:
merge_pull_request(safety),stop_pipeline(safety),get_pull_request_patch(git am format — not useful for AI review),convert_pull_request_to_draft(not supported by Bitbucket API),delete_issue(safety),delete_issue_comment(safety),add_commit_comment(write op),create_pipeline_variable/update_pipeline_variable/delete_pipeline_variable(write ops),create_pipeline_schedule/update_pipeline_schedule/delete_pipeline_schedule(write ops),delete_pipeline_cache(safety),create_environment/delete_environment/create_deployment_variable/update_deployment_variable/delete_deployment_variable(write ops),create_branch_restriction/update_branch_restriction/delete_branch_restriction(write ops). Enable inconfigs/tools.json.
Governance scopes — Branch restriction read tools need the
repositoryscope (repository:adminmay be required depending on repo config); the write tools needrepository:admin. Workspace member/permission tools need theaccountscope. The/membersendpoint lists users without a per-user permission (uselist_workspace_permissionsfor roles).
Deployments scopes — the read tools (
list_environments,get_environment,list_deployments,get_deployment,list_deployment_variables) need thedeploymentscope; the write tools needdeployment:write. Bitbucket has no server-side filter for deployments by environment (BCLOUD-18729) — filter on theenvironmentfield oflist_deploymentsinstead. There is noupdate_environmenttool: Bitbucket exposes noPUTfor environments (onlyPOST .../changesfor locking).
By default the server reads configs/tools.json bundled with the package. You can point to a custom file at runtime without rebuilding:
export BITBUCKET_TOOLS_CONFIG=/path/to/my-tools.json
Fallback chain (first match wins):
BITBUCKET_TOOLS_CONFIG environment variableconfigs/tools.jsonFail-safe behaviour — If
BITBUCKET_TOOLS_CONFIGis set but the file is missing or contains invalid JSON, the server raises an error on startup (explicit failure rather than silently ignoring the override). If the built-in default is missing, all tools are enabled.
Token tip —
get_pull_request_diffaccepts an optionalpathparameter to filter the diff to a single file, reducing token usage by ~95% on large PRs:get_pull_request_diff(repo_slug, pull_request_id, path="src/services/myService.ts")
The server also exposes MCP Prompts — parameterised templates that compatible clients (Claude Code, Cursor, ...) surface as slash commands. Instead of remembering tool names, you invoke a prompt and the assistant orchestrates the right tools for you. They appear in the client's prompt picker (prompts/list).
| Prompt | Arguments | What it does |
|---|---|---|
review_pull_request | repo_slug, pull_request_id | Full AI review: metadata → diffstat → diff → comments → tasks, then Summary / Risk / Quality / Security / Recommendation |
debug_pipeline_failure | repo_slug, pipeline_uuid | Diagnose a failed pipeline: run → steps → failed-step logs, then Root cause / Failed step / Error / Fix |
summarize_repository | repo_slug | Repo overview: info → recent commits → open PRs → CI → issues, then Purpose / Activity / Health / Contributors |
onboard_reviewer | repo_slug, pull_request_id | Help a new reviewer: PR context → commits → diff → review history, then Context / Changes / Review-so-far / Focus |
Prompts are enabled/disabled in configs/tools.json under the top-level prompts key (separate from tools).
.env file (recommended)cp .env.example .env
# Edit .env with your credentials
pip install 'bitbucket-mcp-py[keyring]'
python3 -c "import keyring; keyring.set_password('bitbucket-mcp', 'bitbucket_token', 'YOUR_TOKEN')"
If you prefer running the server in a container:
docker build -t bitbucket-mcp-py .
docker run -d --name bitbucket-mcp --env-file .env bitbucket-mcp-py
Then configure your AI assistant to use docker exec:
{
"mcpServers": {
"bitbucket-mcp": {
"command": "docker",
"args": ["exec", "-i", "bitbucket-mcp", "python", "-m", "src.main", "--transport", "stdio"]
}
}
}
The server speaks stdio by default (the standard transport for local MCP clients). For a network deployment it also supports Streamable HTTP (MCP spec 2025-03-26):
# Streamable HTTP on 0.0.0.0:8080
python -m src.main --transport http --host 0.0.0.0 --port 8080
Clients connect to
http://<host>:<port>/mcp(e.g.http://localhost:8080/mcp).
--transport sse(legacy Server-Sent Events) is still accepted but deprecated — it emits aDeprecationWarning. Prefer--transport http.
--stateless runs the Streamable HTTP transport without server-side sessions: no Mcp-Session-Id, a fresh transport per HTTP request. Any instance behind a load balancer can serve any request — no sticky sessions required.
python -m src.main --transport http --host 0.0.0.0 --port 8080 --stateless
⚠️ Single-tenant only. The server serves its own process-wide Bitbucket token to every caller. Deploy it on a private network or behind an authenticated reverse proxy. Per-request credentials (multi-tenant) are tracked in #72.
--stateless requires --transport http (it is rejected on stdio and on the legacy sse, whose app ignores the setting). It also forces a single JSON response instead of an SSE stream, because edge/serverless runtimes cannot hold a streaming response open — there is currently no way to combine stateless with streaming.
A liveness endpoint is exposed on both HTTP transports for load balancers:
curl http://localhost:8080/healthz # {"status": "ok"}
In a container — the image's default CMD keeps it idle for exec-based stdio usage, so server mode is started by overriding the command:
podman run -d --name bitbucket-mcp-http -p 8000:8000 --env-file .env bitbucket-mcp-py \
python -m src.main --transport http --host 0.0.0.0 --port 8000 --stateless
Works identically with
docker run. The image exposes port 8000.
| Environment variable | Default | Purpose |
|---|---|---|
BITBUCKET_ALLOWED_HOSTS | (unset) | Comma-separated Host allowlist. Enables DNS-rebinding protection when set. |
BITBUCKET_ALLOWED_ORIGINS | (unset) | Comma-separated Origin allowlist. |
BITBUCKET_MAX_PAGES_HARD_CAP | 10 | Max pages a single tool call may fetch in stateless mode. Beyond it the response carries truncated: true — never a silent cut. |
The two allowlists must be set together: an empty
Hostallowlist rejects every request (421), and an emptyOriginallowlist rejects every browser client (403). Setting only one is refused at startup rather than silently locking the server out.
export BITBUCKET_ALLOWED_HOSTS="mcp.example.com"
export BITBUCKET_ALLOWED_ORIGINS="https://app.example.com"
With neither allowlist set, no DNS-rebinding protection is applied — appropriate for a server reached through a private network or a trusted proxy. Set them as soon as the server is exposed on a real hostname.
# Install dev dependencies
uv sync --extra dev
# Run tests
uv run pytest tests/ -v
# Run specific test
uv run pytest tests/test_client.py -v
MIT
FAQs
MCP Server for Bitbucket API - Container optimized with configurable tools, structured output and slim responses
The pypi package bitbucket-mcp-py receives a total of 481 weekly downloads. As such, bitbucket-mcp-py popularity was classified as not popular.
We found that bitbucket-mcp-py demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.