MCP: Add update_note method to save_merge_request_review

Summary

External agents using the GitLab MCP server need to be able to update merge request comments they have previously posted. This issue focuses on adding updating a comment. The ability to delete a comment will be tracked in gitlab.com/gitlab-org/gitlab/-/work_items/631275.

What is already done

Operation MCP tool Status
Create top-level comment save_merge_request_review (create_note) ✅ Done
Create inline diff comment save_merge_request_review (create_diff_note) ✅ Done
Reply to a discussion save_merge_request_review (reply_discussion) ✅ Done
Resolve/unresolve a discussion save_merge_request_review (resolve_discussion) ✅ Done
List comments get_merge_request_notes ✅ Done
Update a comment save_merge_request_review (update_note) ❌ Missing
Delete a comment save_merge_request_review (destroy_note) ❌ Missing

What needs to be built

Add a new method value to the existing save_merge_request_review MCP tool: update_note. The tool already dispatches on a method parameter — this is purely additive.

The underlying GraphQL mutation (updateNote) already exist in GitLab's schema and are used by the frontend. No new backend mutations are needed.

Caution

destroy_note will be addressed via gitlab.com/gitlab-org/gitlab/-/work_items/631275

Implementation guide

Files to change

1. Add new GraphQL query file (model this on the existing ones in the same directory):

  • app/graphql/queries/mcp/merge_requests/update_note.mutation.graphql

For reference, the existing create_note mutation lives at app/graphql/queries/mcp/merge_requests/create_note.mutation.graphql. Frontend examples of updateNote can be found at:

  • app/assets/javascripts/work_items/graphql/notes/update_work_item_note.mutation.graphql

The MCP-specific version should use # @feature_category: mcp_server and return only the fields the tool needs (see below).

Suggested update_note response fields: id, body, updatedAt, url


2. app/services/mcp/tools/merge_requests/save_merge_request_review_service.rb

  • Add entries to METHOD_PARAMS:
    'update_note'  => { required: %i[note_id body], optional: [] },
  • Add 'update_note' to the method enum in input_schema.
  • Add a note_id property to input_schema (type integer, describe which methods use it).
  • Add description for the new method to the tool description string.

3. app/services/mcp/tools/merge_requests/save_merge_request_review_tool.rb

  • Load the new GraphQL file:
    UPDATE_NOTE_QUERY  = load_graphql('merge_requests/update_note.mutation.graphql')
  • Extend graphql_operation and operation_name to dispatch on the new method.
  • Add when 'update_note' case to build_variables:
    • update_note: validate no quick actions on body, build { input: { id: note_global_id, body: params[:body] } }
  • Add a private note_global_id helper that converts the integer note_id param to a gid://gitlab/Note/<id> global ID (see how discussion_global_id does the same for discussions).
  • Extend process_result / add output helpers for the new method.

Note on note_id vs discussion_id

note_id is the ID of a single note (returned as note_id by create_note, create_diff_note, etc.). It is distinct from discussion_id. Agents should use the note_id from a previous create or from get_merge_request_notes to target a specific note for update or delete.

Acceptance criteria

  • save_merge_request_review with method: "update_note" updates the body of the specified note and returns its ID, updated body, and URL.
  • The method rejects quick actions in the body (for update_note), consistent with other write methods.
  • The method returns a clear error if the note does not exist or the user lacks permission.
  • Unit tests cover the happy path and permission-denied case for the method.

Relevant code pointers

File Why
app/services/mcp/tools/merge_requests/save_merge_request_review_service.rb Main service — add method params, schema, descriptions
app/services/mcp/tools/merge_requests/save_merge_request_review_tool.rb GraphQL tool — add query loading, dispatch, variable building
app/graphql/queries/mcp/merge_requests/ Add the two new .graphql mutation files here
app/assets/javascripts/work_items/graphql/notes/update_work_item_note.mutation.graphql Reference for updateNote mutation shape

Labels

featureaddition backend groupagent execution category:agent tools typefeature


This is a good first contribution for someone familiar with Ruby and GraphQL. The pattern is fully established by the existing methods in the same tool — the implementation is additive with no architectural decisions required.

Edited by Amanda Rueda