@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
164 lines (163 loc) • 6.97 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorCode = void 0;
exports.detectErrorType = detectErrorType;
exports.createUserFriendlyErrorMessage = createUserFriendlyErrorMessage;
exports.handleControllerError = handleControllerError;
const error_util_js_1 = require("./error.util.js");
const logger_util_js_1 = require("./logger.util.js");
/**
* Standard error codes for consistent handling
*/
var ErrorCode;
(function (ErrorCode) {
ErrorCode["NOT_FOUND"] = "NOT_FOUND";
ErrorCode["INVALID_CURSOR"] = "INVALID_CURSOR";
ErrorCode["ACCESS_DENIED"] = "ACCESS_DENIED";
ErrorCode["VALIDATION_ERROR"] = "VALIDATION_ERROR";
ErrorCode["UNEXPECTED_ERROR"] = "UNEXPECTED_ERROR";
})(ErrorCode || (exports.ErrorCode = ErrorCode = {}));
/**
* Detect specific error types from raw errors
* @param error The error to analyze
* @param context Context information for better error detection
* @returns Object containing the error code and status code
*/
function detectErrorType(error, context = {}) {
const methodLogger = logger_util_js_1.Logger.forContext('utils/error-handler.util.ts', 'detectErrorType');
methodLogger.debug(`Detecting error type`, { error, context });
const errorMessage = error instanceof Error ? error.message : String(error);
const statusCode = error instanceof Error && 'statusCode' in error
? error.statusCode
: undefined;
// Not Found detection
if (errorMessage.includes('not found') ||
errorMessage.includes('does not exist') ||
statusCode === 404) {
return { code: ErrorCode.NOT_FOUND, statusCode: 404 };
}
// Access Denied detection
if (errorMessage.includes('access') ||
errorMessage.includes('permission') ||
errorMessage.includes('authorize') ||
errorMessage.includes('authentication') ||
statusCode === 401 ||
statusCode === 403) {
return { code: ErrorCode.ACCESS_DENIED, statusCode: statusCode || 403 };
}
// Invalid Cursor detection
if ((errorMessage.includes('cursor') ||
errorMessage.includes('startAt') ||
errorMessage.includes('page')) &&
(errorMessage.includes('invalid') || errorMessage.includes('not valid'))) {
return { code: ErrorCode.INVALID_CURSOR, statusCode: 400 };
}
// Validation Error detection
if (errorMessage.includes('validation') ||
errorMessage.includes('invalid') ||
errorMessage.includes('required') ||
statusCode === 400 ||
statusCode === 422) {
return {
code: ErrorCode.VALIDATION_ERROR,
statusCode: statusCode || 400,
};
}
// Default to unexpected error
return {
code: ErrorCode.UNEXPECTED_ERROR,
statusCode: statusCode || 500,
};
}
/**
* Create user-friendly error messages based on error type and context
* @param code The error code
* @param context Context information for better error messages
* @param originalMessage The original error message
* @returns User-friendly error message
*/
function createUserFriendlyErrorMessage(code, context = {}, originalMessage) {
const methodLogger = logger_util_js_1.Logger.forContext('utils/error-handler.util.ts', 'createUserFriendlyErrorMessage');
const { entityType, entityId, operation } = context;
// Format entity ID for display
let entityIdStr = '';
if (entityId) {
if (typeof entityId === 'string') {
entityIdStr = entityId;
}
else {
// Handle object entityId (like ProjectIdentifier)
entityIdStr = Object.values(entityId).join('/');
}
}
// Determine entity display name
const entity = entityType
? `${entityType}${entityIdStr ? ` ${entityIdStr}` : ''}`
: 'Resource';
let message = '';
switch (code) {
case ErrorCode.NOT_FOUND:
message = `${entity} not found${entityIdStr ? `: ${entityIdStr}` : ''}. Verify the ID is correct and that you have access to this ${entityType?.toLowerCase() || 'resource'}.`;
break;
case ErrorCode.ACCESS_DENIED:
message = `Access denied for ${entity.toLowerCase()}${entityIdStr ? ` ${entityIdStr}` : ''}. Verify your credentials and permissions.`;
break;
case ErrorCode.INVALID_CURSOR:
message = `Invalid pagination cursor. Use the exact cursor string returned from previous results.`;
break;
case ErrorCode.VALIDATION_ERROR:
message =
originalMessage ||
`Invalid data provided for ${operation || 'operation'} ${entity.toLowerCase()}.`;
break;
default:
message = `An unexpected error occurred while ${operation || 'processing'} ${entity.toLowerCase()}.`;
}
// Include original message details if available and appropriate
if (originalMessage &&
code !== ErrorCode.NOT_FOUND &&
code !== ErrorCode.ACCESS_DENIED &&
code !== ErrorCode.VALIDATION_ERROR) {
message += ` Error details: ${originalMessage}`;
}
methodLogger.debug(`Created user-friendly message: ${message}`, {
code,
context,
});
return message;
}
/**
* Handle controller errors consistently
* @param error The error to handle
* @param context Context information for better error messages
* @returns Never returns, always throws an error
*/
function handleControllerError(error, context = {}) {
const methodLogger = logger_util_js_1.Logger.forContext('utils/error-handler.util.ts', 'handleControllerError');
// Extract error details
const errorMessage = error instanceof Error ? error.message : String(error);
const statusCode = error instanceof Error && 'statusCode' in error
? error.statusCode
: undefined;
// Detect error type using utility
const { code, statusCode: detectedStatus } = detectErrorType(error, context);
// Combine detected status with explicit status
const finalStatusCode = statusCode || detectedStatus;
// Format entity information for logging
const { entityType, entityId, operation } = context;
const entity = entityType || 'resource';
const entityIdStr = entityId
? typeof entityId === 'string'
? entityId
: JSON.stringify(entityId)
: '';
const actionStr = operation || 'processing';
// Log detailed error information
methodLogger.error(`Error ${actionStr} ${entity}${entityIdStr ? `: ${entityIdStr}` : ''}: ${errorMessage}`, error);
// Create user-friendly error message for the response
const message = code === ErrorCode.VALIDATION_ERROR
? errorMessage
: createUserFriendlyErrorMessage(code, context, errorMessage);
// Throw an appropriate API error with the user-friendly message
throw (0, error_util_js_1.createApiError)(message, finalStatusCode, error);
}