@aashari/mcp-server-atlassian-bitbucket
Version:
Node.js/TypeScript MCP server for Atlassian Bitbucket. Enables AI systems (LLMs) to interact with workspaces, repositories, and pull requests via tools (list, get, comment, search). Connects AI directly to version control workflows through the standard MC
254 lines (246 loc) • 13.1 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.register = register;
const logger_util_js_1 = require("../utils/logger.util.js");
const error_util_js_1 = require("../utils/error.util.js");
const atlassian_pullrequests_controller_js_1 = __importDefault(require("../controllers/atlassian.pullrequests.controller.js"));
const formatter_util_js_1 = require("../utils/formatter.util.js");
/**
* CLI module for managing Bitbucket pull requests.
* Provides commands for listing pull requests and retrieving pull request details.
* All commands require valid Atlassian credentials.
*/
// Create a contextualized logger for this file
const cliLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts');
// Log CLI initialization
cliLogger.debug('Bitbucket pull requests CLI module initialized');
/**
* Register the command for creating a pull request
* @param program - The Commander program instance
*/
function registerCreatePullRequestCommand(program) {
program
.command('create-pull-request')
.description(`Create a new pull request in a Bitbucket repository.
PURPOSE: Create a new pull request from one branch to another within a repository.
EXAMPLES:
$ mcp-atlassian-bitbucket create-pull-request -w workspace-slug -r repo-slug -t "New feature" -s feature/branch -d main
$ mcp-atlassian-bitbucket create-pull-request -w workspace-slug -r repo-slug -t "Bug fix" -s bugfix/issue-123 -d develop --description "This fixes issue #123" --close-source-branch`)
.requiredOption('-w, --workspace-slug <slug>', 'Workspace slug containing the repository')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug to create the pull request in')
.requiredOption('-t, --title <title>', 'Title for the pull request')
.requiredOption('-s, --source-branch <branch>', 'Source branch name (the branch containing your changes)')
.option('-d, --destination-branch <branch>', 'Destination branch name (the branch you want to merge into, defaults to main)')
.option('--description <text>', 'Description for the pull request')
.option('--close-source-branch', 'Close source branch after pull request is merged', false)
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'create-pull-request');
try {
actionLogger.debug('Processing command options:', options);
// Call controller
const result = await atlassian_pullrequests_controller_js_1.default.create({
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
title: options.title,
sourceBranch: options.sourceBranch,
destinationBranch: options.destinationBranch,
description: options.description,
closeSourceBranch: options.closeSourceBranch,
});
console.log(result.content);
}
catch (error) {
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register pull request commands with the Commander program
* @param program - The Commander program instance
*/
function register(program) {
const methodLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'register');
methodLogger.debug('Registering Bitbucket Pull Requests CLI commands...');
registerListPullRequestsCommand(program);
registerGetPullRequestCommand(program);
registerListPullRequestCommentsCommand(program);
registerAddPullRequestCommentCommand(program);
registerCreatePullRequestCommand(program);
methodLogger.debug('CLI commands registered successfully');
}
/**
* Register the command for listing pull requests within a repository
* @param program - The Commander program instance
*/
function registerListPullRequestsCommand(program) {
program
.command('list-pull-requests')
.description(`List pull requests within a specific Bitbucket repository.
PURPOSE: Discover pull requests in a repository and get their basic metadata, including title, state, author, source/destination branches, and reviewer information. Requires workspace and repository slugs.`)
.requiredOption('-w, --workspace-slug <slug>', 'Workspace slug containing the repository')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug to list pull requests from')
.option('-S, --state <state>', 'Filter by pull request state: OPEN, MERGED, DECLINED, SUPERSEDED')
.option('-q, --query <text>', 'Filter pull requests by title, description, or other properties (simple text search, not query language)')
.option('-l, --limit <number>', 'Maximum number of pull requests to return (1-100)')
.option('-c, --cursor <string>', 'Pagination cursor for retrieving the next set of results')
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'list-pull-requests');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller format
const controllerOptions = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
state: options.state,
query: options.query,
};
// Parse limit as number if provided
if (options.limit) {
const limit = parseInt(options.limit, 10);
if (isNaN(limit) || limit < 1 || limit > 100) {
throw new Error('Limit must be a number between 1 and 100');
}
controllerOptions.limit = limit;
}
// Add cursor if provided
if (options.cursor) {
controllerOptions.cursor = options.cursor;
}
const result = await atlassian_pullrequests_controller_js_1.default.list(controllerOptions);
console.log(result.content);
if (result.pagination) {
console.log((0, formatter_util_js_1.formatPagination)(result.pagination.count || 0, result.pagination.hasMore, result.pagination.nextCursor));
}
}
catch (error) {
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for retrieving a specific Bitbucket pull request
* @param program - The Commander program instance
*/
function registerGetPullRequestCommand(program) {
program
.command('get-pull-request')
.description(`Get detailed information about a specific Bitbucket pull request.
PURPOSE: Retrieve comprehensive metadata for a pull request, including its description, state, author, reviewers, branches, and links.`)
.requiredOption('-w, --workspace-slug <slug>', 'Workspace slug containing the repository')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug containing the pull request')
.requiredOption('-p, --pr-id <id>', 'Pull request ID to retrieve')
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'get-pull-request');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller format
const params = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
prId: options.prId,
};
const result = await atlassian_pullrequests_controller_js_1.default.get(params);
console.log(result.content);
}
catch (error) {
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for listing comments on a specific pull request
* @param program - The Commander program instance
*/
function registerListPullRequestCommentsCommand(program) {
program
.command('list-pr-comments')
.description(`List comments on a specific Bitbucket pull request.
PURPOSE: View all review feedback, discussions, and task comments on a pull request to understand code review context without accessing the web UI.`)
.requiredOption('-w, --workspace-slug <slug>', 'Workspace slug containing the repository')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug containing the pull request')
.requiredOption('-p, --pr-id <id>', 'Pull request ID to list comments from')
.option('-l, --limit <number>', 'Maximum number of comments to return (1-100)')
.option('-c, --cursor <string>', 'Pagination cursor for retrieving the next set of results')
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'list-pr-comments');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller format
const controllerOptions = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
prId: options.prId,
};
// Parse limit as number if provided
if (options.limit) {
const limit = parseInt(options.limit, 10);
if (isNaN(limit) || limit < 1 || limit > 100) {
throw new Error('Limit must be a number between 1 and 100');
}
controllerOptions.limit = limit;
}
// Add cursor if provided
if (options.cursor) {
controllerOptions.cursor = options.cursor;
}
const result = await atlassian_pullrequests_controller_js_1.default.listComments(controllerOptions);
console.log(result.content);
if (result.pagination) {
console.log((0, formatter_util_js_1.formatPagination)(result.pagination.count || 0, result.pagination.hasMore, result.pagination.nextCursor));
}
}
catch (error) {
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for adding a comment to a pull request
* @param program - The Commander program instance
*/
function registerAddPullRequestCommentCommand(program) {
program
.command('add-pr-comment')
.description(`Add a comment to a specific Bitbucket pull request.
PURPOSE: Create comments on a pull request to provide feedback, ask questions, or communicate with other reviewers/developers. Supports both general PR comments and inline code comments.
EXAMPLES:
$ mcp-atlassian-bitbucket add-pr-comment -w workspace-slug -r repo-slug -p 1 -c "This looks good to merge!"
$ mcp-atlassian-bitbucket add-pr-comment -w workspace-slug -r repo-slug -p 1 -c "Consider using a const here" --file src/utils.ts --line 42`)
.requiredOption('-w, --workspace-slug <slug>', 'Workspace slug containing the repository')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug containing the pull request')
.requiredOption('-p, --pr-id <id>', 'Pull request ID to comment on')
.requiredOption('-c, --content <text>', 'Content of the comment to add')
.option('--file <path>', 'File path for inline comments (requires --line)')
.option('--line <number>', 'Line number for inline comments (requires --file)', (val) => parseInt(val, 10))
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.pullrequests.cli.ts', 'add-pr-comment');
try {
actionLogger.debug('Processing command options:', options);
// Validate inline comment options
if ((options.file && !options.line) ||
(!options.file && options.line)) {
throw new Error('Both --file and --line must be provided together for inline comments');
}
// Build inline comment params if needed
const inline = options.file && options.line
? { path: options.file, line: options.line }
: undefined;
// Call controller
const result = await atlassian_pullrequests_controller_js_1.default.addComment({
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
prId: options.prId,
content: options.content,
inline,
});
console.log(result.content);
}
catch (error) {
(0, error_util_js_1.handleCliError)(error);
}
});
}
exports.default = { register };