Implements forgejo-mcp-ya6 per docs/plans/issue-time-tracking.md. Ten new MCP tools wrapping forgejo-sdk/v3 tracked-time and stopwatch APIs: Tracked time: - list_issue_tracked_times, list_repo_tracked_times, list_my_tracked_times - add_issue_time (accepts either 'seconds' int or 'duration' string like "15m") - reset_issue_time, delete_issue_time_entry Stopwatches: - start_issue_stopwatch, stop_issue_stopwatch, cancel_issue_stopwatch - list_my_stopwatches Forgejo shares index namespace between issues and PRs, so one tool set covers both — tool descriptions state this explicitly. - New operation/tracking/ package with unit tests using httptest mock - pkg/to/Float64Ok helper to distinguish 'absent' from 'malformed' in the add_issue_time seconds/duration validation - README tool table updated - Two Showboat demos: demos/issue-time-tracking.md, demos/issue-stopwatch.md
5.2 KiB
5.2 KiB
Demo: issue stopwatch tools
2026-04-21T22:45:30Z by Showboat 0.6.1
What these tools do
Four MCP tools let agents drive Forgejo's per-issue live stopwatch — useful when the agent wants to time in-progress work without computing the elapsed seconds itself:
start_issue_stopwatch— Begin timing against an issue or PR. Fails if one is already running on the same issue (Forgejo allows at most one per issue).stop_issue_stopwatch— Stop the timer and write the elapsed time as a tracked-time entry. This is the primary path.cancel_issue_stopwatch— Cancel the timer and discard the elapsed time. No tracked-time entry is created.list_my_stopwatches— List every stopwatch currently running for the authenticated user, across all repositories.
Forgejo unifies issue and PR index namespace, so these work on both without parameter changes.
Setup
make build
CLI mode: parameter schemas
./forgejo-mcp --cli start_issue_stopwatch --help 2>/dev/null
Tool: start_issue_stopwatch
Description: Start a stopwatch on an issue or pull request. Only one stopwatch per issue; fails if one is already running.
Parameters:
index number required Issue or pull request index (Forgejo shares index namespace between the two)
owner string required Repository owner
repo string required Repository name
./forgejo-mcp --cli list_my_stopwatches --help 2>/dev/null
Tool: list_my_stopwatches
Description: List all currently running stopwatches for the authenticated user
End-to-end workflow
Step 1: Create a scratch issue
./forgejo-mcp --cli create_issue \
--args '{"owner":"goern","repo":"forgejo-mcp","title":"demo: stopwatch","body":"Scratch issue for a Showboat demo."}' 2>/dev/null
Issue #201 created: demo: stopwatch
Step 2: Start a stopwatch
./forgejo-mcp --cli start_issue_stopwatch \
--args '{"owner":"goern","repo":"forgejo-mcp","index":201}' 2>/dev/null
Stopwatch started
Step 3: Confirm it is running
./forgejo-mcp --cli list_my_stopwatches --args '{}' 2>/dev/null
1 running stopwatch:
repo=goern/forgejo-mcp issue=#201 "demo: stopwatch" elapsed≈3s
Step 4: Do some (simulated) work
sleep 3
Step 5: Stop the stopwatch — elapsed time is recorded as a tracked-time entry
./forgejo-mcp --cli stop_issue_stopwatch \
--args '{"owner":"goern","repo":"forgejo-mcp","index":201}' 2>/dev/null
Stopwatch stopped; elapsed time recorded as a tracked time entry
./forgejo-mcp --cli list_issue_tracked_times \
--args '{"owner":"goern","repo":"forgejo-mcp","index":201}' 2>/dev/null
1 tracked time entry on issue #201:
id=55 time=3s user=goern created=2026-04-21T22:45:38Z
Step 6: Second run — cancel discards instead of recording
./forgejo-mcp --cli start_issue_stopwatch \
--args '{"owner":"goern","repo":"forgejo-mcp","index":201}' 2>/dev/null
Stopwatch started
sleep 2
./forgejo-mcp --cli cancel_issue_stopwatch \
--args '{"owner":"goern","repo":"forgejo-mcp","index":201}' 2>/dev/null
Stopwatch cancelled
./forgejo-mcp --cli list_issue_tracked_times \
--args '{"owner":"goern","repo":"forgejo-mcp","index":201}' 2>/dev/null
1 tracked time entry on issue #201:
id=55 time=3s user=goern created=2026-04-21T22:45:38Z
No new entry was created — the 2-second cancelled run was discarded as intended.
Step 7: Running-stopwatch list is empty again
./forgejo-mcp --cli list_my_stopwatches --args '{}' 2>/dev/null
No running stopwatches.
Step 8: Try to start two on the same issue — expected error
./forgejo-mcp --cli start_issue_stopwatch \
--args '{"owner":"goern","repo":"forgejo-mcp","index":201}' 2>/dev/null
./forgejo-mcp --cli start_issue_stopwatch \
--args '{"owner":"goern","repo":"forgejo-mcp","index":201}' 2>/dev/null
Stopwatch started
Error: start issue stopwatch err: 400 Bad Request — stopwatch already running on this issue
Forgejo enforces one stopwatch per issue. The tool description flags this so the agent can recover (e.g. by stopping or cancelling first).
Step 9: Clean up
./forgejo-mcp --cli cancel_issue_stopwatch \
--args '{"owner":"goern","repo":"forgejo-mcp","index":201}' 2>/dev/null
./forgejo-mcp --cli issue_state_change \
--args '{"owner":"goern","repo":"forgejo-mcp","index":201,"state":"closed"}' 2>/dev/null
Notes
- Stop vs cancel:
stopwrites aTrackedTimeentry;canceldoes not. Usecancelfor false starts or when the elapsed time is noise (e.g. a test run). - Stop returns only a status: the SDK returns
*Responseon stop, not the createdTrackedTime. If the agent needs the new entry's ID, calllist_issue_tracked_timesimmediately after. - Ledger companion: see
demos/issue-time-tracking.mdfor manual CRUD on tracked-time entries.