supabase-foia-mcp
v1.1.0
Published
Remote MCP server for searching U.S. FOIA statutes via Supabase. Provides hybrid search (BM25 + vector + RRF) with VoyageAI embeddings and reranking.
Maintainers
Readme
Supabase FOIA MCP Server
Remote Model Context Protocol (MCP) server for searching U.S. Freedom of Information Act (FOIA) statutes. Provides hybrid search combining BM25 keyword matching with vector semantic search, powered by VoyageAI embeddings and reranking.
Features
- 🔍 Hybrid Search: BM25 + Vector Similarity + Reciprocal Rank Fusion (RRF)
- 🤖 VoyageAI Integration: voyage-4-large embeddings (1024-dim) + rerank-2
- 📊 2,159+ Statute Sections: Covering 52 U.S. states + federal FOIA
- ⚡ Fast: Sub-500ms search latency (p95)
- 🔐 Authenticated: Supabase JWT with usage tracking
- 💰 Cost-Effective: ~$0.0013 per search
- 📈 Analytics: Built-in usage tracking for grant reporting
- 🌐 Remote: No local database required
Quick Start
Installation
npm install -g @hole/supabase-foia-mcpOr run directly:
npx @hole/supabase-foia-mcpConfiguration
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"supabase-foia": {
"command": "npx",
"args": ["-y", "@hole/supabase-foia-mcp"],
"env": {
"SUPABASE_URL": "https://your-project.supabase.co",
"SUPABASE_SECRET_KEY": "your_secret_key"
}
}
}
}Claude Code
Add to ~/.config/claude/mcp.json:
{
"mcpServers": {
"supabase-foia": {
"command": "npx",
"args": ["-y", "@hole/supabase-foia-mcp"],
"env": {
"SUPABASE_URL": "https://your-project.supabase.co",
"SUPABASE_SECRET_KEY": "your_secret_key"
}
}
}
}With Doppler (Recommended for HOLE Foundation)
{
"mcpServers": {
"supabase-foia": {
"command": "doppler",
"args": [
"run",
"--project", "backend",
"--config", "dev",
"--",
"npx", "-y", "@hole/supabase-foia-mcp"
]
}
}
}Tools
1. search_statutes
Search FOIA statutes using hybrid search (BM25 + vector similarity + VoyageAI rerank-2).
Parameters:
query(string, required): Search querystate(string, optional): 2-letter state code (e.g., "TX", "CA")limit(number, optional): Max results (1-20, default: 5)mode(string, optional): "hybrid", "keyword", or "vector" (default: "hybrid")alpha(number, optional): BM25 weight 0-1 (default: 0.75)threshold(number, optional): Min similarity 0-1 (default: 0.5)
Example:
{
"query": "attorney fees",
"state": "TX",
"limit": 5,
"mode": "hybrid"
}Response:
{
"results": [
{
"state": "TX",
"citation": "TX § 552-022",
"section_title": "CATEGORIES OF PUBLIC INFORMATION",
"content": "...",
"similarity_score": 0.85
}
],
"query": "attorney fees",
"mode": "hybrid",
"total": 5,
"query_time_ms": 345
}2. get_status
Get database status and statistics.
Parameters:
verbose(boolean, optional): Include per-state breakdown
Example:
{
"verbose": true
}Response:
{
"status": "operational",
"database": "Supabase PostgreSQL",
"total_chunks": 2159,
"states": 52,
"state_breakdown": [...]
}3. inspect_section
Get full statute section by citation.
Parameters:
section_number(string, required): Citation (e.g., "TX § 552-001")
Example:
{
"section_number": "TX § 552-001"
}4. find_discrimination
Find statutes with potentially discriminatory residency requirements.
Parameters:
state(string, optional): Filter by state code
Example:
{
"state": "ID"
}Architecture
┌─────────────────────┐
│ Claude Desktop │
│ Claude Code │
│ LangChain Agent │
└──────────┬──────────┘
│ MCP Protocol (stdio)
▼
┌─────────────────────┐
│ MCP Server │
│ (This Package) │
│ Node.js/TS │
└──────────┬──────────┘
│ HTTP + JSON-RPC 2.0
▼
┌─────────────────────┐
│ Supabase Edge Func │
│ foia-search │
└──────────┬──────────┘
│
┌────┴────┐
▼ ▼
┌──────────┐ ┌──────────┐
│PostgreSQL│ │VoyageAI │
│+ pgvector│ │API │
└──────────┘ └──────────┘Use Cases
Legal Research
"Search for attorney fees provisions in California FOIA law"
"Find deadlines for responding to public records requests in Texas"
"What are the exemptions for law enforcement records in Florida?"Compliance Analysis
"Find all states with residency requirements for FOIA requests"
"Compare fee structures across different states"
"Identify states with unusual FOIA provisions"Data Analysis
"Show me database statistics"
"Which states have the most FOIA statute sections?"
"Get the full text of a specific statute section"Integration
LangChain
from langchain.tools import Tool
import requests
import os
class SupabaseFOIASearch:
def __init__(self):
self.url = os.getenv('SUPABASE_URL') + '/functions/v1/foia-search'
self.api_key = os.getenv('SUPABASE_SECRET_KEY')
def search(self, query: str, state: str = None, limit: int = 5):
response = requests.post(
self.url,
headers={
'Authorization': f'Bearer {self.api_key}',
'Content-Type': 'application/json'
},
json={
'jsonrpc': '2.0',
'method': 'search_statutes',
'params': {'query': query, 'state': state, 'limit': limit},
'id': 1
}
)
data = response.json()
if 'error' in data:
raise Exception(data['error']['message'])
return data['result']
client = SupabaseFOIASearch()
foia_tool = Tool(
name="search_foia_statutes",
description="Search U.S. FOIA statutes using hybrid search. Returns relevant statute sections with citations.",
func=lambda q: str(client.search(q))
)Direct HTTP API
curl -X POST https://your-project.supabase.co/functions/v1/foia-search \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "search_statutes",
"params": {
"query": "attorney fees",
"state": "TX",
"limit": 5
},
"id": 1
}'Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| SUPABASE_URL | Yes | Your Supabase project URL |
| SUPABASE_SECRET_KEY | Yes | Supabase service role or secret key |
| SUPABASE_ANON_KEY | No | Alternative to secret key (lower privileges) |
Getting Your Keys
- Go to Supabase Dashboard
- Select your project
- Navigate to Settings → API
- Copy URL and service_role key (or create a new secret key)
Performance
- Search Latency: <500ms (p95)
- Cold Start: ~1-2s (first request)
- Concurrent Users: Unlimited (Edge Functions auto-scale)
- Cost per Search: ~$0.0013 (VoyageAI embedding + rerank)
Data Coverage
- Total Statutes: 2,159 sections
- States: 52 + FEDERAL
- Embeddings: VoyageAI voyage-4-large (1024 dimensions)
- Search Types: Keyword (BM25), Vector (semantic), Hybrid (both + RRF)
States Included: AL, AK, AZ, AR, CA, CO, CT, DE, DC, FL, GA, HI, ID, IL, IN, IA, KS, KY, LA, ME, MD, MA, MI, MN, MS, MO, MT, NE, NV, NH, NJ, NM, NY, NC, ND, OH, OK, OR, PA, RI, SC, SD, TN, TX, UT, VT, VA, WA, WV, WI, WY, FEDERAL
Development
Build from Source
git clone https://github.com/The-HOLE-Foundation/supabase-foia-mcp.git
cd supabase-foia-mcp
npm install
npm run buildRun Locally
export SUPABASE_URL="https://your-project.supabase.co"
export SUPABASE_SECRET_KEY="your_secret_key"
npm startTest
npm testDeployment
Self-Hosted Supabase Setup
See docs/SUPABASE-SETUP.md for complete instructions on:
- Setting up Supabase project
- Deploying Edge Function
- Loading statute data
- Creating vector indexes
Using HOLE Foundation Instance
Contact: [email protected] for access to our hosted instance.
LangSmith Integration
For monitoring and evaluation with LangSmith:
from langsmith import Client
from langchain.callbacks.tracers import LangChainTracer
langsmith_client = Client()
tracer = LangChainTracer(project_name="foia-search")
# Use with LangChain agent
agent.run("Search for attorney fees", callbacks=[tracer])See docs/LANGSMITH.md for complete integration guide.
Contributing
Contributions welcome! Please see CONTRIBUTING.md.
License
MIT License - see LICENSE for details.
Citation
If you use this in research:
@software{supabase_foia_mcp,
title = {Supabase FOIA MCP Server},
author = {HOLE Foundation},
year = {2026},
url = {https://github.com/The-HOLE-Foundation/supabase-foia-mcp}
}Support
- Documentation: docs/
- Issues: GitHub Issues
- Email: [email protected]
- Website: https://theholetruth.org
Related Projects
- transparency-engine: FastAPI backend with LangChain agents
- hole-web-turborepo: Frontend applications
- us-foia-law-library: Ground truth statute data
Built by HOLE Foundation - Defending transparency and accountability through technology.
