Skip to content

feat(cursor-review): collect structured output through MCP tools#33

Open
huntcsg wants to merge 3 commits into
mainfrom
convert-cursor-review-to-structured-output
Open

feat(cursor-review): collect structured output through MCP tools#33
huntcsg wants to merge 3 commits into
mainfrom
convert-cursor-review-to-structured-output

Conversation

@huntcsg

@huntcsg huntcsg commented Jul 17, 2026

Copy link
Copy Markdown

Summary

Replace Cursor Review's free-form JSON response contract with a small, dependency-free stdio MCP server that gives reviewers and the judge typed output tools.

  • reviewers call cursor_review_record_finding once per issue and cursor_review_finish exactly once
  • the judge calls cursor_review_submit_final exactly once with the adjudicated findings
  • tool arguments are validated and atomically persisted as the normalized artifacts consumed by later jobs
  • model stdout remains diagnostic only and is no longer parsed for review results
  • remove the JSON recovery parser and the second judge call that existed only to reformat malformed output

Strategy

The workflow writes a trusted project-scoped .cursor/mcp.json that starts review-output-mcp.py in reviewer or judge mode. It also writes an exact .cursor/cli.json allowlist for only the output tools needed by that role, avoiding broad --force permissions.

The MCP server owns the result contract:

  1. expose a narrow JSON Schema for findings or final review submission
  2. validate paths, line numbers, sides, severities, body sizes, and exact fields
  3. preserve an explicit non-success state until the agent completes its required submission
  4. atomically replace the artifact only after validation succeeds
  5. refuse subsequent calls from overwriting completed output

The consolidate job continues to consume the existing normalized findings shape, so posting and blocking-gate behavior remain compatible.

Why this should be more reliable

The previous path depended on probabilistic formatting compliance: each model had to place valid JSON in free-form stdout, after which the workflow searched prose and Markdown fences, coerced common wrapper objects, and retried the judge when parsing still failed. That history already includes multiple hardening changes for prose-wrapped, malformed, or otherwise unparseable responses.

This change moves correctness to a typed protocol boundary:

  • prose, Markdown fences, escaping, and truncated response text cannot corrupt results
  • schema-invalid findings are rejected before persistence
  • an empty review is successful only after an explicit finish/final-submit call
  • a reviewer that records findings and then crashes remains visibly incomplete
  • a judge that never submits cannot be mistaken for a clean review
  • missing matrix artifacts become synthetic error cells rather than reducing the apparent panel size or producing a false “no findings” result
  • judge failure still degrades honestly to raw panel findings

MCP or agent execution can still fail, but those failures now remain explicit operational errors. They are no longer ambiguous parsing failures and cannot silently become an empty successful review. In short, the result path changes from heuristic extraction of model-authored text to deterministic validation and persistence of tool arguments.

Security and compatibility

  • uses Cursor CLI's supported project-scoped stdio MCP configuration
  • grants only the three exact MCP tools through project CLI permissions
  • rejects a symlinked .cursor directory and atomically replaces config files
  • supports the recent MCP protocol versions used by Cursor
  • preserves the established findings artifact and post-review.py contracts
  • preserves raw-panel fallback when the judge does not submit

Verification

  • python3 -m unittest discover -s .github/cursor-review/tests -p 'test_*.py' -v — 11 tests pass
  • Python compilation passes
  • workflow YAML parses successfully
  • git diff --check passes
  • local Cursor CLI smoke test successfully loaded the stdio MCP server and listed both reviewer tools
  • a full model-driven tool-call smoke test was not possible in the development workspace because it has no Cursor authentication
  • adversarial implementation re-review found no remaining high-confidence blockers

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 14 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 31b7e63b-9027-47e2-8cea-e7958619b8a0

📥 Commits

Reviewing files that changed from the base of the PR and between 4fcfbbe and 71184ae.

📒 Files selected for processing (11)
  • .github/cursor-review/README.md
  • .github/cursor-review/extract-findings.py
  • .github/cursor-review/post-review.py
  • .github/cursor-review/prompt-adversarial.md
  • .github/cursor-review/prompt-edge-case.md
  • .github/cursor-review/prompt-judge.md
  • .github/cursor-review/review-output-mcp.py
  • .github/cursor-review/tests/test_extract_findings.py
  • .github/cursor-review/tests/test_review_output_mcp.py
  • .github/workflows/cursor-review.yml
  • .github/workflows/test-cursor-review-scripts.yml
📝 Walkthrough

Walkthrough

The Cursor Review pipeline replaces raw JSON extraction with a stdio MCP server that validates and atomically persists panel and judge findings. Prompts, workflows, status handling, documentation, and tests now use the structured-output lifecycle.

Changes

Cursor Review MCP pipeline

