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)| Component | Technology | Purpose |
|---|---|---|
| Database | Supabase Postgres | All application data, change log, RLS |
| Auth | Supabase Auth + Google OAuth | User authentication, agent API keys |
| Media Storage | Supabase Storage | Articles, video clips, audio clips |
| MCP Server | Cloudflare Worker (TypeScript) | Agent-facing tool interface over SSE |
| Email Sync | Cloudflare Worker Cron + Gmail API | Ingest emails from shared inbox |
| Notifications | Slack Webhooks | Alerts 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 tochange_logwith full before/after state - Agent identity tracking — Every mutation records
user_id,agent_id, andagent_session - Single company — No multi-tenancy; simple RLS (all authenticated users see everything)
Prerequisites
Install the required CLI tools:
npm install -g supabase wranglerYou 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
supabase startThis starts a local Postgres database, auth server, and storage server using Docker.
2. Apply migrations and seed data
supabase db resetThis 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
cd mcp-server
npm install
npm run dev # runs wrangler devThe 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
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
supabase db resetPush to production
supabase db pushMigrations 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 accesszod— 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.tsAdding a new tool
- Add the handler function in the appropriate
src/tools/*.tsfile - Define a Zod input schema for validation
- Register the tool in
src/index.ts - 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
cd mcp-server
wrangler deploySet Cloudflare Worker secrets
wrangler secret put SUPABASE_URL
wrangler secret put SUPABASE_SERVICE_ROLE_KEY
wrangler secret put SLACK_WEBHOOK_URLFor email processing, also set:
wrangler secret put GMAIL_CLIENT_ID
wrangler secret put GMAIL_CLIENT_SECRET
wrangler secret put GMAIL_REFRESH_TOKEN
wrangler secret put ANTHROPIC_API_KEYFurther Reading
- Product Specification — full data model and tool inventory
- Development Guide — coding conventions, common tasks, and project guidelines