@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
287 lines (286 loc) • 15.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const logger_util_js_1 = require("../utils/logger.util.js");
const error_util_js_1 = require("../utils/error.util.js");
// Import directly from specialized controllers
const atlassian_repositories_list_controller_js_1 = require("../controllers/atlassian.repositories.list.controller.js");
const atlassian_repositories_details_controller_js_1 = require("../controllers/atlassian.repositories.details.controller.js");
const atlassian_repositories_commit_controller_js_1 = require("../controllers/atlassian.repositories.commit.controller.js");
const atlassian_repositories_branch_controller_js_1 = require("../controllers/atlassian.repositories.branch.controller.js");
const atlassian_repositories_content_controller_js_1 = require("../controllers/atlassian.repositories.content.controller.js");
/**
* CLI module for managing Bitbucket repositories.
* Provides commands for listing repositories and retrieving repository details.
* All commands require valid Atlassian credentials.
*/
// Create a contextualized logger for this file
const cliLogger = logger_util_js_1.Logger.forContext('cli/atlassian.repositories.cli.ts');
// Log CLI initialization
cliLogger.debug('Bitbucket repositories CLI module initialized');
/**
* Register Bitbucket repositories CLI commands with the Commander program
*
* @param program - The Commander program instance to register commands with
* @throws Error if command registration fails
*/
function register(program) {
const methodLogger = logger_util_js_1.Logger.forContext('cli/atlassian.repositories.cli.ts', 'register');
methodLogger.debug('Registering Bitbucket Repositories CLI commands...');
registerListRepositoriesCommand(program);
registerGetRepositoryCommand(program);
registerGetCommitHistoryCommand(program);
registerAddBranchCommand(program);
registerCloneRepositoryCommand(program);
registerGetFileCommand(program);
registerListBranchesCommand(program);
methodLogger.debug('CLI commands registered successfully');
}
/**
* Register the command for listing Bitbucket repositories in a workspace
*
* @param program - The Commander program instance
*/
function registerListRepositoriesCommand(program) {
program
.command('ls-repos')
.description('List repositories in a Bitbucket workspace, with filtering and pagination.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repositories. If not provided, uses your default workspace (configured via BITBUCKET_DEFAULT_WORKSPACE or first workspace in your account). Example: "myteam"')
.option('-q, --query <string>', 'Filter repositories by this query string. Searches repository name and description.')
.option('-p, --project-key <key>', 'Filter repositories belonging to the specified project key. Example: "PROJ"')
.option('-r, --role <string>', 'Filter repositories where the authenticated user has the specified role or higher. Valid roles: `owner`, `admin`, `contributor`, `member`. Note: `member` typically includes all accessible repositories.')
.option('-s, --sort <string>', 'Sort repositories by this field. Examples: "name", "-updated_on" (default), "size".')
.option('-l, --limit <number>', 'Maximum number of items to return (1-100). Defaults to 25 if omitted.')
.option('-c, --cursor <string>', 'Pagination cursor for retrieving the next set of results.')
.action(async (options) => {
const actionLogger = cliLogger.forMethod('ls-repos');
try {
actionLogger.debug('CLI ls-repos called', options);
// Map CLI options to controller options - keep only type conversions
const controllerOptions = {
workspaceSlug: options.workspaceSlug,
query: options.query,
projectKey: options.projectKey,
role: options.role,
sort: options.sort,
limit: options.limit
? parseInt(options.limit, 10)
: undefined,
cursor: options.cursor,
};
// Call controller directly
const result = await (0, atlassian_repositories_list_controller_js_1.handleRepositoriesList)(controllerOptions);
// Output result content
console.log(result.content);
}
catch (error) {
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for retrieving a specific Bitbucket repository
* @param program - The Commander program instance
*/
function registerGetRepositoryCommand(program) {
program
.command('get-repo')
.description('Get detailed information about a specific Bitbucket repository.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repository. If not provided, uses your default workspace (either configured via BITBUCKET_DEFAULT_WORKSPACE or first workspace in your account). Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug to retrieve. Must be a valid repository in the workspace. Example: "project-api"')
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.repositories.cli.ts', 'get-repo');
try {
actionLogger.debug(`Fetching repository: ${options.workspaceSlug}/${options.repoSlug}`);
const result = await (0, atlassian_repositories_details_controller_js_1.handleRepositoryDetails)({
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
});
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for retrieving commit history from a repository
* @param program - The Commander program instance
*/
function registerGetCommitHistoryCommand(program) {
program
.command('get-commit-history')
.description('Get commit history for a Bitbucket repository.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repository. If not provided, uses your default workspace. Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug to get commit history from. Example: "project-api"')
.option('-v, --revision <branch-or-tag>', 'Filter commits by a specific branch, tag, or commit hash.')
.option('--path <file-path>', 'Filter commits to those that affect this specific file path.')
.option('-l, --limit <number>', 'Maximum number of commits to return (1-100). Defaults to 25 if omitted.')
.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.repositories.cli.ts', 'get-commit-history');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller params - keep only type conversions
const requestOptions = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
revision: options.revision,
path: options.path,
limit: options.limit
? parseInt(options.limit, 10)
: undefined,
cursor: options.cursor,
};
actionLogger.debug('Fetching commit history with options:', requestOptions);
const result = await (0, atlassian_repositories_commit_controller_js_1.handleCommitHistory)(requestOptions);
actionLogger.debug('Successfully retrieved commit history');
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for adding a branch to a repository
* @param program - The Commander program instance
*/
function registerAddBranchCommand(program) {
program
.command('add-branch')
.description('Add a new branch in a Bitbucket repository.')
.requiredOption('-w, --workspace-slug <slug>', 'Workspace slug containing the repository.')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug where the branch will be created.')
.requiredOption('-n, --new-branch-name <n>', 'The name for the new branch.')
.requiredOption('-s, --source-branch-or-commit <target>', 'The name of the existing branch or a full commit hash to branch from.')
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.repositories.cli.ts', 'add-branch');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller params
const requestOptions = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
newBranchName: options.newBranchName,
sourceBranchOrCommit: options.sourceBranchOrCommit,
};
actionLogger.debug('Creating branch with options:', requestOptions);
const result = await (0, atlassian_repositories_branch_controller_js_1.handleCreateBranch)(requestOptions);
actionLogger.debug('Successfully created branch');
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for cloning a Bitbucket repository.
*
* @param program - The Commander program instance
*/
function registerCloneRepositoryCommand(program) {
program
.command('clone')
.description('Clone a Bitbucket repository to your local filesystem using SSH (preferred) or HTTPS. ' +
'The repository will be cloned into a subdirectory at targetPath/repoSlug. ' +
'Requires Bitbucket credentials and proper SSH key setup for optimal usage.')
.requiredOption('-w, --workspace-slug <slug>', 'Workspace slug containing the repository. Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug to clone. Example: "project-api"')
.requiredOption('-t, --target-path <path>', 'Directory path where the repository will be cloned. Absolute paths are strongly recommended. Example: "/home/user/projects"')
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.repositories.cli.ts', 'clone');
try {
actionLogger.debug('Processing clone command options:', options);
// Map CLI options to controller params (already correct case)
const controllerOptions = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
targetPath: options.targetPath,
};
actionLogger.debug('Initiating repository clone with options:', controllerOptions);
const result = await (0, atlassian_repositories_content_controller_js_1.handleCloneRepository)(controllerOptions);
actionLogger.info('Clone operation initiated successfully.');
console.log(result.content);
}
catch (error) {
actionLogger.error('Clone operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for getting a file from a Bitbucket repository
*
* @param program - The Commander program instance
*/
function registerGetFileCommand(program) {
program
.command('get-file')
.description('Get the content of a file from a Bitbucket repository.')
.requiredOption('-w, --workspace-slug <slug>', 'Workspace slug containing the repository. Must be a valid workspace slug from your Bitbucket account. Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug to get the file from. Must be a valid repository slug in the specified workspace. Example: "project-api"')
.requiredOption('-f, --file-path <path>', 'Path to the file in the repository. Example: "README.md" or "src/main.js"')
.option('-v, --revision <branch-tag-or-commit>', 'Branch name, tag, or commit hash to retrieve the file from. If omitted, the default branch is used.')
.action(async (options) => {
const actionLogger = logger_util_js_1.Logger.forContext('cli/atlassian.repositories.cli.ts', 'get-file');
try {
actionLogger.debug(`Fetching file: ${options.workspaceSlug}/${options.repoSlug}/${options.filePath}`, options.revision ? { revision: options.revision } : {});
const result = await (0, atlassian_repositories_content_controller_js_1.handleGetFileContent)({
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
path: options.filePath,
ref: options.revision,
});
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
/**
* Register the command for listing branches in a repository
* @param program - The Commander program instance
*/
function registerListBranchesCommand(program) {
program
.command('list-branches')
.description('List branches in a Bitbucket repository.')
.option('-w, --workspace-slug <slug>', 'Workspace slug containing the repository. If not provided, uses your default workspace. Example: "myteam"')
.requiredOption('-r, --repo-slug <slug>', 'Repository slug to list branches from. Example: "project-api"')
.option('-q, --query <string>', 'Filter branches by name or other properties (text search).')
.option('-s, --sort <string>', 'Sort branches by this field. Examples: "name" (default), "-name", "target.date".')
.option('-l, --limit <number>', 'Maximum number of branches to return (1-100). Defaults to 25 if omitted.')
.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.repositories.cli.ts', 'list-branches');
try {
actionLogger.debug('Processing command options:', options);
// Map CLI options to controller params - keep only type conversions
const params = {
workspaceSlug: options.workspaceSlug,
repoSlug: options.repoSlug,
query: options.query,
sort: options.sort,
limit: options.limit
? parseInt(options.limit, 10)
: undefined,
cursor: options.cursor,
};
actionLogger.debug('Fetching branches with parameters:', params);
const result = await (0, atlassian_repositories_branch_controller_js_1.handleListBranches)(params);
actionLogger.debug('Successfully retrieved branches');
console.log(result.content);
}
catch (error) {
actionLogger.error('Operation failed:', error);
(0, error_util_js_1.handleCliError)(error);
}
});
}
exports.default = { register };