## Summary

Adds a single READ-ONLY MCP tool, `curogram_triage_inbox`, to the Curogram MCP server. It pulls recent (default unread) conversations and returns a structured triage record per conversation for the calling LLM to reason over and draft human-approved actions. It does NOT send, draft, mark-read, create tasks, or modify Curogram in any way, and it calls no LLM server-side.

This is an additive change: one new tool registration + one switch case + one handler. No existing tools, `curogram-auth.ts`, or `send-approval.ts` were touched.

## What it returns

Per conversation:
- `conversation_id`, `patient_id` (best-effort from the inbound author of a patient thread, else `null`), `title`, `type`, `unread_count`, `updated_at`
- `last_inbound_snippet` (truncated last patient/inbound message body) + `last_inbound_at`
- `suggested_category` — deterministic keyword tag, one of `confirm | cancel | reschedule | billing | clinical_urgent | question | other`
- `matched_keywords` — which keywords fired
- `suggested_categories` — the enum scaffold for the caller to confirm/override
- optional non-PHI `note` (e.g. thread read failed; falls back to the list-item preview)

Top-level: `read_only: true`, `classification: "deterministic_keyword"`, `category_scaffold`, `unread_only`, `skip`, `limit`, `total_item_count`, `returned`, and `rate_limit_warning` (surfaces `x-frequency-warning` backoff like the other tools).

## Behavior / design

- Reuses the existing list logic (GraphQL `GetConversationList` with `unreadOnly`) and the existing REST `GET /conversations/{id}/messages` read endpoint — same patterns as `curogram_list_conversations` / `curogram_read_thread`.
- Deterministic, dependency-free keyword classification. Clinical-urgent is checked first (safety), then transactional intents, then catch-all `question`, else `other`. Substring matching is bounded by non-word chars so `cancel` matches `canceled` but not `scandal`.
- Inbound detection probes the common payload shape markers and defaults to NOT treating an unknown-shape message as inbound, so a staff reply isn't surfaced as the patient's ask.
- Pagination: `limit` (default 15, capped 50), `skip`, `unread_only` (default true), `snippet_max_chars` (default 280, capped 1000).
- Per-conversation read failures are non-fatal: the record is kept with a non-PHI note and the list-item preview is used for classification.

## Safety / PHI

- Read-only. No write endpoints are called. No mark-read, no task creation, no mutation.
- Message snippets are RETURNED to the MCP caller (expected, that's the tool's purpose) but nothing logs message bodies or patient identifiers to disk/stderr — consistent with the repo's no-PHI-logging rule.
- Human-in-the-loop: output is raw material for the orchestrator to draft actions that a human approves out-of-band. Sends still go through the existing approval-gated `curogram_send_text`.

## Tests

- `bun build tools/curogram-mcp/server.ts` — clean (bundled 305 modules).
- `bun test tools/mcp-config/render.test.ts` — 12 pass / 0 fail.

Base branch is `feat/ai-curogram-mcp` (the canonical v1 server) so the diff is exactly the +391-line tool addition.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
