Skip to main content
Glama
pdogra1299
by pdogra1299

add_comment

Add comments to Bitbucket pull requests with options for general feedback, replies, inline code comments, and code suggestions. Supports line numbers, code snippets, and multi-line replacements for precise feedback.

Instructions

Add a comment to a pull request. Supports: 1) General PR comments, 2) Replies to existing comments, 3) Inline comments on specific code lines (using line_number OR code_snippet), 4) Code suggestions for single or multi-line replacements. For inline comments, you can either provide exact line_number or use code_snippet to auto-detect the line.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
code_snippetNoExact code text from the diff to find and comment on. Use this instead of line_number for auto-detection. Must match exactly including whitespace (optional)
comment_textYesThe main comment text. For suggestions, this is the explanation before the code suggestion.
file_pathNoFile path for inline comment. Required for inline comments. Example: "src/components/Button.js" (optional)
line_numberNoExact line number in the file. Use this OR code_snippet, not both. Required with file_path unless using code_snippet (optional)
line_typeNoType of line: ADDED (green/new lines), REMOVED (red/deleted lines), or CONTEXT (unchanged lines). Default: CONTEXT
match_strategyNoHow to handle multiple matches when using code_snippet. "strict": fail with detailed error showing all matches. "best": automatically pick the highest confidence match. Default: "strict"
parent_comment_idNoID of comment to reply to. Use this to create threaded conversations (optional)
pull_request_idYesPull request ID
repositoryYesRepository slug (e.g., "my-repo")
search_contextNoAdditional context lines to help locate the exact position when using code_snippet. Useful when the same code appears multiple times (optional)
suggestionNoReplacement code for a suggestion. Creates a suggestion block that can be applied in Bitbucket UI. Requires file_path and line_number. For multi-line, include newlines in the string (optional)
suggestion_end_lineNoFor multi-line suggestions: the last line number to replace. If not provided, only replaces the single line at line_number (optional)
workspaceYesBitbucket workspace/project key (e.g., "PROJ")