Layer / File(s) Summary
MCP server contract and state lifecycle
.github/cursor-review/review-output-mcp.py
Adds validated reviewer and judge MCP tools, atomic JSON persistence, lifecycle state handling, JSON-RPC routing, and a CLI entrypoint.
Reviewer and judge tool instructions
.github/cursor-review/prompt-adversarial.md, .github/cursor-review/prompt-edge-case.md, .github/cursor-review/prompt-judge.md
Prompts require structured MCP calls for findings and final review submission instead of JSON in chat responses.
Panel and judge workflow integration
.github/workflows/cursor-review.yml
Configures MCP servers for panel and judge jobs, approves tool calls, reads structured records, adds missing-cell error entries, and derives consolidation status from persisted output.
MCP contract and workflow regression tests
.github/cursor-review/tests/test_review_output_mcp.py, .github/workflows/test-cursor-review-scripts.yml
Tests validation, lifecycle transitions, subprocess JSON-RPC behavior, protocol negotiation, and MCP contract coverage.
Pipeline documentation and record shape
.github/cursor-review/README.md, .github/cursor-review/post-review.py
Documents MCP-based output, atomic normalized records, failed-cell handling, and the ok/error panel status shape.

Sequence Diagram(s)

sequenceDiagram
  participant PanelAgent
  participant ReviewerMCP
  participant PanelJSON
  participant JudgeAgent
  participant JudgeMCP
  PanelAgent->>ReviewerMCP: Record findings and finish
  ReviewerMCP->>PanelJSON: Persist structured panel record
  JudgeAgent->>JudgeMCP: Submit final findings
  JudgeMCP->>PanelJSON: Persist structured judge record
  JudgeMCP-->>JudgeAgent: Return tool result
Loading

Possibly related PRs

Suggested reviewers: mattmillerai

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch convert-cursor-review-to-structured-output
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch convert-cursor-review-to-structured-output

Comment @coderabbitai help to get the list of available commands.

@huntcsg
huntcsg force-pushed the convert-cursor-review-to-structured-output branch from eb033f3 to 4fcfbbe Compare July 17, 2026 22:38
@huntcsg
huntcsg marked this pull request as ready for review July 18, 2026 00:21
@huntcsg huntcsg added the cursor-review Multi-model cursor review label Jul 18, 2026
@coderabbitai
coderabbitai Bot requested a review from mattmillerai July 18, 2026 00:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/cursor-review/review-output-mcp.py:
- Line 228: Update the call_tool invocation in the tool-processing flow to pass
params.get("arguments") unchanged, removing the `or {}` fallback. Preserve
malformed falsy values such as lists, booleans, and strings so downstream
validation can reject them, while retaining the existing default behavior for
truly absent arguments if supported by call_tool.

In @.github/cursor-review/tests/test_review_output_mcp.py:
- Around line 111-119: Update test_invalid_tool_input_does_not_replace_output to
snapshot the initialized record before submission, then send a findings list
containing both valid and invalid entries. Keep the existing error assertions
and additionally fetch or inspect the persisted record afterward, asserting it
exactly matches the initial snapshot.

In @.github/workflows/cursor-review.yml:
- Around line 369-374: Replace the PR-controlled .cursor entry with a fresh
workflow-owned directory before writing trusted configuration: at
.github/workflows/cursor-review.yml lines 369-374, remove the existing .cursor
path and recreate it before the first configuration step; apply the same
replacement at lines 514-519 before configuring judge output. Do not rely only
on symlink detection, since the entry may be a file or other conflicting path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0b3f97d5-a351-4f7b-998f-cb2ed070dc6d

📥 Commits

Reviewing files that changed from the base of the PR and between 3aead23 and 4fcfbbe.

📒 Files selected for processing (11)
  • .github/cursor-review/README.md
  • .github/cursor-review/extract-findings.py
  • .github/cursor-review/post-review.py
  • .github/cursor-review/prompt-adversarial.md
  • .github/cursor-review/prompt-edge-case.md
  • .github/cursor-review/prompt-judge.md
  • .github/cursor-review/review-output-mcp.py
  • .github/cursor-review/tests/test_extract_findings.py
  • .github/cursor-review/tests/test_review_output_mcp.py
  • .github/workflows/cursor-review.yml
  • .github/workflows/test-cursor-review-scripts.yml
💤 Files with no reviewable changes (2)
  • .github/cursor-review/tests/test_extract_findings.py
  • .github/cursor-review/extract-findings.py

Comment thread .github/cursor-review/review-output-mcp.py Outdated
Comment thread .github/cursor-review/tests/test_review_output_mcp.py
Comment thread .github/workflows/cursor-review.yml Outdated
@huntcsg
huntcsg force-pushed the convert-cursor-review-to-structured-output branch from 4fcfbbe to 1c35b8f Compare July 18, 2026 00:51
@huntcsg

huntcsg commented Jul 18, 2026

Copy link
Copy Markdown
Author

End-to-end example

The structured-output workflow was exercised against a deliberately defective, plausible change in Comfy-Org/cloud#5197.

  • Cursor Review workflow run completed successfully.
  • All eight reviewer matrix jobs configured the MCP output server, ran Cursor, persisted/uploaded structured artifacts, and completed successfully.
  • The consolidation job consumed those artifacts, ran the judge through the final-output MCP tool, and posted the review successfully.
  • The resulting consolidated review contains 8 inline findings across critical, high, medium, and low severities.
  • Two reviewers did not complete a valid structured submission; they were reported explicitly as error contributors rather than being mistaken for clean reviews, while the judge still consolidated the six valid contributors. This also exercises the intended partial-panel failure behavior.

The fixture PR is test-only and intentionally retains the reported defects so the posted inline findings remain inspectable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cursor-review Multi-model cursor review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant