@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
175 lines (174 loc) • 8.29 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatRepositoriesList = formatRepositoriesList;
exports.formatRepositoryDetails = formatRepositoryDetails;
exports.formatCommitHistory = formatCommitHistory;
const formatter_util_js_1 = require("../utils/formatter.util.js");
/**
* Format a list of repositories for display
* @param repositoriesData - Raw repositories data from the API
* @returns Formatted string with repositories information in markdown format
*/
function formatRepositoriesList(repositoriesData) {
const repositories = repositoriesData.values || [];
if (repositories.length === 0) {
return 'No repositories found matching your criteria.';
}
const lines = [(0, formatter_util_js_1.formatHeading)('Bitbucket Repositories', 1), ''];
// Format each repository with its details
const formattedList = (0, formatter_util_js_1.formatNumberedList)(repositories, (repo, _index) => {
const itemLines = [];
itemLines.push((0, formatter_util_js_1.formatHeading)(repo.name, 2));
// Basic information
const properties = {
Name: repo.name,
'Full Name': repo.full_name,
Owner: repo.owner?.display_name || repo.owner?.username || 'Unknown',
Description: repo.description || 'No description provided',
'Project Key': repo.project?.key || 'N/A',
Private: repo.is_private ? 'Yes' : 'No',
Created: repo.created_on ? (0, formatter_util_js_1.formatDate)(repo.created_on) : 'N/A',
Updated: repo.updated_on ? (0, formatter_util_js_1.formatDate)(repo.updated_on) : 'N/A',
URL: repo.links?.html?.href
? (0, formatter_util_js_1.formatUrl)(repo.links.html.href, repo.full_name)
: 'N/A',
};
// Format as a bullet list
itemLines.push((0, formatter_util_js_1.formatBulletList)(properties, (key) => key));
return itemLines.join('\n');
});
lines.push(formattedList);
// Add standard footer with timestamp
lines.push('\n\n' + (0, formatter_util_js_1.formatSeparator)());
lines.push(`*Information retrieved at: ${(0, formatter_util_js_1.formatDate)(new Date())}*`);
return lines.join('\n');
}
/**
* Format detailed repository information for display
* @param repositoryData - Raw repository data from the API
* @param pullRequestsData - Optional pull requests data for this repository
* @returns Formatted string with repository details in markdown format
*/
function formatRepositoryDetails(repositoryData, pullRequestsData) {
// Create URL
const repoUrl = repositoryData.links?.html?.href || '';
const lines = [
(0, formatter_util_js_1.formatHeading)(`Repository: ${repositoryData.name}`, 1),
'',
`> A ${repositoryData.is_private ? 'private' : 'public'} repository in the \`${repositoryData.full_name}\` workspace.`,
'',
(0, formatter_util_js_1.formatHeading)('Basic Information', 2),
];
// Format basic information as a bullet list
const basicProperties = {
Name: repositoryData.name,
'Full Name': repositoryData.full_name,
UUID: repositoryData.uuid,
Description: repositoryData.description || 'No description provided',
Language: repositoryData.language || 'Not specified',
'Main Branch': repositoryData.mainbranch?.name || 'N/A',
Private: repositoryData.is_private ? 'Yes' : 'No',
Size: repositoryData.size
? `${(repositoryData.size / 1024).toFixed(2)} KB`
: 'Unknown',
'Created On': repositoryData.created_on
? (0, formatter_util_js_1.formatDate)(repositoryData.created_on)
: 'N/A',
'Updated On': repositoryData.updated_on
? (0, formatter_util_js_1.formatDate)(repositoryData.updated_on)
: 'N/A',
};
lines.push((0, formatter_util_js_1.formatBulletList)(basicProperties, (key) => key));
// Owner information
if (repositoryData.owner) {
lines.push('');
lines.push((0, formatter_util_js_1.formatHeading)('Owner', 2));
const ownerProperties = {
Name: repositoryData.owner.display_name ||
repositoryData.owner.username ||
'Unknown',
Type: repositoryData.owner.type || 'Not specified',
};
lines.push((0, formatter_util_js_1.formatBulletList)(ownerProperties, (key) => key));
}
// Links section
lines.push('');
lines.push((0, formatter_util_js_1.formatHeading)('Links', 2));
if (repoUrl) {
lines.push(`- ${(0, formatter_util_js_1.formatUrl)(repoUrl, 'Open in Bitbucket')}`);
}
// Add recent pull requests section if available
if (pullRequestsData &&
pullRequestsData.values &&
pullRequestsData.values.length > 0) {
lines.push('');
lines.push((0, formatter_util_js_1.formatHeading)('Recent Pull Requests', 2));
const prList = pullRequestsData.values.slice(0, 25); // Ensure max 25
const formattedPrList = (0, formatter_util_js_1.formatNumberedList)(prList, (pr) => {
return `**#${pr.id}**: [${pr.title}](${pr.links.html?.href || '#'}) - ${pr.state} by ${pr.author.display_name || 'Unknown'} (${(0, formatter_util_js_1.formatDate)(pr.updated_on)})`;
});
lines.push(formattedPrList);
if (repoUrl) {
lines.push(`*View all pull requests in Bitbucket: [${repositoryData.full_name}/pull-requests](${repoUrl}/pull-requests)*`);
}
}
else {
// Add the section even if no PRs are available
lines.push('');
lines.push((0, formatter_util_js_1.formatHeading)('Recent Pull Requests', 2));
lines.push('No open pull requests found for this repository.');
if (repoUrl) {
lines.push(`*View all pull requests in Bitbucket: [${repositoryData.full_name}/pull-requests](${repoUrl}/pull-requests)*`);
}
}
// Add standard footer with timestamp
lines.push('\n\n' + (0, formatter_util_js_1.formatSeparator)());
lines.push(`*Information retrieved at: ${(0, formatter_util_js_1.formatDate)(new Date())}*`);
// Optionally keep the direct link
if (repoUrl) {
lines.push(`*View this repository in Bitbucket: ${repoUrl}*`);
}
return lines.join('\n');
}
/**
* Format commit history for display.
* @param commitsData - Raw paginated commits data from the API.
* @param options - Filtering options used to retrieve the history.
* @returns Formatted string with commit history in markdown format.
*/
function formatCommitHistory(commitsData, options = {}) {
const commits = commitsData.values || [];
if (commits.length === 0) {
return 'No commits found matching your criteria.';
}
const headerParts = ['Commit History'];
if (options.revision) {
headerParts.push(`for revision \`${options.revision}\``);
}
if (options.path) {
headerParts.push(`on path \`${options.path}\``);
}
const lines = [(0, formatter_util_js_1.formatHeading)(headerParts.join(' '), 1), ''];
const formattedList = (0, formatter_util_js_1.formatNumberedList)(commits, (commit) => {
const commitLines = [];
const author = commit.author?.user?.display_name ||
commit.author?.raw ||
'Unknown';
const commitUrl = commit.links?.html?.href;
const shortHash = commit.hash.substring(0, 7);
// Header: Hash (linked) - Date
commitLines.push(`**${commitUrl ? (0, formatter_util_js_1.formatUrl)(commitUrl, shortHash) : shortHash}** - ${(0, formatter_util_js_1.formatDate)(commit.date)}`);
// Author
commitLines.push(` Author: ${author}`);
// Message (indented blockquote)
const message = commit.message.trim().replace(/\n/g, '\n > ');
commitLines.push(' >');
commitLines.push(` > ${message}`);
return commitLines.join('\n');
});
lines.push(formattedList);
// Add standard footer with timestamp
lines.push('\n\n' + (0, formatter_util_js_1.formatSeparator)());
lines.push(`*Information retrieved at: ${(0, formatter_util_js_1.formatDate)(new Date())}*`);
return lines.join('\n');
}