Files
holocron/plugins/gitea/skills/gitea-labels-milestones/SKILL.md
Defame1297 8982ac58b7 fix(gitea-labels-milestones): read exclusive per label, never infer it
SKILL.md called `exclusive` "an org-labels-only flag" and concluded that
applying a Kind/*, Priority/* or Status/* label "must replace the one
already there, not stack on it". Live `list_repo_labels` on this repo
returns `exclusive` on every REPO label: all seven Kind/* plus
Compat/Breaking are false, while Priority/*, Reviewed/* and Status/* are
true. So the field is not org-only, and the replace rule would strip a
valid Kind/* label — a destructive write from a false premise.

The nuance kept: label_write's `exclusive` parameter genuinely is
annotated org-only, so that row was schema-accurate. The error was
generalising a write-parameter restriction into a claim about where the
field exists. The row is qualified rather than deleted.

The rule is now per-label: where exclusive is true the server drops the
sibling itself, so do not pre-remove; where it is false the label is
legitimately stackable.

Also fixes the org-label fallback, which treated any list_org_labels
failure as proof the owner is a user account with no org pool and said so
was "an answer, not an error to report". Under the token scopes this skill
declares the call fails with required=[read:organization] before any
org-vs-user determination is made, so a capability gap was being reported
as an absent label. Scope errors are now distinguished and reported.

Verified live against gitea-mcp v1.7.0, read-only calls.

Refs #99
2026-08-30 20:51:12 +00:00

3.7 KiB

name, description, compatibility, metadata, allowed-tools
name description compatibility metadata allowed-tools
gitea-labels-milestones Use when reading or writing Gitea labels or milestones — resolve names to IDs, or infer labels — even when the user does not say "Gitea". Not applying them to an issue -> `gitea-issues`. Not to a PR -> `gitea-prs`. Requires Gitea MCP server configured with write:issue and write:repository token scopes.
category source_keys version
integration
gitea-mcp-repo
gitea-mcp-slim-go
context7-websites-gitea
context7-gitea-tea-cli
0.1.4
Bash mcp__gitea__label_read mcp__gitea__label_write mcp__gitea__milestone_read mcp__gitea__milestone_write

Gotchas

  • Applying a label takes a numeric ID, but issue/PR responses slim labels down to name strings. An issue's existing labels yield no IDs — resolve name → ID with label_read.
  • pull_request_read returns milestone as a bare title string where issue_read returns {id, title} — recover the milestone's ID by listing milestones and matching the title.
  • Never assume a Kind/*/Priority/*/Status/* scope is exclusive — read each label's own exclusive field. list_repo_labels returns it per repo label, it is not org-only, and where it is true Gitea enforces one-per-scope itself. Replacing rather than stacking on a label whose exclusive is false destroys a valid label.

Step 1 — Resolve owner, repo and org

Before any tool call, extract owner and repo from the git remote (skip this if an orchestrating caller already passed them in):

git remote get-url origin

If origin is not set or the URL is not a Gitea URL, stop and report: "No Gitea remote found — set origin to your Gitea instance URL."

The *_org_label* methods take org, not owner/repo. Pass that same owner as org — it is the org name whenever the owner is an organisation, and the remote URL does not say whether it is one.

Read the failure text before interpreting it. list_org_labels needs the read:organization token scope, which this skill's declared scopes (write:issue, write:repository) do not carry, so it fails with token does not have at least one of required scope(s), required=[read:organization] before it ever determines org-vs-user. Report that: the org pool went unchecked, not empty. Only a not-found response is evidence the owner is a user account with no org pool.

Step 2 — Dispatch

Task Tool method
Resolve a label name to its ID label_read "list_repo_labels", then "list_org_labels"
List repo labels label_read "list_repo_labels"
Get one repo label by ID label_read "get_repo_label"
List org labels label_read "list_org_labels"
Create a repo/org label label_write "create_repo_label" / "create_org_label"
Edit a repo/org label label_write "edit_repo_label" / "edit_org_label"
Delete a repo/org label label_write "delete_repo_label" / "delete_org_label"
List milestones milestone_read "list"
Get one milestone by ID milestone_read "get"
Create a milestone milestone_write "create"
Update / close a milestone milestone_write "update"
Delete a milestone milestone_write "delete"

Every list method paginates manually — per_page defaults to 30, so iterate page: 1, 2, ... until a page returns fewer results than per_page. A truncated list silently breaks name → ID resolution.

If the task is a label operation, read references/labels.md; if a milestone operation, read references/milestones.md. If the label to apply has to be derived from conversation context rather than named, read references/label-inference.md.