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) |
|
| Create inline diff comment | save_merge_request_review (create_diff_note) |
|
| Reply to a discussion | save_merge_request_review (reply_discussion) |
|
| Resolve/unresolve a discussion | save_merge_request_review (resolve_discussion) |
|
| List comments | get_merge_request_notes |
|
| Update a comment | save_merge_request_review (update_note) |
|
| Delete a comment | save_merge_request_review (destroy_note) |
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 themethodenum ininput_schema. - Add a
note_idproperty toinput_schema(typeinteger, describe which methods use it). - Add description for the new method to the tool
descriptionstring.
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_operationandoperation_nameto dispatch on the new method. - Add
when 'update_note'case tobuild_variables:update_note: validate no quick actions onbody, build{ input: { id: note_global_id, body: params[:body] } }
- Add a private
note_global_idhelper that converts the integernote_idparam to agid://gitlab/Note/<id>global ID (see howdiscussion_global_iddoes 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_reviewwithmethod: "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.