Scrum4Me/docs/manual/04-mcp-integration.md
Janpeter Visser bd7478861b
PBI-58: Developer manual + in-app /manual page (#148)
* docs(PBI-58): add developer manual chapters under docs/manual/

Adds a 7-file English-language manual targeted at new human contributors:
index, overview, statuses & transitions (with mermaid state diagrams),
git workflow, MCP integration, docker, and troubleshooting. The manual
is the *map* — it cross-references existing runbooks/ADRs/architecture
docs rather than duplicating their content.

Regenerates docs/INDEX.md and validates with check-doc-links.mjs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(PBI-58): add markdown rendering deps + manual:build script

Adds mermaid, rehype-slug, rehype-autolink-headings for the in-app
/manual page. Wires manual:build into prebuild so production builds
always regenerate the chapter TOC.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-58): codegen script for in-app manual TOC

scripts/build-manual.mjs walks docs/manual/, parses YAML front-matter,
strips it from the body, and emits lib/manual.generated.ts with a typed
ManualEntry[] containing slug, title, description, filePath, and the
embedded markdown body. Pure Node 20, mirrors generate-docs-index.mjs.

Inlining the markdown at build time keeps runtime serverless functions
free of filesystem reads, which avoids whole-project NFT tracing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-58): /manual route renders developer manual chapters in-app

Catch-all route at app/(app)/manual/[[...slug]]/page.tsx with
generateStaticParams covering every TOC entry. Server-side
MarkdownView uses react-markdown with remark-gfm, rehype-slug, and
rehype-autolink-headings; mermaid code blocks are routed to a
client-only MermaidBlock that dynamic-imports mermaid on mount.

ManualSidebar (client) reads the typed TOC and highlights the active
chapter via usePathname.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-58): add Manual link to main nav bar

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 18:00:10 +02:00

121 lines
7.3 KiB
Markdown

