@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
103 lines (102 loc) • 4.61 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDiffstat = getDiffstat;
exports.getRawDiff = getRawDiff;
const zod_1 = require("zod");
const logger_util_js_1 = require("../utils/logger.util.js");
const transport_util_js_1 = require("../utils/transport.util.js");
const error_util_js_1 = require("../utils/error.util.js");
const vendor_atlassian_repositories_diff_types_js_1 = require("./vendor.atlassian.repositories.diff.types.js");
/**
* Base API path for Bitbucket REST API v2
*/
const API_PATH = '/2.0';
const serviceLogger = logger_util_js_1.Logger.forContext('services/vendor.atlassian.repositories.diff.service.ts');
serviceLogger.debug('Bitbucket diff service initialised');
/**
* Retrieve diffstat (per–file summary) between two refs (branches, tags or commits).
* Follows Bitbucket Cloud endpoint:
* GET /2.0/repositories/{workspace}/{repo_slug}/diffstat/{spec}
*/
async function getDiffstat(params) {
const methodLogger = serviceLogger.forMethod('getDiffstat');
methodLogger.debug('Fetching diffstat with params', params);
// Validate params
try {
vendor_atlassian_repositories_diff_types_js_1.GetDiffstatParamsSchema.parse(params);
}
catch (err) {
if (err instanceof zod_1.z.ZodError) {
throw (0, error_util_js_1.createApiError)(`Invalid parameters: ${err.errors.map((e) => e.message).join(', ')}`, 400, err);
}
throw err;
}
const credentials = (0, transport_util_js_1.getAtlassianCredentials)();
if (!credentials) {
throw (0, error_util_js_1.createAuthMissingError)('Atlassian credentials are required');
}
const query = new URLSearchParams();
if (params.pagelen)
query.set('pagelen', String(params.pagelen));
if (params.cursor)
query.set('page', String(params.cursor));
if (params.topic !== undefined)
query.set('topic', String(params.topic));
const queryString = query.toString() ? `?${query.toString()}` : '';
const encodedSpec = encodeURIComponent(params.spec);
const path = `${API_PATH}/repositories/${params.workspace}/${params.repo_slug}/diffstat/${encodedSpec}${queryString}`;
methodLogger.debug(`Requesting: ${path}`);
try {
const rawData = await (0, transport_util_js_1.fetchAtlassian)(credentials, path);
try {
const validated = vendor_atlassian_repositories_diff_types_js_1.DiffstatResponseSchema.parse(rawData);
return validated;
}
catch (error) {
if (error instanceof zod_1.z.ZodError) {
methodLogger.error('Bitbucket API response validation failed:', error.format());
throw (0, error_util_js_1.createApiError)(`Invalid response format from Bitbucket API for diffstat: ${error.message}`, 500, error);
}
throw error; // Re-throw any other errors
}
}
catch (error) {
if (error instanceof error_util_js_1.McpError)
throw error;
throw (0, error_util_js_1.createApiError)(`Failed to fetch diffstat: ${error instanceof Error ? error.message : String(error)}`, 500, error);
}
}
/**
* Retrieve raw unified diff between two refs.
* Endpoint: /diff/{spec}
*/
async function getRawDiff(params) {
const methodLogger = serviceLogger.forMethod('getRawDiff');
methodLogger.debug('Fetching raw diff', params);
try {
vendor_atlassian_repositories_diff_types_js_1.GetRawDiffParamsSchema.parse(params);
}
catch (err) {
if (err instanceof zod_1.z.ZodError) {
throw (0, error_util_js_1.createApiError)(`Invalid parameters: ${err.errors.map((e) => e.message).join(', ')}`, 400, err);
}
throw err;
}
const credentials = (0, transport_util_js_1.getAtlassianCredentials)();
if (!credentials) {
throw (0, error_util_js_1.createAuthMissingError)('Atlassian credentials are required');
}
const encodedSpec = encodeURIComponent(params.spec);
const path = `${API_PATH}/repositories/${params.workspace}/${params.repo_slug}/diff/${encodedSpec}`;
methodLogger.debug(`Requesting: ${path}`);
try {
// fetchAtlassian will return string for text/plain
const diffText = await (0, transport_util_js_1.fetchAtlassian)(credentials, path);
return diffText;
}
catch (error) {
if (error instanceof error_util_js_1.McpError)
throw error;
throw (0, error_util_js_1.createApiError)(`Failed to fetch raw diff: ${error instanceof Error ? error.message : String(error)}`, 500, error);
}
}