@rip-user/rls-debugger-mcp
v0.1.0-beta.1
Published
AI-powered MCP server for debugging Supabase Row Level Security policies with Claude structured outputs
Downloads
54
Maintainers
Readme
RLS Policy Debugger MCP Server
An AI-powered Model Context Protocol (MCP) server for debugging Supabase Row Level Security (RLS) policies. This tool uses Claude's advanced reasoning to analyze complex policy interactions, identify access issues, and suggest fixes with guaranteed structured outputs.
Features
- AI-Powered Analysis: Uses Claude Sonnet 4.5 with structured outputs to analyze RLS policies
- Policy Logic Compilation: Generates human-readable decision trees showing how policies combine
- Memory System: Remembers architectural decisions and known issues across debugging sessions
- Root Cause Identification: Pinpoints exactly why access is granted or denied
- SQL Recommendations: Provides ready-to-use SQL statements to fix policy issues
- Risk Assessment: Evaluates the safety of recommended changes
Why This Tool?
The official Supabase MCP server can create and manage RLS policies, but it:
- Throws errors on policies with spaces in names
- Lacks understanding of how policies interact
- Can't analyze the "big picture" of your security model
- Doesn't provide debugging insights
This RLS Debugger MCP server is purpose-built for debugging complex RLS scenarios where multiple policies interact in unexpected ways.
Installation
Via Claude Code CLI (Recommended)
For Claude Code users, install directly using the MCP CLI:
# Project-specific installation
claude mcp add --transport stdio \
--command "npx" \
--arg "-y" \
--arg "@rip-user/rls-debugger-mcp" \
rls-debugger
# Global installation (all projects)
claude mcp add --scope user --transport stdio \
--command "npx" \
--arg "-y" \
--arg "@rip-user/rls-debugger-mcp" \
rls-debuggerWindows users: Use cmd /c npx instead of npx:
claude mcp add --transport stdio \
--command "cmd" \
--arg "/c" \
--arg "npx" \
--arg "-y" \
--arg "@rip-user/rls-debugger-mcp" \
rls-debuggerThe CLI will add environment variables interactively. You'll be prompted for:
SUPABASE_URL: Your Supabase project URLSUPABASE_SERVICE_KEY: Service role keyANTHROPIC_API_KEY: Your Anthropic API key
Manual Installation
npm install -g @rip-user/rls-debugger-mcp
# or
npx @rip-user/rls-debugger-mcpFrom Source
git clone https://github.com/rip-user/rls-debugger-mcp
cd rls-debugger-mcp
npm install
npm run buildConfiguration
For Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"rls-debugger": {
"command": "node",
"args": ["/path/to/Supabase-rls-mcp/dist/index.js"],
"env": {
"SUPABASE_URL": "https://your-project.supabase.co",
"SUPABASE_SERVICE_KEY": "your-service-role-key",
"ANTHROPIC_API_KEY": "your-anthropic-api-key",
"MEMORY_DIR": "./.rls-memory"
}
}
}
}For Claude Code
Three configuration scopes available:
1. Project-specific (.mcp.json):
{
"mcpServers": {
"rls-debugger": {
"command": "npx",
"args": ["-y", "@rip-user/rls-debugger-mcp"],
"env": {
"SUPABASE_URL": "https://your-project.supabase.co",
"SUPABASE_SERVICE_KEY": "your-service-role-key",
"ANTHROPIC_API_KEY": "your-anthropic-api-key"
}
}
}
}2. User-global (~/.mcp.json):
Same as above, but applies to all projects.
3. Local override (.mcp.local.json):
Project-specific overrides (gitignored). Use for development or different credentials per project.
Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| SUPABASE_URL | Yes | Your Supabase project URL |
| SUPABASE_SERVICE_KEY | Yes | Service role key (has admin access) |
| ANTHROPIC_API_KEY | Yes | Anthropic API key for Claude |
| CLAUDE_MODEL | No | Claude model to use (default: claude-sonnet-4-5-20250514) |
| MEMORY_DIR | No | Directory for storing policy knowledge (default: ./.rls-memory) |
Model Configuration:
- Default:
claude-sonnet-4-5-20250514(fast, cost-effective) - For thorough analysis:
claude-opus-4-1-20250514(slower, more detailed) - Set via
CLAUDE_MODELenvironment variable
Available Tools
analyze_rls_policies
Analyzes RLS policies using AI to debug access issues.
Parameters:
scenario(required): Describe the access problem (e.g., "Why can't user X see their order?")table_name(optional): Focus on a specific table
Returns: Structured analysis including:
- Scenario summary
- Applicable policies and whether they grant access
- Policy combination logic explanation
- Root cause of the issue
- Required relationships verification
- Recommendations with SQL and risk levels
Example:
Using the rls-debugger MCP server, analyze why a team admin
with role 'admin' can't see their documents in the documents tablecompile_policy_logic
Compiles all RLS policies for a table into a decision tree.
Parameters:
table_name(required): Table to analyze
Returns: Logic tree showing:
- PERMISSIVE policies (OR logic)
- RESTRICTIVE policies (AND logic)
- Complete decision flow
- Parsed conditions (auth checks, relationships, joins)
list_all_policies
Lists all RLS policies in your database.
Parameters:
table_name(optional): Filter by table
Returns: Array of policies with details:
- Policy name, type (PERMISSIVE/RESTRICTIVE)
- Operation (SELECT, INSERT, UPDATE, DELETE, ALL)
- USING and WITH CHECK clauses
- Role the policy applies to
save_policy_knowledge
Saves insights to memory for future debugging sessions.
Parameters:
knowledge_type:policy_intent,known_issue,architectural_decision, orcorrectioncontent: The knowledge to saverelated_tables: Array of table namesrelated_policies(optional): Array of policy names
Example:
Save to memory: The documents table uses a two-tier access model where
team admins need both a team_members record AND admin roleget_policy_knowledge
Retrieves saved knowledge from memory.
Parameters:
table_name(optional): Filter by tableknowledge_type(optional): Filter by type
get_memory_summary
Gets statistics about saved knowledge.
Returns:
- Total entries
- Breakdown by type
- Breakdown by table
How It Works
1. Structured Outputs (Nov 14, 2025 API)
Uses Claude's native response_format with JSON Schema for guaranteed structured responses:
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-5-20250514',
betas: ["structured-outputs-2025-11-13"],
response_format: {
type: "json_schema",
json_schema: {
name: "rls_analysis",
strict: true,
schema: {
type: 'object',
properties: {
scenario_summary: { type: 'string' },
applicable_policies: { type: 'array', items: {...} },
root_cause: { type: 'object', ... },
recommendations: { type: 'array', ... }
},
required: [...],
additionalProperties: false
}
}
},
messages: [...]
});This ensures every analysis follows the same structure with zero parsing errors.
2. Policy Fetching from PostgreSQL
Queries PostgreSQL system tables (pg_policy, pg_class, pg_namespace) to get complete policy information:
SELECT
nsp.nspname AS schemaname,
rel.relname AS tablename,
pol.polname AS policyname,
CASE pol.polpermissive
WHEN true THEN 'PERMISSIVE'
WHEN false THEN 'RESTRICTIVE'
END AS polpermissive,
CASE pol.polcmd
WHEN 'r' THEN 'SELECT'
WHEN 'a' THEN 'INSERT'
...
END AS polcmd,
pg_get_expr(pol.polqual, pol.polrelid) AS policyqual,
pg_get_expr(pol.polwithcheck, pol.polrelid) AS policywithcheck
FROM pg_catalog.pg_policy pol
...3. Memory System
Stores debugging insights in a JSON file for persistence across sessions:
[
{
"type": "architectural_decision",
"content": "documents uses dual-key access: team_members + role check",
"tables": ["documents", "team_members"],
"timestamp": "2025-01-15T10:30:00Z"
}
]4. Policy Logic Compilation
Parses policy conditions to extract:
- Authentication requirements (
auth.uid()) - Relationship checks (
EXISTSclauses) - Referenced tables
- Join conditions
- Comparison operators
Understanding RLS Policy Logic
PERMISSIVE Policies (Default)
Use OR logic - if ANY policy grants access, the user can access the row:
-- Policy 1: User owns the record
CREATE POLICY "users_own_records" ON posts
FOR SELECT USING (user_id = auth.uid());
-- Policy 2: Record is public
CREATE POLICY "public_posts" ON posts
FOR SELECT USING (is_public = true);
-- Result: User can see a post if EITHER:
-- - They own it, OR
-- - It's publicRESTRICTIVE Policies
Use AND logic - ALL policies must pass:
CREATE POLICY "must_be_active" ON posts
FOR SELECT AS RESTRICTIVE
USING (status = 'active');
-- Result: User can see a post if:
-- (owns it OR it's public) AND status = 'active'Common Issues This Tool Detects
- Missing Relationships: Policy checks for a record that doesn't exist
- Policy Conflicts: Multiple PERMISSIVE policies that never both pass
- Incorrect Policy Type: Should be RESTRICTIVE but defined as PERMISSIVE
- Missing WITH CHECK: INSERT/UPDATE allowed but shouldn't be
- Overly Restrictive: Multiple conditions that are impossible to satisfy together
Example Usage
Scenario 1: Debugging Access Denial
I have a user with UUID 'abc-123' who is an admin in organization 'xyz-789',
but they can't see their documents. Why?The tool will:
- Fetch all policies for
documents - Load any saved knowledge about this table
- Analyze each policy to see if it would grant access
- Identify the root cause (e.g., missing
team_membersrecord) - Provide verification SQL to check relationships
- Suggest fixes with risk assessment
Scenario 2: Understanding Policy Logic
Show me how all the policies on the user_roles table combineReturns a decision tree:
PERMISSIVE POLICIES (need at least ONE to pass):
1. Check "user_roles_select_policy":
EXISTS (SELECT 1 FROM organizations WHERE id = org_id AND owner_id = auth.uid())
OR
2. Check "admin_access":
role = 'admin' AND user_id = auth.uid()
FINAL DECISION: GRANT if any PERMISSIVE policy passesScenario 3: Saving Knowledge
After fixing an issue:
Save to memory: Fixed documents access by ensuring team_members
records exist for all admins. The issue was new admins weren't getting
team_members entries created.Next time you analyze documents, this knowledge will be included in the analysis.
Companion Skills
Optional Claude Skills enhance the MCP server with systematic debugging workflows and RLS best practices.
Installation (copy to your Skills directory):
# Global installation (recommended)
mkdir -p ~/.claude/skills
cp -r examples/skills/rls-debugger ~/.claude/skills/
# Project-local installation
mkdir -p .claude/skills
cp -r examples/skills/rls-debugger .claude/skills/What Skills provide:
- 5-step systematic debugging workflow
- Common RLS pattern recognition (multi-tenant, role-based, hierarchical)
- Performance optimization tips
- Issue detection and best practices
- Automatic activation when you mention RLS debugging
See examples/skills/rls-debugger/README.md for details.
Development
# Install dependencies
npm install
# Build TypeScript
npm run build
# Watch mode during development
npm run watch
# Run directly with tsx (development)
npm run devHow This Differs from Official Supabase MCP
| Feature | Official Supabase MCP | RLS Debugger MCP | |---------|----------------------|------------------| | Create/modify policies | ✅ | ❌ | | List policies | ✅ | ✅ | | Analyze policy interactions | ❌ | ✅ | | Debug access denials | ❌ | ✅ | | Explain policy logic | ❌ | ✅ | | Remember fixes | ❌ | ✅ | | Structured analysis output | ❌ | ✅ | | Suggest fixes with SQL | ❌ | ✅ | | Risk assessment | ❌ | ✅ |
Use together: Official Supabase MCP for policy management + RLS Debugger MCP for debugging.
Requirements
- Node.js 18 or later
- Supabase project with service role key
- Anthropic API key
- TypeScript 5.7+ (for development)
Roadmap
v0.2.0 (Planned)
- Async operations: Long-running analysis with progress updates
- MCP Nov 25, 2025 spec: Support for asynchronous tool execution
- Batch analysis: Analyze multiple tables/policies concurrently
- Enhanced memory: Vector-based semantic search for saved knowledge
v0.1.0-beta (Current)
- ✅ Structured outputs (Nov 14, 2025 API)
- ✅ MCP 2025-06-18 compliance (outputSchema, title fields)
- ✅ Configurable model selection
- ✅ Companion Skills
- ✅ Generic examples (non-domain-specific)
License
MIT
Contributing
Issues and pull requests welcome!
Credits
Built using:
- Model Context Protocol SDK (v1.22.0)
- Anthropic SDK for Claude AI
- Supabase JS Client
- Claude Sonnet 4.5 for AI-powered analysis
