The gotcha claimed Gitea never auto-closes issues on merge. Confirmed empirically (issue #63 / PR #64) that a regular merge preserving an original commit's closing keyword does auto-close — only squash merges (this skill's default) are unreliable. Also drops search_issues from allowed-tools since no dispatch route calls it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
11 KiB
name, description, compatibility, allowed-tools, metadata
| name | description | compatibility | allowed-tools | metadata | ||
|---|---|---|---|---|---|---|
| gitea | Use when the user wants to interact with Gitea — create or update issues, open or merge pull requests, manage labels and milestones, list branches, or check repo status. Always use this skill to interact with the GiteaMCP, never use GiteaMCP directly. Triggers on: "create an issue", "open a PR", "what's open", "label this issue", "create a milestone", "merge the PR", "list branches", "close this issue" — even when the user doesn't say "Gitea" explicitly. Owner and repo are derived automatically from the git remote; no config required. Do not use for releases, CI/Actions, wiki, file operations, notifications, or package management — those are out of scope. | Requires Gitea MCP server configured in ~/.claude.json with write:issue and write:repository token scopes. Requires git remote "origin" pointing to the Gitea instance. | Bash mcp__gitea__list_issues mcp__gitea__issue_read mcp__gitea__issue_write mcp__gitea__label_read mcp__gitea__label_write mcp__gitea__milestone_read mcp__gitea__milestone_write mcp__gitea__list_pull_requests mcp__gitea__pull_request_read mcp__gitea__pull_request_write mcp__gitea__list_branches mcp__gitea__create_branch |
|
Gotchas
- Label writes take IDs, reads return names.
issue_write(add_labels, replace_labels) requireslabels: [3, 7](numeric IDs). Issue and PR responses returnlabels: ["bug", "enhancement"](name strings). These are never interchangeable. Always calllabel_read method: "list_repo_labels"first and resolve names → IDs before any label write. - Issues and PRs share a number space.
#5might be an issue or a PR — there is only one counter per repo.list_issuesreturns issues only — it has notypeparameter. Uselist_pull_requestsseparately for PRs. Checkis_pullon a single-itemissue_readresponse to determine whether a number refers to an issue or PR. - Milestone write takes ID, not title.
issue_writetakesmilestone: <numeric id>. The title is not accepted. Inissue_readresponses the milestone is{id, title}, but inpull_request_readresponses it's a bare title string — you cannot recover the ID from a PR response. Callmilestone_read method: "list"and match by title if you need the ID from a PR context. get_meis unavailable with the current token (write:issue, write:repositoryonly —read:useris missing). Owner and repo must always be derived from the git remote, never fromget_meorlist_my_repos.- Merging a PR does not itself close linked issues — but a commit message landing on the default branch can. Gitea has no GitHub-style "merge triggers close" event. It does, however, parse closing keywords (
Fixes #N,Closes #N) in commit messages pushed to the default branch. A regular (non-squash) merge preserves each original commit message, so if any of those commits saysFixes #N, the issue auto-closes at merge time — confirmed empirically (PR #64 auto-closed #63 this way, before any explicitissue_writecall was made). This skill's ownpr mergedispatch defaults tomerge_style: "squash"(Step 3), which rewrites history into one commit — whether the keyword survives depends on what message that squash commit ends up with, so squash-merged PRs are the case most likely to still need an explicit close. Always callissue_read method: "get"to check current state before manually closing after a merge — closing an already-closed issue is a harmless no-op, but don't assume a manual close is always needed. - Pagination is manual. List tools return one page at a time — no auto-pagination. When building complete datasets (e.g. all labels for name→ID mapping), iterate
page: 1, 2, ...until result count <per_page. pull_request_read method: "get"returnsreview_scomments, notreview_comments. This is a source-level typo in gitea-mcp v1.3.0. Do not accessreview_comments— it will always be undefined. Usereview_scomments.- Cross-repo fork PRs require
headas"fork-owner:branch-name". A bare branch name causes Gitea to search the base repo and return 422. Thepr createdispatch assumes same-repo PRs (bare branch name). For fork-based PRs, passheadexplicitly in theowner:branchformat. draft: trueon PR create prependsWIP:to the title. There is no first-class draft field — Gitea implements draft PRs via title prefix. To un-draft, callpull_request_write method: "update"and pass the title without theWIP:prefix. This differs from GitHub's draft PR model.- HTTP 404 may mean 403. Gitea hides permission errors as not-found to avoid leaking resource existence. If a tool call returns 404 unexpectedly, check
references/token-access.mdbefore assuming the resource does not exist.
Step 1 — Resolve owner and repo
Before any tool call, extract owner and repo from the git remote:
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."
Step 2 — Dispatch
Route on the first argument:
| Invocation | Action |
|---|---|
/gitea (no args) |
Status — list open issues + open PRs |
/gitea issue |
Create issue from conversation context |
/gitea issue <N> |
Get issue details |
/gitea issue close <N> |
Close issue |
/gitea issue comment <N> |
Add comment from conversation context |
/gitea label <N> <names...> |
Apply named labels to issue/PR |
/gitea milestone |
List milestones |
/gitea milestone create <title> |
Create milestone |
/gitea pr |
Create PR from current branch → main |
/gitea pr <N> |
Get PR status and diff summary |
/gitea pr merge <N> |
Merge PR (squash, delete branch) |
/gitea branch |
List branches |
/gitea branch create <name> |
Create branch from current branch |
Step 3 — Execute
Status (default)
Call list_issues state: "open" and list_pull_requests state: "open" in parallel. list_issues does not accept a type parameter — it returns issues only. list_pull_requests returns PRs. Report as two sections.
issue (create)
Extract title and body from conversation context. Use the most recent task, bug description, grill output, or explicit statement. If no body text is available from context, fall back to empty string. Fire immediately — no confirmation step.
Label inference (do this before the create call):
- Call
label_read method: "list_repo_labels"to get all available labels with their IDs. - From conversation context, infer which labels apply:
- Issue type →
Kind/*: bug reports →Kind/Bug; new capabilities →Kind/Feature; improvements →Kind/Enhancement; docs →Kind/Documentation; security →Kind/Security - Urgency signals →
Priority/*: "blocking", "critical", "urgent" →Priority/Critical; "soon", "high priority" →Priority/High; default →Priority/Medium - Explicit blocking →
Status/Blocked
- Issue type →
- Resolve inferred label names to IDs from the label list. Labels require numeric IDs — never pass name strings to
issue_write. If no labels can be confidently inferred, omit thelabelsparameter entirely rather than guessing.
Set ref to the current branch name (git branch --show-current) if a branch is already checked out for this work.
Call issue_write method: "create" title: <extracted> body: <extracted or ""> labels: [<inferred IDs or omit>] ref: <current-branch-if-applicable>.
issue
Call issue_read method: "get" issue_number: <N>. If the response includes is_pull: true, the number refers to a PR — report it as such and offer pr <N> for a full PR summary.
issue close
Call issue_write method: "update" issue_number: <N> state: "closed". There is no method: "close" — using a non-existent method will error.
issue comment
Extract the comment body from conversation context (same sourcing as issue create). Call issue_write method: "add_comment" issue_number: <N> body: <extracted>.
label <names...>
- Call
label_read method: "list_repo_labels"— paginate until complete if > 30 labels. - Match each provided name (case-insensitive) against the label list → collect IDs.
- Call
issue_write method: "add_labels" issue_number: <N> labels: [<matched IDs>]. - Report applied labels and warn on any names that did not match, listing available labels.
Do not fail the operation because of unmatched names — apply what matches.
milestone
Call milestone_read method: "list". Report each milestone as: id, title, state (open/closed), open issue count, closed issue count.
pr (create)
git branch --show-current→ head branch.- Title: extract from conversation context; fall back to the last commit message (
git log -1 --pretty=%s). - Body: extract from conversation; fall back to empty.
- Call
pull_request_write method: "create" head: <branch> base: "main" title: <derived in step 2> body: <derived in step 3>.
Note: this dispatch assumes a same-repo PR (bare branch name for head). For cross-repo fork PRs, head must be "fork-owner:branch-name" — see Gotchas.
pr
Call pull_request_read method: "get" and pull_request_read method: "get_status" in parallel (both take pull_number: <N>). Report: title, state, draft/merged flag, head → base, labels, CI status from get_status. Note: milestone in PR responses is a bare title string, not an object — you cannot extract a milestone ID from it.
pr merge
First call pull_request_read method: "get_status" pull_number: <N>. If CI status is failing, report it and warn the user — but do not block the merge unless they say to stop.
Then call pull_request_write method: "merge" pull_number: <N> merge_style: "squash" delete_branch: true. To use a different merge style, the user must specify it explicitly.
Squashing rewrites history into one commit — whether a linked issue's closing keyword survives depends on what message that squash commit ends up with. After merging, call issue_read method: "get" on any issue referenced by the PR to check whether it auto-closed before deciding whether to close it explicitly (see the auto-close gotcha above).