6 Commits

Author SHA1 Message Date
18ec0ab0ff fix(gitea): correct token-scope claim in gitea-branches docs
SKILL.md, README.md, and references/{branches,commits}.md claimed
list_branches, list_commits, and get_commit "work with write:issue
alone." This contradicted docs/research/docs/gitea/overview.md, which
documents write:repository as gating both reads and writes for
repo-scoped tool families (Gitea hides these reads behind write
scope). The prior empirical justification was invalid: it tested under
a token holding both write:issue and write:repository simultaneously,
which doesn't isolate which scope actually enabled the reads.

Corrected all four files to state that list_branches, create_branch,
and delete_branch require write:repository, confirmed directly by
overview.md's scope enumeration. list_commits/get_commit are flagged
as inferred to need the same scope by analogy rather than an
overview.md-confirmed fact, since overview.md's write:repository
enumeration names PR/branch/file/release/tag but not commits — this
distinction surfaced during an independent audit pass and is now
called out explicitly so the claim isn't overstated.

Bumped SKILL.md metadata.version 0.1.0 -> 0.1.1 (patch: doc
correction, no behavior change).
2026-07-05 19:14:57 +00:00
3a4ae44500 fix(gitea): correct create-vs-update param scoping in gitea-prs docs
references/pull-requests.md wrongly scoped pull_request_write's
milestone param to "update" only, and reviewers/team_reviewers to
add_reviewers/remove_reviewers only. The canonical create example in
docs/research/docs/gitea/examples.md sets milestone and reviewers
directly on "create", and api-reference.md lists these params
generically without method scoping. Corrects both to reflect that
they're settable on create, with add_reviewers/remove_reviewers
reserved for adjusting an already-open PR.

