The retrofit left only a descriptive sentence on the loaded path — "Gitea never infers a prerelease from a -beta/-rc tag name" — and moved the imperative into references/conventions.md behind a trigger listing semver naming, release-notes sourcing and release-to-tag relationships. Draft and prerelease are not in that list, and "cut a v2.0.0-beta.1" is exactly the request where the caller does not raise the topic, so the rule was unreachable from the flow that needs it. Severity comes from the repair path: the MCP surface has create, get, get_latest, list and delete only — there is no update or edit tool. A release published without is_pre_release can only be corrected by delete_release plus a fresh create, and get_latest_release points consumers at the beta meanwhile. Neither SKILL.md nor call-signatures.md said so anywhere. The flags are now set explicitly on every create, the missing update tool and its delete-and-recreate consequence are stated in the body, and the semver pass-through rule stranded behind the same trigger is promoted alongside it. call-signatures.md now cites the deployed tool description as direct evidence that get_latest_release excludes drafts, while keeping the prerelease half hedged — that remains unconfirmed. Verified live against gitea-mcp v1.7.0, read-only calls. Refs #99
4.1 KiB
4.1 KiB
name, description, metadata
| name | description | metadata | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| gitea-releases | Use when managing Gitea releases or the git tags underneath them — list, get, create, or delete either — even when the user does not say "release" or "Gitea". Not branches or commit history -> `gitea-branches`. |
|
Gotchas
- Deleting a release never deletes its tag. A release is a metadata wrapper around a tag, so removing both takes two independent destructive calls. The reverse — whether deleting a tag deletes its release — is unconfirmed; verify with
list_releases/get_releaseafterdelete_tagrather than assume it survives. - Set
is_draft/is_pre_releaseexplicitly on everycreate_release— Gitea never infers a prerelease from a-beta/-rctag name. A tag namedv2.0.0-beta.1publishes as a full release, and becomes the repo's latest, unlessis_pre_release: trueis passed in the same call. The response object names themdraft/prerelease; passingdraftas an input key is silently ignored, not rejected. list_releases/list_tagsdefaultper_pageto 20, where most other gitea-mcp list tools default to 30 — a caller assuming 30 under-counts the pages a full sweep needs.
Dispatch table
| Action | Tool | Required params | Optional params |
|---|---|---|---|
| List releases | list_releases |
owner, repo |
is_draft, is_pre_release, page (default 1), per_page (default 20) |
| Get one release | get_release |
owner, repo, id (number) |
— |
| Get latest release | get_latest_release |
owner, repo |
— |
| Create release | create_release |
owner, repo, tag_name, target, title |
body, is_draft, is_pre_release |
| Delete release | delete_release |
owner, repo, id (number) |
— |
| List tags | list_tags |
owner, repo |
page (default 1), per_page (default 20) |
| Get one tag | get_tag |
owner, repo, tag_name |
— |
| Create tag | create_tag |
owner, repo, tag_name |
target, message |
| Delete tag | delete_tag |
owner, repo, tag_name |
— |
target (on create_release/create_tag) is a commitish — a branch name, existing tag, or commit SHA — the point the new tag is cut from.
Pass a caller-supplied tag_name through verbatim. Semver with a v prefix is a tooling convention, not a Gitea constraint — the API accepts any string — so never validate or rewrite it.
Workflow
- Creating a release: Call
create_releasewithtag_name,target,title, andis_draft/is_pre_releaseset explicitly — never left to default. There is no update or edit tool on this surface:create_release,get_release,get_latest_release,list_releasesanddelete_releaseare the whole set. A release published with the wrong flag therefore has no non-destructive repair — the only fix isdelete_releaseplus a freshcreate_release. Gitea is assumed to create the tag fromtargetwhentag_namedoes not yet exist — plausible from the API shape, not confirmed in the research docs — so a separatecreate_tagis only needed to tag a commit without wrapping it in a release. Verify withget_tagafterward if the caller depends on it. - Deleting a release:
delete_releasetakes the numericidand never atag_name;delete_tagis the mirror opposite and never takes an id. With only a tag name in hand, resolve the id throughlist_releases(paginating if needed) orget_releasefirst. - Deleting a tag along with its release: Delete the release first, then call
delete_tag— confirm both are intended before proceeding, since each is irreversible on its own. - Listing every page: Loop
page: 1, 2, 3...until a response returns fewer thanper_pageentries. Nothing here auto-paginates.
If exact input params or response field shapes are needed, read references/call-signatures.md. If the caller raises semver tag naming, draft/prerelease semantics, release-notes sourcing, or how a release relates to its tag, read references/conventions.md.