Skip to content

Supabase MCP Integration Guide

This guide shows how to use the Supabase Model Context Protocol (MCP) tools with your Juddges App database.

πŸ”§ Available MCP Tools

Based on the MCP tools available in your Claude Code session, you can interact with your Supabase database programmatically:

Database Schema Operations

  1. mcp__supabase__list_tables - List all tables in your database
  2. mcp__supabase__list_extensions - List PostgreSQL extensions (pgvector, etc.)
  3. mcp__supabase__list_migrations - View migration history

Data Operations

  1. mcp__supabase__execute_sql - Run SQL queries (SELECT, UPDATE, DELETE)
  2. mcp__supabase__apply_migration - Apply new database migrations

Monitoring & Analytics

  1. mcp__supabase__get_logs - View service logs (API, Postgres, Auth, etc.)
  2. mcp__supabase__get_advisors - Get security & performance recommendations

Project Management

  1. mcp__supabase__get_project_url - Get your project's API URL
  2. mcp__supabase__get_publishable_keys - Get API keys for client access

TypeScript Type Generation

  1. mcp__supabase__generate_typescript_types - Generate TypeScript types from schema

Branching (Development Environments)

  1. mcp__supabase__create_branch - Create development branch
  2. mcp__supabase__list_branches - List all branches
  3. mcp__supabase__merge_branch - Merge branch to production

πŸ“ Common Usage Examples

Example 1: List Tables

Check what tables exist in your database:

// Using MCP tool
mcp__supabase__list_tables({
  schemas: ["public"]
})

// Expected response:
// Tables: judgments, auth.users, ...

Example 2: Query Judgments

Retrieve judgments from your database:

-- Using execute_sql tool
SELECT
  id,
  case_number,
  jurisdiction,
  title,
  decision_date,
  court_name
FROM judgments
WHERE jurisdiction = 'PL'
ORDER BY decision_date DESC
LIMIT 10;

Example 3: Count by Jurisdiction

Get statistics on your judgment data:

SELECT
  jurisdiction,
  COUNT(*) as total_judgments,
  COUNT(DISTINCT court_name) as unique_courts,
  MIN(decision_date) as earliest_date,
  MAX(decision_date) as latest_date
FROM judgments
GROUP BY jurisdiction;

Search judgments by vector similarity:

-- First, you'd generate an embedding for the query
-- Then search using the function we created:
SELECT * FROM search_judgments_by_embedding(
  ARRAY[0.1, 0.2, ...]::vector(768),   -- Your query embedding
  0.7,  -- Similarity threshold
  10,   -- Number of results
  'PL'  -- Filter by jurisdiction (optional)
);

Search judgments using PostgreSQL full-text search:

SELECT * FROM search_judgments_by_text(
  'criminal appeal tax liability',  -- Search query
  'UK',  -- Filter by jurisdiction (optional)
  20     -- Number of results
);

Example 6: Get Recent Judgments

Query the most recently added judgments:

SELECT
  case_number,
  jurisdiction,
  title,
  decision_date,
  created_at
FROM judgments
ORDER BY created_at DESC
LIMIT 20;

Example 7: Check Embeddings Status

See how many judgments have embeddings:

SELECT
  jurisdiction,
  COUNT(*) as total,
  COUNT(embedding) as with_embeddings,
  ROUND(100.0 * COUNT(embedding) / COUNT(*), 2) as percentage
FROM judgments
GROUP BY jurisdiction;

Example 8: Search by Keywords

Find judgments matching specific keywords:

SELECT
  case_number,
  title,
  keywords,
  jurisdiction
FROM judgments
WHERE keywords && ARRAY['tax', 'liability']  -- Overlaps with keywords
ORDER BY decision_date DESC
LIMIT 10;

πŸ” Security & Access Control

Row Level Security (RLS)

If you want to enable RLS for user-specific access:

-- Enable RLS on judgments table
ALTER TABLE judgments ENABLE ROW LEVEL SECURITY;

-- Allow public read access (all users can view judgments)
CREATE POLICY "Allow public read access"
ON judgments
FOR SELECT
TO public
USING (true);

-- Only authenticated users can insert
CREATE POLICY "Authenticated users can insert"
ON judgments
FOR INSERT
TO authenticated
WITH CHECK (true);

-- Only service role can update/delete
CREATE POLICY "Service role full access"
ON judgments
FOR ALL
TO service_role
USING (true);

API Key Management

