Bitbucket MCP (Model Context Protocol) server built with FastMCP that provides programmatic access to Bitbucket API v2.0
Project description
Unified Tool Server
This directory contains an alternative Bitbucket MCP server implementation that exposes all functionality through a single unified tool backed by comprehensive server instructions, following the patterns outlined in the MCP Server Instructions blog post.
Overview
Instead of providing 10 separate tools (pr_list, pr_overview, pr_review, etc.), the unified server exposes a single bitbucket tool with an action parameter. The server instructions (~200 lines) provide:
- Recommended workflows for common tasks (PR review, creation, pipeline debugging, workspace discovery)
- Action-specific guidance with parameter requirements and usage patterns
- Performance optimization tips (batching, pagination, auto-reviewers)
- Rate limits and constraints to prevent API abuse
- Error handling guidance for common issues
- Security notes for credential management
Architecture
unified_server.py # Main entry point
├─ src/modules/tools/unified.py # Single tool implementation
└─ Uses same infrastructure as server.py:
├─ src/modules/resources/ # MCP resources (unchanged)
├─ src/modules/prompts/ # MCP prompts (unchanged)
├─ src/modules/middleware/ # Auth middleware (unchanged)
└─ src/utils/ # Shared utilities (unchanged)
Running the Unified Server
# Direct execution
python unified_server.py --host 0.0.0.0 --port 8000
# With environment variables
FASTMCP_HOST=localhost FASTMCP_PORT=8000 python unified_server.py
Tool Interface
Single Tool: bitbucket
All Bitbucket operations are performed through this one tool by specifying the action parameter.
Available Actions:
pr_list- List pull requests with filteringpr_overview- Get PR digest with blockers, comments, diffstatpr_review- Generate structured review summarypr_comment_add- Add PR comments (inline or general)pr_comments_list- List comments on a pull requestpr_tasks_list- List PR tasks with detailspr_tasks_sync- Create/resolve PR tasks in batchpr_upsert- Create or update pull requestspipe_fail_summary- Analyze failing pipeline stepsworkspace_list- List repos, members, projects, or reviewersrepo_get- Get repository basics with PR sampleme_whoami- Get authenticated user identity
Example Usage
# List open PRs for current user
{
"action": "pr_list",
"author": "me",
"state": "OPEN",
"limit": 10
}
# Get PR overview
{
"action": "pr_overview",
"pr": "123"
}
# Create PR with auto-reviewers
{
"action": "pr_upsert",
"title": "Add new feature",
"source": "feature/my-branch",
"destination": "main",
"auto_reviewers": "default"
}
# Add inline comment
{
"action": "pr_comment_add",
"pr": "123",
"text": "Consider extracting this to a helper function",
"file": "src/main.py",
"line": 42
}
Command-Line Interface (bb-cli)
The same action-based surface is available from the terminal via bb-cli. It runs a
single action and prints the JSON result to stdout — clean to pipe into jq or consume
from an agent with bash access. Diagnostic logs go to stderr (silence with --quiet),
and the exit code is 0 on success, 1 on error (errors are emitted as parseable JSON).
# After `pip install -e .` the console script is on PATH:
bb-cli pr_list --author me --state OPEN --limit 5 --quiet | jq '.items'
# Or run the module directly without installing:
python cli.py pr_list --author me --state OPEN --limit 5 --quiet
Examples
# List open PRs for the current user
bb-cli pr_list --author me --state OPEN --limit 10
# PR overview / review
bb-cli pr_overview --pr 123
bb-cli pr_review --pr 123 --repo workspace/repo
# Add an inline comment (writes to Bitbucket)
bb-cli pr_comment_add --pr 123 --text "Extract this to a helper" --file src/main.py --line 42
# Batch create / resolve PR tasks
bb-cli pr_tasks_sync --pr 123 \
--create '[{"text":"fix typo","file":"a.py","line":3}]' \
--resolve 456,789
# Create a PR with auto-assigned reviewers
bb-cli pr_upsert --title "Add feature" --source feature/my-branch \
--destination main --auto-reviewers default
# Workspace discovery and repo basics
bb-cli workspace_list --kind repos --limit 20
bb-cli repo_get --slug workspace/repo --pretty
# Summarize the latest failing pipeline (with log excerpts)
bb-cli pipe_fail_summary --include-logs
List-valued flags (--create, --resolve, --reviewers) accept either a JSON array or
a comma-separated string. --state, --verbosity, --task-state, --kind, and
--auto-reviewers are restricted to the choices shown in --help.
-h, --help
usage: bb-cli [-h] [--quiet] [--pretty] [--repo REPO] [--limit LIMIT]
[--cursor CURSOR] [--verbosity {ids,summary,full}]
[--author AUTHOR]
[--state {OPEN,MERGED,DECLINED,SUPERSEDED,ALL}] [--pr PR]
[--text TEXT] [--file FILE] [--line LINE]
[--task-state {OPEN,RESOLVED,ALL}] [--create CREATE]
[--resolve RESOLVE] [--title TITLE] [--source SOURCE]
[--destination DESTINATION] [--summary SUMMARY]
[--reviewers REVIEWERS] [--auto-reviewers {default,all,none}]
[--close-source] [--draft]
[--kind {repos,members,projects,reviewers}]
[--workspace WORKSPACE] [--slug SLUG] [--pipeline PIPELINE]
[--include-logs]
{pr_list,pr_overview,pr_review,pr_comment_add,pr_comments_list,pr_tasks_list,pr_tasks_sync,pr_upsert,pipe_fail_summary,workspace_list,repo_get,me_whoami}
Run a single Bitbucket action and print its JSON result.
positional arguments:
{pr_list,pr_overview,pr_review,pr_comment_add,pr_comments_list,pr_tasks_list,pr_tasks_sync,pr_upsert,pipe_fail_summary,workspace_list,repo_get,me_whoami}
Operation to perform.
options:
-h, --help show this help message and exit
--quiet, -q Suppress diagnostic logs on stderr.
--pretty Pretty-print the JSON result.
--repo REPO 'workspace/repo' slug; falls back to configured
default.
--limit LIMIT Max items to return (1-50).
--cursor CURSOR Pagination cursor.
--verbosity {ids,summary,full}
Response detail level.
--author AUTHOR Filter PRs by author nickname; 'me' for current user.
--state {OPEN,MERGED,DECLINED,SUPERSEDED,ALL}
PR state filter.
--pr PR PR identifier, e.g. '123' or '#123'.
--text TEXT Comment text.
--file FILE File path for inline anchoring.
--line LINE Line number for inline anchoring.
--task-state {OPEN,RESOLVED,ALL}
Filter tasks by state.
--create CREATE Tasks to create: JSON array of {text,file,line}.
--resolve RESOLVE Task IDs to resolve: JSON array or comma-separated.
--title TITLE PR title.
--source SOURCE Source branch.
--destination DESTINATION
Destination branch.
--summary SUMMARY PR description/summary.
--reviewers REVIEWERS
Reviewer identifiers: JSON array or comma-separated.
--auto-reviewers {default,all,none}
Auto-assign reviewers.
--close-source Close source branch on merge.
--draft Create/update as draft.
--kind {repos,members,projects,reviewers}
Item type to list.
--workspace WORKSPACE
Workspace slug.
--slug SLUG Repository slug or 'workspace/repo'.
--pipeline PIPELINE Specific pipeline ID/number to analyze.
--include-logs Include full log excerpts.
Each action uses a subset of the flags below; unused flags are ignored. Run a
destructive action (pr_comment_add, pr_tasks_sync, pr_upsert) only when you
mean it — they write to Bitbucket.
Server Instructions
The unified server includes comprehensive instructions that are automatically injected into the LLM's context. These instructions guide the LLM to:
-
Follow optimal workflows
- Example: Use
pr_overviewbeforepr_reviewto gather context - Example: Use
pr_tasks_syncfor batch task operations instead of individual calls
- Example: Use
-
Understand cross-action relationships
- How
pr_upsertwithauto_reviewers="default"automatically fetches and assigns reviewers - When to use
pipe_fail_summaryafterpr_overviewshows failing checks
- How
-
Optimize performance
- Prefer
pr_overviewover multiple separate API calls - Use batching with
pr_tasks_syncfor multiple tasks - Leverage pagination with appropriate limits
- Prefer
-
Handle edge cases
- Required vs optional parameters for each action
- Parameter format variations (e.g., repo as "workspace/slug" or just "slug")
- Error messages and resolutions
Comparison: Multi-Tool vs Unified
Multi-Tool Server (server.py)
# Three separate tool calls
response1 = call_tool("pr_overview", {"pr": "123"})
response2 = call_tool("pr_review", {"pr": "123"})
response3 = call_tool("pr_comment_add", {
"pr": "123",
"text": "LGTM",
})
Pros:
- Fine-grained tool selection
- Familiar pattern for traditional MCP clients
- Can filter specific tools via
ALLOWED_TOOLS
Cons:
- Limited guidance on workflows
- LLM must infer optimal sequences
- Tool descriptions have space constraints
Unified Tool Server (unified_server.py)
# Same functionality, one tool interface
response1 = call_tool("bitbucket", {"action": "pr_overview", "pr": "123"})
response2 = call_tool("bitbucket", {"action": "pr_review", "pr": "123"})
response3 = call_tool("bitbucket", {
"action": "pr_comment_add",
"pr": "123",
"text": "LGTM"
})
Pros:
- Comprehensive server instructions guide optimal usage
- Documented workflows (PR review, creation, debugging)
- Performance optimization tips built-in
- Cross-action relationships explained
- Better for LLMs that benefit from detailed guidance
Cons:
- Single tool interface (action-based)
- Cannot selectively disable specific actions
- Server instructions increase context size (~200 lines)
When to Use Unified Server
Choose the unified server when:
- ✅ Your LLM client benefits from detailed contextual guidance
- ✅ You want optimized workflows documented in server instructions
- ✅ You prefer action-based tool invocation
- ✅ You want to follow MCP server instructions best practices
- ✅ You're working with LLMs that struggle with complex multi-tool orchestration
Choose the multi-tool server when:
- ✅ You need fine-grained tool filtering
- ✅ Your client has strict context size limits
- ✅ You prefer traditional tool-per-operation pattern
- ✅ You're integrating with existing MCP tooling
Implementation Details
The unified tool (src/modules/tools/unified.py) is a thin wrapper that:
- Accepts an
actionparameter and action-specific arguments - Validates required parameters based on the action
- Routes to the underlying implementation functions
- Returns the same response format as the individual tools
Key point: The unified server doesn't duplicate code. It uses the exact same tool implementations as the multi-tool server, just exposed through a different interface.
# unified.py routes to existing implementations
match action:
case BitbucketAction.PR_LIST:
return await pr_list(...) # Same function as multi-tool server
case BitbucketAction.PR_OVERVIEW:
return await pr_overview(...)
# ... etc
Configuration
The unified server uses the same configuration system as the multi-tool server:
Environment Variables:
BITBUCKET_USERNAME=your_username
BITBUCKET_APP_PASSWORD=your_app_password
BITBUCKET_WORKSPACE=workspace-name
BITBUCKET_REPO=repo-slug
FASTMCP_PORT=8000
FASTMCP_HOST=localhost
HTTP Headers (per-request):
X-BITBUCKET-WORKSPACE: override-workspace
X-BITBUCKET-REPO: override-repo
Authorization: Bearer <token>
Resources and Prompts
The unified server mounts the same resources and prompts as the multi-tool server:
Resources:
- Repository information
- Recent pipeline runs
- Open pull requests
- Workspace members
- Available branches
- Workspace projects
Prompts:
- All prompts from the resources server are available
Testing
# Syntax validation
python -m py_compile unified_server.py
python -m py_compile src/modules/tools/unified.py
# Type checking (with mypy installed)
mypy unified_server.py --ignore-missing-imports
# Runtime test (requires dependencies)
python unified_server.py --help
Migration from Multi-Tool Server
If you're currently using the multi-tool server and want to migrate:
-
Update your tool calls:
# Before call_tool("pr_list", {"author": "me"}) # After call_tool("bitbucket", {"action": "pr_list", "author": "me"})
-
Update your server startup:
# Before python server.py --port 8000 # After python unified_server.py --port 8000
-
No changes needed for:
- Environment variables
- HTTP headers
- Resources
- Prompts
- Authentication
Benefits of Server Instructions Pattern
Following the MCP blog post recommendations:
✅ Cross-feature relationships - Documents how actions interact ✅ Operational patterns - Specifies performance-optimized sequences ✅ Constraints and limitations - Clarifies rate limits and boundaries ✅ Model-agnostic language - Factual guidance without assumptions
The blog post testing showed 60% improvement in GPT models following optimal workflows when instructions were present.
Changelog
1.2.4
- Fix
me_whoamiand workspace auto-discovery hittingGET /2.0/workspaces, which Atlassian removed in CHANGE-2770 (returns410 Gone). Both now use the user-scoped replacementGET /2.0/user/workspaces.
1.2.3
- Add
bb-cli, a command-line wrapper over the unified tool surface. - Remove hardcoded credentials from
config.py.
License
Same as the main project.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bb_mcp_server-1.3.0.tar.gz.
File metadata
- Download URL: bb_mcp_server-1.3.0.tar.gz
- Upload date:
- Size: 51.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
14a96f89ee49ccb99e304ab94d91ce33304cd9b810f6574f4664e9d5b92e203a
|
|
| MD5 |
c58809796d0f87fcae429e2cd991d339
|
|
| BLAKE2b-256 |
30213dbdd3a114a62ac0f1e55129a602835bde5abf7a0e9adbbf80fc14e0ae08
|
Provenance
The following attestation bundles were made for bb_mcp_server-1.3.0.tar.gz:
Publisher:
publish.yml on jasonpaulso/bitbucket-openapi-generated
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bb_mcp_server-1.3.0.tar.gz -
Subject digest:
14a96f89ee49ccb99e304ab94d91ce33304cd9b810f6574f4664e9d5b92e203a - Sigstore transparency entry: 1816838702
- Sigstore integration time:
-
Permalink:
jasonpaulso/bitbucket-openapi-generated@6250382624016fbfa603825f695ddb0707b023da -
Branch / Tag:
refs/tags/v1.3.0 - Owner: https://github.com/jasonpaulso
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6250382624016fbfa603825f695ddb0707b023da -
Trigger Event:
push
-
Statement type:
File details
Details for the file bb_mcp_server-1.3.0-py3-none-any.whl.
File metadata
- Download URL: bb_mcp_server-1.3.0-py3-none-any.whl
- Upload date:
- Size: 59.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3940f31c2b1e588e8cdf7ee77a3f813dcf0eb4ce07361ebaea5fcfa05623301e
|
|
| MD5 |
de0ac580d698acbfa298a01c22ee6d3b
|
|
| BLAKE2b-256 |
de6335a72632e3fd573079612b8ab2dc18549832ba82553ed9e052a3af1e57f0
|
Provenance
The following attestation bundles were made for bb_mcp_server-1.3.0-py3-none-any.whl:
Publisher:
publish.yml on jasonpaulso/bitbucket-openapi-generated
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bb_mcp_server-1.3.0-py3-none-any.whl -
Subject digest:
3940f31c2b1e588e8cdf7ee77a3f813dcf0eb4ce07361ebaea5fcfa05623301e - Sigstore transparency entry: 1816838897
- Sigstore integration time:
-
Permalink:
jasonpaulso/bitbucket-openapi-generated@6250382624016fbfa603825f695ddb0707b023da -
Branch / Tag:
refs/tags/v1.3.0 - Owner: https://github.com/jasonpaulso
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6250382624016fbfa603825f695ddb0707b023da -
Trigger Event:
push
-
Statement type: