Skip to main content
Glama

Atlassian Bitbucket MCP Server

by aashari
atlassian.pullrequests.comments.controller.ts7.53 kB
import { ControllerResponse } from '../types/common.types.js'; import { ListPullRequestCommentsToolArgsType, CreatePullRequestCommentToolArgsType, } from '../tools/atlassian.pullrequests.types.js'; import { atlassianPullRequestsService, Logger, handleControllerError, extractPaginationInfo, PaginationType, formatPagination, formatPullRequestComments, DEFAULT_PAGE_SIZE, applyDefaults, enhanceCommentsWithSnippets, optimizeBitbucketMarkdown, getDefaultWorkspace, ListCommentsParams, CreateCommentParams, } from './atlassian.pullrequests.base.controller.js'; /** * List comments on a Bitbucket pull request * @param options - Options including workspace slug, repo slug, and pull request ID * @returns Promise with formatted pull request comments as Markdown content */ async function listComments( options: ListPullRequestCommentsToolArgsType, ): Promise<ControllerResponse> { const methodLogger = Logger.forContext( 'controllers/atlassian.pullrequests.comments.controller.ts', 'listComments', ); try { // Create defaults object const defaults: Partial<ListPullRequestCommentsToolArgsType> = { limit: DEFAULT_PAGE_SIZE, }; // Apply defaults const mergedOptions = applyDefaults<ListPullRequestCommentsToolArgsType>( options, defaults, ); // Handle optional workspaceSlug - get default if not provided if (!mergedOptions.workspaceSlug) { methodLogger.debug( 'No workspace provided, fetching default workspace', ); const defaultWorkspace = await getDefaultWorkspace(); if (!defaultWorkspace) { throw new Error( 'Could not determine a default workspace. Please provide a workspaceSlug.', ); } mergedOptions.workspaceSlug = defaultWorkspace; methodLogger.debug( `Using default workspace: ${mergedOptions.workspaceSlug}`, ); } const { workspaceSlug, repoSlug, prId } = mergedOptions; // Validate required parameters if (!workspaceSlug || !repoSlug || !prId) { throw new Error( 'Workspace slug, repository slug, and pull request ID are required', ); } methodLogger.debug( `Listing comments for PR ${workspaceSlug}/${repoSlug}/${prId}`, { limit: mergedOptions.limit, cursor: mergedOptions.cursor }, ); // Map controller options to service parameters const serviceParams: ListCommentsParams = { workspace: workspaceSlug, repo_slug: repoSlug, pull_request_id: parseInt(prId, 10), pagelen: mergedOptions.limit, page: mergedOptions.cursor ? parseInt(mergedOptions.cursor, 10) : undefined, }; // Get comments from the service const commentsData = await atlassianPullRequestsService.getComments(serviceParams); methodLogger.debug( `Retrieved ${commentsData.values?.length || 0} comments`, ); // If no comments found, return a simple message if (!commentsData.values || commentsData.values.length === 0) { return { content: 'No comments found on this pull request.' }; } // Extract pagination information const pagination = extractPaginationInfo( commentsData, PaginationType.PAGE, ); // Enhance comments with code snippets (for inline comments) const enhancedComments = await enhanceCommentsWithSnippets( commentsData, 'listComments', ); // Format the comments using the formatter const formattedComments = formatPullRequestComments( enhancedComments, prId, ); // Create the final content by combining formatted comments with pagination info let finalContent = formattedComments; // Add pagination information if available if ( pagination && (pagination.hasMore || pagination.count !== undefined) ) { const paginationString = formatPagination(pagination); finalContent += '\n\n' + paginationString; } return { content: finalContent, }; } catch (error) { // Use the standardized error handler throw handleControllerError(error, { entityType: 'Pull Request Comments', operation: 'listing', source: 'controllers/atlassian.pullrequests.comments.controller.ts@listComments', additionalInfo: { options }, }); } } /** * Add a comment to a Bitbucket pull request * @param options - Options including workspace slug, repo slug, PR ID, and comment content * @returns Promise with a success message as content */ async function addComment( options: CreatePullRequestCommentToolArgsType, ): Promise<ControllerResponse> { const methodLogger = Logger.forContext( 'controllers/atlassian.pullrequests.comments.controller.ts', 'addComment', ); try { // Apply defaults if needed (none for this operation) const mergedOptions = applyDefaults<CreatePullRequestCommentToolArgsType>(options, {}); // Handle optional workspaceSlug - get default if not provided if (!mergedOptions.workspaceSlug) { methodLogger.debug( 'No workspace provided, fetching default workspace', ); const defaultWorkspace = await getDefaultWorkspace(); if (!defaultWorkspace) { throw new Error( 'Could not determine a default workspace. Please provide a workspaceSlug.', ); } mergedOptions.workspaceSlug = defaultWorkspace; methodLogger.debug( `Using default workspace: ${mergedOptions.workspaceSlug}`, ); } const { workspaceSlug, repoSlug, prId, content, inline } = mergedOptions; // Validate required parameters if (!workspaceSlug || !repoSlug || !prId || !content) { throw new Error( 'Workspace slug, repository slug, pull request ID, and comment content are required', ); } // For inline comments, both file path and line number are required if (inline && (!inline.path || inline.line === undefined)) { throw new Error( 'Both file path and line number are required for inline comments', ); } // Prepare the raw content, applying any Bitbucket-specific markdown optimizations const optimizedContent = optimizeBitbucketMarkdown(content); methodLogger.debug( `Adding${ inline ? ' inline' : '' } comment to PR ${workspaceSlug}/${repoSlug}/${prId}`, { contentLength: optimizedContent.length, isInline: !!inline, inlinePath: inline?.path, inlineLine: inline?.line, }, ); // Map controller options to service parameters const serviceParams: CreateCommentParams = { workspace: workspaceSlug, repo_slug: repoSlug, pull_request_id: parseInt(prId, 10), content: { raw: optimizedContent, }, }; // For inline comments, add the inline property if (inline) { serviceParams.inline = { path: inline.path, to: inline.line, }; } // For replies, add the parent property if (mergedOptions.parentId) { serviceParams.parent = { id: parseInt(mergedOptions.parentId, 10), }; } // Create the comment through the service const commentResult = await atlassianPullRequestsService.createComment(serviceParams); methodLogger.debug('Comment created successfully', { commentId: commentResult.id, isInline: !!inline, }); // Return a success message const commentType = inline ? 'inline' : ''; return { content: `${commentType} Comment successfully added to pull request #${prId}. Comment ID: ${commentResult.id}`, }; } catch (error) { // Use the standardized error handler throw handleControllerError(error, { entityType: 'Pull Request Comment', operation: 'adding', source: 'controllers/atlassian.pullrequests.comments.controller.ts@addComment', additionalInfo: { options }, }); } } // Export the controller functions export default { listComments, addComment };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aashari/mcp-server-atlassian-bitbucket'

If you have feedback or need assistance with the MCP directory API, please join our Discord server