// Get your publishable keys
mcp__supabase__get_publishable_keys()

// Returns:
// - anon key (safe for client-side)
// - service_role key (server-side only, never expose)

πŸ“Š Monitoring & Performance

View API Logs

// Check API request logs
mcp__supabase__get_logs({
  service: "api"  // Options: api, postgres, auth, storage, realtime
})

Get Security Advisors

// Check for security issues
mcp__supabase__get_advisors({
  type: "security"  // Options: security, performance
})

// Common advisories:
// - Missing RLS policies
// - Unindexed foreign keys
// - Exposed service role keys

Performance Optimization

-- Check query performance
EXPLAIN ANALYZE
SELECT * FROM judgments
WHERE jurisdiction = 'UK'
AND decision_date > '2020-01-01';

-- Check index usage
SELECT
  schemaname,
  tablename,
  indexname,
  idx_scan as scans,
  idx_tup_read as tuples_read
FROM pg_stat_user_indexes
WHERE schemaname = 'public'
ORDER BY idx_scan DESC;

πŸ”„ Development Workflow

Create Development Branch

For testing schema changes without affecting production:

// Create a development branch
mcp__supabase__create_branch({
  name: "develop",
  confirm_cost_id: "cost_id_from_confirmation"
})

// List branches
mcp__supabase__list_branches()

// Work on your branch, then merge when ready
mcp__supabase__merge_branch({
  branch_id: "your_branch_id"
})

🎨 TypeScript Type Generation

Generate TypeScript types for your frontend:

// Generate types from your schema
mcp__supabase__generate_typescript_types()

// Save to file: frontend/types/supabase.ts
// Use in your Next.js app:
// import { Database } from '@/types/supabase'

πŸš€ Advanced Queries

Complex Search with Filters

SELECT
  j.id,
  j.case_number,
  j.title,
  j.decision_date,
  j.court_name,
  ts_rank(
    to_tsvector('english', j.full_text),
    plainto_tsquery('english', 'criminal liability')
  ) as relevance
FROM judgments j
WHERE
  j.jurisdiction = 'UK'
  AND j.decision_date BETWEEN '2020-01-01' AND '2024-12-31'
  AND j.case_type = 'Criminal'
  AND to_tsvector('english', j.full_text) @@
      plainto_tsquery('english', 'criminal liability')
ORDER BY relevance DESC, j.decision_date DESC
LIMIT 20;

Aggregate Statistics

SELECT
  DATE_TRUNC('year', decision_date) as year,
  jurisdiction,
  court_name,
  COUNT(*) as judgment_count
FROM judgments
WHERE decision_date IS NOT NULL
GROUP BY year, jurisdiction, court_name
ORDER BY year DESC, judgment_count DESC;

Similar Cases (Vector Similarity)

-- Find cases similar to a specific case
WITH target_case AS (
  SELECT embedding
  FROM judgments
  WHERE case_number = 'I ACa 123/21'
)
SELECT
  j.case_number,
  j.title,
  1 - (j.embedding <=> tc.embedding) as similarity
FROM judgments j, target_case tc
WHERE j.embedding IS NOT NULL
  AND j.case_number != 'I ACa 123/21'
ORDER BY j.embedding <=> tc.embedding
LIMIT 10;

πŸ› οΈ Maintenance Tasks

Vacuum and Analyze

Keep your database performant:

-- Vacuum to reclaim storage
VACUUM ANALYZE judgments;

-- Update statistics
ANALYZE judgments;

Check Database Size

SELECT
  pg_size_pretty(pg_database_size(current_database())) as db_size,
  pg_size_pretty(pg_relation_size('judgments')) as judgments_table_size,
  pg_size_pretty(pg_indexes_size('judgments')) as judgments_indexes_size;

Backup Data

-- Export to JSON (use execute_sql with COPY TO)
COPY (
  SELECT json_agg(t)
  FROM (
    SELECT * FROM judgments
    WHERE jurisdiction = 'PL'
    LIMIT 100
  ) t
) TO '/tmp/polish_judgments_backup.json';

πŸ“š Resources

  • Supabase Docs: https://supabase.com/docs
  • PostgreSQL Docs: https://www.postgresql.org/docs/
  • pgvector Docs: https://github.com/pgvector/pgvector
  • MCP Specification: https://modelcontextprotocol.io/

Pro Tip: Use the MCP tools in your Claude Code sessions to quickly query and manage your Juddges database without leaving your development environment!