Skip to content

Developer Setup

This guide covers the technical architecture and local development setup for PR Tracker.

Architecture Overview

AI Agents (Claude Cowork, Claude Code)

        │  MCP over SSE

Cloudflare Worker (TypeScript)
   - MCP server
   - Auth validation
   - Tool handlers
   - Email sync (cron)


Supabase
   - Postgres database
   - Google OAuth (Auth)
   - Media file storage (Storage)
   - Row-level security


Slack (webhook notifications)
ComponentTechnologyPurpose
DatabaseSupabase PostgresAll application data, change log, RLS
AuthSupabase Auth + Google OAuthUser authentication, agent API keys
Media StorageSupabase StorageArticles, video clips, audio clips
MCP ServerCloudflare Worker (TypeScript)Agent-facing tool interface over SSE
Email SyncCloudflare Worker Cron + Gmail APIIngest emails from shared inbox
NotificationsSlack WebhooksAlerts on opportunity changes

Key Design Decisions

  • Agent-first, no GUI — MCP tools are the only interface
  • Non-destructive — No hard deletes; soft delete via archived_at; all mutations logged to change_log with full before/after state
  • Agent identity tracking — Every mutation records user_id, agent_id, and agent_session
  • Single company — No multi-tenancy; simple RLS (all authenticated users see everything)

Prerequisites

Install the required CLI tools:

bash
npm install -g supabase wrangler

You also need:

  • Node.js 18+
  • A Supabase account (for production) or Docker (for local Supabase)
  • A Cloudflare account (for deployment)

Local Development

1. Start Supabase locally

bash
supabase start

This starts a local Postgres database, auth server, and storage server using Docker.

2. Apply migrations and seed data

bash
supabase db reset

This runs all migrations in supabase/migrations/ and then supabase/seed.sql. The seed data creates the default "General" campaign and any other baseline records.

3. Start the MCP server

bash
cd mcp-server
npm install
npm run dev  # runs wrangler dev

The MCP server will be available locally for testing tool calls.

4. Set up environment variables

Create a .env.local file in the project root (not committed to git):

SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=<from supabase start output>
SUPABASE_SERVICE_ROLE_KEY=<from supabase start output>

Database Migrations

All schema changes go through Supabase migrations. Never modify the database directly.

Create a new migration

bash
supabase migration new <description>

This creates a new timestamped SQL file in supabase/migrations/.

Write the migration

Edit the generated file. Follow these conventions:

  • Table names are singular snake_case (e.g., outlet, contact_outlet)
  • Use UUIDs for all primary keys (gen_random_uuid())
  • All tables with user data get: archived_at, created_at, updated_at
  • All tables get the log_change() trigger
  • Use enums for fixed sets (channel_type, opportunity_stage)
  • Use JSONB for flexible attributes
  • Index foreign keys and commonly filtered columns

Test locally

bash
supabase db reset

Push to production

bash
supabase db push

Migrations are forward-only. If you need to undo something, create a new migration that reverses the change. Never drop tables — archive or deprecate them instead.

MCP Server Development

The MCP server is a Cloudflare Worker written in TypeScript. It uses:

  • @modelcontextprotocol/sdk — MCP TypeScript SDK
  • @supabase/supabase-js — Database access
  • zod — Input validation

Project structure

mcp-server/src/
├── index.ts        # Worker entry, MCP server setup
├── auth.ts         # API key validation, session context
├── db.ts           # Supabase client setup
├── types.ts        # Shared TypeScript types
├── email-sync.ts   # Gmail API cron sync
└── tools/          # One file per tool group
    ├── outlets.ts
    ├── contacts.ts
    ├── channels.ts
    ├── campaigns.ts
    ├── opportunities.ts
    ├── coverage.ts
    ├── media.ts
    ├── search.ts
    ├── emails.ts
    ├── notes.ts
    ├── audit.ts
    └── notifications.ts

Adding a new tool

  1. Add the handler function in the appropriate src/tools/*.ts file
  2. Define a Zod input schema for validation
  3. Register the tool in src/index.ts
  4. Test locally with wrangler dev

Each tool handler should:

  • Validate input with Zod
  • Set session context (app.user_id, app.agent_id, app.agent_session)
  • Call Supabase
  • Return structured JSON with meaningful error messages

Tool naming conventions

Tool names use snake_case: create_outlet, list_opportunities_by_stage, get_interaction_log.

Deployment

Deploy the MCP server

bash
cd mcp-server
wrangler deploy

Set Cloudflare Worker secrets

bash
wrangler secret put SUPABASE_URL
wrangler secret put SUPABASE_SERVICE_ROLE_KEY
wrangler secret put SLACK_WEBHOOK_URL

For email processing, also set:

bash
wrangler secret put GMAIL_CLIENT_ID
wrangler secret put GMAIL_CLIENT_SECRET
wrangler secret put GMAIL_REFRESH_TOKEN
wrangler secret put ANTHROPIC_API_KEY

Further Reading