Finding 13: five blocks of near-identical wording were repeated across skills within a plugin — the gitea "resolve owner and repo" step (5 skills), the 404-masks-403 note (6 files), the manual pagination explanation (8 files), the git plugin's main/master force-push refusal (7 files, some with multiple internal restatements), and the bin skills' domain-glossary/ADR paragraph (5 skills). Tightened each instance in place — same meaning, fewer words — rather than extracting to a shared file, which ADR-0014's one-file-per-skill install constraint rules out. Left the three git skills' structured-result JSON shapes alone (coupled to the separate, out-of-scope git-orchestrate merge candidate, finding 19). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
6.1 KiB
topic, source_keys
| topic | source_keys | ||
|---|---|---|---|
| issues |
|
Issue operations
Call signatures below were verified live against the deployed gitea-mcp server via ToolSearch,
not copied from api-reference.md — this is deliberate: research docs are generated from source at
a point in time and can drift from the server actually deployed. Last verified against gitea-mcp
v1.7.0, as reported by get_gitea_mcp_server_version. Drift runs in both directions: this file
previously recorded list_issues as having neither a type nor a milestones parameter, and
v1.7.0 has both. Re-verify against the live schema if these tools appear to behave differently than
documented here.
list_issues
Parameters (live schema):
owner(string, required)repo(string, required)state(string, optional, default"all") — conventional values"open"/"closed"/"all", not schema-enforced as an enumlabels(array of strings, optional) — filter by label name (not ID)milestones(array of strings, optional) — filter by milestone name or numeric ID, both passed as stringstype(string, enum"issues"|"pulls", optional) — omit it and the response mixes bothsince(string, optional) — ISO 8601, issues updated after this timebefore(string, optional) — ISO 8601, issues updated before this timepage(number, optional, default1)per_page(number, optional, default30)
Pass type: "issues" on any listing meant to show issues. Issues and PRs share one repo number
space and the unfiltered response interleaves them; the only thing distinguishing them on a list
item is the html_url path segment (/issues/ vs /pulls/), since is_pull is not returned on
list items — see the Gotchas section of SKILL.md.
Call:
list_issues owner: <owner> repo: <repo> state: "open" type: "issues"
Response (list item): number, title, state, html_url, user, comments, created_at,
updated_at, and optionally labels ([]string), milestone ({id, title}), ref, deadline.
Body and closed_at are omitted from list responses — call issue_read method: "get" for those.
Paginate: page/per_page, stop once the count is below per_page.
issue_read
Parameters (live schema, matches api-reference.md):
method(string, required, enum) —"get"|"get_comments"|"get_labels"owner(string, required)repo(string, required)issue_number(number, required)
get — full issue: number, title, body, state, html_url, user, labels
([]string), comments, created_at, updated_at, closed_at, and optionally assignees
([]string), milestone ({id, title}), ref, deadline, is_pull (present only when this
number is backed by a pull request — absent, not false, on true issues).
get_comments — array of {id, body, user, html_url, created_at, updated_at}.
get_labels — array of full label objects (id, name, color, description — not slimmed
to name strings, unlike the labels array on get).
Call:
issue_read method: "get" owner: <owner> repo: <repo> issue_number: <N>
Always check is_pull before treating a number as a plain issue — see the shared number-space
gotcha in SKILL.md.
issue_write
Parameters (live schema, matches api-reference.md):
method(string, required, enum) —"create"|"update"|"add_comment"|"edit_comment"|"add_labels"|"remove_label"|"replace_labels"|"clear_labels"owner(string, required)repo(string, required)issue_number(number, required for every method except"create")title(string, required for"create")body(string, required for"create","add_comment","edit_comment")assignees(array of strings, optional) — login names (seereferences/enrichments.mdfor why this is usually omitted)milestone(number, optional) — milestone ID, never a titlestate(string, enum"open"/"closed"/"all", optional) — for"update"commentID(number, optional, required for"edit_comment")labels(array of numbers, optional) — label IDs, never names — foradd_labels/replace_labelslabel_id(number, optional, required for"remove_label") — singular, not the array formref(string, optional) — branch association, informational onlydeadline(string, optional) — ISO 8601remove_deadline(boolean, optional)
Create:
issue_write method: "create"
owner: <owner> repo: <repo>
title: <title> body: <body>
labels: [<resolved IDs>] ← omit if none confidently inferred
milestone: <resolved ID> ← omit if none clearly fits
assignees: ["<login>"] ← omit if no default configured
Close:
issue_write method: "update" owner: <owner> repo: <repo> issue_number: <N> state: "closed"
No method: "close" exists — using one errors.
Comment:
issue_write method: "add_comment" owner: <owner> repo: <repo> issue_number: <N> body: <text>
Apply resolved label IDs directly (bypassing references/enrichments.md's inference step, e.g.
when the caller already named exact labels):
issue_write method: "add_labels" owner: <owner> repo: <repo> issue_number: <N> labels: [<IDs>]
To replace all labels atomically instead of adding: method: "replace_labels".
To remove one: method: "remove_label" label_id: <single ID>.
Default to add_labels. replace_labels clears every label not in the array, so it drops
labels the caller never mentioned. Reach for it only when the caller asked for the issue's label
set to become exactly what they listed. In particular, do not use it to enforce one-label-per-scope:
exclusivity is a per-label property — the server drops the sibling itself for a label whose
exclusive field is true, and a label whose exclusive is false (every Kind/* on this
instance) is legitimately stackable. See gitea-labels-milestones for how to read that field.
Token scope
All of list_issues, issue_read, and issue_write are verified working under a token holding
write:issue + write:repository.