Spec-only change for Codeberg #190 — no implementation, so docs: keeps the changelog clean (code ships under feat: when the tasks are applied). Capabilities: - label-crud: repo + org label CRUD tools (create/edit/delete/get, repo-prefixed names), SDK for repo + raw-HTTP DoJSON for org, shared hex-color normalisation (6-digit), PATCH edit, safe delete with a delete_mode "safe"|"force" enum + in-use guard. - mcp-resource-label: forgejo://repo/{o}/{r}/labels{?page,limit}, /label/{id}, and forgejo://org/{org}/labels{?page,limit}. - mcp-resources-core (modified): adds a Collection-resource requirement. Adversarially reviewed by a debate team; synthesis + open questions recorded in design.md. Pre-code verification gates: org get-one endpoint, 3-digit hex acceptance. Codeberg #190
5.7 KiB
ADDED Requirements
Requirement: Single label resource template
The server SHALL register a resource template with URI forgejo://repo/{owner}/{repo}/label/{id} and MIME type application/json describing a single repo label. A label URI SHALL always carry its full scope path (repo/{owner}/{repo}/... or, for org labels, org/{org}/...); a scope-less forgejo://label/{id} form is NOT valid, because repo and org label ids share an integer space and would otherwise be ambiguous.
Scenario: Template appears in templates list
- WHEN a client issues
resources/templates/list - THEN the response SHALL include a template with
uriTemplate = "forgejo://repo/{owner}/{repo}/label/{id}" - AND the template's
mimeTypeSHALL beapplication/json
Scenario: Existing label resolves
- WHEN a client reads
forgejo://repo/goern/forgejo-mcp/label/335058 - THEN the response SHALL contain one
application/jsoncontent block - AND the JSON SHALL include
id = 335058, a non-emptyname, and acolor
Scenario: Non-numeric id rejected
- WHEN a client reads
forgejo://repo/{owner}/{repo}/label/abc - THEN the server SHALL return MCP error code
-32602 - AND SHALL NOT call the upstream API
Scenario: Missing label returns -32003
- WHEN a client reads a
forgejo://repo/{owner}/{repo}/label/{id}URI for an id that does not exist - AND the upstream returns
404 - THEN the server SHALL return MCP error code
-32003
Scenario: Private repo without access returns -32002
- WHEN a client reads a label URI for a private repo
- AND the authenticated token lacks read permission
- THEN the server SHALL return MCP error code
-32002
Requirement: Bounded label list resource template
The server SHALL register a resource template with URI forgejo://repo/{owner}/{repo}/labels{?page,limit} and MIME type application/json returning a bounded list of repo labels. The list SHALL accept optional page and limit query parameters as the client-controlled bound (mirroring fetchOrgLabels), fetch that page, and apply operation/resource.Bounded with EmbeddedListCap only as a hard safety ceiling. When the result is truncated — by limit, by the ceiling, or because more pages exist — the response SHALL append the shared truncation sentinel naming list_repo_labels and the next page. This satisfies docs/design/output-bounding.md (client-controlled bound via page/limit + resumability via the next-page sentinel + documented parameters).
Scenario: Template appears in templates list
- WHEN a client issues
resources/templates/list - THEN the response SHALL include a template with
uriTemplate = "forgejo://repo/{owner}/{repo}/labels{?page,limit}" - AND the template's
mimeTypeSHALL beapplication/json
Scenario: Client-controlled limit bounds the page
- WHEN a client reads
forgejo://repo/{owner}/{repo}/labels?limit=Nfor a repo with more thanNlabels - THEN the response SHALL contain at most
Nlabels - AND SHALL append a sentinel referencing the next
page
Scenario: Under-cap list returns all labels with no sentinel
- WHEN a client reads
forgejo://repo/{owner}/{repo}/labelsfor a repo with fewer thanEmbeddedListCaplabels - THEN the response SHALL contain every label
- AND SHALL NOT contain a truncation sentinel
Scenario: Over-cap list is truncated with a sentinel naming the list tool
- WHEN a client reads the labels resource for a repo with more than
EmbeddedListCaplabels - THEN the response SHALL contain at most
EmbeddedListCaplabels - AND SHALL contain a truncation sentinel naming
list_repo_labelsas the enumeration fallback
Scenario: Missing repo returns -32003
- WHEN a client reads the labels resource for a repo that does not exist
- AND the upstream returns
404 - THEN the server SHALL return MCP error code
-32003
Requirement: Bounded org-label list resource template
The server SHALL register a resource template with URI forgejo://org/{org}/labels{?page,limit} and MIME type application/json returning a bounded list of an organization's labels. As with the repo list, it SHALL accept optional page/limit as the client-controlled bound, apply operation/resource.Bounded with EmbeddedListCap as the ceiling, and append the shared truncation sentinel naming list_org_labels and the next page when truncated. This satisfies the mcp-resources-core Collection resource requirement and docs/design/output-bounding.md.
Scenario: Template appears in templates list
- WHEN a client issues
resources/templates/list - THEN the response SHALL include a template with
uriTemplate = "forgejo://org/{org}/labels{?page,limit}" - AND the template's
mimeTypeSHALL beapplication/json
Scenario: Over-cap org-label list is truncated with a sentinel naming the list tool
- WHEN a client reads
forgejo://org/{org}/labelsfor an org with more thanEmbeddedListCaplabels - THEN the response SHALL contain at most
EmbeddedListCaplabels - AND SHALL contain a truncation sentinel naming
list_org_labelsas the enumeration fallback
Scenario: Missing org returns -32003
- WHEN a client reads the org-label list for an org that does not exist
- AND the upstream returns
404 - THEN the server SHALL return MCP error code
-32003
Requirement: Label resources documented
The README "Resources" section and the AGENTS.md resource table SHALL list all three label resource-templates.
Scenario: Docs list all templates
- WHEN the README Resources section is rendered
- THEN it SHALL include rows for
forgejo://repo/{owner}/{repo}/labels,forgejo://repo/{owner}/{repo}/label/{id}, andforgejo://org/{org}/labels