An MCP (Model Context Protocol) server that provides tools for interacting with the Bitbucket API, supporting both Bitbucket Cloud and Bitbucket Server.
-
get_pull_request
- Retrieve detailed information about a pull request -
list_pull_requests
- List pull requests with filters (state, author, pagination) -
create_pull_request
- Create new pull requests -
update_pull_request
- Update PR details (title, description, reviewers, destination branch) -
add_comment
- Add comments to pull requests (supports replies) -
merge_pull_request
- Merge pull requests with various strategies -
delete_branch
- Delete branches after merge
-
list_branches
- List branches with filtering and pagination -
delete_branch
- Delete branches (with protection checks) -
get_branch
- Get detailed branch information including associated PRs
-
list_directory_content
- List files and directories in a repository path -
get_file_content
- Get file content with smart truncation for large files
-
get_pull_request_diff
- Get the diff/changes for a pull request -
approve_pull_request
- Approve a pull request -
unapprove_pull_request
- Remove approval from a pull request -
request_changes
- Request changes on a pull request -
remove_requested_changes
- Remove change request from a pull request
The easiest way to use this MCP server is directly with npx:
{
"mcpServers": {
"bitbucket": {
"command": "npx",
"args": [
"-y",
"@nexus2520/bitbucket-mcp-server"
],
"env": {
"BITBUCKET_USERNAME": "your-username",
"BITBUCKET_APP_PASSWORD": "your-app-password"
}
}
}
}
For Bitbucket Server:
{
"mcpServers": {
"bitbucket": {
"command": "npx",
"args": [
"-y",
"@nexus2520/bitbucket-mcp-server"
],
"env": {
"BITBUCKET_USERNAME": "your.email@company.com",
"BITBUCKET_TOKEN": "your-http-access-token",
"BITBUCKET_BASE_URL": "https://bitbucket.yourcompany.com"
}
}
}
}
- Clone or download this repository
- Install dependencies:
npm install
- Build the TypeScript code:
npm run build
This server uses Bitbucket App Passwords for authentication.
- Log in to your Bitbucket account
- Navigate to: https://bitbucket.org/account/settings/app-passwords/
- Click "Create app password"
- Give it a descriptive label (e.g., "MCP Server")
- Select the following permissions:
- Account: Read
- Repositories: Read, Write
- Pull requests: Read, Write
- Click "Create"
- Important: Copy the generated password immediately (you won't be able to see it again!)
node scripts/setup-auth.js
This will guide you through the authentication setup process.
Add the server to your MCP settings file (usually located at ~/.vscode-server/data/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json
):
{
"mcpServers": {
"bitbucket": {
"command": "node",
"args": ["/absolute/path/to/bitbucket-mcp-server/build/index.js"],
"env": {
"BITBUCKET_USERNAME": "your-username",
"BITBUCKET_APP_PASSWORD": "your-app-password"
}
}
}
}
Replace:
-
/absolute/path/to/bitbucket-mcp-server
with the actual path to this directory -
your-username
with your Bitbucket username (not email) -
your-app-password
with the app password you created
For Bitbucket Server, use:
{
"mcpServers": {
"bitbucket": {
"command": "node",
"args": ["/absolute/path/to/bitbucket-mcp-server/build/index.js"],
"env": {
"BITBUCKET_USERNAME": "your.email@company.com",
"BITBUCKET_TOKEN": "your-http-access-token",
"BITBUCKET_BASE_URL": "https://bitbucket.yourcompany.com"
}
}
}
}
Important for Bitbucket Server users:
- Use your full email address as the username (e.g., "john.doe@company.com")
- This is required for approval/review actions to work correctly
Once configured, you can use the available tools:
{
"tool": "get_pull_request",
"arguments": {
"workspace": "PROJ", // Required - your project key
"repository": "my-repo",
"pull_request_id": 123
}
}
Returns detailed information about the pull request including:
- Title and description
- Author and reviewers
- Source and destination branches
- Approval status
- Links to web UI and diff
-
Merge commit details (when PR is merged):
-
merge_commit_hash
: The hash of the merge commit -
merged_by
: Who performed the merge -
merged_at
: When the merge occurred -
merge_commit_message
: The merge commit message
-
-
Active comments with nested replies (unresolved comments that need attention):
-
active_comments
: Array of active comments (up to 20 most recent top-level comments)- Comment text and author
- Creation date
- Whether it's an inline comment (with file path and line number)
-
Nested replies (for Bitbucket Server):
-
replies
: Array of reply comments with same structure - Replies can be nested multiple levels deep
-
-
Parent reference (for Bitbucket Cloud):
-
parent_id
: ID of the parent comment for replies
-
-
active_comment_count
: Total count of unresolved comments (including nested replies) -
total_comment_count
: Total count of all comments (including resolved and replies)
-
-
File changes:
-
file_changes
: Array of all files modified in the PR- File path
- Status (added, modified, removed, or renamed)
- Old path (for renamed files)
-
file_changes_summary
: Summary statistics- Total files changed
-
- And more...
{
"tool": "list_pull_requests",
"arguments": {
"workspace": "PROJ", // Required - your project key
"repository": "my-repo",
"state": "OPEN", // Optional: OPEN, MERGED, DECLINED, ALL (default: OPEN)
"author": "username", // Optional: filter by author (see note below)
"limit": 25, // Optional: max results per page (default: 25)
"start": 0 // Optional: pagination start index (default: 0)
}
}
Returns a paginated list of pull requests with:
- Array of pull requests with same details as get_pull_request
- Total count of matching PRs
- Pagination info (has_more, next_start)
Note on Author Filter:
- For Bitbucket Cloud: Use the username (e.g., "johndoe")
- For Bitbucket Server: Use the full email address (e.g., "john.doe@company.com")
{
"tool": "create_pull_request",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"title": "Add new feature",
"source_branch": "feature/new-feature",
"destination_branch": "main",
"description": "This PR adds a new feature...", // Optional
"reviewers": ["john.doe", "jane.smith"], // Optional
"close_source_branch": true // Optional (default: false)
}
}
{
"tool": "update_pull_request",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"title": "Updated title", // Optional
"description": "Updated description", // Optional
"destination_branch": "develop", // Optional
"reviewers": ["new.reviewer"] // Optional - see note below
}
}
Important Note on Reviewers:
- When updating a PR without specifying the
reviewers
parameter, existing reviewers and their approval status are preserved - When providing the
reviewers
parameter:- The reviewer list is replaced with the new list
- For reviewers that already exist on the PR, their approval status is preserved
- New reviewers are added without approval status
- This prevents accidentally removing reviewers when you only want to update the PR description or title
Add a comment to a pull request, either as a general comment or inline on specific code:
// General comment
{
"tool": "add_comment",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"comment_text": "Great work on this PR!"
}
}
// Inline comment on specific line
{
"tool": "add_comment",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"comment_text": "Consider extracting this into a separate function",
"file_path": "src/utils/helpers.js",
"line_number": 42,
"line_type": "CONTEXT" // ADDED, REMOVED, or CONTEXT
}
}
// Reply to existing comment
{
"tool": "add_comment",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"comment_text": "I agree with this suggestion",
"parent_comment_id": 456
}
}
// Add comment with code suggestion (single line)
{
"tool": "add_comment",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"comment_text": "This variable name could be more descriptive.",
"file_path": "src/utils/helpers.js",
"line_number": 42,
"line_type": "CONTEXT",
"suggestion": "const userAuthenticationToken = token;"
}
}
// Add comment with multi-line code suggestion
{
"tool": "add_comment",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"comment_text": "This function could be simplified using array methods.",
"file_path": "src/utils/calculations.js",
"line_number": 50,
"suggestion_end_line": 55,
"line_type": "CONTEXT",
"suggestion": "function calculateTotal(items) {\n return items.reduce((sum, item) => sum + item.price, 0);\n}"
}
}
The suggestion feature formats comments using GitHub-style markdown suggestion blocks that Bitbucket can render. When adding a suggestion:
-
suggestion
is required and contains the replacement code -
file_path
andline_number
are required when using suggestions -
suggestion_end_line
is optional and used for multi-line suggestions (defaults toline_number
) - The comment will be formatted with a ````suggestion` markdown block that may be applicable in the Bitbucket UI
The add_comment
tool now supports finding line numbers automatically using code snippets. This is especially useful when AI tools analyze diffs and may struggle with exact line numbers:
// Add comment using code snippet
{
"tool": "add_comment",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"comment_text": "This variable name could be more descriptive",
"file_path": "src/components/Button.res",
"code_snippet": "let isDisabled = false",
"search_context": {
"before": ["let onClick = () => {"],
"after": ["setLoading(true)"]
}
}
}
// Handle multiple matches with strategy
{
"tool": "add_comment",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"comment_text": "Consider extracting this",
"file_path": "src/utils/helpers.js",
"code_snippet": "return result;",
"search_context": {
"before": ["const result = calculate();"],
"after": ["}"]
},
"match_strategy": "best" // Auto-select highest confidence match
}
}
Code Snippet Parameters:
-
code_snippet
: The exact code line to find (alternative toline_number
) -
search_context
: Optional context to disambiguate multiple matches-
before
: Array of lines that should appear before the target -
after
: Array of lines that should appear after the target
-
-
match_strategy
: How to handle multiple matches-
"strict"
(default): Fail with error showing all matches -
"best"
: Auto-select the highest confidence match
-
Error Response for Multiple Matches (strict mode):
{
"error": {
"code": "MULTIPLE_MATCHES_FOUND",
"message": "Code snippet 'return result;' found in 3 locations",
"occurrences": [
{
"line_number": 42,
"file_path": "src/utils/helpers.js",
"preview": " const result = calculate();\n> return result;\n}",
"confidence": 0.9,
"line_type": "ADDED"
},
// ... more matches
],
"suggestion": "To resolve, either:\n1. Add more context...\n2. Use match_strategy: 'best'...\n3. Use line_number directly"
}
}
This feature is particularly useful for:
- AI-powered code review tools that analyze diffs
- Scripts that automatically add comments based on code patterns
- Avoiding line number confusion in large diffs
Note on comment replies:
- Use
parent_comment_id
to reply to any comment (general or inline) - In
get_pull_request
responses:- Bitbucket Server shows replies nested in a
replies
array - Bitbucket Cloud shows a
parent_id
field for reply comments
- Bitbucket Server shows replies nested in a
- You can reply to replies, creating nested conversations
Note on inline comments:
-
file_path
: The path to the file as shown in the diff -
line_number
: The line number as shown in the diff -
line_type
:-
ADDED
- For newly added lines (green in diff) -
REMOVED
- For deleted lines (red in diff) -
CONTEXT
- For unchanged context lines
-
The add_comment
tool supports multiple scenarios. Here's when and how to use each approach:
1. General PR Comments (No file/line)
- Use when: Making overall feedback about the PR
- Required params:
comment_text
only - Example: "LGTM!", "Please update the documentation"
2. Reply to Existing Comments
- Use when: Continuing a conversation thread
- Required params:
comment_text
,parent_comment_id
- Works for both general and inline comment replies
3. Inline Comments with Line Number
- Use when: You know the exact line number from the diff
- Required params:
comment_text
,file_path
,line_number
- Optional:
line_type
(defaults to CONTEXT)
4. Inline Comments with Code Snippet
- Use when: You have the code but not the line number (common for AI tools)
- Required params:
comment_text
,file_path
,code_snippet
- The tool will automatically find the line number
- Add
search_context
if the code appears multiple times - Use
match_strategy: "best"
to auto-select when multiple matches exist
5. Code Suggestions
- Use when: Proposing specific code changes
- Required params:
comment_text
,file_path
,line_number
,suggestion
- For multi-line: also add
suggestion_end_line
- Creates applicable suggestion blocks in Bitbucket UI
Decision Flow for AI/Automated Tools:
1. Do you want to suggest code changes?
→ Use suggestion with line_number
2. Do you have the exact line number?
→ Use line_number directly
3. Do you have the code snippet but not line number?
→ Use code_snippet (add search_context if needed)
4. Is it a general comment about the PR?
→ Use comment_text only
5. Are you replying to another comment?
→ Add parent_comment_id
Common Pitfalls to Avoid:
- Don't use both
line_number
andcode_snippet
- pick one - Suggestions always need
file_path
andline_number
- Code snippets must match exactly (including whitespace)
- REMOVED lines reference the source file, ADDED/CONTEXT reference the destination
{
"tool": "merge_pull_request",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"merge_strategy": "squash", // Optional: merge-commit, squash, fast-forward
"close_source_branch": true, // Optional
"commit_message": "Custom merge message" // Optional
}
}
{
"tool": "list_branches",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"filter": "feature", // Optional: filter by name pattern
"limit": 25, // Optional (default: 25)
"start": 0 // Optional: for pagination (default: 0)
}
}
Returns a paginated list of branches with:
- Branch name and ID
- Latest commit hash
- Default branch indicator
- Pagination info
{
"tool": "delete_branch",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"branch_name": "feature/old-feature",
"force": false // Optional (default: false)
}
}
Note: Branch deletion requires appropriate permissions. The branch will be permanently deleted.
{
"tool": "get_branch",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"branch_name": "feature/new-feature",
"include_merged_prs": false // Optional (default: false)
}
}
Returns comprehensive branch information including:
- Branch details:
- Name and ID
- Latest commit (hash, message, author, date)
- Default branch indicator
- Open pull requests from this branch:
- PR title and ID
- Destination branch
- Author and reviewers
- Approval status (approved by, changes requested by, pending)
- PR URL
- Merged pull requests (if
include_merged_prs
is true):- PR title and ID
- Merge date and who merged it
- Statistics:
- Total open PRs count
- Total merged PRs count
- Days since last commit
This tool is particularly useful for:
- Checking if a branch has open PRs before deletion
- Getting an overview of branch activity
- Understanding PR review status
- Identifying stale branches
Get the diff/changes for a pull request with optional filtering capabilities:
// Get full diff (default behavior)
{
"tool": "get_pull_request_diff",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"context_lines": 5 // Optional (default: 3)
}
}
// Exclude specific file types
{
"tool": "get_pull_request_diff",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"exclude_patterns": ["*.lock", "*.svg", "node_modules/**", "*.min.js"]
}
}
// Include only specific file types
{
"tool": "get_pull_request_diff",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"include_patterns": ["*.res", "*.resi", "src/**/*.js"]
}
}
// Get diff for a specific file only
{
"tool": "get_pull_request_diff",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"file_path": "src/components/Button.res"
}
}
// Combine filters
{
"tool": "get_pull_request_diff",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"include_patterns": ["src/**/*"],
"exclude_patterns": ["*.test.js", "*.spec.js"]
}
}
Filtering Options:
-
include_patterns
: Array of glob patterns to include (whitelist) -
exclude_patterns
: Array of glob patterns to exclude (blacklist) -
file_path
: Get diff for a specific file only - Patterns support standard glob syntax (e.g.,
*.js
,src/**/*.res
,!test/**
)
Response includes filtering metadata:
{
"message": "Pull request diff retrieved successfully",
"pull_request_id": 123,
"diff": "..filtered diff content..",
"filter_metadata": {
"total_files": 15,
"included_files": 12,
"excluded_files": 3,
"excluded_file_list": ["package-lock.json", "logo.svg", "yarn.lock"],
"filters_applied": {
"exclude_patterns": ["*.lock", "*.svg"]
}
}
}
{
"tool": "approve_pull_request",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123
}
}
{
"tool": "request_changes",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"pull_request_id": 123,
"comment": "Please address the following issues..." // Optional
}
}
{
"tool": "list_directory_content",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"path": "src/components", // Optional (defaults to root)
"branch": "main" // Optional (defaults to default branch)
}
}
Returns directory listing with:
- Path and branch information
- Array of contents with:
- Name
- Type (file or directory)
- Size (for files)
- Full path
- Total items count
{
"tool": "get_file_content",
"arguments": {
"workspace": "PROJ",
"repository": "my-repo",
"file_path": "src/index.ts",
"branch": "main", // Optional (defaults to default branch)
"start_line": 1, // Optional: starting line (1-based, use negative for from end)
"line_count": 100, // Optional: number of lines to return
"full_content": false // Optional: force full content (default: false)
}
}
Smart Truncation Features:
- Automatically truncates large files (>50KB) to prevent token overload
- Default line counts based on file type:
- Config files (.yml, .json): 200 lines
- Documentation (.md, .txt): 300 lines
- Code files (.ts, .js, .py): 500 lines
- Log files: Last 100 lines
- Use
start_line: -50
to get last 50 lines (tail functionality) - Files larger than 1MB require explicit
full_content: true
or line parameters
Returns file content with:
- File path and branch
- File size and encoding
- Content (full or truncated based on parameters)
- Line information (if truncated):
- Total lines in file
- Range of returned lines
- Truncation indicator
- Last modified information (commit, author, date)
Example responses:
// Small file - returns full content
{
"file_path": "package.json",
"branch": "main",
"size": 1234,
"encoding": "utf-8",
"content": "{\n \"name\": \"my-project\",\n ...",
"last_modified": {
"commit_id": "abc123",
"author": "John Doe",
"date": "2025-01-21T10:00:00Z"
}
}
// Large file - automatically truncated
{
"file_path": "src/components/LargeComponent.tsx",
"branch": "main",
"size": 125000,
"encoding": "utf-8",
"content": "... first 500 lines ...",
"line_info": {
"total_lines": 3500,
"returned_lines": {
"start": 1,
"end": 500
},
"truncated": true,
"message": "Showing lines 1-500 of 3500. File size: 122.1KB"
}
}
-
npm run dev
- Watch mode for development -
npm run build
- Build the TypeScript code -
npm start
- Run the built server
- Authentication errors: Double-check your username and app password
- 404 errors: Verify the workspace, repository slug, and PR ID
- Permission errors: Ensure your app password has the required permissions
MIT