Co-dev review MCP
Allows reviewing GitHub pull requests: fetches PR details, diffs, and full file context, validates inline comment anchors against the PR head commit, and publishes approved comments as individual review comments (no formal APPROVE/REQUEST_CHANGES verdict).
Allows reviewing colleagues' GitLab merge requests: reads MR metadata, patches, full file context, and existing discussions, validates inline comment anchors against added/deleted lines (preserving both paths on renames), and posts comments as individual discussions once a draft is approved.
Reads SonarCloud analysis results for a configured project key and token, feeding static-analysis findings into the review workflow via the review_sonar tool. Read-only: no Sonar issue-status mutation is exposed.
Reads SonarQube (or SonarCloud) analysis results for a configured project key and token, feeding static-analysis findings into the review workflow via the review_sonar tool. Read-only: no Sonar issue-status mutation is exposed.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Co-dev review MCPreview MR !42 against ticket PROJ-123 and draft inline comments"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
co-dev-review
A senior code reviewer for your AI assistant. co-dev-review is an MCP server that lets Claude Code, Codex, GitHub Copilot, Cursor, Antigravity or any other MCP client review merge requests the way an experienced colleague would. It runs your compiler and linters, checks the callers outside the diff, traces edge cases and algorithmic cost, and posts only the comments you approve.
It also turns Azure DevOps, Jira or GitHub tickets into estimated tasks and helps triage SonarQube results.
You: Review MR 306 against ticket 54639, comments in French.
Assistant: checks out MR 306 in a separate worktree · runs tsc + eslint · lists 14 callers outside the diff
· reviews 31 hunks with the correctness, complexity, design, test and React rubrics
→ 2 blockers (confirmed), 3 majors, 1 question
[approval form: tick what to post] → 5 comments posted on GitLabWhy it is different
It checks the evidence, not only the diff. Each MR/PR is checked out in its own git worktree, without touching your branch. The repository's own TypeScript compiler, ESLint and
dotnet buildrun there, the unit tests related to the change run too, and every call site of a changed symbol outside the diff is listed.It's light on context. Responses are compact and shaped for review, without the providers' raw payloads. Mechanical steps can run on a cheaper subagent, so the reviewer's context is kept for the code.
It reviews like a senior. Rubrics for correctness (edge cases traced through each function, guarantees lost in removed lines), complexity (realistic n, derived Big O), design (duplicated helpers, smells that cause bugs) and tests are applied to every change. React/TypeScript, .NET, security and build rubrics add the specifics.
It can't skip work silently. Every changed hunk needs a verdict. The compiler and call-site passes must have run on the exact commit under review, or the draft must say why they were skipped. A blocker must be
confirmed.Nothing is posted without you. You approve each draft in the chat (
approve all except R2), or, if you prefer, in a form, a local browser page or the terminal. Your words are recorded with the approval.It works with any LLM. The server has no model dependency, and every MCP client works.
Related MCP server: MCP Code Review Server
Quick start
Requirements: Node.js 20.20.2 or later, and git.
git clone https://github.com/MohamedAmineBoufares/co-dev-review.git
cd co-dev-review
npm ci
npm run setupnpm run setup asks for your tokens, checks them, registers the server in every assistant it finds on your machine, and links the review skills. Restart your assistant, then ask:
List the tools from co-dev-review.
You should see review_work, plan_ticket_tasks and review_sonar. Details: Configuration.
What you need to configure
Fill in only what you use:
To… | Configure |
Review GitLab merge requests |
|
Review GitHub pull requests |
|
Run the compiler, linters and call-site search |
|
Read tickets and create tasks in Azure DevOps |
|
… in Jira |
|
… in GitHub Issues |
|
Read Sonar results |
|
Use it
Talk to your assistant normally:
Review MR 123 against ticket 456. Comments in French; let me skip non-blockers.
Review my local branch against origin/develop before I push. Don't post anything.
Split ticket 456 into implementation and test tasks with hour estimates.
List my open Azure tickets in the current iteration.
Check Sonar for MR 123 and fix the issues in my checkout.
In assistants that load skills (Claude Code, Codex, Copilot), the review-mr skill runs the complete sequence: just ask for a review, or invoke it directly (/review-mr 123 fr; /co-dev-review:review-mr 123 fr when loaded as a Claude Code plugin).
Starting a session from a template
Each task has a ready-made opening message: who the assistant is, its rules, the steps and the expected answer. Use them as slash commands (/mcp__co-dev-review__review-mr 306 fr in Claude Code), or print one to paste anywhere:
co-dev-review template explain-ticket ticket=PROJ-123The templates: review-mr, address-threads, review-local, plan-ticket, explain-ticket, qa-ticket, fix-sonar, fix-pipeline and work-ticket. You can override them or add your own: see Templates.
Approving what gets posted
When the comments or tasks are ready, the assistant shows them right in the chat. Each one shows its severity, file:line, the code it lands on and the text. You reply:
approve all except R2
Only what you named is posted. You can also say approve R1 R3, add later to approve without posting, or ask to reword an item first. If you'd rather approve outside the chat (a form, a local browser page or the terminal), set REVIEW_APPROVAL. See Approval and safety.
Before a review, the assistant also asks how deep to go: diff only (fast, cheap) or a local worktree with the compiler, linters and tests. For a worktree, it asks which package manager to use; when the MR doesn't touch dependencies, your own node_modules are linked in seconds.
Supported assistants
npm run setup registers the server automatically in:
Assistant | Skills linked |
Claude Code (CLI and IDE extensions) | yes |
Claude Desktop | no (rubrics are served over MCP) |
Codex (CLI, app, IDE extension) | yes |
VS Code with GitHub Copilot | yes |
GitHub Copilot CLI | yes |
Cursor | no (rubrics are served over MCP) |
Windsurf | no (rubrics are served over MCP) |
Google Antigravity | no (rubrics are served over MCP) |
Gemini CLI | no (rubrics are served over MCP) |
Any other MCP client works with a manual entry from examples/.
Commands
Command | What it does |
| Configure, check, register in assistants, link skills |
| Check credentials and connectivity (read-only) |
| Approve a draft in the terminal |
| List drafts and their state |
| List or safely remove review worktrees |
| Print a conversation template, filled in |
| Show what the last reviews actually did |
| Remove the registrations and skill links |
| All commands and options |
co-dev-review becomes available in any terminal once installed globally; setup offers to do it. In this folder, npm run doctor and npm run approve work too.
Documentation
How a review works: rubrics, worktree, compiler pass, blast radius, coverage ledger, evidence rules, trace
Configuration: every setting, where state lives, assistant registration, corporate proxies
Approval and safety: approval modes, what the model can and cannot do, failure recovery
Templates: conversation starters per task, and how to write your own
Tool reference: the MCP tools and their steps, for client implementers
Project layout
src/ MCP server, CLI and providers (GitLab, GitHub, Azure DevOps, Sonar)
skills/ review rubrics as SKILL.md files (review-mr is the entry point)
templates/ conversation starters per task, served as MCP prompts
docs/ documentation
examples/ manual MCP client configuration
test/ node:test suite; never calls real servicesDevelopment
npm run verify # static checks, then the test suite
npm run tools # start a temporary server and list its tools and steps
npm run schema # also report the JSON Schema constructs each tool usesTests cover MCP stdio discovery and validation, provider request contracts against mock HTTP, approval selection, expiry and tampering, the in-chat and browser approval paths, stale heads, uncertain writes, locks, diff anchors, the hunk ledger, coverage gaps, deterministic evidence and rubric routing.
License
Available Tools
3 toolsplan_ticket_tasksADestructive
request.step is one of: search, read, prepare, request_approval, approve, revise, view_draft, publish. Works with Azure DevOps, Jira and GitHub Issues. Turn a ticket into clear implementation and testing tasks with estimated hours, created under it after approval (Azure child Tasks, Jira sub-tasks, GitHub sub-issues). Use step=search to find tickets: WIQL or a saved query id for Azure, JQL or a filter id for Jira, a search query for GitHub. step=read returns the ticket, its children and discussion. step=prepare saves the plan for approval.
| Name | Required | Description | Default |
|---|---|---|---|
| request | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, readOnlyHint=false, idempotentHint=false and openWorldHint=true. The description adds the crucial mitigating context that creation happens only 'after approval' and names the concrete artifacts created in each tracker; it also surfaces the approval/return-value framing. It does not, however, explain what publish/approve/revise actually mutate, so it adds value without closing the gap fully.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four dense sentences with no filler, each carrying information about purpose, tracker support, or step behavior. The opening sentence is a bare enum dump of internal field values, which is slightly awkward as a lead, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-branch discriminated union with no output schema and destructive semantics, the description covers the create/approve spine well but leaves half the state machine (approve flow details, revise, view_draft, publish) unexplained. An agent can start a search/read/prepare flow but must open the schema to drive the approval half.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The top-level schema is effectively a single 'request' union with 0% reported description coverage, and the description compensates only partially: it explains step=search, step=read and step=prepare, but the other five steps (request_approval, approve, revise, view_draft, publish) are merely enumerated by name with no semantic guidance. It adds marginal meaning over the schema's const values rather than full coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb+resource: 'Turn a ticket into clear implementation and testing tasks with estimated hours, created under it after approval', and names the tracker targets (Azure child Tasks, Jira sub-tasks, GitHub sub-issues). It is clear what the tool does, but it never distinguishes itself from the sibling review_work / review_sonar tools, so an agent has no explicit routing cue between them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It maps steps to situations ('Use step=search to find tickets', 'step=read returns the ticket...', 'step=prepare saves the plan for approval') and gives per-tracker query selection for search (WIQL/query id, JQL/filter id, GitHub search). There is no explicit when-not guidance or statement of which step to start with vs. the siblings, so it stops short of 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
review_sonarARead-onlyIdempotent
Inspect a PR/MR and its Sonar quality gate, coverage, duplication, issues and hotspots together. The assistant explains failures and, when asked, fixes code using its local editing/testing tools. Supply ruleKey for remediation details or filePath (and lines) for source context. Use review_work read for the diff. This tool reads evidence; a new Sonar analysis is needed to confirm a fix.
| Name | Required | Description | Default |
|---|---|---|---|
| full | No | Raw Sonar responses instead of the compact view | |
| page | No | ||
| lines | No | Line range of filePath, e.g. "40-90" | |
| target | Yes | ||
| project | No | Sonar project key; defaults to configuration | |
| ruleKey | No | ||
| filePath | No | Optional repository-relative file to inspect at the PR head |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safe read profile (readOnly, idempotent, non-destructive), so the bar is lower, yet the description still adds real context: it notes this tool 'reads evidence' and that a new Sonar analysis is needed to confirm a fix, which clarifies the read-only, non-verifying nature. It does not contradict the annotations and adds useful caveat context beyond them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence and the parameter/alternative guidance follows efficiently. The sentence about the assistant fixing code with local editing tools is slightly tangential to tool selection but still frames how the tool fits into a workflow.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter, nested-object tool with no output schema, the description covers purpose, sibling routing, key parameter usage, and the read-only/verification caveat. It omits pagination and return-shape detail, but given the compact-view intent and existing annotations, nothing critical to correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 57%, so the description must compensate, and it does for the key gaps: it explains ruleKey (remediation details) and filePath with lines (source context), which are the least-documented parameters. It leaves page/full behavior to the schema, keeping the added meaning focused rather than exhaustive.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb (inspect) and resource (PR/MR plus its Sonar quality gate, coverage, duplication, issues, hotspots), and explicitly carves out the boundary with the sibling review_work for the diff. An agent can distinguish this from review_work without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It routes the agent to a concrete alternative ('Use review_work read for the diff') and gives the condition for parameter use (ruleKey for remediation, filePath/lines for source context). It stops short of a full when-to-use/when-not framing, e.g. it doesn't say when a review of the quality gate is not warranted.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
review_workADestructive
request.step is one of: read, read_file, rubric, pipeline, checkout, checks, blast_radius, tests, prepare_comments, request_approval, approve, revise, view_draft, publish. Review local changes before pushing or a GitLab MR/GitHub PR. Start with step=read; it returns the diff, a per-hunk ledger and the domain rubrics to load. step=rubric returns the full text of a rubric for clients that cannot load skill files. step=pipeline reports the failing CI stages of a remote MR/PR with their cause and file:line. step=checkout puts a remote MR/PR head in a dedicated worktree. step=checks runs the repository's own compiler and linters over the change; step=blast_radius lists call sites outside the diff; step=tests runs the unit tests related to the change. Each returns a runId; prepare_comments requires the first two. The assistant examines code, explains blockers and suggestions, and can prepare French/English comments. Publishing requires the user approval of the saved draft: by default you show its preview and relay their reply with step=approve. These steps support one review; they are not separate tools.
| Name | Required | Description | Default |
|---|---|---|---|
| request | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and openWorldHint=true; the description adds non-redundant behavior, notably that step=checkout materializes a remote head in a dedicated worktree and that publish is gated on explicit user approval of a saved draft. It is less explicit about the remote write side of publish and the dependency-install side effect of checkout, which limits it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition opens with a bare enumeration of the 14 step values, which duplicates the schema's const values and pushes the actual purpose sentence into second position. The remaining sentences mostly earn their place, but the front-loading is inverted and the density is high.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 14-branch discriminated union with no output schema, the description covers what the key steps return (read: diff, ledger, rubrics; pipeline: failing stages with cause and file:line; checks/blast_radius/tests) and the approval gate. The back half of the flow (approve, revise, view_draft, publish) is only named, not described, leaving a modest gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Top-level schema coverage is reported as 0%, so the description must carry meaning, and it does: it maps each of the 14 step const values to concrete behavior that the schema's bare consts do not explain, and it states the runId chaining contract. It leaves mode, base, and most target fields entirely to the schema, so it is not exhaustive.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: "Review local changes before pushing or a GitLab MR/GitHub PR," and adds the scope-clarifying note that the steps "support one review; they are not separate tools." It does not name or differentiate itself from the siblings review_sonar or plan_ticket_tasks, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Strong internal routing guidance: "Start with step=read," prepare_comments "requires the first two" runIds, and "Publishing requires the user approval of the saved draft." It never states when to prefer this tool over review_sonar or when not to use it, so it stops at a clear-context 4.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v1.4.0- Changed
plan_ticket_tasks1 field changed- changed
Input schema / properties / request / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "continuationToken": { - "type": "string" - }, - "step": { - "const": "read", - "type": "string" - }, - "ticketId": { - "exclusiveMinimum": 0, - "type": "integer" - } - }, - "required": [ - "step", - "ticketId" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "language": { - "enum": [ - "fr", - "en" - ], - "type": "string" - }, - "step": { - "const": "prepare", - "type": "string" - }, - "tasks": { - "items": { - "additionalProperties": false, - "properties": { - "description": { - "description": "Final task description in Azure HTML: scope, completion criteria, dependencies and estimate assumptions", - "maxLength": 30000, - "minLength": 1, - "type": "string" - }, - "estimatedHours": { - "description": "Required effort estimate in hours, not a promised completion date", - "exclusiveMinimum": 0, - "maximum": 100000, - "type": "number" - }, - "title": { - "maxLength": 255, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "title", - "description", - "estimatedHours" - ], - "type": "object" - }, - "maxItems": 50, - "minItems": 1, - "type": "array" - }, - "ticketId": { - "exclusiveMinimum": 0, - "type": "integer" - } - }, - "required": [ - "step", - "ticketId", - "language", - "tasks" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "draftId": { - "format": "uuid", - "type": "string" - }, - "step": { - "const": "view_draft", - "type": "string" - } - }, - "required": [ - "step", - "draftId" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "draftId": { - "$ref": "#/properties/request/anyOf/2/properties/draftId" - }, - "step": { - "const": "publish", - "type": "string" - } - }, - "required": [ - "step", - "draftId" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "query": { + "description": "Azure: WIQL (supports @project, @Me). Jira: JQL, e.g. \"assignee = currentUser() AND statusCategory != Done\". GitHub: issue search, e.g. \"is:open assignee:@me label:bug\" (repo:GITHUB_REPO is added when no repo/org is named)", + "maxLength": 4000, + "minLength": 1, + "type": "string" + }, + "queryId": { + "description": "Azure saved query GUID (from its URL) or Jira filter id", + "pattern": "^[\\w-]{1,64}$", + "type": "string" + }, + "step": { + "const": "search", + "type": "string" + }, + "tracker": { + "description": "Ticket tracker; inferred from the id, else azure (TICKET_TRACKER)", + "enum": [ + "azure", + "jira", + "github" + ], + "type": "string" + }, + "wiql": { + "description": "Same as query, for Azure", + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "step" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "continuationToken": { + "type": "string" + }, + "full": { + "default": false, + "description": "Every raw field instead of the reviewer-relevant ones", + "type": "boolean" + }, + "step": { + "const": "read", + "type": "string" + }, + "ticketId": { + "anyOf": [ + { + "exclusiveMinimum": 0, + "type": "integer" + }, + { + "pattern": "^(?:[A-Za-z][A-Za-z0-9_]+-\\d+|(?:[\\w.-]+\\/[\\w.-]+)?#\\d+|\\d+)$", + "type": "string" + } + ], + "description": "Azure work item id (42), Jira key (PROJ-123) or GitHub issue (owner/repo#45, or #45 with GITHUB_REPO)" + }, + "tracker": { + "$ref": "#/properties/request/anyOf/0/properties/tracker" + } + }, + "required": [ + "step", + "ticketId" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "approval": { + "default": "default", + "description": "Where the user approves. default = conversation (REVIEW_APPROVAL). conversation: you show the preview and relay the user's reply with step=approve. in-chat: an MCP form. browser: a local page. terminal: co-dev-review approve. auto: form, then browser, then terminal", + "enum": [ + "default", + "conversation", + "in-chat", + "browser", + "terminal", + "auto" + ], + "type": "string" + }, + "language": { + "enum": [ + "fr", + "en" + ], + "type": "string" + }, + "step": { + "const": "prepare", + "type": "string" + }, + "tasks": { + "items": { + "additionalProperties": false, + "properties": { + "assignedTo": { + "description": "Azure: email or unique name; Jira Cloud: accountId (Server: user name); GitHub: login. Defaults to AZURE_DEVOPS_ASSIGNEE, JIRA_ASSIGNEE or GITHUB_ASSIGNEE", + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + "description": { + "description": "Final task description in the tracker's format (Azure DevOps HTML, Jira wiki markup, GitHub Markdown): scope, completion criteria, dependencies and estimate assumptions", + "maxLength": 30000, + "minLength": 1, + "type": "string" + }, + "estimatedHours": { + "description": "Required effort estimate in hours, not a promised completion date. Azure: Original Estimate and Remaining Work; Jira: Original Estimate; GitHub: written in the body.", + "exclusiveMinimum": 0, + "maximum": 100000, + "type": "number" + }, + "title": { + "maxLength": 255, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "title", + "description", + "estimatedHours" + ], + "type": "object" + }, + "maxItems": 50, + "minItems": 1, + "type": "array" + }, + "ticketId": { + "$ref": "#/properties/request/anyOf/1/properties/ticketId" + }, + "tracker": { + "$ref": "#/properties/request/anyOf/0/properties/tracker" + } + }, + "required": [ + "step", + "ticketId", + "language", + "tasks" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "approval": { + "$ref": "#/properties/request/anyOf/2/properties/approval" + }, + "draftId": { + "format": "uuid", + "type": "string" + }, + "step": { + "const": "request_approval", + "type": "string" + } + }, + "required": [ + "step", + "draftId" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "draftId": { + "$ref": "#/properties/request/anyOf/3/properties/draftId" + }, + "publish": { + "default": true, + "description": "false only when the user asked to approve without posting now", + "type": "boolean" + }, + "selectedIds": { + "description": "Exactly the item ids the user approved in their reply, e.g. [\"R1\",\"R3\"]", + "items": { + "pattern": "^[RT]\\d{1,3}$", + "type": "string" + }, + "maxItems": 100, + "minItems": 1, + "type": "array" + }, + "step": { + "const": "approve", + "type": "string" + }, + "userWords": { + "description": "The user's approving reply, quoted verbatim; it is stored with the approval", + "maxLength": 500, + "minLength": 2, + "type": "string" + } + }, + "required": [ + "step", + "draftId", + "selectedIds", + "userWords" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "draftId": { + "$ref": "#/properties/request/anyOf/3/properties/draftId" + }, + "itemId": { + "pattern": "^[RT]\\d{1,3}$", + "type": "string" + }, + "step": { + "const": "revise", + "type": "string" + }, + "text": { + "description": "The reworded comment (Markdown) or task description (Azure HTML) the user asked for", + "maxLength": 30000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "step", + "draftId", + "itemId", + "text" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "draftId": { + "$ref": "#/properties/request/anyOf/3/properties/draftId" + }, + "step": { + "const": "view_draft", + "type": "string" + } + }, + "required": [ + "step", + "draftId" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "draftId": { + "$ref": "#/properties/request/anyOf/3/properties/draftId" + }, + "step": { + "const": "publish", + "type": "string" + } + }, + "required": [ + "step", + "draftId" + ], + "type": "object" + } +]
- Changed
review_sonar2 fields changed- added
Input schema / properties / fullAdded value: +{ + "default": false, + "description": "Raw Sonar responses instead of the compact view", + "type": "boolean" +} - added
Input schema / properties / linesAdded value: +{ + "description": "Line range of filePath, e.g. \"40-90\"", + "pattern": "^\\s*\\d*\\s*-?\\s*\\d*\\s*$", + "type": "string" +}
- Changed
review_work1 field changed- changed
Input schema / properties / request / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "base": { - "default": "HEAD", - "description": "For local branch review use the intended comparison ref, e.g. origin/develop", - "type": "string" - }, - "mode": { - "default": "working", - "enum": [ - "working", - "staged", - "branch" - ], - "type": "string" - }, - "page": { - "default": 1, - "maximum": 1000, - "minimum": 1, - "type": "integer" - }, - "step": { - "const": "read", - "type": "string" - }, - "target": { - "additionalProperties": false, - "description": "Remote MR/PR; omit to review the configured local checkout", - "properties": { - "number": { - "exclusiveMinimum": 0, - "type": "integer" - }, - "project": { - "description": "GitLab ID/path or GitHub owner/repository; defaults to configured GitLab project", - "minLength": 1, - "type": "string" - }, - "provider": { - "enum": [ - "gitlab", - "github" - ], - "type": "string" - } - }, - "required": [ - "provider", - "number" - ], - "type": "object" - } - }, - "required": [ - "step" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "path": { - "minLength": 1, - "type": "string" - }, - "ref": { - "description": "Head SHA from the reviewed snapshot", - "minLength": 1, - "type": "string" - }, - "step": { - "const": "read_file", - "type": "string" - }, - "target": { - "$ref": "#/properties/request/anyOf/0/properties/target" - } - }, - "required": [ - "step", - "target", - "path", - "ref" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "names": { - "description": "Rubric or repository skill names from the read result, e.g. [\"review-react-ts\", \"house-conventions\"]", - "items": { - "maxLength": 64, - "minLength": 1, - "type": "string" - }, - "maxItems": 8, - "minItems": 1, - "type": "array" - }, - "step": { - "const": "rubric", - "type": "string" - } - }, - "required": [ - "step", - "names" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "base": { - "default": "HEAD", - "type": "string" - }, - "mode": { - "default": "working", - "enum": [ - "working", - "staged", - "branch" - ], - "type": "string" - }, - "only": { - "description": "Restrict which runners execute; omit to run every one that is available", - "items": { - "enum": [ - "tsc", - "eslint", - "dotnet" - ], - "type": "string" - }, - "type": "array" - }, - "step": { - "const": "checks", - "type": "string" - } - }, - "required": [ - "step" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "base": { - "default": "HEAD", - "type": "string" - }, - "mode": { - "default": "working", - "enum": [ - "working", - "staged", - "branch" - ], - "type": "string" - }, - "step": { - "const": "blast_radius", - "type": "string" - } - }, - "required": [ - "step" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "coverage": { - "description": "Every hunk in the diff needs exactly one verdict. The draft is rejected while any hunk is unaccounted for.", - "items": { - "additionalProperties": false, - "properties": { - "hunks": { - "description": "Hunk ids from the read ledger: \"7.2\", a whole file as \"7.*\", a range as \"7.2-7.5\", or a comma-separated mix", - "minLength": 1, - "type": "string" - }, - "note": { - "description": "Required in practice for not-applicable: say why the hunk needs no judgement", - "maxLength": 500, - "type": "string" - }, - "verdict": { - "enum": [ - "finding", - "reviewed-clean", - "not-applicable" - ], - "type": "string" - } - }, - "required": [ - "hunks", - "verdict" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, - "items": { - "items": { - "additionalProperties": false, - "properties": { - "body": { - "description": "Exact comment text in the selected language; include impact and actionable evidence", - "maxLength": 30000, - "minLength": 1, - "type": "string" - }, - "line": { - "exclusiveMinimum": 0, - "type": "integer" - }, - "path": { - "minLength": 1, - "type": "string" - }, - "severity": { - "enum": [ - "blocker", - "major", - "minor", - "suggestion" - ], - "type": "string" - }, - "side": { - "default": "RIGHT", - "enum": [ - "LEFT", - "RIGHT" - ], - "type": "string" - } - }, - "required": [ - "body", - "severity" - ], - "type": "object" - }, - "maxItems": 100, - "minItems": 1, - "type": "array" - }, - "language": { - "enum": [ - "fr", - "en" - ], - "type": "string" - }, - "rubricsApplied": { - "description": "Names of the rubric skills and repository skills you actually read and applied for this review, e.g. [\"review-react-ts\", \"house-conventions\"]. An empty array is accepted and is shown to the approver as such.", - "items": { - "maxLength": 64, - "minLength": 1, - "type": "string" - }, - "maxItems": 20, - "type": "array" - }, - "step": { - "const": "prepare_comments", - "type": "string" - }, - "target": { - "$ref": "#/properties/request/anyOf/0/properties/target" - } - }, - "required": [ - "step", - "target", - "language", - "items", - "coverage", - "rubricsApplied" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "draftId": { - "format": "uuid", - "type": "string" - }, - "step": { - "const": "view_draft", - "type": "string" - } - }, - "required": [ - "step", - "draftId" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "draftId": { - "$ref": "#/properties/request/anyOf/6/properties/draftId" - }, - "step": { - "const": "publish", - "type": "string" - } - }, - "required": [ - "step", - "draftId" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "base": { + "default": "HEAD", + "description": "For local branch review use the intended comparison ref, e.g. origin/develop", + "type": "string" + }, + "mode": { + "default": "working", + "enum": [ + "working", + "staged", + "branch" + ], + "type": "string" + }, + "page": { + "default": 1, + "maximum": 1000, + "minimum": 1, + "type": "integer" + }, + "step": { + "const": "read", + "type": "string" + }, + "target": { + "additionalProperties": false, + "description": "Remote MR/PR; omit to review the configured local checkout", + "properties": { + "number": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "project": { + "description": "GitLab ID/path or GitHub owner/repository; defaults to configured GitLab project", + "minLength": 1, + "type": "string" + }, + "provider": { + "enum": [ + "gitlab", + "github" + ], + "type": "string" + } + }, + "required": [ + "provider", + "number" + ], + "type": "object" + } + }, + "required": [ + "step" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "lines": { + "description": "Line range such as \"120-220\", \"120-\" or \"-80\"; read only what you need. Without it, files longer than 1500 lines are cut with a continuation hint", + "pattern": "^\\s*\\d*\\s*-?\\s*\\d*\\s*$", + "type": "string" + }, + "path": { + "minLength": 1, + "type": "string" + }, + "ref": { + "description": "Head SHA from the reviewed snapshot", + "minLength": 1, + "type": "string" + }, + "step": { + "const": "read_file", + "type": "string" + }, + "target": { + "$ref": "#/properties/request/anyOf/0/properties/target" + } + }, + "required": [ + "step", + "target", + "path", + "ref" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "names": { + "description": "Rubric or repository skill names from the read result, e.g. [\"review-react-ts\", \"house-style\"]", + "items": { + "maxLength": 64, + "minLength": 1, + "type": "string" + }, + "maxItems": 8, + "minItems": 1, + "type": "array" + }, + "step": { + "const": "rubric", + "type": "string" + } + }, + "required": [ + "step", + "names" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "install": { + "default": true, + "description": "Install dependencies from the lockfile (lifecycle scripts skipped) when node_modules is missing or the lockfile changed", + "type": "boolean" + }, + "packageManager": { + "default": "auto", + "description": "auto links your checkout's node_modules when the change touches no lockfile or package.json, else installs with the lockfile's manager; link, pnpm, npm or yarn force one; none skips dependencies. Ask the user first", + "enum": [ + "auto", + "link", + "pnpm", + "npm", + "yarn", + "none" + ], + "type": "string" + }, + "step": { + "const": "checkout", + "type": "string" + }, + "target": { + "$ref": "#/properties/request/anyOf/0/properties/target" + } + }, + "required": [ + "step", + "target" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "base": { + "default": "HEAD", + "type": "string" + }, + "detail": { + "default": "summary", + "description": "summary keeps results short; full returns every finding or caller", + "enum": [ + "summary", + "full" + ], + "type": "string" + }, + "mode": { + "default": "working", + "enum": [ + "working", + "staged", + "branch" + ], + "type": "string" + }, + "only": { + "description": "Restrict which runners execute; omit to run every one that is available", + "items": { + "enum": [ + "tsc", + "eslint", + "dotnet" + ], + "type": "string" + }, + "type": "array" + }, + "step": { + "const": "checks", + "type": "string" + }, + "target": { + "$ref": "#/properties/request/anyOf/0/properties/target", + "description": "Remote MR/PR prepared with step=checkout; runs in its worktree against the review base, ignoring mode and base" + } + }, + "required": [ + "step" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "base": { + "default": "HEAD", + "type": "string" + }, + "detail": { + "default": "summary", + "description": "summary keeps results short; full returns every finding or caller", + "enum": [ + "summary", + "full" + ], + "type": "string" + }, + "mode": { + "default": "working", + "enum": [ + "working", + "staged", + "branch" + ], + "type": "string" + }, + "step": { + "const": "blast_radius", + "type": "string" + }, + "symbols": { + "description": "Expand every caller of these symbols only", + "items": { + "maxLength": 64, + "minLength": 1, + "type": "string" + }, + "maxItems": 10, + "type": "array" + }, + "target": { + "$ref": "#/properties/request/anyOf/0/properties/target", + "description": "Remote MR/PR prepared with step=checkout; runs in its worktree against the review base, ignoring mode and base" + } + }, + "required": [ + "step" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "step": { + "const": "pipeline", + "type": "string" + }, + "target": { + "$ref": "#/properties/request/anyOf/0/properties/target" + } + }, + "required": [ + "step", + "target" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "base": { + "default": "HEAD", + "type": "string" + }, + "mode": { + "default": "working", + "enum": [ + "working", + "staged", + "branch" + ], + "type": "string" + }, + "step": { + "const": "tests", + "type": "string" + }, + "target": { + "$ref": "#/properties/request/anyOf/0/properties/target", + "description": "Remote MR/PR prepared with step=checkout; runs in its worktree against the review base, ignoring mode and base" + } + }, + "required": [ + "step" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "approval": { + "default": "default", + "description": "Where the user approves. default = conversation (REVIEW_APPROVAL). conversation: you show the preview and relay the user's reply with step=approve. in-chat: an MCP form. browser: a local page. terminal: co-dev-review approve. auto: form, then browser, then terminal", + "enum": [ + "default", + "conversation", + "in-chat", + "browser", + "terminal", + "auto" + ], + "type": "string" + }, + "coverage": { + "description": "Every hunk in the diff needs exactly one verdict. The draft is rejected while any hunk is unaccounted for.", + "items": { + "additionalProperties": false, + "properties": { + "hunks": { + "description": "Hunk ids from the read ledger: \"7.2\", a whole file as \"7.*\", a range as \"7.2-7.5\", or a comma-separated mix", + "minLength": 1, + "type": "string" + }, + "note": { + "description": "Required in practice for not-applicable: say why the hunk needs no judgement", + "maxLength": 500, + "type": "string" + }, + "verdict": { + "enum": [ + "finding", + "reviewed-clean", + "not-applicable" + ], + "type": "string" + } + }, + "required": [ + "hunks", + "verdict" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "deterministic": { + "additionalProperties": false, + "description": "Proof that step=checks and step=blast_radius ran on this review head against its base, or an explicit reason each was skipped. A run on another commit or base is rejected.", + "properties": { + "blastRadius": { + "$ref": "#/properties/request/anyOf/8/properties/deterministic/properties/checks" + }, + "checks": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "runId": { + "description": "runId returned by the step for this same target", + "format": "uuid", + "type": "string" + } + }, + "required": [ + "runId" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "skipped": { + "description": "Why the pass could not be run; shown to the approver", + "maxLength": 500, + "minLength": 20, + "type": "string" + } + }, + "required": [ + "skipped" + ], + "type": "object" + } + ] + }, + "tests": { + "$ref": "#/properties/request/anyOf/8/properties/deterministic/properties/checks", + "description": "runId of step=tests on this head, when tests were run" + } + }, + "required": [ + "checks", + "blastRadius" + ], + "type": "object" + }, + "items": { + "items": { + "additionalProperties": false, + "properties": { + "body": { + "description": "Exact comment text in the selected language; include impact and actionable evidence", + "maxLength": 30000, + "minLength": 1, + "type": "string" + }, + "confidence": { + "description": "After trying to refute the finding: confirmed = trigger named and no protection found; likely = plausible, protection not ruled out; question = needs the author's knowledge, written as a question", + "enum": [ + "confirmed", + "likely", + "question" + ], + "type": "string" + }, + "line": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "lineText": { + "description": "Preferred anchor: the exact content of the added (RIGHT) or removed (LEFT) line, without its +/- prefix. The server finds its line number; do not count lines. line, when also given, only picks between identical lines", + "maxLength": 500, + "minLength": 1, + "type": "string" + }, + "path": { + "minLength": 1, + "type": "string" + }, + "severity": { + "enum": [ + "blocker", + "major", + "minor", + "suggestion" + ], + "type": "string" + }, + "side": { + "default": "RIGHT", + "enum": [ + "LEFT", + "RIGHT" + ], + "type": "string" + } + }, + "required": [ + "body", + "severity", + "confidence" + ], + "type": "object" + }, + "maxItems": 100, + "minItems": 1, + "type": "array" + }, + "language": { + "enum": [ + "fr", + "en" + ], + "type": "string" + }, + "rubricsApplied": { + "description": "Names of the rubric skills and repository skills you actually read and applied for this review, e.g. [\"review-react-ts\", \"house-style\"]. Every rubric skill routed by read must be here or in rubricsSkipped.", + "items": { + "maxLength": 64, + "minLength": 1, + "type": "string" + }, + "maxItems": 20, + "type": "array" + }, + "rubricsSkipped": { + "default": [], + "description": "Routed rubrics you deliberately did not apply, each with a reason the approver sees", + "items": { + "additionalProperties": false, + "properties": { + "name": { + "maxLength": 64, + "minLength": 1, + "type": "string" + }, + "reason": { + "maxLength": 300, + "minLength": 15, + "type": "string" + } + }, + "required": [ + "name", + "reason" + ], + "type": "object" + }, + "maxItems": 20, + "type": "array" + }, + "step": { + "const": "prepare_comments", + "type": "string" + }, + "target": { + "$ref": "#/properties/request/anyOf/0/properties/target" + } + }, + "required": [ + "step", + "target", + "language", + "items", + "coverage", + "rubricsApplied", + "deterministic" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "approval": { + "$ref": "#/properties/request/anyOf/8/properties/approval" + }, + "draftId": { + "format": "uuid", + "type": "string" + }, + "step": { + "const": "request_approval", + "type": "string" + } + }, + "required": [ + "step", + "draftId" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "draftId": { + "$ref": "#/properties/request/anyOf/9/properties/draftId" + }, + "publish": { + "default": true, + "description": "false only when the user asked to approve without posting now", + "type": "boolean" + }, + "selectedIds": { + "description": "Exactly the item ids the user approved in their reply, e.g. [\"R1\",\"R3\"]", + "items": { + "pattern": "^[RT]\\d{1,3}$", + "type": "string" + }, + "maxItems": 100, + "minItems": 1, + "type": "array" + }, + "step": { + "const": "approve", + "type": "string" + }, + "userWords": { + "description": "The user's approving reply, quoted verbatim; it is stored with the approval", + "maxLength": 500, + "minLength": 2, + "type": "string" + } + }, + "required": [ + "step", + "draftId", + "selectedIds", + "userWords" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "draftId": { + "$ref": "#/properties/request/anyOf/9/properties/draftId" + }, + "itemId": { + "pattern": "^[RT]\\d{1,3}$", + "type": "string" + }, + "step": { + "const": "revise", + "type": "string" + }, + "text": { + "description": "The reworded comment (Markdown) or task description (Azure HTML) the user asked for", + "maxLength": 30000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "step", + "draftId", + "itemId", + "text" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "draftId": { + "$ref": "#/properties/request/anyOf/9/properties/draftId" + }, + "step": { + "const": "view_draft", + "type": "string" + } + }, + "required": [ + "step", + "draftId" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "draftId": { + "$ref": "#/properties/request/anyOf/9/properties/draftId" + }, + "step": { + "const": "publish", + "type": "string" + } + }, + "required": [ + "step", + "draftId" + ], + "type": "object" + } +]
3 tool updates
v1.1.0- First observed
plan_ticket_tasks - First observed
review_sonar - First observed
review_work
TDQS
Scored across 3 tools
The three tools target mostly distinct domains: review_work handles general code review workflow, plan_ticket_tasks handles ticket decomposition, and review_sonar handles Sonar evidence. However, review_work and review_sonar both operate on PR/MR quality assessment, so an agent may be unsure which to call first without reading the descriptions carefully.
All names use snake_case, but the verb+object pattern is inconsistent: review_work and review_sonar share a 'review_' prefix, while plan_ticket_tasks uses 'plan_' with a three-word noun phrase. 'work' is also a vague noun compared to 'sonar', making the naming less predictable.
Three tools roughly map to the server's three apparent domains, which is reasonable. However, review_work alone packs thirteen distinct step operations into one tool, suggesting the surface is slightly under-factored and could benefit from narrower tools.
review_work provides an end-to-end lifecycle from diff reading to publishing comments, plan_ticket_tasks covers ticket search through approval and creation, and review_sonar covers Sonar evidence. Minor gaps exist, such as no explicit tool for updating existing tickets or merging MRs, but agents can work around them within the stated review scope.
Maintenance
Related MCP Connectors
AI-native git hosting — repos, PRs, issues, CI gates, and AI code review over MCP (60 tools).
AI code review for GitHub PRs with an MCP autofix loop for Claude Code and Cursor
A Model Context Protocol (MCP) application for automated GitHub PR analysis and issue management.…
Security reviews, threat models over a repo or website, and remediation tracking, in your editor. MCP Endpoints - US - https://mcp.trent.ai/mcp - EU - https://mcp.eu.trent.ai/mcp
Related MCP Servers
- AlicenseBqualityCmaintenanceEnables code review operations on GitHub and GitLab, including fetching pull/merge requests, viewing diffs, adding comments, analyzing code quality, and creating merge requests directly from your MCP client.159 npm4MIT
- FlicenseNot gradedqualityDmaintenanceEnables automated AI-powered code review for pull requests across GitHub, GitLab, Bitbucket, and Azure DevOps via webhooks, and manual code review through MCP tools using Groq, Claude, or GPT-4.1-
- FlicenseNot gradedqualityBmaintenanceEnables manual review of GitLab Merge Requests and GitHub Pull Requests, loading context, generating comment previews, and preparing commit-based fixes for unresolved threads. Every write — comments, replies, and commits — requires explicit user confirmation and an approved preview before it is published.-
- AlicenseNot gradedqualityCmaintenanceEnables pull request review, risk rating, and improvement suggestions directly inside MCP clients by pasting a GitLab/GitHub URL; it can post review comments back to the PR/MR.MIT