Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesMcp ServerMCP server — QA plan

MCP server — QA plan

Automated

make test-unit-api covers apps/api/src/mcp/*.unit.spec.ts, apps/api/src/ai/agent/tools/leaves/workouts.tools.unit.spec.ts and apps/api/src/ai/agent/context-builder.unit.spec.ts (see code map). make test-e2e-api runs apps/api/test/e2e/day-grain-coaching.e2e.spec.ts (also Spotter’s tool list and prompt), day-grain-parse.e2e.spec.ts (replayed parses: titles, one-call confirm-and-save) and session-grain-coaching.e2e.spec.ts (integrator flow) over the real POST /mcp.

Manual

  1. curl -i -X POST <api>/mcp -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' → 401 with a WWW-Authenticate header naming resource_metadata.
  2. curl <api>/.well-known/oauth-protected-resource/mcp → authorization_servers is the Clerk Frontend API for this environment.
  3. Add the server as a Claude custom connector → OAuth sign-in via Clerk completes and tools appear.
  4. As a multi-org owner without ?orgId= → organization_required listing both orgs. With ?orgId= → tools listed.
  5. As a coach → no owner/admin-only tools (e.g. revenue analytics) are listed.
  6. Ask the client to search members, then create a task → task exists in the app, and an audit log row task.create is attributed to the user.
  7. Ask the client to delete a workout → it reports the tool is unavailable; nothing is deleted.
  8. As a member-only user → 403.

Day grain

  1. initialize returns the day-grain instructions; workouts_upsert and workouts_parse are listed; workouts_create, workouts_set_sections and programs_session_create carry the day-grain descriptions.
  2. Paste a real coach day into Claude (brief + Warm-up/Lift/Strength/Conditioning/Optional Successory). It sends the text to workouts_parse with the date and save, confirms any unresolved movements in ONE more workouts_parse call with save.resolutions, and makes ONE programs_session_create for the date. In the app the day is one workout named for its date and program (never its Hebrew brief) on the web list and in the mobile athlete view: the brief on top, parts with their clock windows, notes and optional badge, the conditioning score slot only.
  3. Send a Back Squat loaded percent_1rm under “Percentages off your Back Squat 3RM” → the write succeeds and returns a percent_base_mismatch warning.
  4. In PostHog, mcp.tool.executed for those calls carries sectionCount, partCount, slotCount, warningsCount (and mcpSessionId when the client sends one) and no coach text.
  5. Paste the same coach day into Spotter in the app → it calls workouts.parse (save + date), confirms suggestions with save.resolutions (asking with a picker when several candidates fit), tells you each warning, and publishes once; asking it to hand-write sourceText is refused.
  6. scripts/mcp-programming-sync.mjs call workouts_parse '{...}' on a long day completes (default 180s tool-call timeout); TAIKAN_MCP_TIMEOUT_MS=5000 makes the same call fail fast with an abort.