Bumps gitea-prs skill version 0.1.0 -> 0.1.1 for the docs fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwtxcDXuLZxYzWnT2FaoZU
2026-07-05 19:14:57 +00:00
7b85e33d9c fix(gitea): register gitea-orchestrate agent in plugin manifest
plugins/gitea/agents/gitea-orchestrate.md and .agent.md were fully
written but the plugin manifest never declared an "agents" key, so
the plugin loader had no path to discover/register the agent (unlike
plugins/git and plugins/kyberforge, which both declare "agents":
"agents/"). Bump the patch version in both manifests per plugin-author's
UPDATE flow convention, since consumers cache plugin metadata by version.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwtxcDXuLZxYzWnT2FaoZU
2026-07-05 19:14:57 +00:00
d09375556a fix(gitea): add missing gotchas to gitea-files docs
A documentation-accuracy audit against research docs found three gotchas
in troubleshooting.md that were dropped from gitea-files/SKILL.md during
original authoring: signed-commit branch protection silently blocking
file writes (a distinct failure mode from stale-SHA that an agent could
otherwise misdiagnose and retry indefinitely), reverse-proxy 413s on
large base64-encoded write payloads, and 404-vs-403 scope masking on the
read tools. Also adds the context7-gitea-tea-cli provenance entry to
references/sources.md (Contributing files: none) to resolve a
pre-existing skill-audit provenance FAIL surfaced while validating this
change, matching the pattern already used by sibling skills.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwtxcDXuLZxYzWnT2FaoZU
2026-07-05 19:14:57 +00:00
1cd496e208 fix(gitea): correct label-scope and closing-keyword claims in issues/labels skills
A documentation-accuracy audit against plugins/gitea/docs/research/docs/gitea/*.md
found three overclaims/unsupported claims in skill content:

- gitea-labels-milestones: reworded the exclusive-flag gotcha and
  label-inference.md's "scoped labels" section — exclusive is documented as
  org-labels-only (api-reference.md, data-model.md) and unsupported by the
  live create_repo_label/edit_repo_label schema, so repo-level exclusivity
  for Kind/*/Priority/*/Status/* is a client-side convention this skill
  enforces via replace_labels, not a server guarantee.
- gitea-labels-milestones: added a "Step 1 — Resolve owner and repo" section
  (git remote get-url origin) and Bash to allowed-tools, since
  milestone_read/milestone_write and repo-scoped label_read/label_write
  hard-require owner+repo and the skill is documented as directly invokable,
  matching the pattern already in gitea-issues/SKILL.md.
- gitea-issues: softened the claim that Gitea parses Fixes #N/Closes #N in
  commit messages to auto-close issues — no research doc supports this, and
  examples.md states issues are not auto-closed on PR merge. Now notes the
  behavior is plausible but unconfirmed, keeping the issue_read re-check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwtxcDXuLZxYzWnT2FaoZU
2026-07-05 19:14:57 +00:00
940e414980 fix(gitea): correct is_draft param and soften unverified claims in gitea-releases docs
An audit against plugins/gitea/docs/research/docs/gitea/*.md found the
gitea-releases skill told callers to set create_release's draft flag
as `draft` instead of `is_draft` (the actual input param; `draft` is
only the response field name) - a call following that gotcha would
have the flag silently ignored, publishing a non-draft release.

Also corrected an overclaimed "verified against live MCP schema"
provenance note in call-signatures.md/README.md (its sources are
gitea-mcp source-code extraction, not a live tool call - now noted
alongside a narrow live ToolSearch cross-check performed this session
for 3 of the 9 tools' input params), and softened three behavioral
claims (create_release auto-creating tags, get_latest_release
excluding drafts/prereleases, delete_tag preserving a wrapping
release) that don't trace to any research doc, with a recommendation
to verify release/tag state after delete operations rather than
assume it.
2026-07-05 19:12:10 +00:00
17 changed files with 90 additions and 38 deletions

View File

@@ -15,5 +15,5 @@
], ],
"license": "MIT", "license": "MIT",
"name": "gitea", "name": "gitea",
"version": "1.3.0" "version": "1.3.1"
} }

View File

@@ -1,4 +1,5 @@
{ {
"agents": "agents/",
"author": { "author": {
"email": "defame1297@rkdr.net", "email": "defame1297@rkdr.net",
"name": "Defame1297" "name": "Defame1297"
@@ -19,5 +20,5 @@
"skills": [ "skills": [
"skills/" "skills/"
], ],
"version": "1.3.0" "version": "1.3.1"
} }

View File

@@ -12,9 +12,11 @@ explicit confirmation, and treating unexpected 404s as possible masked 403s).
## Before you start ## Before you start
Requires a Gitea MCP server configured with a token. `list_branches`, `list_commits`, and Requires a Gitea MCP server configured with a token that has `write:repository` scope. This is
`get_commit` work with `write:issue` alone; `create_branch` and `delete_branch` need confirmed for `list_branches`, `create_branch`, and `delete_branch` (Gitea gates reads behind write
`write:repository`. Requires a git remote named `origin` pointing at the Gitea instance. scope for repo-scoped operations); `list_commits` and `get_commit` are inferred to need the same
scope by analogy, not explicitly confirmed — see `references/commits.md`. Requires a git remote
named `origin` pointing at the Gitea instance.
## Usage ## Usage

View File

@@ -13,11 +13,11 @@ description: >
git-history) or for PR-side branch references like cross-repo fork PR heads git-history) or for PR-side branch references like cross-repo fork PR heads
(use gitea-prs). (use gitea-prs).
compatibility: Requires Gitea MCP server configured with a token; list_branches, list_commits, and get_commit work with write:issue alone, create_branch and delete_branch require write:repository. Requires git remote "origin" pointing to the Gitea instance. compatibility: Requires Gitea MCP server configured with a token with write:repository scope; this is confirmed to gate list_branches, create_branch, and delete_branch (Gitea gates reads behind write scope for repo-scoped operations), and is inferred by analogy (not explicitly confirmed by source docs) to also gate list_commits and get_commit. Requires git remote "origin" pointing to the Gitea instance.
metadata: metadata:
category: integration category: integration
version: "0.1.0" version: "0.1.1"
source_keys: source_keys:
- gitea-mcp-repo - gitea-mcp-repo
- gitea-mcp-slim-go - gitea-mcp-slim-go

View File

@@ -73,6 +73,9 @@ protected, every time, regardless of how the request is phrased.
## Token scope ## Token scope
`list_branches` works with `write:issue` alone. `create_branch` and `delete_branch` need All three — `list_branches`, `create_branch`, `delete_branch` — require `write:repository`. Gitea
`write:repository`. All three are verified working empirically under a token with both scopes gates reads behind write scope for repo-scoped operations, so `list_branches` needs the same scope
(`write:issue` + `write:repository`). as the write operations, not `write:issue` alone. An earlier version of this doc claimed
`write:issue` alone was sufficient for `list_branches`, based on empirical testing under a token
that held both `write:issue` and `write:repository` simultaneously — that test didn't isolate the
variable, so it couldn't actually establish `write:issue` alone as sufficient.

View File

@@ -63,5 +63,11 @@ edge cases, `get_commit` will not.
## Token scope ## Token scope
Both tools are read-only and work with `write:issue` alone (no `write:repository` needed), verified Both tools are believed to require `write:repository`, even though they're read-only — inferred by
empirically against the deployed server. analogy with the scope-gating principle in `overview.md` (Gitea gates reads behind write scope for
repo-scoped operations), not a claim `overview.md` makes for commits by name: its explicit
`write:repository` enumeration lists PR, branch, file, release, and tag operations, but doesn't
mention commits. An earlier version of this doc claimed `write:issue` alone worked, based on
empirical testing under a token that held both `write:issue` and `write:repository`
simultaneously — that test didn't isolate the variable either. Treat this as unverified until
tested under a token scoped to `write:issue` only (no `write:repository`).

View File

@@ -28,7 +28,10 @@ allowed-tools: mcp__gitea__get_file_contents mcp__gitea__get_dir_contents mcp__g
## Gotchas ## Gotchas
- **A 404 from any read call may actually be a 403 in disguise.** `get_file_contents`, `get_dir_contents`, and `get_repository_tree` all gate on `write:repository` scope, not just read access — some Gitea endpoints return 404 instead of 403 when the token's scope is insufficient, to avoid leaking whether the resource exists. If a read fails with 404 on a path you're confident is correct, check the token's configured scopes before concluding the file or directory doesn't exist.
- **SHA is the concurrency token for every write — and it lives at the top level of `get_file_contents`'s response, not nested under `content`.** `create_or_update_file` without `sha` is always treated as a *create*: if the path already exists, Gitea returns HTTP 409. `delete_file` has no optional path at all — omitting `sha` returns HTTP 422. The safe sequence for any update or delete is always: call `get_file_contents` first, read the top-level `sha` field, then pass that exact value to the write call. Never guess or reuse a stale SHA — a mismatched SHA is rejected the same as a missing one. - **SHA is the concurrency token for every write — and it lives at the top level of `get_file_contents`'s response, not nested under `content`.** `create_or_update_file` without `sha` is always treated as a *create*: if the path already exists, Gitea returns HTTP 409. `delete_file` has no optional path at all — omitting `sha` returns HTTP 422. The safe sequence for any update or delete is always: call `get_file_contents` first, read the top-level `sha` field, then pass that exact value to the write call. Never guess or reuse a stale SHA — a mismatched SHA is rejected the same as a missing one.
- **A write can also fail because the branch requires signed commits — a separate failure mode from a bad SHA.** `create_or_update_file` and `delete_file` create commits server-side via a bare API token call with no 2FA/PGP context. If the target branch's protection rule requires signed commits, Gitea rejects the write outright — surfaced as a generic 403 or 422, not an error naming "signed commit required," and reads against that same branch keep succeeding right up until you try to write. When a write fails without a clean 409 (missing/stale SHA) or 404 (bad path) explanation, check whether the branch's protection rule requires signed commits before assuming the SHA is wrong and retrying.
- **A large `create_or_update_file` payload can hit a reverse-proxy 413 that has nothing to do with Gitea.** `content` is base64-encoded, which inflates the payload ~33% over the raw file size; a 413 is commonly a reverse-proxy body-size limit in front of the Gitea instance, not a Gitea-side rejection. No amount of retrying, or changing the SHA, path, or branch, will fix it — it needs the proxy's config raised, which is outside this skill's or the calling agent's control. Surface that distinction to the user instead of retrying the same call.
- **`get_dir_contents` and `get_repository_tree` are not SHA sources for a specific file's write.** `get_dir_contents` entries carry no `sha` at all. `get_repository_tree` entries do carry a `sha` (a blob/tree hash), but fetching it means an extra round trip with no content — `get_file_contents` is the canonical path since it returns the decoded content and the write-ready `sha` in one call. - **`get_dir_contents` and `get_repository_tree` are not SHA sources for a specific file's write.** `get_dir_contents` entries carry no `sha` at all. `get_repository_tree` entries do carry a `sha` (a blob/tree hash), but fetching it means an extra round trip with no content — `get_file_contents` is the canonical path since it returns the decoded content and the write-ready `sha` in one call.
- **`owner` and `repo` are always caller-supplied inputs, never resolved here.** This skill doesn't infer them from a git remote. If invoked directly by a human, ask for them if not stated. If invoked by `gitea-workflow` or an orchestrating agent, expect them to already be resolved and passed in. - **`owner` and `repo` are always caller-supplied inputs, never resolved here.** This skill doesn't infer them from a git remote. If invoked directly by a human, ask for them if not stated. If invoked by `gitea-workflow` or an orchestrating agent, expect them to already be resolved and passed in.
- **Direct commits to a branch are a first-class action, not a workaround.** Gitea's own web UI defaults to editing files directly against a branch — `create_or_update_file`/`delete_file` used that way is normal, not an API escape hatch to avoid. The SHA-currency requirement above is the actual risk to manage, not the act of committing directly. - **Direct commits to a branch are a first-class action, not a workaround.** Gitea's own web UI defaults to editing files directly against a branch — `create_or_update_file`/`delete_file` used that way is normal, not an API escape hatch to avoid. The SHA-currency requirement above is the actual risk to manage, not the act of committing directly.

View File

@@ -34,3 +34,13 @@
**Contributing files:** **Contributing files:**
- SKILL.md (Gotchas — "Direct commits to a branch are a first-class action, not a workaround") - SKILL.md (Gotchas — "Direct commits to a branch are a first-class action, not a workaround")
## context7-gitea-tea-cli
**Description:** Official `tea` CLI (reference Gitea client) docs on Context7 — practitioner command patterns for issues, PRs, and releases, including semver tag/release conventions, draft/prerelease flags, and release-notes-from-file conventions. Consulted alongside `context7-websites-gitea` while researching `workflow-conventions.md` (both sources contribute to that research doc, backing `gitea-workflow`); its file-command patterns did not end up informing any gitea-files content.
**Source:** context7:/git_gitea_com/gitea_tea
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
**Contributing files:** (none)

View File

@@ -35,7 +35,7 @@ allowed-tools: Bash mcp__gitea__list_issues mcp__gitea__issue_read mcp__gitea__i
- **`search_issues` does have a working `type` filter** (`"issues"` | `"pulls"`) — unlike `list_issues`. Its `labels` parameter is also shaped differently: a comma-separated string, not an array of names. - **`search_issues` does have a working `type` filter** (`"issues"` | `"pulls"`) — unlike `list_issues`. Its `labels` parameter is also shaped differently: a comma-separated string, not an array of names.
- **Labels are numeric IDs on write, name strings on read.** `issue_write`'s `labels` parameter (used by `add_labels`/`replace_labels`) takes IDs. `list_issues`/`issue_read` return names. Never resolve this yourself — compose `gitea-labels-milestones` (see `references/enrichments.md`) to get IDs. - **Labels are numeric IDs on write, name strings on read.** `issue_write`'s `labels` parameter (used by `add_labels`/`replace_labels`) takes IDs. `list_issues`/`issue_read` return names. Never resolve this yourself — compose `gitea-labels-milestones` (see `references/enrichments.md`) to get IDs.
- **Milestone on `issue_read` is `{id, title}`** — an object, not a bare string. This skill only ever needs the `id`. (The bare-title-string case only happens on the PR side, which is `gitea-prs`' problem, not this skill's.) - **Milestone on `issue_read` is `{id, title}`** — an object, not a bare string. This skill only ever needs the `id`. (The bare-title-string case only happens on the PR side, which is `gitea-prs`' problem, not this skill's.)
- **A closing keyword in a commit message can auto-close an issue without any `issue_write` call.** Gitea has no GitHub-style "merge closes issue" event, but it does parse `Fixes #N`/`Closes #N` in commit messages landing on the default branch. After a PR merges (a `gitea-prs` operation), re-check the issue's state here via `issue_read method: "get"` before deciding whether to close it manually — closing an already-closed issue is a harmless no-op, but don't assume a manual close is always needed. - **Closing-keyword auto-close behavior is plausible but unconfirmed in our research docs.** Our research docs confirm Gitea does NOT auto-close an issue on a plain PR merge (unlike GitHub) — closing keywords like `Fixes #N`/`Closes #N` in a commit message are not documented one way or the other. After a PR merges (a `gitea-prs` operation), always re-check the issue's state here via `issue_read method: "get"` before deciding whether to close it manually — closing an already-closed issue is a harmless no-op, but don't assume a manual close is always needed.
- **Pagination is manual.** `list_issues` and `search_issues` return one page at a time. Iterate `page: 1, 2, ...` until the returned count is less than `per_page`. - **Pagination is manual.** `list_issues` and `search_issues` return one page at a time. Iterate `page: 1, 2, ...` until the returned count is less than `per_page`.
- **HTTP 404 may actually mean 403.** Gitea hides permission errors as not-found. If a call 404s unexpectedly, verify the token holds `write:issue` scope (see `references/issues.md`'s Token scope note) before concluding the issue doesn't exist. - **HTTP 404 may actually mean 403.** Gitea hides permission errors as not-found. If a call 404s unexpectedly, verify the token holds `write:issue` scope (see `references/issues.md`'s Token scope note) before concluding the issue doesn't exist.

View File

@@ -21,9 +21,9 @@ metadata:
- gitea-mcp-slim-go - gitea-mcp-slim-go
- context7-websites-gitea - context7-websites-gitea
- context7-gitea-tea-cli - context7-gitea-tea-cli
version: "0.1.0" version: "0.1.1"
allowed-tools: mcp__gitea__label_read mcp__gitea__label_write mcp__gitea__milestone_read mcp__gitea__milestone_write allowed-tools: Bash mcp__gitea__label_read mcp__gitea__label_write mcp__gitea__milestone_read mcp__gitea__milestone_write
--- ---
## Gotchas ## Gotchas
@@ -33,11 +33,21 @@ allowed-tools: mcp__gitea__label_read mcp__gitea__label_write mcp__gitea__milest
- **Milestone representation differs between issues and PRs.** `issue_read` returns `milestone: {id, title}` — an object. `pull_request_read` returns `milestone: "title string"` — title only, no ID. You cannot recover a milestone ID from a PR response directly; call `milestone_read method: "list"` and match by title instead. - **Milestone representation differs between issues and PRs.** `issue_read` returns `milestone: {id, title}` — an object. `pull_request_read` returns `milestone: "title string"` — title only, no ID. You cannot recover a milestone ID from a PR response directly; call `milestone_read method: "list"` and match by title instead.
- **Repo labels and org labels are separate pools, never mixed in one call.** `label_read`/`label_write` take either `owner`+`repo` (repo-scoped methods) or `org` (org-scoped methods) — passing both or neither for a given method is a caller error, not something the schema enforces for you. Repo and org labels can both apply to the same issue, but you list/create/edit them through different method values. - **Repo labels and org labels are separate pools, never mixed in one call.** `label_read`/`label_write` take either `owner`+`repo` (repo-scoped methods) or `org` (org-scoped methods) — passing both or neither for a given method is a caller error, not something the schema enforces for you. Repo and org labels can both apply to the same issue, but you list/create/edit them through different method values.
- **`milestone_write` accepts `"update"` and `"edit"` as the same operation.** Both method values map to the identical update call. Prefer `"update"` for consistency with `issue_write`/`pull_request_write`. - **`milestone_write` accepts `"update"` and `"edit"` as the same operation.** Both method values map to the identical update call. Prefer `"update"` for consistency with `issue_write`/`pull_request_write`.
- **A `/` in a label name plus `exclusive: true` means mutual exclusivity, not just a naming convention.** This repo's `Kind/*`, `Priority/*`, `Status/*` labels follow Gitea's native scoped-label feature: applying a new label within a scope (e.g. `Priority/High`) is expected to replace any existing label in that same scope, not add alongside it. Label inference (see `references/label-inference.md`) must respect this — replace, don't stack. - **`exclusive` is documented as an org-labels-only flag — it isn't what enforces exclusivity here.** Gitea's docs scope the settable/server-enforced `exclusive` flag to org labels only, and the live `label_write` schema for `create_repo_label`/`edit_repo_label` doesn't document accepting it at all. This repo's `Kind/*`, `Priority/*`, `Status/*` groups still behave as one-label-per-scope, but that's a manually-enforced convention this skill implements client-side, not a guaranteed server behavior for repo labels: applying a new label within a scope (e.g. `Priority/High`) must replace any existing label in that same scope, not add alongside it, and nothing on the server enforces that for you. Label inference (see `references/label-inference.md`) must respect this — replace, don't stack.
- **Pagination is manual on every list call.** `label_read` and `milestone_read` both default to `per_page: 30`. Iterate `page: 1, 2, ...` until the result count is less than `per_page` — there is no cursor or auto-pagination. - **Pagination is manual on every list call.** `label_read` and `milestone_read` both default to `per_page: 30`. Iterate `page: 1, 2, ...` until the result count is less than `per_page` — there is no cursor or auto-pagination.
- **Schema requiredness differs between the two tool families.** `milestone_read`/`milestone_write` have `owner` and `repo` as hard-required parameters (the call fails validation without them). `label_read`/`label_write` only hard-require `method` — `owner`/`repo`/`org` are functionally required per method but not schema-enforced, so passing none produces a runtime error from Gitea, not a client-side validation error. - **Schema requiredness differs between the two tool families.** `milestone_read`/`milestone_write` have `owner` and `repo` as hard-required parameters (the call fails validation without them). `label_read`/`label_write` only hard-require `method` — `owner`/`repo`/`org` are functionally required per method but not schema-enforced, so passing none produces a runtime error from Gitea, not a client-side validation error.
## Dispatch ## Step 1 — Resolve owner and repo
Before any tool call, extract `owner` and `repo` from the git remote (skip this if an orchestrating caller already passed them in):
```bash
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
| Task | Tool | method | | Task | Tool | method |
|---|---|---| |---|---|---|

View File

@@ -14,9 +14,13 @@ asks to label something without naming exact labels.
## Scoped labels are mutually exclusive — replace, don't stack ## Scoped labels are mutually exclusive — replace, don't stack
Each of `Kind/*`, `Priority/*`, `Status/*` is a Gitea scoped-label group (the `/` delimiter plus Each of `Kind/*`, `Priority/*`, `Status/*` is treated as a scoped-label group by convention (the `/`
`exclusive: true` on the label). Applying a new label within a scope is expected to replace any delimiter naming pattern). Gitea's `exclusive` flag — the mechanism that would let the server itself
existing label in that same scope on the target issue/PR, not add alongside it. When inference enforce one-label-per-scope — is documented as an org-labels-only setting, and the repo-level
`label_write` methods used here don't accept it at all. So exclusivity within these scopes is a
convention this skill enforces client-side, not something the server guarantees: applying a new
label within a scope is expected to replace any existing label in that same scope on the target
issue/PR, not add alongside it. When inference
selects a `Priority/High` label and the issue already carries `Priority/Medium`, the write should selects a `Priority/High` label and the issue already carries `Priority/Medium`, the write should
result in only `Priority/High` remaining — use `replace_labels` scoped to that group's labels, or at result in only `Priority/High` remaining — use `replace_labels` scoped to that group's labels, or at
minimum remove the superseded label before adding the new one. Never leave two labels from the same minimum remove the superseded label before adding the new one. Never leave two labels from the same

View File

@@ -20,7 +20,7 @@ metadata:
- gitea-mcp-slim-go - gitea-mcp-slim-go
- context7-websites-gitea - context7-websites-gitea
- context7-gitea-tea-cli - context7-gitea-tea-cli
version: "0.1.0" version: "0.1.1"
allowed-tools: mcp__gitea__list_pull_requests mcp__gitea__pull_request_read mcp__gitea__pull_request_write mcp__gitea__pull_request_review_write allowed-tools: mcp__gitea__list_pull_requests mcp__gitea__pull_request_read mcp__gitea__pull_request_write mcp__gitea__pull_request_review_write
--- ---

View File

@@ -56,14 +56,14 @@ List responses trim PRs down to summary fields — `head`/`base` are bare ref st
- `base` (string, required for `"create"`) — target branch - `base` (string, required for `"create"`) — target branch
- `assignee` (string, optional) — single login - `assignee` (string, optional) — single login
- `assignees` (array of strings, optional) — login names - `assignees` (array of strings, optional) — login names
- `milestone` (number, optional, for `"update"`) — milestone ID, never a title - `milestone` (number, optional) — milestone ID, never a title; settable on both `"create"` and `"update"`
- `state` (string, optional, for `"update"`) — `"open"` | `"closed"` (no `"all"` — unlike issue state filters) - `state` (string, optional, for `"update"`) — `"open"` | `"closed"` (no `"all"` — unlike issue state filters)
- `allow_maintainer_edit` (boolean, optional, for `"update"`) - `allow_maintainer_edit` (boolean, optional, for `"update"`)
- `labels` (array of numbers, optional) — label IDs, never names — resolve via `gitea-labels-milestones` first - `labels` (array of numbers, optional) — label IDs, never names — resolve via `gitea-labels-milestones` first
- `deadline` (string, optional) — ISO 8601 - `deadline` (string, optional) — ISO 8601
- `remove_deadline` (boolean, optional) - `remove_deadline` (boolean, optional)
- `reviewers` (array of strings, optional, for `"add_reviewers"`/`"remove_reviewers"`) — login names - `reviewers` (array of strings, optional) — login names; settable directly on `"create"`, or use `"add_reviewers"`/`"remove_reviewers"` to adjust reviewers on an already-open PR
- `team_reviewers` (array of strings, optional, for `"add_reviewers"`/`"remove_reviewers"`) - `team_reviewers` (array of strings, optional) — same as `reviewers`: settable on `"create"`, or via `"add_reviewers"`/`"remove_reviewers"` post-creation
- `draft` (boolean, optional, for `"create"`) — prepends `"WIP:"` to the title (see Gotcha) - `draft` (boolean, optional, for `"create"`) — prepends `"WIP:"` to the title (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`. 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`.

View File

@@ -19,6 +19,6 @@ Describe your release/tag task: list releases, get the latest release, create a
| File | Purpose | | File | Purpose |
|------|---------| |------|---------|
| `SKILL.md` | Skill instructions for agents | | `SKILL.md` | Skill instructions for agents |
| `references/call-signatures.md` | Verified tool parameters and response shapes for all 9 release/tag tools | | `references/call-signatures.md` | Tool parameters and response shapes derived from gitea-mcp source (see `references/sources.md`); input params for 3 of the 9 tools additionally live-cross-checked |
| `references/conventions.md` | Semver/draft/prerelease practitioner conventions and pagination behavior | | `references/conventions.md` | Semver/draft/prerelease practitioner conventions and pagination behavior |
| `references/sources.md` | Research sources backing the call signatures and conventions | | `references/sources.md` | Research sources backing the call signatures and conventions |

View File

@@ -23,7 +23,7 @@ metadata:
- **`delete_release` takes a numeric `id`, never a tag name.** `delete_tag` is the mirror opposite — it takes the `tag_name` string, never a numeric id. These two tools are asymmetric on purpose; passing a tag name to `delete_release` or a numeric id to `delete_tag` fails. Always resolve the numeric release id via `list_releases` or `get_release` first if you only have a tag name in hand. - **`delete_release` takes a numeric `id`, never a tag name.** `delete_tag` is the mirror opposite — it takes the `tag_name` string, never a numeric id. These two tools are asymmetric on purpose; passing a tag name to `delete_release` or a numeric id to `delete_tag` fails. Always resolve the numeric release id via `list_releases` or `get_release` first if you only have a tag name in hand.
- **Deleting a release does not delete its tag.** They are separate destructive operations against separate resources — a release is a wrapper (title, notes, draft/prerelease flags, assets) around a tag, not the tag itself. If the intent is to remove both, call `delete_release` and `delete_tag` separately. - **Deleting a release does not delete its tag.** They are separate destructive operations against separate resources — a release is a wrapper (title, notes, draft/prerelease flags, assets) around a tag, not the tag itself. If the intent is to remove both, call `delete_release` and `delete_tag` separately.
- **`list_releases`/`list_tags` default to `per_page: 20`**, unlike most other gitea-mcp tools which default to 30. There is no auto-pagination in the MCP layer — to get a complete result set, loop `page` upward until a page returns fewer than `per_page` results. - **`list_releases`/`list_tags` default to `per_page: 20`**, unlike most other gitea-mcp tools which default to 30. There is no auto-pagination in the MCP layer — to get a complete result set, loop `page` upward until a page returns fewer than `per_page` results.
- **`draft`/`is_pre_release` are explicit booleans the caller sets on `create_release` — never inferred from `tag_name`.** Practitioner convention (per the `tea` CLI) uses `-beta`/`-rc` suffixes for prereleases (e.g. `v2.0.0-beta.1`), but Gitea does not enforce or infer this from the tag string. If the user names a tag that looks like a prerelease, set `is_pre_release: true` explicitly rather than assuming the flag is redundant with the name. - **`is_draft`/`is_pre_release` are explicit booleans the caller sets on `create_release` — never inferred from `tag_name`.** Note the input param is `is_draft`, which maps to the `draft` field on the *response* object (see Dispatch table below and `references/call-signatures.md`) — `draft` is never a valid input key. Practitioner convention (per the `tea` CLI) uses `-beta`/`-rc` suffixes for prereleases (e.g. `v2.0.0-beta.1`), but Gitea does not enforce or infer this from the tag string. If the user names a tag that looks like a prerelease, set `is_pre_release: true` explicitly rather than assuming the flag is redundant with the name.
- **Tag names are conventionally semver, `v`-prefixed** (`v1.2.0`, `v2.0.0-beta.1`), but this is a practitioner convention, not a Gitea constraint — don't reject or rewrite a caller-supplied tag name that doesn't follow it. - **Tag names are conventionally semver, `v`-prefixed** (`v1.2.0`, `v2.0.0-beta.1`), but this is a practitioner convention, not a Gitea constraint — don't reject or rewrite a caller-supplied tag name that doesn't follow it.
## Dispatch table ## Dispatch table
@@ -44,7 +44,7 @@ metadata:
## Workflow ## Workflow
- [ ] **Creating a release:** Call `create_release` directly with `tag_name` + `target` + `title` — it creates the underlying tag automatically if `tag_name` doesn't already exist, so a separate `create_tag` call is only needed when you want to tag a commit without wrapping it in a release yet. Set `is_pre_release`/`is_draft` explicitly per the Gotchas above; don't leave them to default inference. - [ ] **Creating a release:** Call `create_release` directly with `tag_name` + `target` + `title` — Gitea is assumed to create the underlying tag automatically if `tag_name` doesn't already exist (this is plausible behavior inferred from the API shape, not directly confirmed in the research docs), so a separate `create_tag` call is only needed when you want to tag a commit without wrapping it in a release yet. Verify the tag exists afterward if this matters to the caller. Set `is_pre_release`/`is_draft` explicitly per the Gotchas above; don't leave them to default inference.
- [ ] **Deleting a release safely:** Resolve the numeric id first — call `list_releases` (paginate if needed, see Gotchas) or `get_release` if the id is already known, find the entry matching the target `tag_name`, then call `delete_release` with that `id`. Never pass `tag_name` to `delete_release`. - [ ] **Deleting a release safely:** Resolve the numeric id first — call `list_releases` (paginate if needed, see Gotchas) or `get_release` if the id is already known, find the entry matching the target `tag_name`, then call `delete_release` with that `id`. Never pass `tag_name` to `delete_release`.
- [ ] **Deleting a tag along with its release:** Delete the release first (frees the id lookup), then call `delete_tag` with the `tag_name` separately — confirm both are intended before proceeding, since each is an independent irreversible operation. - [ ] **Deleting a tag along with its release:** Delete the release first (frees the id lookup), then call `delete_tag` with the `tag_name` separately — confirm both are intended before proceeding, since each is an independent irreversible operation.
- [ ] **Listing completely:** If the caller needs all releases or tags (not just the first page), loop `page: 1, 2, 3...` until a response has fewer than `per_page` entries. - [ ] **Listing completely:** If the caller needs all releases or tags (not just the first page), loop `page: 1, 2, 3...` until a response has fewer than `per_page` entries.

View File

@@ -7,9 +7,18 @@ source_keys:
# Release and tag call signatures # Release and tag call signatures
Verified against the live MCP tool schemas at authoring time (not copied from upstream API docs, Signatures and response shapes are derived from gitea-mcp source (`operation/*.go` and `slim.go`,
which can drift from the deployed gitea-mcp version). `owner` and `repo` are required strings on see `references/sources.md`) rather than copied from upstream API docs, which can drift from the
every tool below and are omitted from the per-tool lists for brevity. deployed gitea-mcp version — but this is a source-code extraction, not a live MCP tool call.
Input parameter schemas for 3 of the 9 tools here — `create_release`, `delete_tag`, and
`get_latest_release` — were additionally cross-checked live via `ToolSearch` against the deployed
`mcp__gitea__*` tools in session 2026-07-05, and confirmed to match exactly (required/optional
params and names). That check covered only input params for those 3 tools, not response shapes,
and not the other 6 tools — treat the rest of this document as source-derived, not live-verified.
`owner` and `repo` are required strings on every tool below and are omitted from the per-tool lists
for brevity.
## Releases ## Releases
@@ -23,12 +32,12 @@ every tool below and are omitted from the per-tool lists for brevity.
**`get_latest_release`** **`get_latest_release`**
- No parameters beyond `owner`/`repo`. - No parameters beyond `owner`/`repo`.
- Returns a single release object for the most recently published (non-draft, non-prerelease by Gitea's own "latest" definition) release. - Returns a single release object for the most recently published release. It is assumed (by analogy with typical "latest release" semantics) that this excludes drafts and prereleases, but that exclusion is not directly confirmed by any of the research docs — verify with `list_releases` if the caller depends on this.
**`create_release`** **`create_release`**
- Required: `tag_name` (string), `target` (string — branch, tag, or commit SHA to cut the tag from), `title` (string) - Required: `tag_name` (string), `target` (string — branch, tag, or commit SHA to cut the tag from), `title` (string)
- Optional: `body` (string — release notes), `is_draft` (boolean), `is_pre_release` (boolean) - Optional: `body` (string — release notes), `is_draft` (boolean), `is_pre_release` (boolean)
- If `tag_name` doesn't already exist as a tag, Gitea creates it against `target` as part of this call. - Assumed (not confirmed by the research docs) that if `tag_name` doesn't already exist as a tag, Gitea creates it against `target` as part of this call. Verify with `get_tag`/`list_tags` afterward if the caller needs certainty.
**`delete_release`** **`delete_release`**
- Required: `id` (number) — same numeric id as `get_release`. Does not accept `tag_name`. - Required: `id` (number) — same numeric id as `get_release`. Does not accept `tag_name`.
@@ -56,7 +65,7 @@ id, tag_name, target, title, body, draft, prerelease, html_url, author, created_
**`delete_tag`** **`delete_tag`**
- Required: `tag_name` (string). Does not accept a numeric id. - Required: `tag_name` (string). Does not accept a numeric id.
- Does not delete any release wrapping the tag. - Assumed by symmetry with `delete_release` (documented above as not deleting the underlying tag) to also not delete any release wrapping the tag — but this reverse direction is not independently confirmed by the research docs, and is the more dangerous direction to get wrong: an agent might skip an explicit `delete_release` call assuming the release survives. Verify with `list_releases`/`get_release` after calling `delete_tag` rather than assume.
## Pagination ## Pagination

View File

@@ -27,11 +27,15 @@ caller-supplied tag name against semver; just pass it through.
## Draft and prerelease are explicit flags ## Draft and prerelease are explicit flags
`draft` and `is_pre_release`/`prerelease` are booleans the caller sets directly on `create_release` `is_draft` and `is_pre_release` are booleans the caller sets directly on `create_release` — Gitea
— Gitea does not infer either from the tag name, even though the `-beta`/`-rc` suffix convention does not infer either from the tag name, even though the `-beta`/`-rc` suffix convention above is
above is commonly used to signal a prerelease to humans. When a user asks to "cut a beta" or commonly used to signal a prerelease to humans. When a user asks to "cut a beta" or "publish a
"publish a release candidate," set `is_pre_release: true` explicitly in the same call rather than release candidate," set `is_pre_release: true` explicitly in the same call rather than relying on
relying on the tag string to carry that meaning. the tag string to carry that meaning.
Note the input/output naming mismatch: the input param is `is_draft`, but the release object
returned by the API uses `draft` (and `prerelease`) as the field names. `draft` is never a valid
input key — passing `draft: true` to `create_release` is silently ignored rather than erroring.
## Release notes sourcing ## Release notes sourcing