--- topic: reviews source_keys: - gitea-mcp-repo - gitea-mcp-slim-go --- # PR review execution detail Parameter signatures below are cross-checked live against the deployed gitea-mcp server tool schema, not copied from the plugin's research doc verbatim — same sourcing discipline as `references/pull-requests.md`. Last verified against **v1.7.0**, as reported by `get_gitea_mcp_server_version`. ## Review state machine A review is not a single write. It moves through states: 1. **`create`** — opens a review in `"PENDING"` state, optionally attaching inline comments. Nothing is visible to other users yet. 2. **`submit`** — finalizes the pending review with a terminal `state`: `"APPROVED"`, `"REQUEST_CHANGES"`, or `"COMMENT"`. This is the point at which the review becomes visible and counts toward merge-gate requirements (see `references/merging.md`). 3. **`dismiss`** — invalidates an already-submitted review (e.g. an approval that's no longer valid after force-push), with an optional `message` giving the reason. Dismissal does not delete the review record — it stays visible but marked dismissed. 4. **`delete`** — removes a review outright. Use only for a review that was never submitted (e.g. abandoning a `PENDING` draft); do not use `delete` to retract a submitted review — use `dismiss` instead. ## `pull_request_review_write` **Parameters:** - `method` (string, required) — `"create"` | `"submit"` | `"delete"` | `"dismiss"` | `"reply_comment"` | `"resolve_thread"` | `"unresolve_thread"` - `owner` (string, required) - `repo` (string, required) - `pull_number` (number, required for every method except `"resolve_thread"` and `"unresolve_thread"`, which locate the thread from `comment_id` alone) — the schema's own `required` list is only `method`/`owner`/`repo`, so a missing `pull_number` surfaces as a runtime error, not client-side validation - `review_id` (number) — required for `"submit"`, `"delete"` and `"dismiss"`; `"create"` returns the ID to use for that follow-up call. Not used by `"reply_comment"`, `"resolve_thread"` or `"unresolve_thread"`, which key off `comment_id` instead - `comment_id` (number, required for `"reply_comment"`, `"resolve_thread"` and `"unresolve_thread"`) — an individual review comment's ID, obtained from `pull_request_read method: "get_review_comments"`. For the two thread methods this must be the thread's **first** comment, not an arbitrary one in it - `state` (string, optional) — `"APPROVED"` | `"REQUEST_CHANGES"` | `"COMMENT"` | `"PENDING"` — set on `"create"` (typically `"PENDING"`, or a terminal state to create-and-submit in one call if the server supports it) or `"submit"` (terminal state) - `body` (string, optional) — the overall review comment text on `"create"`/`"submit"`; on `"reply_comment"` it is the reply text and is the payload of the call - `commit_id` (string, optional, for `"create"`) — anchors inline comments to a specific commit SHA (typically the PR's current head SHA from `pull_request_read method: "get"`) - `message` (string, optional, for `"dismiss"`) — dismissal reason - `comments` (array of objects, optional, for `"create"`) — inline comments, each: `{path, body, old_line_num, new_line_num}` — `path` is the file path, `body` is the comment text, `new_line_num` anchors to a line in the new (added) side of the diff, `old_line_num` anchors to a line in the old (removed) side; use whichever side the comment applies to, not both ## Comment threads Three further methods act on an individual review comment rather than on a review as a whole. They sit outside the state machine above — a thread can be replied to or resolved whatever state its parent review is in — and none of them takes a `review_id`. - **`reply_comment`** — posts `body` as a reply to the comment named by `comment_id`, threading under it rather than starting a new top-level comment. Takes `pull_number`. - **`resolve_thread`** — marks the thread containing `comment_id` resolved. Pass the thread's **first** comment ID; another ID in the same thread is not equivalent. Does not take `pull_number`. - **`unresolve_thread`** — reopens a resolved thread, under the same first-comment rule. Get the `comment_id` from `pull_request_read method: "get_review_comments"`. Call it with no `review_id` to list every inline comment on the PR, then pick the thread to act on; scoping it to one `review_id` only finds threads opened by that review. ## Reading reviews (`pull_request_read`) - `method: "get_reviews"` — array of review summaries: `id`, `state`, `body`, `user` (login), `comments_count`, `submitted_at`, `html_url`, `stale` (bool — the PR was pushed to after this review was submitted, meaning it may be outdated), `official` (bool), `dismissed` (bool). - `method: "get_review"` (requires `review_id` — omitting it fails with `review_id is required`) — single review detail. - `method: "get_review_comments"` (`review_id` **optional** — omit it to list every inline comment on the PR in one call, rather than one review's) — array of inline comments: `id`, `body`, `path`, `position`, `old_position`, `diff_hunk`, `user`, `html_url`, `created_at`, `updated_at`. **`review_comments` on the `"get"` response is a count, not the comments — and it may be absent.** Where the full PR object returned by `pull_request_read method: "get"` carries `review_comments`, it is an integer: the number of inline review comments. Presence is not guaranteed. A live `"get"` against a PR with zero inline comments carried no such key at all — only `comments`, which counts issue-style comments, not review ones. Treat it as present only when non-zero, and check for the key before reading it rather than assuming the response shape. Either way it is distinct from the `get_review_comments` method above, which returns the actual comment objects; reading the count is no substitute for that call. Older gitea-mcp releases misspelled this key as `review_scomments`; the misspelling was corrected upstream and the deployed v1.7.0 response carries no such key, so treat any instruction that reaches for `review_scomments` as stale. **Inline-comment field names differ between write and read.** The `comments` array on `pull_request_review_write method: "create"` uses `old_line_num`/`new_line_num`. The `get_review_comments` read response uses different field names for the same concept — `position` (new-side line) and `old_position` (old-side line). Do not assume the same key names apply on both sides of the round trip.