Skip to content

feat(venue-mcp): Deno MCP server wrapping the venue API (auth'd, Deno Deploy) #100

Description

@JoshuaVSherman

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_venuesoft-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_templatesoft-delete

Outreach — propose → approve → send (human-in-loop)

  • propose_targetsGET /outreach/candidates (eligible, not-yet-pitched for the dates)
  • send_batchPOST /outreach/batch (sends ONLY Josh's approved venueIds)
  • booking_statusGET /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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions