Use the Supabase MCP server for database operations, authentication management, and storage operations. Use this skill when working with Supabase via MCP tools.
This skill covers using the Supabase MCP server to interact with Supabase projects programmatically, managing databases, authentication, storage, and Edge Functions.
Use Supabase MCP tools when:
Note: For local Supabase development (migrations, type generation, etc.), use the supabase-development skill and Nx targets. Use MCP tools for runtime operations.
The Supabase MCP server provides these tools (prefix: mcp_supabase_):
mcp_supabase_query - Execute SQL queries
Parameters:
sql (required): SQL query to executeproject_ref (optional): Supabase project referenceExample usage:
// Select data
mcp_supabase_query({
sql: "SELECT * FROM words WHERE latin LIKE $1 LIMIT 10",
project_ref: "your-project-ref",
});
// Insert data
mcp_supabase_query({
sql: `INSERT INTO bookmarks (user_id, word_id) VALUES ($1, $2)`,
project_ref: "your-project-ref",
});
// Update data
mcp_supabase_query({
sql: "UPDATE users SET last_login = NOW() WHERE id = $1",
project_ref: "your-project-ref",
});
mcp_supabase_select - Select rows from a table
Parameters:
table (required): Table namecolumns (optional): Columns to select (default: '*')filters (optional): WHERE conditionslimit (optional): Maximum rows to returnorder_by (optional): Sort orderproject_ref (optional): Supabase project referenceExample usage:
// Select all columns
mcp_supabase_select({
table: "words",
limit: 10,
});
// Select specific columns with filter
mcp_supabase_select({
table: "bookmarks",
columns: "id, word_id, created_at",
filters: { user_id: "user-uuid-here" },
order_by: "created_at DESC",
});
mcp_supabase_insert - Insert rows into a table
Parameters:
table (required): Table namedata (required): Object or array of objects to insertproject_ref (optional): Supabase project referenceExample usage:
// Insert single row
mcp_supabase_insert({
table: "bookmarks",
data: {
user_id: "user-uuid",
word_id: "amor",
},
});
// Insert multiple rows
mcp_supabase_insert({
table: "words",
data: [
{ latin: "amor", english: "love" },
{ latin: "vita", english: "life" },
],
});
mcp_supabase_update - Update rows in a table
Parameters:
table (required): Table namedata (required): Object with fields to updatefilters (required): WHERE conditionsproject_ref (optional): Supabase project referenceExample usage:
mcp_supabase_update({
table: "users",
data: { last_login: new Date().toISOString() },
filters: { id: "user-uuid" },
});
mcp_supabase_delete - Delete rows from a table
Parameters:
table (required): Table namefilters (required): WHERE conditionsproject_ref (optional): Supabase project referenceExample usage:
mcp_supabase_delete({
table: "bookmarks",
filters: { user_id: "user-uuid", word_id: "amor" },
});
mcp_supabase_rpc - Call a stored procedure
Parameters:
function_name (required): RPC function nameparams (optional): Function parametersproject_ref (optional): Supabase project referenceExample usage:
// Call RPC function
mcp_supabase_rpc({
function_name: "search_words",
params: {
query: "amor",
limit_count: 20,
},
});
mcp_supabase_list_users - List authentication users
Parameters:
page (optional): Page numberper_page (optional): Users per pageproject_ref (optional): Supabase project referenceExample usage:
mcp_supabase_list_users({
page: 1,
per_page: 50,
});
mcp_supabase_get_user - Get user by ID
Parameters:
user_id (required): User UUIDproject_ref (optional): Supabase project referenceExample usage:
mcp_supabase_get_user({
user_id: "user-uuid-here",
});
mcp_supabase_create_user - Create a new user
Parameters:
email (required): User emailpassword (required): User passworduser_metadata (optional): Additional metadataproject_ref (optional): Supabase project referenceExample usage:
mcp_supabase_create_user({
email: "[email protected]",
password: "secure-password",
user_metadata: {
name: "John Doe",
role: "user",
},
});
mcp_supabase_delete_user - Delete a user
Parameters:
user_id (required): User UUIDproject_ref (optional): Supabase project referenceExample usage:
mcp_supabase_delete_user({
user_id: "user-uuid-here",
});
mcp_supabase_upload_file - Upload a file to Storage
Parameters:
bucket (required): Storage bucket namepath (required): File path in bucketfile (required): File data (Buffer or string)content_type (optional): MIME typeproject_ref (optional): Supabase project referenceExample usage:
mcp_supabase_upload_file({
bucket: "avatars",
path: "user-123/profile.jpg",
file: fileBuffer,
content_type: "image/jpeg",
});
mcp_supabase_download_file - Download a file from Storage
Parameters:
bucket (required): Storage bucket namepath (required): File path in bucketproject_ref (optional): Supabase project referenceExample usage:
mcp_supabase_download_file({
bucket: "avatars",
path: "user-123/profile.jpg",
});
mcp_supabase_delete_file - Delete a file from Storage
Parameters:
bucket (required): Storage bucket namepath (required): File path in bucketproject_ref (optional): Supabase project referenceExample usage:
mcp_supabase_delete_file({
bucket: "avatars",
path: "user-123/old-profile.jpg",
});
mcp_supabase_list_files - List files in a bucket
Parameters:
bucket (required): Storage bucket namepath (optional): Directory path (default: root)project_ref (optional): Supabase project referenceExample usage:
mcp_supabase_list_files({
bucket: "avatars",
path: "user-123/",
});
Check table structure:
// Query information schema
mcp_supabase_query({
sql: `
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = $1
`,
project_ref: "your-project",
});
Query data:
mcp_supabase_select({
table: "words",
columns: "id, latin, english",
filters: { latin: { like: "am%" } },
limit: 10,
});
Process results: Handle returned data and errors appropriately
List users:
const users = mcp_supabase_list_users({
per_page: 100,
});
Get specific user:
const user = mcp_supabase_get_user({
user_id: "user-uuid",
});
Update user metadata:
mcp_supabase_query({
sql: `
UPDATE auth.users
SET raw_user_meta_data = raw_user_meta_data || $1::jsonb
WHERE id = $2
`,
project_ref: "your-project",
});
Prepare file:
const fileBuffer = await fs.readFile("path/to/file.jpg");
Upload to Storage:
mcp_supabase_upload_file({
bucket: "images",
path: `uploads/${Date.now()}-file.jpg`,
file: fileBuffer,
content_type: "image/jpeg",
});
Get public URL:
mcp_supabase_query({
sql: `
SELECT storage.url($1, $2) as public_url
`,
project_ref: "your-project",
});
Search words:
mcp_supabase_rpc({
function_name: "search_words",
params: {
query: "amor",
limit_count: 20,
},
project_ref: "lexico-project-ref",
});
Get user bookmarks:
mcp_supabase_select({
table: "bookmarks",
columns: "word_id, created_at",
filters: { user_id: "user-uuid" },
order_by: "created_at DESC",
project_ref: "lexico-project-ref",
});
Add bookmark:
mcp_supabase_insert({
table: "bookmarks",
data: {
user_id: "user-uuid",
word_id: "amor",
},
project_ref: "lexico-project-ref",
});
MCP tools use Supabase service role key for authentication. NEVER expose service role key in client code.
MCP tools bypass RLS policies by default (service role). For user-scoped operations:
Use RPC functions with auth checks:
CREATE FUNCTION get_user_bookmarks()
RETURNS TABLE (...) AS $$
BEGIN
RETURN QUERY
SELECT * FROM bookmarks
WHERE user_id = auth.uid();
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
Set user context in queries:
mcp_supabase_query({
sql: `
SET LOCAL role TO authenticated;
SET LOCAL request.jwt.claims TO '{"sub": "user-uuid"}';
SELECT * FROM bookmarks;
`,
});
Always validate inputs before passing to MCP tools:
// ❌ Bad - SQL injection risk
const userInput = req.body.query;
mcp_supabase_query({
sql: `SELECT * FROM words WHERE latin = '${userInput}'`,
});
// ✅ Good - Parameterized query
const userInput = req.body.query;
mcp_supabase_query({
sql: "SELECT * FROM words WHERE latin = $1",
params: [userInput],
});
Permission denied:
try {
await mcp_supabase_select({ table: "private_table" });
} catch (error) {
if (error.message.includes("permission denied")) {
// Handle RLS policy violation
}
}
Row not found:
const result = await mcp_supabase_select({
table: "words",
filters: { id: "nonexistent" },
});
if (!result.data || result.data.length === 0) {
// Handle not found
}
Unique constraint violation:
try {
await mcp_supabase_insert({
table: "bookmarks",
data: { user_id: "uuid", word_id: "amor" },
});
} catch (error) {
if (error.message.includes("unique constraint")) {
// Bookmark already exists
}
}
Query performance depends on database indexes:
-- Create index for common queries
CREATE INDEX idx_bookmarks_user_id ON bookmarks(user_id);
CREATE INDEX idx_words_latin ON words(latin);
Always use limit to prevent large result sets:
mcp_supabase_select({
table: "words",
limit: 100, // Prevent fetching millions of rows
});
Instead of multiple round trips:
// ❌ Multiple calls
const words = await mcp_supabase_select({ table: "words" });
for (const word of words.data) {
const examples = await mcp_supabase_select({
table: "examples",
filters: { word_id: word.id },
});
}
// ✅ Single RPC call
const results = await mcp_supabase_rpc({
function_name: "get_words_with_examples",
});
Use array operations for bulk inserts:
// Insert multiple rows at once
mcp_supabase_insert({
table: "words",
data: [
{ latin: "amor", english: "love" },
{ latin: "vita", english: "life" },
{ latin: "pax", english: "peace" },
],
});
Connection errors:
Query timeout:
RLS policy violations:
Type mismatches: