Part of WebJamApps/web-jam-back#818. Depends on the web-jam-back venue + outreach + template APIs (all shipped/live).
Note: the cron half originally tracked here is DONE + LIVE (PR #102; Deno Deploy app webjam-outreach-cron, daily 9am-ET → /outreach/advance). This issue now covers only the MCP server.
⏸ DEFERRED (2026-06-24): lower priority than #825 gmail reply-detection and #821 xlsx cutover — do those first. The venue-MCP is a convenience (the AdminVenues web UI #1134 already covers venue management from the phone browser), so it waits.
Stand up an MCP server so the phone Claude app (Sonnet) can manage venues + templates and run the propose→approve→send booking flow conversationally. Phone Sonnet has no shell/HTTP, only MCP connectors, so this is its only viable path.
✅ Decisions (locked 2026-06-24)
- Auth = OAuth 2.1 + PKCE. Forced by the Claude app: its custom-connector UI does not support user-pasted bearer tokens or API keys (only OAuth fields appear;
static_bearer and ?token= are explicitly unsupported as of 2026). A private connector therefore must use OAuth. (anthropics/claude-ai-mcp#112, Claude connector auth docs)
- Full CRUD on venues AND templates. An interim "read-only reporting" scope was considered to justify a light presented-key door — superseded: since the Claude app forces full OAuth either way, there's no auth saving in staying read-only, so expose the full toolset. Writes go through web-jam-back's caps + are stamped
actor: sonnet.
- Outreach = propose → human-approve → send (NOT autonomous send). Sonnet proposes the candidate target list; Josh approves/trims it in chat; only then does Sonnet send the approved batch. This is the same human-in-loop approval the AdminVenues UI does, moved into chat — consistent with the #844 redesign after the mis-send incident.
- Delete = soft-delete (archive, recoverable per #818 locked-decision §4); hard purge stays admin-UI-only.
Shape
- New
web-jam-tools/venue-mcp/ — stateless Streamable-HTTP MCP server (official TS MCP SDK on Deno), deployed to Deno Deploy (deploy-only-from-main; must pass the CI security gate).
- OAuth 2.1 + PKCE in front; once authorized, the server forwards to web-jam-back with the shared
web-jam-llm AI-agent token (Deno Deploy env var), stamping actor: sonnet on writes. web-jam-back enforces venue:* / outreach:* / template:* — do not duplicate authz here.
- Register as a remote connector in the phone Claude app (OAuth flow on connect).
Tools
Venue — full CRUD
list_venues — filtered: outreachEligible, bookingStatus, interested, needs-contact-verification, etc.
search_venue — by name / partial
get_venue — one by name/id
create_venue — upsert/dedupe (web-jam-back natural-key)
update_venue — edit fields / tags
delete_venue — soft-delete (archive, recoverable)
Templates — full CRUD
list_templates — live template copy (cold + returning × 3 types)
get_template — one by type/stage
create_template
update_template — edit copy, add song-recording links directly
delete_template — soft-delete
Outreach — propose → approve → send (human-in-loop)
propose_targets → GET /outreach/candidates (eligible, not-yet-pitched for the dates)
send_batch → POST /outreach/batch (sends ONLY Josh's approved venueIds)
booking_status → GET /outreach (records + status: sent / replied / no-response)
🔴 Hard requirements / safety
- Endpoint must NOT be publicly usable — OAuth-gated; no anonymous access (it holds a privileged token).
- Server refuses any venue that isn't
outreachEligible (core mis-send guard).
autoApprove stays OFF — nothing sends without Josh's explicit in-chat approval; Sonnet never self-approves a batch.
- The AI-agent identity it forwards as holds only venue/outreach/template privileges (minimize blast radius; rotation = remint the token + re-set the env var).
- Must pass the web-jam-tools CI gate (check · lint · fmt · ≥80% coverage · Trivy audit · Semgrep sast).
Part of WebJamApps/web-jam-back#818. Depends on the web-jam-back venue + outreach + template APIs (all shipped/live).
Stand up an MCP server so the phone Claude app (Sonnet) can manage venues + templates and run the propose→approve→send booking flow conversationally. Phone Sonnet has no shell/HTTP, only MCP connectors, so this is its only viable path.
✅ Decisions (locked 2026-06-24)
static_bearerand?token=are explicitly unsupported as of 2026). A private connector therefore must use OAuth. (anthropics/claude-ai-mcp#112, Claude connector auth docs)actor: sonnet.Shape
web-jam-tools/venue-mcp/— stateless Streamable-HTTP MCP server (official TS MCP SDK on Deno), deployed to Deno Deploy (deploy-only-from-main; must pass the CI security gate).web-jam-llmAI-agent token (Deno Deploy env var), stampingactor: sonneton writes. web-jam-back enforcesvenue:*/outreach:*/template:*— do not duplicate authz here.Tools
Venue — full CRUD
list_venues— filtered:outreachEligible,bookingStatus,interested, needs-contact-verification, etc.search_venue— by name / partialget_venue— one by name/idcreate_venue— upsert/dedupe (web-jam-back natural-key)update_venue— edit fields / tagsdelete_venue— soft-delete (archive, recoverable)Templates — full CRUD
list_templates— live template copy (cold + returning × 3 types)get_template— one by type/stagecreate_templateupdate_template— edit copy, add song-recording links directlydelete_template— soft-deleteOutreach — propose → approve → send (human-in-loop)
propose_targets→GET /outreach/candidates(eligible, not-yet-pitched for the dates)send_batch→POST /outreach/batch(sends ONLY Josh's approved venueIds)booking_status→GET /outreach(records + status: sent / replied / no-response)🔴 Hard requirements / safety
outreachEligible(core mis-send guard).autoApprovestays OFF — nothing sends without Josh's explicit in-chat approval; Sonnet never self-approves a batch.