forked from zereight/gitlab-mcp
-
Notifications
You must be signed in to change notification settings - Fork 1
feat(mrs): Add suggestion apply actions (apply_suggestion, apply_suggestions) #66
Copy link
Copy link
Labels
enhancementNew feature, new MCP tool, new capabilityNew feature, new MCP tool, new capability
Description
Summary
Add suggestion apply functionality to complete code review workflow. This closes the only significant gap compared to specialized code review MCP servers (midodimori/gitlab-review-mcp).
Motivation
GitLab suggestions allow reviewers to propose specific code changes inline:
```suggestion
const result = items.filter(x => x.active);
Currently we support:
- ✅ Creating line comments with suggestions (via `manage_mr_discussion:thread`)
- ✅ Reading discussions with suggestions (via `browse_mr_discussions:list`)
- ❌ **Applying suggestions** - missing!
Without apply functionality, the workflow is incomplete - users must go to GitLab UI to apply suggestions.
## Proposed Solution
Add two new actions to `manage_mr_discussion`:
### Action: `apply_suggestion`
Apply a single suggestion to create a commit.
```typescript
{
"action": "apply_suggestion",
"project_id": "myproject",
"merge_request_iid": 42,
"suggestion_id": 12345,
"commit_message": "Apply suggestion: use filter instead of manual loop"
}
Response:
{
"id": 12345,
"applied": true,
"commit": {
"sha": "abc123def",
"message": "Apply suggestion: use filter instead of manual loop"
}
}Action: apply_suggestions
Batch apply multiple suggestions in a single commit.
{
"action": "apply_suggestions",
"project_id": "myproject",
"merge_request_iid": 42,
"suggestion_ids": [12345, 12346, 12347],
"commit_message": "Apply code review suggestions"
}Response:
{
"applied_count": 3,
"commit": {
"sha": "def456abc",
"message": "Apply code review suggestions"
}
}GitLab API
Apply Single Suggestion
PUT /projects/:id/merge_requests/:merge_request_iid/suggestions/:suggestion_id/apply
Body (optional):
{
"commit_message": "Custom commit message"
}Batch Apply Suggestions
PUT /projects/:id/merge_requests/:merge_request_iid/suggestions/batch_apply
Body:
{
"ids": [12345, 12346, 12347],
"commit_message": "Apply suggestions"
}Implementation
Schema Changes
// src/entities/mrs/schema.ts
// Add to ManageMrDiscussionSchema discriminated union:
const ApplySuggestionSchema = z.object({
action: z.literal("apply_suggestion").describe("Apply a single code suggestion"),
project_id: projectIdField,
merge_request_iid: mergeRequestIidField,
suggestion_id: requiredId.describe("ID of the suggestion to apply"),
commit_message: z.string().optional().describe("Custom commit message for the apply commit"),
});
const ApplySuggestionsSchema = z.object({
action: z.literal("apply_suggestions").describe("Batch apply multiple code suggestions"),
project_id: projectIdField,
merge_request_iid: mergeRequestIidField,
suggestion_ids: z.array(z.number()).min(1).describe("Array of suggestion IDs to apply"),
commit_message: z.string().optional().describe("Custom commit message for the apply commit"),
});Handler Changes
// src/entities/mrs/registry.ts - in manage_mr_discussion handler
case "apply_suggestion": {
const { project_id, merge_request_iid, suggestion_id, commit_message } = input;
const encodedProjectId = encodeURIComponent(project_id);
const body: Record<string, unknown> = {};
if (commit_message) {
body.commit_message = commit_message;
}
return gitlab.put(
`projects/${encodedProjectId}/merge_requests/${merge_request_iid}/suggestions/${suggestion_id}/apply`,
{ body: Object.keys(body).length > 0 ? body : undefined, contentType: "json" }
);
}
case "apply_suggestions": {
const { project_id, merge_request_iid, suggestion_ids, commit_message } = input;
const encodedProjectId = encodeURIComponent(project_id);
const body: Record<string, unknown> = {
ids: suggestion_ids,
};
if (commit_message) {
body.commit_message = commit_message;
}
return gitlab.put(
`projects/${encodedProjectId}/merge_requests/${merge_request_iid}/suggestions/batch_apply`,
{ body, contentType: "json" }
);
}Use Cases
1. AI Code Review Workflow
User: "Review the changes in MR !42 and apply any suggestions you agree with"
Agent:
1. browse_mr_discussions({ action: "list", project_id: "x", merge_request_iid: 42 })
→ Gets discussions with suggestions
2. Analyzes each suggestion
3. manage_mr_discussion({ action: "apply_suggestions", suggestion_ids: [1,2,3], ... })
→ Applies approved suggestions in single commit
2. Interactive Review
User: "Apply the suggestion about using async/await"
Agent:
1. Finds suggestion ID from previous context
2. manage_mr_discussion({ action: "apply_suggestion", suggestion_id: 123, ... })
3. Batch Apply After Review
User: "Apply all the formatting suggestions from the linting review"
Agent:
1. Filters suggestions by reviewer/content
2. manage_mr_discussion({ action: "apply_suggestions", suggestion_ids: [...] })
Testing
Unit Tests
describe("manage_mr_discussion", () => {
describe("apply_suggestion", () => {
it("applies a single suggestion", async () => {
mockEnhancedFetch.mockResolvedValueOnce({
id: 12345,
applied: true,
});
const result = await handler({
action: "apply_suggestion",
project_id: "test/project",
merge_request_iid: 42,
suggestion_id: 12345,
});
expect(mockEnhancedFetch).toHaveBeenCalledWith(
expect.stringContaining("/suggestions/12345/apply"),
expect.objectContaining({ method: "PUT" })
);
});
it("includes custom commit message when provided", async () => {
// ...
});
});
describe("apply_suggestions", () => {
it("batch applies multiple suggestions", async () => {
// ...
});
});
});Integration Tests
describe("suggestion workflow", () => {
it("creates suggestion and applies it", async () => {
// 1. Create MR with changes
// 2. Add discussion with suggestion
// 3. Apply suggestion
// 4. Verify commit was created
});
});Tasks
- Add
ApplySuggestionSchemato schema.ts - Add
ApplySuggestionsSchemato schema.ts - Update
ManageMrDiscussionSchemadiscriminated union - Implement
apply_suggestionhandler - Implement
apply_suggestionshandler - Add unit tests for both actions
- Add integration test for suggestion workflow
- Update tool description to mention suggestion support
- Document in TOOLS.md
Acceptance Criteria
-
apply_suggestionapplies single suggestion and returns result -
apply_suggestionsbatch applies multiple suggestions - Custom commit messages are supported
- Errors are handled gracefully (already applied, conflicts, etc.)
- Works with GitLab Free tier (suggestions are free feature)
Complexity
Low - ~50-100 lines of code, straightforward API mapping
Priority
HIGH - Completes code review workflow, closes gap with competitors
Dependencies
None - can be implemented immediately
Related
- Competitive analysis: midodimori/gitlab-review-mcp has this feature
- Enhances existing
manage_mr_discussiontool
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature, new MCP tool, new capabilityNew feature, new MCP tool, new capability