workflow_run_status exists but requires an explicit run_id. There is no way to list recent workflow runs via the MCP — to even get an ID, the caller has to either remember it or fall back to the gitea REST API with a token scoped for read:repository.
Concrete blocker hit 2026-05-17 watching the CD for commit 11f86f5 (issue #27 rollout): the connector could confirm "run #338 = success" only by guessing the ID (prior run was #336, mental arithmetic for +2 commits). On a busy day with parallel CI for branch + tag + commit fan-out, that arithmetic stops working.
Same shape as #28 (issue_list) — every *_get(id) tool wants a *_list() partner.
head_sha — commit SHA, full or short (the killer-feature param for the use case above)
workflow — workflow file name (e.g. cd.yml)
page / limit — pagination (cap at 50, same as repo_list)
Tool spec
tool: workflow_run_list
params:
owner: string (required, allowlisted)
name: string (required)
branch: string? (default: none — all branches)
head_sha: string? (filter to runs for a specific commit; short SHA accepted)
status: "queued" | "in_progress" | "completed" | "all" (default: all)
event: "push" | "pull_request" | "schedule" | "workflow_dispatch" | "all" (default: all)
workflow: string? (workflow file name, e.g. cd.yml)
page: integer? (default 1)
limit: integer? (default 10, max 50)
returns:
runs: [
{ id, display_title, status, conclusion, event, head_sha,
head_branch, workflow_id, run_number, started_at, updated_at,
html_url, actor }
]
total: integer (from X-Total-Count header if present)
Defaults tuned for the most common "what just happened" query: limit=10, all events, all statuses, no branch filter. Most callers will pass head_sha to pin to one commit.
Acceptance criteria
workflow_run_list registered in cmd/gitea-mcp/main.go
Allowlist check, same as the rest of the family
head_sha filter accepts both short (7-char) and full SHAs — short is the natural form callers already have from git log
Pagination respects capLimit helper
Table-driven test in internal/tools/workflow_run_list_test.go: happy path, empty result, allowlist rejection, status filter, head_sha filter (short + full), branch filter
Gitea client method ListWorkflowRuns(ctx, owner, name, args) in internal/gitea/workflows.go
task check green
Out of scope
Streaming run logs — separate workflow_run_logs tool
Per-job breakdown — separate workflow_run_jobs tool
Cancelling a run — separate workflow_run_cancel tool
Cross-repo aggregation
Related
#28 — feat: issue_list tool (same gap, different domain)
## Problem
`workflow_run_status` exists but requires an explicit `run_id`. There is no way to **list** recent workflow runs via the MCP — to even get an ID, the caller has to either remember it or fall back to the gitea REST API with a token scoped for `read:repository`.
Concrete blocker hit 2026-05-17 watching the CD for commit `11f86f5` (issue #27 rollout): the connector could confirm "run #338 = success" only by guessing the ID (prior run was #336, mental arithmetic for +2 commits). On a busy day with parallel CI for branch + tag + commit fan-out, that arithmetic stops working.
Same shape as #28 (`issue_list`) — every `*_get(id)` tool wants a `*_list()` partner.
## Gitea API
```
GET /api/v1/repos/{owner}/{repo}/actions/runs
```
Query params worth surfacing:
- `event` — `push` | `pull_request` | `schedule` | `workflow_dispatch` (filter by trigger)
- `status` — `queued` | `in_progress` | `completed`
- `actor` — username
- `branch` — branch name (e.g. `main`)
- `head_sha` — commit SHA, full or short (the killer-feature param for the use case above)
- `workflow` — workflow file name (e.g. `cd.yml`)
- `page` / `limit` — pagination (cap at 50, same as `repo_list`)
## Tool spec
```
tool: workflow_run_list
params:
owner: string (required, allowlisted)
name: string (required)
branch: string? (default: none — all branches)
head_sha: string? (filter to runs for a specific commit; short SHA accepted)
status: "queued" | "in_progress" | "completed" | "all" (default: all)
event: "push" | "pull_request" | "schedule" | "workflow_dispatch" | "all" (default: all)
workflow: string? (workflow file name, e.g. cd.yml)
page: integer? (default 1)
limit: integer? (default 10, max 50)
returns:
runs: [
{ id, display_title, status, conclusion, event, head_sha,
head_branch, workflow_id, run_number, started_at, updated_at,
html_url, actor }
]
total: integer (from X-Total-Count header if present)
```
Defaults tuned for the most common "what just happened" query: `limit=10`, all events, all statuses, no branch filter. Most callers will pass `head_sha` to pin to one commit.
## Acceptance criteria
- [ ] `workflow_run_list` registered in `cmd/gitea-mcp/main.go`
- [ ] Allowlist check, same as the rest of the family
- [ ] `head_sha` filter accepts both short (7-char) and full SHAs — short is the natural form callers already have from `git log`
- [ ] Pagination respects `capLimit` helper
- [ ] Table-driven test in `internal/tools/workflow_run_list_test.go`: happy path, empty result, allowlist rejection, status filter, head_sha filter (short + full), branch filter
- [ ] Gitea client method `ListWorkflowRuns(ctx, owner, name, args)` in `internal/gitea/workflows.go`
- [ ] `task check` green
## Out of scope
- Streaming run logs — separate `workflow_run_logs` tool
- Per-job breakdown — separate `workflow_run_jobs` tool
- Cancelling a run — separate `workflow_run_cancel` tool
- Cross-repo aggregation
## Related
- #28 — feat: issue_list tool (same gap, different domain)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
workflow_run_statusexists but requires an explicitrun_id. There is no way to list recent workflow runs via the MCP — to even get an ID, the caller has to either remember it or fall back to the gitea REST API with a token scoped forread:repository.Concrete blocker hit 2026-05-17 watching the CD for commit
11f86f5(issue #27 rollout): the connector could confirm "run #338 = success" only by guessing the ID (prior run was #336, mental arithmetic for +2 commits). On a busy day with parallel CI for branch + tag + commit fan-out, that arithmetic stops working.Same shape as #28 (
issue_list) — every*_get(id)tool wants a*_list()partner.Gitea API
Query params worth surfacing:
event—push|pull_request|schedule|workflow_dispatch(filter by trigger)status—queued|in_progress|completedactor— usernamebranch— branch name (e.g.main)head_sha— commit SHA, full or short (the killer-feature param for the use case above)workflow— workflow file name (e.g.cd.yml)page/limit— pagination (cap at 50, same asrepo_list)Tool spec
Defaults tuned for the most common "what just happened" query:
limit=10, all events, all statuses, no branch filter. Most callers will passhead_shato pin to one commit.Acceptance criteria
workflow_run_listregistered incmd/gitea-mcp/main.gohead_shafilter accepts both short (7-char) and full SHAs — short is the natural form callers already have fromgit logcapLimithelperinternal/tools/workflow_run_list_test.go: happy path, empty result, allowlist rejection, status filter, head_sha filter (short + full), branch filterListWorkflowRuns(ctx, owner, name, args)ininternal/gitea/workflows.gotask checkgreenOut of scope
workflow_run_logstoolworkflow_run_jobstoolworkflow_run_canceltoolRelated