Supabase
PostgreSQL database operations with real-time features.
Provider: Supabase
Authentication: API Key required
Category: Database & Storage
Credit Cost: 1 credit per operation
Overview
Supabase tools provide full CRUD (Create, Read, Update, Delete) operations on your Supabase PostgreSQL tables. Perfect for storing application data, building data pipelines, and integrating database operations into AI workflows.
Setup
Get Supabase Credentials
- Go to your Supabase Dashboard
- Select your project (or create a new one)
- Navigate to Settings → API
- Copy:
- Project URL:
https://xxxxx.supabase.co - anon/public key or service_role key
- Project URL:
Which Key to Use?
- anon key: Respects Row Level Security (RLS) policies
- service_role key: Bypasses RLS (use for admin operations)
Add to Reeva
- Dashboard → Accounts → Add Account
- Select Supabase
- Fill in:
- Supabase URL: Your project URL
- Supabase Key: Your API key
- Click Save
Available Tools
Read Records
Query records from any table with filtering, sorting, and pagination.
Tool ID: supabase_read_records
Credit Cost: 1 credit
Parameters:
table(string, required): Table namecolumns(string, optional): Comma-separated column names or*for all- Default:
"*" - Example:
"id,name,email"
- Default:
filters(object, optional): Key-value pairs for filtering- Supports operators:
eq,neq,gt,gte,lt,lte,like,ilike,in,is
- Supports operators:
limit(integer, optional): Maximum number of records- Default: 100
- Range: 1-1000
offset(integer, optional): Number of records to skip- Default: 0
order_by(object, optional): Sorting options- Format:
{"column_name": "asc|desc"}
- Format:
Response:
{
"data": [
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"age": 30,
"created_at": "2025-11-22T10:30:00.000Z"
},
{
"id": 2,
"name": "Jane Smith",
"email": "jane@example.com",
"age": 25,
"created_at": "2025-11-22T11:00:00.000Z"
}
],
"count": 2
}
Example Usage:
# Python - Basic query
response = client.call_tool(
name="supabase_read_records",
arguments={
"table": "users",
"columns": "id,name,email",
"limit": 10
}
)
for user in response["data"]:
print(f"{user['name']}: {user['email']}")
// TypeScript - With filters and sorting
const response = await client.callTool({
name: "supabase_read_records",
arguments: {
table: "orders",
columns: "id,customer_id,total,status",
filters: {
"status": {"eq": "pending"},
"total": {"gte": 100}
},
order_by: {"created_at": "desc"},
limit: 50
}
});
# cURL - Paginated query
curl -X POST https://api.joinreeva.com/mcp/server_YOUR_ID \
-H "Authorization: Bearer mcpk_your_key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "supabase_read_records",
"arguments": {
"table": "products",
"limit": 20,
"offset": 40
}
},
"id": 1
}'
Filter Operators:
| Operator | Description | Example |
|---|---|---|
eq | Equals | {"status": {"eq": "active"}} |
neq | Not equals | {"status": {"neq": "deleted"}} |
gt | Greater than | {"age": {"gt": 18}} |
gte | Greater than or equal | {"price": {"gte": 100}} |
lt | Less than | {"quantity": {"lt": 10}} |
lte | Less than or equal | {"score": {"lte": 50}} |
like | Pattern match (case-sensitive) | {"name": {"like": "%john%"}} |
ilike | Pattern match (case-insensitive) | {"email": {"ilike": "%@gmail.com"}} |
in | In array | {"status": {"in": ["active", "pending"]}} |
is | Is null/not null | {"deleted_at": {"is": null}} |
Use Cases:
- Query application data
- Build dashboards and reports
- Search and filter records
- Paginated data retrieval
Create Records
Insert one or multiple records into a table.
Tool ID: supabase_create_records
Credit Cost: 1 credit
Parameters:
table(string, required): Table namerecords(object or array, required): Single record object or array of records
Response:
{
"data": [
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"created_at": "2025-11-22T10:30:00.000Z"
}
],
"count": 1
}
Example Usage:
# Python - Create single record
response = client.call_tool(
name="supabase_create_records",
arguments={
"table": "users",
"records": {
"name": "John Doe",
"email": "john@example.com",
"age": 30
}
}
)
print(f"Created user with ID: {response['data'][0]['id']}")
// TypeScript - Batch insert
const response = await client.callTool({
name: "supabase_create_records",
arguments: {
table: "products",
records: [
{name: "Product A", price: 29.99, category: "electronics"},
{name: "Product B", price: 49.99, category: "electronics"},
{name: "Product C", price: 19.99, category: "accessories"}
]
}
});
console.log(`Created ${response.count} products`);
# cURL - Create with all fields
curl -X POST https://api.joinreeva.com/mcp/server_YOUR_ID \
-H "Authorization: Bearer mcpk_your_key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "supabase_create_records",
"arguments": {
"table": "orders",
"records": {
"customer_id": 123,
"total": 150.00,
"status": "pending",
"items": ["item1", "item2"]
}
}
},
"id": 1
}'
Use Cases:
- Store form submissions
- Log events and activities
- Save scraped data
- Create user records
- Batch data import
Update Records
Update existing records based on filter conditions.
Tool ID: supabase_update_records
Credit Cost: 1 credit
Parameters:
table(string, required): Table nameupdates(object, required): Fields to update with new valuesfilters(object, required): Conditions to identify records to update
Response:
{
"data": [
{
"id": 1,
"name": "John Doe",
"age": 31,
"updated_at": "2025-11-22T15:45:00.000Z"
}
],
"count": 1
}
Example Usage:
# Python - Update by ID
response = client.call_tool(
name="supabase_update_records",
arguments={
"table": "users",
"updates": {
"age": 31,
"last_login": "2025-11-22T10:30:00Z"
},
"filters": {
"id": {"eq": 1}
}
}
)
// TypeScript - Bulk update by condition
const response = await client.callTool({
name: "supabase_update_records",
arguments: {
table: "orders",
updates: {
status: "shipped",
shipped_at: new Date().toISOString()
},
filters: {
status: {eq: "processing"},
created_at: {lt: "2025-11-20"}
}
}
});
console.log(`Updated ${response.count} orders`);
# cURL - Update status
curl -X POST https://api.joinreeva.com/mcp/server_YOUR_ID \
-H "Authorization: Bearer mcpk_your_key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "supabase_update_records",
"arguments": {
"table": "tasks",
"updates": {"status": "completed"},
"filters": {"id": {"eq": 42}}
}
},
"id": 1
}'
Use Cases:
- Update record status
- Modify user profiles
- Track last activity
- Bulk status changes
- Soft deletes
Warning: Updates affect ALL records matching the filter. Be specific with filters.
Delete Records
Remove records based on filter conditions.
Tool ID: supabase_delete_records
Credit Cost: 1 credit
Parameters:
table(string, required): Table namefilters(object, required): Conditions to identify records to delete
Response:
{
"data": [
{
"id": 1,
"name": "Deleted User",
"email": "deleted@example.com"
}
],
"count": 1
}
Example Usage:
# Python - Delete by ID
response = client.call_tool(
name="supabase_delete_records",
arguments={
"table": "users",
"filters": {
"id": {"eq": 1}
}
}
)
print(f"Deleted {response['count']} record(s)")
// TypeScript - Delete old records
const response = await client.callTool({
name: "supabase_delete_records",
arguments: {
table: "sessions",
filters: {
expires_at: {lt: "2025-11-01"}
}
}
});
# cURL - Delete by condition
curl -X POST https://api.joinreeva.com/mcp/server_YOUR_ID \
-H "Authorization: Bearer mcpk_your_key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "supabase_delete_records",
"arguments": {
"table": "temp_data",
"filters": {"created_at": {"lt": "2025-11-01"}}
}
},
"id": 1
}'
Use Cases:
- Remove old/expired records
- Clean up test data
- Delete user accounts
- Purge temporary data
Warning: Deletions are permanent. Consider soft deletes (updating a deleted_at field) for important data.
Common Patterns
Data Pipeline
# Scrape data and store in Supabase
def scrape_and_store(urls):
for url in urls:
# Scrape content
content = client.call_tool(
name="web_scraper_Get_Website_Markdown",
arguments={"url": url}
)
# Store in database
client.call_tool(
name="supabase_create_records",
arguments={
"table": "scraped_content",
"records": {
"url": url,
"title": content["title"],
"content": content["markdown"],
"scraped_at": datetime.now().isoformat()
}
}
)
CRUD Operations
# Complete CRUD example
class DataManager:
def create(self, table, data):
return client.call_tool(
name="supabase_create_records",
arguments={"table": table, "records": data}
)
def read(self, table, filters=None, limit=100):
args = {"table": table, "limit": limit}
if filters:
args["filters"] = filters
return client.call_tool(
name="supabase_read_records",
arguments=args
)
def update(self, table, id, updates):
return client.call_tool(
name="supabase_update_records",
arguments={
"table": table,
"updates": updates,
"filters": {"id": {"eq": id}}
}
)
def delete(self, table, id):
return client.call_tool(
name="supabase_delete_records",
arguments={
"table": table,
"filters": {"id": {"eq": id}}
}
)
Activity Logging
# Log user activities
def log_activity(user_id, action, details):
return client.call_tool(
name="supabase_create_records",
arguments={
"table": "activity_logs",
"records": {
"user_id": user_id,
"action": action,
"details": details,
"timestamp": datetime.now().isoformat(),
"ip_address": get_client_ip()
}
}
)
Pagination
# Paginate through all records
def get_all_records(table, batch_size=100):
all_records = []
offset = 0
while True:
response = client.call_tool(
name="supabase_read_records",
arguments={
"table": table,
"limit": batch_size,
"offset": offset,
"order_by": {"id": "asc"}
}
)
records = response["data"]
if not records:
break
all_records.extend(records)
offset += batch_size
return all_records
Search and Analytics
# Search with multiple conditions
def search_orders(status=None, min_total=None, customer_id=None):
filters = {}
if status:
filters["status"] = {"eq": status}
if min_total:
filters["total"] = {"gte": min_total}
if customer_id:
filters["customer_id"] = {"eq": customer_id}
return client.call_tool(
name="supabase_read_records",
arguments={
"table": "orders",
"filters": filters,
"order_by": {"created_at": "desc"}
}
)
Best Practices
Security
- Use RLS (Row Level Security) policies
- Use
anonkey for user-facing operations - Use
service_rolekey only for admin tasks - Never expose service_role key in client code
Performance
- Select only needed columns
- Use appropriate filters to reduce data
- Implement pagination for large datasets
- Add database indexes for filtered columns
Data Integrity
- Validate data before inserting
- Use specific filters for updates/deletes
- Implement soft deletes for important data
- Add timestamps for auditing
Error Handling
- Check for empty results
- Handle constraint violations
- Validate filter syntax
- Log failed operations
Troubleshooting
"Table not found" Error
Cause: Table doesn't exist or no access
Solutions:
- Verify table name spelling
- Check RLS policies allow access
- Ensure API key has table permissions
"Column not found" Error
Cause: Querying non-existent column
Solutions:
- Check column name spelling
- Verify column exists in table
- Use
*to see all available columns
"Unique constraint violation" Error
Cause: Duplicate value in unique column
Solutions:
- Check for existing records before insert
- Use upsert pattern if available
- Handle error and retry with different value
Empty Results
Cause: No matching records or filter issue
Solutions:
- Verify filter syntax is correct
- Check filter values match data types
- Test with broader filters first
- Ensure data exists in table
Permission Denied
Cause: RLS policy blocking access
Solutions:
- Check RLS policies on table
- Verify API key permissions
- Use service_role key for admin access
- Ensure user context is correct
Related Tools
- Notion - Alternative structured data storage
- Mem0 - AI memory storage
- Web Scraper - Scrape data to store
- Perplexity - Research data to store
See Also
- Creating Custom Tools - Pre-configure table settings
- Managing Credentials - Store Supabase credentials
- All Tools - Complete tool catalog