The gitea-prs reference documented `milestone` as "settable on both "create" and "update"". It is not: `pull_request_write method: "create"` accepts the parameter, returns no error or warning, and discards it. Verified against the gitea-mcp v1.6.0 source rather than by observation alone. `createPullRequestFn` builds its `CreatePullRequestOption` from owner, repo, title, body, head, base, draft, labels and deadline only — so the drop is not limited to `milestone` as issue #104 supposed. `assignee`, `assignees`, `reviewers` and `team_reviewers` are discarded on create too, and `reviewers`/`team_reviewers` are discarded on "update" as well; they are only ever read by "add_reviewers" and "remove_reviewers". Two properties made the original error easy to make and hard to catch, so both are now written down next to the correction: `labels` sits beside `milestone`, reads identically, and does apply on create; and `issue_write method: "create"` honours `assignees` and `milestone`, so the asymmetry is specific to pull requests. While in the file, corrected the adjacent draft gotcha. It prescribed reconstructing the un-prefixed title by hand to un-draft a PR; `applyDraftPrefix` shows "update" with `draft: false` and no `title` fetches the stored title and strips the prefix server-side. Impact: documentation only, no behaviour change. Callers following the old text silently created PRs with no milestone, assignee or reviewer. Confined to references/pull-requests.md, so the ADR-0020 skill gates do not apply and gitea-prs needs no #99 retrofit first. Fixes: #104 Refs: #99 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ETxbGFetkbJQBHsx442Brt
7.7 KiB
topic, source_keys
| topic | source_keys | ||
|---|---|---|---|
| pull-requests |
|
Pull request read/write execution detail
Parameter signatures below are cross-checked live against the deployed gitea-mcp server tool schemas at authoring time — not copied verbatim from the plugin's research doc for this domain, which has a known history of drifting from the deployed server (e.g. a prior type parameter that no longer exists on list_issues, and the review_scomments typo covered in references/reviews.md). Re-verify via ToolSearch before trusting this file if the gitea-mcp version changes.
list_pull_requests
Parameters:
owner(string, required)repo(string, required)state(string, optional, default"all") —"open"|"closed"|"all"sort(string, optional, default"recentupdate") —"oldest"|"recentupdate"|"leastupdate"|"mostcomment"|"leastcomment"|"priority"milestone(number, optional) — milestone ID filter, not a titlepage(number, optional, default 1)per_page(number, optional, default 30)
List responses trim PRs down to summary fields — head/base are bare ref strings and milestone does not appear as an object. Don't rely on this call to resolve a milestone's ID; see the Gotcha below.
pull_request_read
Parameters:
method(string, required) —"get"|"get_diff"|"get_files"|"get_status"|"get_reviews"|"get_review"|"get_review_comments"owner(string, required)repo(string, required)pull_number(number, required)review_id(number, optional) — required for"get_review"and"get_review_comments"; seereferences/reviews.mdbinary(boolean, optional) — include binary diff content for"get_diff"page(number, optional, default 1)per_page(number, optional, default 30)
"get", "get_diff", "get_files", and "get_status" are covered here. "get_reviews", "get_review", and "get_review_comments" are covered in references/reviews.md.
"get"returns the full PR object: state, draft, merged, mergeable flags;head/baseas full objects ({ref, sha, repo?});milestoneas a bare title string (not{id, title});review_scomments(typo, seereferences/reviews.md)."get_diff"returns raw diff text."get_files"returns the list of changed file objects."get_status"returns the combined commit status for the PR's head commit — CI result only, not review/approval state (seereferences/merging.md).
Milestone gotcha: because pull_request_read only ever returns a milestone title, never an ID, resolving "which milestone ID does this PR belong to" requires calling into gitea-labels-milestones' milestone_read method: "list" and matching by title. Do not attempt to infer or guess the ID. This is the read-side milestone problem; for the separate write-side one, see the "create" drop Gotcha under pull_request_write.
pull_request_write
Parameters:
method(string, required) —"create"|"update"|"close"|"reopen"|"merge"|"update_branch"|"add_reviewers"|"remove_reviewers"owner(string, required)repo(string, required)pull_number(number, required for every method except"create"— this is enforced by convention, not by the tool's schema, so passing it incorrectly produces a runtime error rather than a client-side validation error)title(string, required for"create"; optional for"update")body(string, required for"create"; optional for"update")head(string, required for"create") — source branch; same-repo PRs use a bare branch name, cross-repo fork PRs use"fork-owner:branch-name"(see Gotcha)base(string, required for"create") — target branchassignee(string, optional) — single login;"update"only — silently dropped on"create"(see Gotcha)assignees(array of strings, optional) — login names;"update"only — silently dropped on"create"(see Gotcha)milestone(number, optional) — milestone ID, never a title;"update"only — silently dropped on"create"(see Gotcha)state(string, optional, for"update") —"open"|"closed"(no"all"— unlike issue state filters)allow_maintainer_edit(boolean, optional, for"update")labels(array of numbers, optional) — label IDs, never names — resolve viagitea-labels-milestonesfirstdeadline(string, optional) — ISO 8601remove_deadline(boolean, optional)reviewers(array of strings, optional) — login names;"add_reviewers"/"remove_reviewers"only — silently dropped on both"create"and"update"(see Gotcha)team_reviewers(array of strings, optional) — same asreviewers:"add_reviewers"/"remove_reviewers"onlydraft(boolean, optional) — prepends"WIP:"to the title; honoured on both"create"and"update"(see Gotcha)
Merge-specific parameters (merge_style, delete_branch, force_merge, merge_when_checks_succeed, head_commit_id, message as merge commit message) are covered in references/merging.md.
"create" silently drops most optional parameters. "create" reads only owner, repo, title, body, head, base, draft, labels, and deadline. Every other optional parameter — assignee, assignees, milestone, reviewers, team_reviewers — is accepted without error and discarded. There is no error, no warning, and nothing in the response distinguishing a dropped parameter from one that was never passed: the response simply omits the key. Setting any of them requires a second call after the PR exists — "update" for assignee/assignees/milestone, "add_reviewers" for reviewers/team_reviewers.
Two things make this easy to miss:
labelsdoes apply on"create". It sits next tomilestonein the parameter list and reads identically, so a caller who confirms the labels landed will reasonably assume the milestone did too.issue_write method: "create"does honourassigneesandmilestone. The asymmetry is specific to pull requests; experience with the issue write does not transfer.
To verify a milestone actually applied, re-read the PR and check for the milestone key, or check that the milestone's open_issues count moved — the create response alone cannot tell you.
Cross-repo head format: head must be "fork-owner:branch-name" for a PR originating from a fork of the base repo. Passing a bare branch name causes Gitea to search for that branch in the base repo instead, and returns 422 when it isn't found there.
Draft/WIP behavior: draft: true on "create" is implemented by prepending "WIP:" to the title — there is no first-class draft boolean stored separately from the title. The title returned by subsequent reads will include the prefix. To un-draft, call "update" with draft: false and no title — the server reads the PR's current title and strips the prefix itself, so you do not need to reconstruct the un-prefixed text. Passing title alongside draft applies the prefix rule to the title you passed rather than the stored one.
update_branch: takes only owner, repo, pull_number — no other parameters. It merges the current base branch into the PR's head branch server-side, resolving a PR that Gitea reports as behind its base (analogous to GitHub's "Update branch" button). Use it when a PR shows mergeable: false or an out-of-date status due to base-branch drift rather than an actual conflict; if the head and base have truly diverged with conflicting changes, this call fails and the conflict must be resolved by pushing a merge/rebase to the head branch directly, outside this skill's scope.