* feat(M13 T-519b): SSE worker_heartbeat + NavBar stand-by badge Aanvulling op scrum4me-mcp PR #25 (worker_heartbeat MCP-tool). - app/api/realtime/solo/route.ts: WorkerHeartbeatPayload type + isWorkerHeartbeatPayload guard + shouldEmit-routing op user_id. - stores/solo-store.ts: workerQuotaPct + workerQuotaCheckAt state + setWorkerQuota action. Reset bij decrementWorkers naar 0. - lib/realtime/use-solo-realtime.ts: handle worker_heartbeat-event, roep setWorkerQuota. - components/solo/nav-status-indicators.tsx: stand-by badge wanneer workerQuotaPct < minQuotaPct + tooltip met drempel. - components/shared/nav-bar.tsx + app/(app)/layout.tsx: minQuotaPct prop plumbing van User.min_quota_pct naar NavStatusIndicators. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(M13 T-520b): pre-flight quota-check sectie in mcp-integration Documenteert de batch-loop-uitbreiding: 1. get_worker_settings → min_quota_pct 2. bin/worker-quota-probe.sh → pct + reset 3. worker_heartbeat naar server (NavBar stand-by-badge) 4. Sleep tot reset bij low quota; anders wait_for_job Verwijst naar bin/worker-quota-probe.sh in scrum4me-docker (zie PR daar). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
119 lines
7.6 KiB
Markdown
119 lines
7.6 KiB
Markdown
---
|
|
title: "MCP Integration — Scrum4Me Tools"
|
|
status: active
|
|
audience: [ai-agent]
|
|
language: nl
|
|
last_updated: 2026-05-03
|
|
when_to_read: "When using MCP tools to interact with the Scrum4Me backlog."
|
|
---
|
|
|
|
# MCP-integratie
|
|
|
|
Scrum4Me heeft een eigen MCP-server in repo [`madhura68/scrum4me-mcp`](https://github.com/madhura68/scrum4me-mcp) die de REST-API als native tools voor Claude Code aanbiedt. Schema's worden gedeeld via een git submodule (`vendor/scrum4me`), niet gedupliceerd.
|
|
|
|
## Tools beschikbaar in Claude Code (18)
|
|
|
|
**Read / context:**
|
|
- `mcp__scrum4me__health` — service + DB ping
|
|
- `mcp__scrum4me__list_products` — producten waar de tokengebruiker toegang tot heeft
|
|
- `mcp__scrum4me__get_claude_context` — bundled product / actieve sprint / next story (met tasks) / open todos
|
|
|
|
**Authoring (PBI/Story/Task aanmaken):**
|
|
- `mcp__scrum4me__create_pbi` — `{ product_id, title, description?, priority, sort_order? }`; auto sort_order = last+1 binnen prio-groep
|
|
- `mcp__scrum4me__create_story` — `{ pbi_id, title, description?, acceptance_criteria?, priority, sort_order? }`; product_id afgeleid uit PBI; status=OPEN
|
|
- `mcp__scrum4me__create_task` — `{ story_id, title, description?, implementation_plan?, priority, sort_order? }`; sprint_id geërfd van story; status=TO_DO
|
|
- `mcp__scrum4me__create_todo` — losse todo (optioneel product-scoped)
|
|
|
|
**Task / story writes:**
|
|
- `mcp__scrum4me__update_task_status`, `mcp__scrum4me__update_task_plan`
|
|
- `mcp__scrum4me__log_implementation`, `mcp__scrum4me__log_test_result`, `mcp__scrum4me__log_commit`
|
|
|
|
**Vraag-antwoord-kanaal (M11):**
|
|
- `mcp__scrum4me__ask_user_question` — post een vraag over een story; optionele `wait_seconds` (max 600) polt voor het antwoord
|
|
- `mcp__scrum4me__get_question_answer` — huidige status + antwoord (voor latere session-pickup)
|
|
- `mcp__scrum4me__list_open_questions` — eigen vragen, max 50, recente eerst
|
|
- `mcp__scrum4me__cancel_question` — asker-only annulering van een eigen open vraag
|
|
|
|
**Job queue — agent worker mode (M13):**
|
|
- `mcp__scrum4me__wait_for_job` — blokkeert ≤600s, claimt atomisch een QUEUED-job via FOR UPDATE SKIP LOCKED. **Sinds M12** retourneert de payload een `kind`-discriminator:
|
|
- `kind: 'TASK_IMPLEMENTATION'` (default) — payload met `implementation_plan`, `story`, `pbi`, `sprint`, `repo_url`
|
|
- `kind: 'IDEA_GRILL'` of `'IDEA_MAKE_PLAN'` — payload met `idea`, `product`, `repo_url`, en `prompt_text` (de embedded prompt uit `lib/idea-prompts/`)
|
|
Stale CLAIMED-jobs (>30min) worden eerst terug naar QUEUED gezet. Lege queue na block-time = klaar.
|
|
- `mcp__scrum4me__update_job_status` — agent rapporteert `running|done|failed` + optionele branch/summary/error; triggert automatisch SSE-event. Bij `failed` voor `IDEA_GRILL`/`IDEA_MAKE_PLAN` wordt de idea-status automatisch op `GRILL_FAILED` resp. `PLAN_FAILED` gezet. Auth: Bearer-token moet matchen `claimed_by_token_id`. Optionele token-velden: `model_id` (string), `input_tokens`, `output_tokens`, `cache_read_tokens`, `cache_write_tokens` (alle non-negative int) — worden opgeslagen op de ClaudeJob-rij bij done/failed.
|
|
|
|
**Idea-jobs (M12) — agent gedrag per kind:**
|
|
|
|
| Kind | Werkwijze | Eind-call |
|
|
|---|---|---|
|
|
| `IDEA_GRILL` | Lees `prompt_text` (embedded grill-prompt) + `idea.grill_md` als startpunt; itereer met `ask_user_question(idea_id=...)`/`get_question_answer`; log onderweg `log_idea_decision`; eindig met `update_idea_grill_md(markdown)` | `update_job_status('done')` |
|
|
| `IDEA_MAKE_PLAN` | Lees `prompt_text` (embedded make-plan-prompt) + `idea.grill_md` + repo-context. **Stel GEEN vragen** — single-pass output. Bouw plan in strict yaml-frontmatter format en eindig met `update_idea_plan_md(markdown)`. Server-side parser kan parse-fail → `PLAN_FAILED` | `update_job_status('done')` |
|
|
|
|
**MCP-tools — Idea-laag (M12):**
|
|
- `mcp__scrum4me__get_idea_context(idea_id)` — `{ idea, product, repo_url, grill_md_so_far, open_questions, prompt_text }`
|
|
- `mcp__scrum4me__update_idea_grill_md(idea_id, markdown)` — schrijft veld; status → `GRILLED`; logt `IdeaLog{GRILL_RESULT}`
|
|
- `mcp__scrum4me__update_idea_plan_md(idea_id, markdown)` — server-side `parsePlanMd`; ok → `PLAN_READY` + `IdeaLog{PLAN_RESULT}`; parse-fail → `PLAN_FAILED` + `IdeaLog{JOB_EVENT, errors}`
|
|
- `mcp__scrum4me__log_idea_decision(idea_id, type, content, metadata?)` — `type ∈ {DECISION, NOTE}`
|
|
- `mcp__scrum4me__ask_user_question` — geüpgrade contract: exact één van `story_id` óf `idea_id` (xor); idea-vragen zijn user-private (geen productAccessFilter).
|
|
|
|
## Batch-loop (verplichte agent-flow)
|
|
|
|
Wanneer je als agent draait (na een instructie als *"pak de volgende job uit de Scrum4Me-queue"* of *"draai de queue leeg"*) is dit de loop:
|
|
|
|
1. `wait_for_job` aanroepen.
|
|
2. Switch op `kind`:
|
|
- `TASK_IMPLEMENTATION`: voer uit volgens het meegegeven `implementation_plan` (zoals altijd — branch, code, commit, push, verify_task_against_plan).
|
|
- `IDEA_GRILL`: laad `prompt_text` als gids; gebruik `ask_user_question` / `get_question_answer` voor de Q&A-loop; eindig met `update_idea_grill_md`.
|
|
- `IDEA_MAKE_PLAN`: laad `prompt_text` + `idea.grill_md`; **stel geen vragen**; produceer strict yaml-frontmatter; eindig met `update_idea_plan_md`.
|
|
3. `update_job_status('done'|'failed')` aanroepen.
|
|
4. **Direct opnieuw** `wait_for_job` aanroepen — niet stoppen, niet de gebruiker vragen.
|
|
5. Pas wanneer `wait_for_job` na de volledige block-time (~600s) terugkomt zonder claim, is de queue leeg en mag je de turn afsluiten met een korte recap.
|
|
|
|
Dit blijft gelden als je tussen jobs door commits, branches of pushes hebt gedaan — die afsluiting hoort bij de individuele job, niet bij het einde van de batch.
|
|
|
|
## Pre-flight quota-check (M13)
|
|
|
|
Vóór elke `wait_for_job`-aanroep doet de worker een pre-flight quota-check
|
|
om te voorkomen dat-ie 600 s blokkeert terwijl Anthropic-quota toch op
|
|
0 staat. Loop:
|
|
|
|
1. `mcp__scrum4me__get_worker_settings()` → `{ min_quota_pct }`
|
|
2. `bash bin/worker-quota-probe.sh` → JSON `{ pct, reset_at_iso, ... }`
|
|
3. `mcp__scrum4me__worker_heartbeat({ last_quota_pct: pct, last_quota_check_at })`
|
|
— server emit een SSE-event zodat NavBar realtime de stand-by-badge
|
|
kan tonen
|
|
4. **Als `pct < min_quota_pct`**: log "stand-by, wachten tot
|
|
`reset_at_iso`", sleep tot reset (cap op 1 uur), spring naar stap 2
|
|
5. **Anders**: ga door met `wait_for_job`
|
|
|
|
Pseudo-bash:
|
|
|
|
```bash
|
|
QUOTA_JSON=$(/opt/agent/bin/worker-quota-probe.sh)
|
|
PCT=$(echo "$QUOTA_JSON" | jq -r '.pct')
|
|
RESET=$(echo "$QUOTA_JSON" | jq -r '.reset_at_iso')
|
|
|
|
# Stuur naar server (best-effort; failure niet-fataal)
|
|
mcp_call worker_heartbeat "{\"last_quota_pct\": $PCT}"
|
|
|
|
if [[ "$PCT" -lt "$MIN_PCT" ]]; then
|
|
log "stand-by until $RESET (pct=$PCT < min=$MIN_PCT)"
|
|
sleep_until "$RESET"
|
|
continue
|
|
fi
|
|
```
|
|
|
|
**Beperking**: de probe kost ~1 outputtoken per check. 12 checks/uur =
|
|
12 tokens/uur overhead — verwaarloosbaar. De `min_quota_pct`-setting
|
|
staat per default op 20% — bij vrije Pro/Max-plans typisch ruim genoeg
|
|
om dagelijks werk niet te verstoren.
|
|
|
|
**Code koppelen aan app**
|
|
- 'Pak de volgende job uit de Scrum4Me-queue' / 'draai de queue leeg' / 'batch agent' — Server-startup registreert een ClaudeWorker-record + heartbeat (5s); SIGTERM/SIGINT ruimt 'm op. UI in NavBar telt actieve workers via `last_seen_at < now() - 15s`.
|
|
|
|
## Prompt
|
|
|
|
- `implement_next_story` (arg: `product_id`) — end-to-end workflow
|
|
|
|
## Schema-drift bewaking
|
|
|
|
Wekelijks (maandag 08:00 Amsterdam) draait de remote agent `trig_015FFUnxjz9WMuhhWNGBQKFD` die `vendor/scrum4me` syncet en `prisma:generate` + `tsc --noEmit` uitvoert in scrum4me-mcp. Als die agent drift rapporteert, hoort dat **vóór** een Scrum4Me-PR met schema-wijziging gemerged kan worden — anders breekt de MCP-server stilletjes op runtime.
|