Implementation Reference

  • Main execution logic for the add_comment tool: argument validation, line resolution from code snippets, suggestion formatting, API request construction for Bitbucket Server/Cloud, and posting the comment with response formatting.
    async handleAddComment(args: any) {
      if (!isAddCommentArgs(args)) {
        throw new McpError(
          ErrorCode.InvalidParams,
          'Invalid arguments for add_comment'
        );
      }
    
      let { 
        workspace, 
        repository, 
        pull_request_id, 
        comment_text, 
        parent_comment_id, 
        file_path, 
        line_number, 
        line_type,
        suggestion,
        suggestion_end_line,
        code_snippet,
        search_context,
        match_strategy = 'strict'
      } = args;
    
      let sequentialPosition: number | undefined;
      if (code_snippet && !line_number && file_path) {
        try {
          const resolved = await this.resolveLineFromCode(
            workspace,
            repository,
            pull_request_id,
            file_path,
            code_snippet,
            search_context,
            match_strategy
          );
          
          line_number = resolved.line_number;
          line_type = resolved.line_type;
          sequentialPosition = resolved.sequential_position;
        } catch (error) {
          throw error;
        }
      }
    
      if (suggestion && (!file_path || !line_number)) {
        throw new McpError(
          ErrorCode.InvalidParams,
          'Suggestions require file_path and line_number to be specified'
        );
      }
    
      const isInlineComment = file_path !== undefined && line_number !== undefined;
    
      let finalCommentText = comment_text;
      if (suggestion) {
        finalCommentText = formatSuggestionComment(
          comment_text,
          suggestion,
          line_number,
          suggestion_end_line || line_number
        );
      }
    
      try {
        let apiPath: string;
        let requestBody: any;
    
        if (this.apiClient.getIsServer()) {
          // Bitbucket Server API
          apiPath = `/rest/api/1.0/projects/${workspace}/repos/${repository}/pull-requests/${pull_request_id}/comments`;
          requestBody = {
            text: finalCommentText
          };
          
          if (parent_comment_id !== undefined) {
            requestBody.parent = { id: parent_comment_id };
          }
          
          if (isInlineComment) {
            requestBody.anchor = {
              line: line_number,
              lineType: line_type || 'CONTEXT', 
              fileType: line_type === 'REMOVED' ? 'FROM' : 'TO',
              path: file_path,
              diffType: 'EFFECTIVE'
            };
            
          }
        } else {
          // Bitbucket Cloud API
          apiPath = `/repositories/${workspace}/${repository}/pullrequests/${pull_request_id}/comments`;
          requestBody = {
            content: {
              raw: finalCommentText
            }
          };
          
          if (parent_comment_id !== undefined) {
            requestBody.parent = { id: parent_comment_id };
          }
          
          if (isInlineComment) {
            requestBody.inline = {
              to: line_number,
              path: file_path
            };
          }
        }
    
        const comment = await this.apiClient.makeRequest<any>('post', apiPath, requestBody);
    
        const responseMessage = suggestion 
          ? 'Comment with code suggestion added successfully'
          : (isInlineComment ? 'Inline comment added successfully' : 'Comment added successfully');
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                message: responseMessage,
                comment: {
                  id: comment.id,
                  text: this.apiClient.getIsServer() ? comment.text : comment.content.raw,
                  author: this.apiClient.getIsServer() ? comment.author.displayName : comment.user.display_name,
                  created_on: this.apiClient.getIsServer() ? new Date(comment.createdDate).toLocaleString() : comment.created_on,
                  file_path: isInlineComment ? file_path : undefined,
                  line_number: isInlineComment ? line_number : undefined,
                  line_type: isInlineComment ? (line_type || 'CONTEXT') : undefined,
                  has_suggestion: !!suggestion,
                  suggestion_lines: suggestion ? (suggestion_end_line ? `${line_number}-${suggestion_end_line}` : `${line_number}`) : undefined
                }
              }, null, 2),
            },
          ],
        };
      } catch (error) {
        return this.apiClient.handleApiError(error, `adding ${isInlineComment ? 'inline ' : ''}comment to pull request ${pull_request_id} in ${workspace}/${repository}`);
      }
    }
  • JSON Schema definition for the add_comment tool input parameters, including descriptions and validation rules for all fields like workspace, comment_text, file_path, line_number, suggestion, code_snippet, etc.
      name: 'add_comment',
      description: 'Add a comment to a pull request. Supports: 1) General PR comments, 2) Replies to existing comments, 3) Inline comments on specific code lines (using line_number OR code_snippet), 4) Code suggestions for single or multi-line replacements. For inline comments, you can either provide exact line_number or use code_snippet to auto-detect the line.',
      inputSchema: {
        type: 'object',
        properties: {
          workspace: {
            type: 'string',
            description: 'Bitbucket workspace/project key (e.g., "PROJ")',
          },
          repository: {
            type: 'string',
            description: 'Repository slug (e.g., "my-repo")',
          },
          pull_request_id: {
            type: 'number',
            description: 'Pull request ID',
          },
          comment_text: {
            type: 'string',
            description: 'The main comment text. For suggestions, this is the explanation before the code suggestion.',
          },
          parent_comment_id: {
            type: 'number',
            description: 'ID of comment to reply to. Use this to create threaded conversations (optional)',
          },
          file_path: {
            type: 'string',
            description: 'File path for inline comment. Required for inline comments. Example: "src/components/Button.js" (optional)',
          },
          line_number: {
            type: 'number',
            description: 'Exact line number in the file. Use this OR code_snippet, not both. Required with file_path unless using code_snippet (optional)',
          },
          line_type: {
            type: 'string',
            description: 'Type of line: ADDED (green/new lines), REMOVED (red/deleted lines), or CONTEXT (unchanged lines). Default: CONTEXT',
            enum: ['ADDED', 'REMOVED', 'CONTEXT'],
          },
          suggestion: {
            type: 'string',
            description: 'Replacement code for a suggestion. Creates a suggestion block that can be applied in Bitbucket UI. Requires file_path and line_number. For multi-line, include newlines in the string (optional)',
          },
          suggestion_end_line: {
            type: 'number',
            description: 'For multi-line suggestions: the last line number to replace. If not provided, only replaces the single line at line_number (optional)',
          },
          code_snippet: {
            type: 'string',
            description: 'Exact code text from the diff to find and comment on. Use this instead of line_number for auto-detection. Must match exactly including whitespace (optional)',
          },
          search_context: {
            type: 'object',
            properties: {
              before: {
                type: 'array',
                items: { type: 'string' },
                description: 'Array of code lines that appear BEFORE the target line. Helps disambiguate when code_snippet appears multiple times',
              },
              after: {
                type: 'array',
                items: { type: 'string' },
                description: 'Array of code lines that appear AFTER the target line. Helps disambiguate when code_snippet appears multiple times',
              },
            },
            description: 'Additional context lines to help locate the exact position when using code_snippet. Useful when the same code appears multiple times (optional)',
          },
          match_strategy: {
            type: 'string',
            enum: ['strict', 'best'],
            description: 'How to handle multiple matches when using code_snippet. "strict": fail with detailed error showing all matches. "best": automatically pick the highest confidence match. Default: "strict"',
          },
        },
        required: ['workspace', 'repository', 'pull_request_id', 'comment_text'],
      },
    },
  • src/index.ts:104-105 (registration)
    Tool registration and dispatch: routes 'add_comment' calls to the PullRequestHandlers.handleAddComment method.
    case 'add_comment':
      return this.pullRequestHandlers.handleAddComment(request.params.arguments);
  • Type guard function isAddCommentArgs used in the handler for runtime input validation matching the tool schema.
    export const isAddCommentArgs = (
      args: any
    ): args is {
      workspace: string;
      repository: string;
      pull_request_id: number;
      comment_text: string;
      parent_comment_id?: number;
      file_path?: string;
      line_number?: number;
      line_type?: 'ADDED' | 'REMOVED' | 'CONTEXT';
      suggestion?: string;
      suggestion_end_line?: number;
      code_snippet?: string;
      search_context?: {
        before?: string[];
        after?: string[];
      };
      match_strategy?: 'strict' | 'best';
    } =>
      typeof args === 'object' &&
      args !== null &&
      typeof args.workspace === 'string' &&
      typeof args.repository === 'string' &&
      typeof args.pull_request_id === 'number' &&
      typeof args.comment_text === 'string' &&
      (args.parent_comment_id === undefined || typeof args.parent_comment_id === 'number') &&
      (args.file_path === undefined || typeof args.file_path === 'string') &&
      (args.line_number === undefined || typeof args.line_number === 'number') &&
      (args.line_type === undefined || ['ADDED', 'REMOVED', 'CONTEXT'].includes(args.line_type)) &&
      (args.suggestion === undefined || typeof args.suggestion === 'string') &&
      (args.suggestion_end_line === undefined || typeof args.suggestion_end_line === 'number') &&
      (args.code_snippet === undefined || typeof args.code_snippet === 'string') &&
      (args.search_context === undefined || (
        typeof args.search_context === 'object' &&
        (args.search_context.before === undefined || Array.isArray(args.search_context.before)) &&
        (args.search_context.after === undefined || Array.isArray(args.search_context.after))
      )) &&
      (args.match_strategy === undefined || ['strict', 'best'].includes(args.match_strategy));

Latest Blog Posts

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/pdogra1299/bitbucket-mcp-server'

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