Adds the *_list partners that the existing *_get tools have been
missing. Same pattern as repo_list — owner allowlisted, capLimit
helper for pagination, next_page surfaced when the page is full.
internal/gitea/issues.go:
- ListIssues(owner, repo, args) hitting
GET /api/v1/repos/{owner}/{repo}/issues with type=issues server-side
so PRs don't leak in (gitea conflates them on this endpoint).
- ListIssuesArgs struct: State, Labels, Since (ISO 8601), Page, Limit.
internal/gitea/workflows.go:
- ListWorkflowRuns(owner, repo, args) hitting
GET /api/v1/repos/{owner}/{repo}/actions/runs.
- Expanded WorkflowRun struct with DisplayTitle, Event, HeadSHA,
HeadBranch, WorkflowID, RunNumber, UpdatedAt, Actor so callers
can pin runs to a commit / branch without a second lookup.
- ListWorkflowRunsArgs: Branch, HeadSHA, Status, Event, Workflow,
Page, Limit. Status/Event 'all' treated as no-filter.
internal/tools/issue_list.go:
- Default state=open, default limit=30 (matches repo_list).
- next_page returned only when len(issues) == limit.
internal/tools/workflow_run_list.go:
- Default limit=10 (most common use is 'what just happened',
not paging).
- Returns runs + total + optional next_page.
Tests: table-driven for both — happy path, empty result, filter
combinations, allowlist rejection. workflow_run_list also asserts
the 'status=all is no-op' behavior (no query param emitted).
Closes#28Closes#29
Adds two MCP tools that PATCH /api/v1/repos/{owner}/{name}/issues/{number}
with {"state":"closed"} or {"state":"open"}. Both use a shared
SetIssueState helper on the gitea client.
- internal/gitea/issues.go: SetIssueState method using the existing
PatchJSON + MapStatus + json.Unmarshal pattern from GetIssue.
- internal/tools/issue_close.go: IssueClose tool. owner+name+number
args. Owner allowlist enforced. Returns the updated issue. Reversible
via issue_reopen, classified LOW risk.
- internal/tools/issue_reopen.go: mirror of IssueClose with
state="open". Same risk profile.
- Registered both tools in cmd/gitea-mcp/main.go.
- Tests for both: success (asserts PATCH method, path, body), 404,
and allowlist rejection — same shape as issue_get_test.go.
Closes#30
issue_get: GET /repos/{owner}/{repo}/issues/{number} — full issue with labels, assignees, comment count
release_create: POST /repos/{owner}/{repo}/releases — create release and tag in one call
repo_delete: DELETE /repos/{owner}/{repo} — confirm=<repo name> required, blocks accidents