Agentic AI code review for GitLab MRs and GitHub PRs, with the LLM of your choice. Exposes review state and trigger via MCP tools.
Bubo demonstrates solid tool design with clear naming (verb_noun pattern), comprehensive parameter descriptions, and well-documented schemas. All 7 tools have descriptions (194 - 350 chars, within baseline 34 - 392 range). Parameters include type definitions and constraints (e.g., limit clamped to [1, 200], since_hours to [1, 720]). However, output schemas are not explicitly documented in the source, descriptions mention what is returned but JSON Schema output structures are absent. Error handling is minimal: no recovery guidance, no categorization of retryable vs. fatal errors. The review_change tool (WRITE operation) lacks confirmation/dry-run support. Tool composition is strong: each tool has one responsibility, and chaining is enabled (e.g., list_recent_reviews → get_review → get_findings). Security is adequate: no credentials in parameters, read-only operations properly marked.
Return per-finding resolution state for `(project, iid[, sha])`. Populated by `bubo-poller --sync-outcomes` (and the GitHub equivalent). Each row tells you whether the developer resolved / deleted / replied to / disputed / marked false-positive / marked duplicate the finding's discussion, plus `merged_unresolved` for findings that were merged in without resolution. Empty when no sync has run for this MR/PR yet.
Return one row per finding for `(project, iid[, sha])`. When `sha` is omitted, findings for the most recent reviewed SHA are returned. Each row carries the structured fields the reviewer extracted (file, line, severity, category, confidence, type, status) plus the rendered `body` actually posted as a comment, and the `discussion_id` / `note_id` from the SCM.
Aggregate counts and totals across recent reviews. Returns a dict with review counts, finding statistics, and outcome summaries within the specified look-back window.
Return the most recent `reviewed_mrs` row for one MR/PR. If `sha` is omitted, the row with the freshest `updated_at` for `(project, iid)` wins. Pass `sha` explicitly to pin a specific revision. Returns `{"found": False, "project": ..., "iid": ..., "sha": ...}` when no row matches.
Report whether the reviewer has produced state recently. Mirrors `bubo-poller --health` but returns structured data instead of an exit code. The MCP client decides what "stale" means for its display. Returns a dict with: `status` ("empty" if no reviews have ever been recorded; otherwise "ok"), `last_status` (the most recent `reviewed_mrs.status` e.g. "success", "no_findings", "failed"), `last_updated_at` (ISO-8601 timestamp of the most recent row), `age_seconds` (float, seconds since `last_updated_at`).
Output schemas not documented. Descriptions state what is returned (e.g., 'dict with status, last_status, last_updated_at, age_seconds') but no formal JSON Schema output definitions are visible in source. LLMs cannot plan downstream tool calls or extract fields reliably without structured output schemas.
review_change (WRITE operation) lacks confirmation or dry-run support. Agents can invoke code review on arbitrary MRs/PRs without a safety gate. No error guidance for recovery if the reviewer command fails.
Error handling is minimal. No recovery guidance (e.g., 'If MR not found, try list_recent_reviews first'). No error categorization (retryable vs. user-fixable vs. fatal). Agents cannot self-correct on failures.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 64 | 2026-07-28+ | v2 |
Return up to `limit` rows from `reviewed_mrs` newest-first. Supports optional filtering by status (e.g. "success", "no_findings", "failed", "running", "queued") and project (GitLab path-with-namespace or GitHub `owner/repo`).
Run the configured `[agents].reviewer_command` against one MR/PR (by URL or `(provider, project, number)`) and return the parsed findings JSON. Supports both GitHub PR URLs and GitLab MR URLs. Returns structured findings array extracted from the reviewer's output.
Tool annotations missing. No readOnlyHint, destructiveHint, or idempotentHint declarations. Clients cannot infer which tools are safe to retry or which modify state without reading descriptions.
Pagination guidance incomplete. list_recent_reviews accepts 'limit' but no 'offset' or 'cursor' parameter visible. No indication of total count or next_cursor in response. Large result sets may exhaust context.