feat: workflow_run_list tool #29

Closed
opened 2026-05-17 07:49:54 +00:00 by mathias · 0 comments
Owner

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:

  • eventpush | pull_request | schedule | workflow_dispatch (filter by trigger)
  • statusqueued | 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
  • #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)
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mathias/gitea-mcp#29