---
title: "MCP Integration"
status: active
audience: [contributor]
language: en
last_updated: 2026-05-07
when_to_read: "Whenever Claude Code is interacting with Scrum4Me — opening a story, claiming a job, asking the user a question."
---
# 04 — MCP Integration
Scrum4Me exposes its REST API as native Claude Code tools through a dedicated **MCP server** living in [`madhura68/scrum4me-mcp`](https://github.com/madhura68/scrum4me-mcp). Schemas are shared via a git submodule (`vendor/scrum4me`) so there's exactly one definition of every type. From the agent's perspective, Scrum4Me looks like a set of native tools prefixed `mcp__scrum4me__*`.
This chapter is the **onboarding tour**. The full tool reference (all 18 tools, their parameters, and edge cases) is in [`docs/runbooks/mcp-integration.md`](../runbooks/mcp-integration.md).
## Three ways the agent works
| Mode | Triggered by | Loop |
|---|---|---|
| **Track A — MCP-driven** | User says *"implement the next story"* | `get_claude_context` → execute tasks → `update_task_status` → commit per layer → repeat until queue empty → push + PR |
| **Track B — Manual** | User describes a one-off change in chat | Read pattern + styling → edit → verify → wait for `commit it` → commit |
| **Worker — Queue-driven** | Background worker container running on a Mac/NAS | `wait_for_job` (blocks ≤600s) → switch on `kind` → execute → `update_job_status` → loop forever |
CLAUDE.md describes Track A and Track B; this manual focuses on the **Worker** mode because it's the most novel and the most likely to surprise a new contributor reading server logs.
## A typical Track A run
```mermaid
sequenceDiagram
participant U as User
participant C as Claude
participant M as MCP server
participant DB as Postgres
U->>C: "implement the next story"
C->>M: get_claude_context(product_id)
M->>DB: SELECT product, sprint, next story, tasks
M-->>C: { story, tasks[], pbi, sprint }
loop per task in sort_order
C->>M: update_task_status(task_id, 'in_progress')
C->>C: read pattern + styling, edit files
C->>M: log_implementation(story_id, content)
C->>M: update_task_status(task_id, 'review')
C->>M: log_test_result(story_id, 'PASSED')
C->>M: update_task_status(task_id, 'done')
end
C->>U: "milestone ready for your test"
U->>C: "looks good, push it"
C->>C: git push + gh pr create
```
The contract every step relies on:
- All inputs are **lowercase API enums** (`'in_progress'`, never `'IN_PROGRESS'`); the MCP server applies [`lib/task-status.ts`](../../lib/task-status.ts) under the hood.
- Status writes are **forbidden for demo accounts** — they return `403`. See [02 — Statuses](./02-statuses-and-transitions.md#db-vs-api-mapping) and [`docs/adr/0006-demo-user-three-layer-policy.md`](../adr/0006-demo-user-three-layer-policy.md).
- Bearer tokens are bound to a product. `list_products` returns only what the token can see; `get_claude_context` is product-scoped.
## Idea jobs vs task implementation
The worker `wait_for_job` returns a payload with a `kind` discriminator. The agent must switch on it:
| `kind` | Behaviour |
|---|---|
| `TASK_IMPLEMENTATION` | Default. Execute the `implementation_plan`, follow the [git workflow](./03-git-workflow.md), end with `update_job_status('done')`. |
| `IDEA_GRILL` | Read embedded `prompt_text` + existing `idea.grill_md`. Iterate with `ask_user_question` / `get_question_answer`. End with `update_idea_grill_md(markdown)`. |
| `IDEA_MAKE_PLAN` | Read `prompt_text` + `idea.grill_md`. **Do not ask questions** — single-pass output in strict YAML-frontmatter. End with `update_idea_plan_md(markdown)`. Server-side parser may reject → `PLAN_FAILED`. |
| `PLAN_CHAT` | Conversational refinement loop on an existing plan (M12+). |
| `SPRINT_IMPLEMENTATION` | Sprint-level run that cascades through every task; `update_task_status` calls must include the `sprint_run_id`. |
For the full Idea state machine (DRAFT → GRILLING → … → PLANNED) see [02 — Statuses & Transitions § Idea](./02-statuses-and-transitions.md#idea).
## The Q&A channel
When Claude needs a human decision mid-run, it doesn't block silently — it posts a question through the MCP and either polls or returns control:
```mermaid
sequenceDiagram
participant C as Claude
participant M as MCP
participant DB as Postgres
participant U as User (NavBar bell)
C->>M: ask_user_question({ story_id, question, wait_seconds: 600 })
M->>DB: INSERT user_question; NOTIFY user_question_created
DB-->>U: SSE event → bell pulses
U->>M: POST /api/questions/:id/answer
M->>DB: UPDATE user_question; NOTIFY user_question_answered
DB-->>C: ask_user_question returns { answer }
C->>C: continue execution
```
Key facts:
- `wait_seconds` is capped at 600. If the user doesn't answer in time, `ask_user_question` returns with status `pending`; Claude can resume later via `get_question_answer(question_id)`.
- Idea questions (`{ idea_id }` instead of `{ story_id }`) are **user-private** — they bypass `productAccessFilter`, so collaborators don't see them.
- A question can be cancelled by the asker via `cancel_question`.
The persistent design (table + `LISTEN/NOTIFY`) is documented in [`docs/architecture/claude-question-channel.md`](../architecture/claude-question-channel.md).
## The worker's pre-flight quota check
The worker doesn't blindly call `wait_for_job`. Each iteration it first checks Anthropic API quota via `bin/worker-quota-probe.sh` so it doesn't burn a 10-minute block on a queue it can't actually process. The full algorithm — settings, `worker_heartbeat` SSE event, sleep-until-reset — is in [`docs/runbooks/mcp-integration.md`](../runbooks/mcp-integration.md#pre-flight-quota-check-m13). The Docker chapter ([05](./05-docker.md#quota-probe)) shows how to test it locally.
## Schema-drift watchdog
If Scrum4Me's Prisma schema changes but `scrum4me-mcp` isn't synced, the MCP server will fail at runtime — not at deploy. To prevent that, a remote agent runs every Monday at 08:00 Amsterdam time, syncs `vendor/scrum4me`, and runs `prisma:generate` + `tsc --noEmit` in `scrum4me-mcp`. Drift reports must be resolved **before** any Scrum4Me PR with schema changes can merge. See [`docs/runbooks/mcp-integration.md`](../runbooks/mcp-integration.md#schema-drift-bewaking).
## Deep links
| Topic | Authoritative source |
|---|---|
| Tool reference (all 18 tools) | [`docs/runbooks/mcp-integration.md`](../runbooks/mcp-integration.md) |
| Worker idempotency & job-status protocol | [`docs/runbooks/worker-idempotency.md`](../runbooks/worker-idempotency.md) |
| Q&A channel architecture (table + LISTEN/NOTIFY) | [`docs/architecture/claude-question-channel.md`](../architecture/claude-question-channel.md) |
| Idea-laag plan & prompts | [`docs/plans/M12-ideas.md`](../plans/M12-ideas.md) |
| Sprint execution modes (PER_TASK vs SPRINT_BATCH) | [`docs/architecture/sprint-execution-modes.md`](../architecture/sprint-execution-modes.md) |
| Realtime NOTIFY payload contract | [`docs/patterns/realtime-notify-payload.md`](../patterns/realtime-notify-payload.md) |
| Demo-user write protection | [`docs/adr/0006-demo-user-three-layer-policy.md`](../adr/0006-demo-user-three-layer-policy.md) |
## What's next
→ [05 — Docker](./05-docker.md) covers how the worker container is run, debugged, and operated.