# personalize.run > Agent-first outbound email platform. Operators (humans) launch multi-stage email > sequences through an LLM agent; the MCP tool surface is the product. CAN-SPAM > compliant, server-enforced approval gates, scoped Gmail DWD, full audit log. Built on the Agent-First framework v0.5. ## Install ``` npm install -g @capitalthought/personalize-mcp ``` Then add to your MCP client config: ``` "personalize": { "command": "personalize-mcp", "env": { "PERSONALIZE_REFRESH_TOKEN": "..." } } ``` The refresh token is per-operator and lives in the operator's 1Password. Ask the operator. ## Canonical resources - https://personalize.run/agents.md — operator contract; read this first, every session - https://personalize.run/.well-known/mcp.json — tool registry, auto-generated from mcp/server.ts - https://personalize.run/changelog.json — machine-readable changelog feed (what shipped, newest first) - https://personalize.run/health — JSON health check, unauthenticated - https://personalize.run/api/dashboard — read-only HTML dashboard (JWT-authed) - https://personalize.run/privacy — privacy policy (Google API Services User Data Policy compliant) - https://personalize.run/terms — terms of service (Capital Thought, LLC) ## Tool surface (15 verbs) - personalize_create_sequence — Draft a multi-stage email sequence under an operator. Stage triggers: 'always', 'no_reply', 'no_engagement'. - personalize_add_recipients — Attach recipients; suppression auto-applied. - personalize_import_recipients — Bulk-import recipients from a CSV blob (e.g., fetched from a Sheet). Header row required; 'email' column mandatory. - personalize_launch — Launch a sequence; >50 recipients require approval header. Self-test gate (default-on) renders stage 1 to owner_email before fan-out. - personalize_approve_self_test — Approve the self-test send and fan out the rest cohort. Idempotent. - personalize_update_stage — Edit a stage subject or body before send. - personalize_preflight_check — Run deliverability pre-flight (DNS, headers, content, volume) without launching. - personalize_link_check — Verify every resolves AND click tracking round-trips correctly (catches HSN-2026-class encoding regressions before launch). - personalize_pause — Halt an in-flight sequence. Pass terminal=true to archive it (terminal state) instead. - personalize_resume — Resume a paused sequence (re-runs the approval gate). - personalize_get_status — Recipient counts, send counts, engagement, replies. - personalize_list_sequences — Filterable list of an operator's sequences. - personalize_create_snippet — Save a versioned shared template (set parent_id to revise). - personalize_search_snippets — Search the shared snippet library by name, owner, category. - personalize_create_team_prompt — Create a team voice/style prompt — markdown the agent reads when composing on behalf of a team. Admin only. - personalize_list_team_prompts — List active team prompts. Read these BEFORE composing a stage on behalf of a team. - personalize_get_team_prompt — Get one team prompt by slug. - personalize_suppress — Add an email or domain to the do-not-contact list. - personalize_update_operator — Update display_name, physical_address, or admin caps. - personalize_request_approval — Mint a token for >1000-recipient launches. - personalize_audit — Query the audit_log scoped to your own actor rows. - personalize_get_recipient — Read a recipient's state, send history, and engagement events. - personalize_get_replies — List reply + bounce events on a sequence with counts. - personalize_estimate — Pre-launch sizing: caps, cap room, projected duration. - personalize_preview — Render stage 1 subject + body for a recipient. - personalize_what_now — Operator state-machine — tells the agent the next onboarding action ('needs_address', 'ready_for_send_test', 'fully_onboarded', etc.). Surfaces a quickstart_url for the first-sequence walkthrough. - personalize_send_test — 1-stage smoke test send to a configured test recipient — verifies auth + send pipeline end-to-end. - personalize_send_test_sequence — Render a stage of an existing sequence against a recipient's variables and email the preview to the operator's own inbox. Subject prefixed [test]. Defaults: stage 1, newest recipient. - personalize_feedback — File a feedback report; backs the agent-feedback signed-URL pipeline. - personalize_cluster_replies — Reply Triage: read a reply pile + cluster into emergent groups (read-only, no drafts/sends). Source = sequence_id | gmail_query | thread_ids; body-read sources need the internal read flag. - personalize_draft_group_replies — Reply Triage: execute the operator's direction for a group — reply (draft, template-only by default) / escalate / skip / suppress. Drafts only; safety-gated; no send. - personalize_approve_reply_batch — Reply Triage: approve a drafted reply batch (batch_id + token) → cron sends threaded, commercial-only footer + suppression, paced. The recorded human approval; no auto-send. - personalize_get_reply_batch — Reply Triage: read-only batch status — per-draft state, recipient, is_commercial, grounding_ok, confidence, body. - personalize_suggest_reply_sources — Reply Triage discovery: rank reply piles worth triaging (sequences scope works for all; sent_fanouts/recent need the read flag). Read-only, no bodies/LLM; each suggestion pipes into cluster_replies. - personalize_list_waitlist — Admin: list public beta-waitlist signups (landing page) to promote into the ≤100 Google test-user slots. Filter by status. - personalize_invite_waitlist — Admin: mark a waitlist signup invited (after adding their email to the OAuth test-user list). - personalize_set_subject_variants — Register 2-4 stage-1 subject A/B variants. Sequence must be draft + tracking_enabled. Recipients get assigned uniformly at random. - personalize_promote_variant — Pick the winning A/B subject. Subsequent stages render the winner's subject for all recipients. Sequence must be active|paused|completed. - personalize_extend_pilot — Extend an in-flight A/B pilot's decision deadline by additional_hours. Idempotent (additive). Used to buy more data before the 72h escalation ladder fires the relaxed-rule fallback or escalates to manual. - personalize_get_perspective_review — Read a perspective-review record (AF4). Triggered on operator's first launch above 10 recipients. V2 observe-only (status='skipped'); V3 will dispatch multipov review with 3 personas. - personalize_create_engagement_webhook — Register an engagement webhook on a sequence (CRM/Asana V1). Admin-only. Returns signing_secret + key_id once. Domain allowlist enforced. Justification required + audited. - personalize_list_engagement_webhooks — List engagement webhooks on a sequence. Admin-only. No secrets in response. - personalize_disable_engagement_webhook — Soft-disable an engagement webhook. Admin-only. - personalize_rotate_engagement_webhook_secret — Rotate signing_secret + bump key_id. Admin-only. Returns new secret once. Sender dual-signs (current + previous) for a 7-day grace window so receivers update on their own schedule. - personalize_register_recipient_phone — Capture phone consent for iMessage outbound on a recipient (Josh-only v1). Stores phone + consent_method + verbatim consent_disclosure_text + consent_at; audit-logs hashed phone. - personalize_revoke_recipient_phone — Revoke iMessage phone consent (operator-side STOP). Flips phone_consent_for_imessage=false, inserts an imessage suppression row, audit-logs the revoke. Josh-only. - personalize_get_recipient_phone — Read a recipient's phone-consent state + iMessage send history (last_imessage_sent_at, total_imessage_sent). Josh-only. - personalize_list_imessage_outbound — List iMessage outbound rows for a sequence (queued/dispatching/sent/delivered/read/failed/superseded). Phone numbers in the response are SHA-256-hashed per AGENTS.md §7. Josh-only. - personalize_list_address_proposals — List address-change proposals scoped to the calling operator (AUR5). Default status=pending. Each row is the platform's suggestion to swap a recipient's email after a bounce / auto-reply / FBL named a new address. - personalize_approve_address_proposal — Approve a pending address-change proposal — atomically swaps recipients.email, inserts a recipient_address_history row, audit-logs. Optional new_email override (required when the proposal has no extracted address, e.g., AUR4 blind-bounce). - personalize_reject_address_proposal — Reject a pending address-change proposal — leaves recipients.email untouched, audit-logs with the reason. Reason 5-500 chars; feeds AUR8 detection-quality scoring. - personalize_admin_list_operators — List tenant operator roster (Phase 8 admin parity for /admin/operators). Admin-only. Optional `search` substring filter on email. - personalize_admin_queue_snapshot — Tenant-wide send-queue health (Phase 8 admin parity for /admin/queue-health). Returns queue depth, per-operator breaker state, cron freshness, tenant cap headroom. Admin-only. - personalize_admin_audit_search — Admin-flavored convenience wrap over /api/audit (Phase 8 admin parity for /admin/audit). Filters: actor, action, since, before-cursor, limit (default 100, max 500). Payloads may contain hashed PII per §7. - personalize_health — Public health probe (returns ok + iso timestamp). ## Operating rules (summary; full text in agents.md) 1. Suppression check before every add_recipients call. 2. Launches >50 recipients require an approval header on the launch call. - 51–500: confirm: - 501–1,000: multipov: - 1,001+: token: from personalize_request_approval 3. Gov/mil domains auto-skip tracking pixel + link rewrite, server-enforced. 4. CAN-SPAM footer is appended server-side from operators.physical_address. 5. Sender identity is the operator's Gmail; sequences cannot be sent on behalf of someone outside the operators table. 6. State transitions are versioned; CAS conflicts trigger a re-read, never a blind overwrite. ## Architecture ``` Claude → MCP server (stdio) → Worker API (Hono) → Supabase + Gmail API ^ ^ \___ 1-min cron drains queue _/ ```