Scrum4Me/docs/runbooks/mcp-integration.md
Scrum4Me Agent bc6936159d docs(ST-qfpqpxzy): worker-quota-probe.sh + uitgebreide pre-flight runbook + architectuurdoc
- scripts/worker-quota-probe.sh: curl-probe die rate-limit-headers parset en { remaining, limit, pct, reset_at_iso } JSON retourneert
- mcp-integration.md: pre-flight sectie uitgebreid met bash-script voorbeeld, retry-strategie (sleep tot reset+5s), bekende beperking
- claude-question-channel.md: M13 quota-gate flow diagram + pre-flight loop uitleg

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 03:55:58 +02:00

133 lines
8.2 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
**Worker-instellingen + quota (M13):**
- `mcp__scrum4me__get_worker_settings` — geen args; retourneert `{ min_quota_pct }` afgeleid van het Bearer-token. Gebruik dit voor de pre-flight quota-check.
- `mcp__scrum4me__worker_heartbeat` — optionele args: `last_quota_pct` (0-100), `last_quota_check_at` (ISO-8601), `is_low` (boolean). Slaat quota-state op in `ClaudeWorker` en triggert een `worker_heartbeat` SSE-event zodat de NavBar een stand-by badge kan tonen.
**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.
**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`.
## Pre-flight quota-check
Vóór elke `wait_for_job` kan de worker controleren of er voldoende Claude-quota is.
**Helper-script:** `scripts/worker-quota-probe.sh` doet een minimale API-call (1 token) en geeft JSON terug:
```json
{ "remaining": 180000, "limit": 200000, "pct": 90, "reset_at_iso": "2026-05-06T13:00:00Z" }
```
**Stappenplan:**
1. Haal drempel op: `get_worker_settings``min_quota_pct` (bijv. 20).
2. Probe quota:
```bash
PROBE=$(bash scripts/worker-quota-probe.sh)
PCT=$(echo "$PROBE" | grep -o '"pct":[0-9]*' | cut -d: -f2)
RESET_AT=$(echo "$PROBE" | grep -o '"reset_at_iso":"[^"]*"' | cut -d'"' -f4)
```
3. Vergelijk en meld via `worker_heartbeat`:
```
worker_heartbeat(
last_quota_pct=<PCT>,
last_quota_check_at=<nu als ISO-8601>,
is_low=<PCT < min_quota_pct>
)
```
4. Bij low quota: retry-strategie — slaap tot reset + 5s:
```bash
if [ "$PCT" -lt "$MIN_QUOTA_PCT" ]; then
RESET_S=$(date -d "$RESET_AT" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%SZ" "$RESET_AT" +%s 2>/dev/null || echo 0)
NOW_S=$(date +%s)
SLEEP_S=$(( RESET_S - NOW_S + 5 ))
echo "Wachten tot quota-reset om $(date -d "$RESET_AT" '+%H:%M' 2>/dev/null || echo "$RESET_AT")"
[ "$SLEEP_S" -gt 0 ] && sleep "$SLEEP_S"
fi
```
5. Na de sleep: herhaal stap 2 (re-probe) voordat `wait_for_job` wordt aangeroepen.
**Bekende beperking:** elke probe kost ~1 token; bij 12x/uur is de overhead 12 tokens/uur — verwaarloosbaar ten opzichte van taak-gebruik.
## 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.