Skip to main content

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

  1. Go to your Supabase Dashboard
  2. Select your project (or create a new one)
  3. Navigate to SettingsAPI
  4. Copy:
    • Project URL: https://xxxxx.supabase.co
    • anon/public key or service_role key

Which Key to Use?

  • anon key: Respects Row Level Security (RLS) policies
  • service_role key: Bypasses RLS (use for admin operations)

Add to Reeva

  1. Dashboard → AccountsAdd Account
  2. Select Supabase
  3. Fill in:
    • Supabase URL: Your project URL
    • Supabase Key: Your API key
  4. 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 name
  • columns (string, optional): Comma-separated column names or * for all
    • Default: "*"
    • Example: "id,name,email"
  • filters (object, optional): Key-value pairs for filtering
    • Supports operators: eq, neq, gt, gte, lt, lte, like, ilike, in, is
  • 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"}

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:

OperatorDescriptionExample
eqEquals{"status": {"eq": "active"}}
neqNot equals{"status": {"neq": "deleted"}}
gtGreater than{"age": {"gt": 18}}
gteGreater than or equal{"price": {"gte": 100}}
ltLess than{"quantity": {"lt": 10}}
lteLess than or equal{"score": {"lte": 50}}
likePattern match (case-sensitive){"name": {"like": "%john%"}}
ilikePattern match (case-insensitive){"email": {"ilike": "%@gmail.com"}}
inIn array{"status": {"in": ["active", "pending"]}}
isIs 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 name
  • records (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 name
  • updates (object, required): Fields to update with new values
  • filters (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 name
  • filters (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 anon key for user-facing operations
  • Use service_role key 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

See Also