Skip to main content
Glama
HenkDz

PostgreSQL MCP Server

pg_manage_rls

Enable, disable, or manage PostgreSQL Row-Level Security policies to control data access at the row level for specific tables.

Instructions

Manage PostgreSQL Row-Level Security - enable/disable RLS and manage policies. Examples: operation="enable" with tableName="users", operation="create_policy" with tableName, policyName, using, check

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
connectionStringNoPostgreSQL connection string (optional)
operationYesOperation: enable/disable RLS, create_policy, edit_policy, drop_policy, get_policies
tableNameNoTable name (required for enable/disable/create_policy/edit_policy/drop_policy, optional filter for get_policies)
schemaNoSchema name (defaults to public)
policyNameNoPolicy name (required for create_policy/edit_policy/drop_policy)
usingNoUSING expression for policy (required for create_policy, optional for edit_policy)
checkNoWITH CHECK expression for policy (optional for create_policy/edit_policy)
commandNoCommand the policy applies to (for create_policy)
roleNoRole the policy applies to (for create_policy)
replaceNoWhether to replace policy if exists (for create_policy)
rolesNoList of roles for policy (for edit_policy)
ifExistsNoInclude IF EXISTS clause (for drop_policy)

Implementation Reference

  • Primary handler implementation for the 'pg_manage_rls' tool. This PostgresTool object defines the tool's name, description, input schema, and execute function which dispatches RLS operations (enable/disable RLS on tables, create/edit/drop/get policies) by calling internal helper functions.
    export const manageRLSTool: PostgresTool = { name: 'pg_manage_rls', description: 'Manage PostgreSQL Row-Level Security - enable/disable RLS and manage policies. Examples: operation="enable" with tableName="users", operation="create_policy" with tableName, policyName, using, check', inputSchema: z.object({ connectionString: z.string().optional().describe('PostgreSQL connection string (optional)'), operation: z.enum(['enable', 'disable', 'create_policy', 'edit_policy', 'drop_policy', 'get_policies']).describe('Operation: enable/disable RLS, create_policy, edit_policy, drop_policy, get_policies'), // Common parameters tableName: z.string().optional().describe('Table name (required for enable/disable/create_policy/edit_policy/drop_policy, optional filter for get_policies)'), schema: z.string().optional().describe('Schema name (defaults to public)'), // Policy-specific parameters policyName: z.string().optional().describe('Policy name (required for create_policy/edit_policy/drop_policy)'), using: z.string().optional().describe('USING expression for policy (required for create_policy, optional for edit_policy)'), check: z.string().optional().describe('WITH CHECK expression for policy (optional for create_policy/edit_policy)'), command: z.enum(['ALL', 'SELECT', 'INSERT', 'UPDATE', 'DELETE']).optional().describe('Command the policy applies to (for create_policy)'), role: z.string().optional().describe('Role the policy applies to (for create_policy)'), replace: z.boolean().optional().describe('Whether to replace policy if exists (for create_policy)'), // Edit policy parameters roles: z.array(z.string()).optional().describe('List of roles for policy (for edit_policy)'), // Drop policy parameters ifExists: z.boolean().optional().describe('Include IF EXISTS clause (for drop_policy)') }), // biome-ignore lint/suspicious/noExplicitAny: <explanation> execute: async (args: any, getConnectionStringVal: GetConnectionStringFn): Promise<ToolOutput> => { const { connectionString: connStringArg, operation, tableName, schema, policyName, using, check, command, role, replace, roles, ifExists } = args as { connectionString?: string; operation: 'enable' | 'disable' | 'create_policy' | 'edit_policy' | 'drop_policy' | 'get_policies'; tableName?: string; schema?: string; policyName?: string; using?: string; check?: string; command?: 'ALL' | 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE'; role?: string; replace?: boolean; roles?: string[]; ifExists?: boolean; }; const resolvedConnString = getConnectionStringVal(connStringArg); let result: FunctionResult; try { switch (operation) { case 'enable': { if (!tableName) { return { content: [{ type: 'text', text: 'Error: tableName is required for enable operation' }], isError: true }; } result = await _enableRLS(resolvedConnString, tableName, schema); break; } case 'disable': { if (!tableName) { return { content: [{ type: 'text', text: 'Error: tableName is required for disable operation' }], isError: true }; } result = await _disableRLS(resolvedConnString, tableName, schema); break; } case 'create_policy': { if (!tableName || !policyName || !using) { return { content: [{ type: 'text', text: 'Error: tableName, policyName, and using are required for create_policy operation' }], isError: true }; } result = await _createRLSPolicy(resolvedConnString, tableName, policyName, using, check, { schema, command, role, replace }); break; } case 'edit_policy': { if (!tableName || !policyName) { return { content: [{ type: 'text', text: 'Error: tableName and policyName are required for edit_policy operation' }], isError: true }; } result = await _editRLSPolicy(resolvedConnString, tableName, policyName, { schema, roles, using, check }); break; } case 'drop_policy': { if (!tableName || !policyName) { return { content: [{ type: 'text', text: 'Error: tableName and policyName are required for drop_policy operation' }], isError: true }; } result = await _dropRLSPolicy(resolvedConnString, tableName, policyName, { schema, ifExists }); break; } case 'get_policies': { result = await _getRLSPolicies(resolvedConnString, tableName, schema); if (result.success) { return { content: [{ type: 'text', text: JSON.stringify(result.details, null, 2) || result.message }] }; } break; } default: return { content: [{ type: 'text', text: `Error: Unknown operation "${operation}". Supported operations: enable, disable, create_policy, edit_policy, drop_policy, get_policies` }], isError: true }; } if (result.success) { return { content: [{ type: 'text', text: result.message + (result.details ? ` Details: ${JSON.stringify(result.details)}` : '') }] }; } return { content: [{ type: 'text', text: result.message }], isError: true }; } catch (error) { return { content: [{ type: 'text', text: `Error executing ${operation} operation: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } };
  • Zod input schema validation for the pg_manage_rls tool parameters.
    inputSchema: z.object({ connectionString: z.string().optional().describe('PostgreSQL connection string (optional)'), operation: z.enum(['enable', 'disable', 'create_policy', 'edit_policy', 'drop_policy', 'get_policies']).describe('Operation: enable/disable RLS, create_policy, edit_policy, drop_policy, get_policies'), // Common parameters tableName: z.string().optional().describe('Table name (required for enable/disable/create_policy/edit_policy/drop_policy, optional filter for get_policies)'), schema: z.string().optional().describe('Schema name (defaults to public)'), // Policy-specific parameters policyName: z.string().optional().describe('Policy name (required for create_policy/edit_policy/drop_policy)'), using: z.string().optional().describe('USING expression for policy (required for create_policy, optional for edit_policy)'), check: z.string().optional().describe('WITH CHECK expression for policy (optional for create_policy/edit_policy)'), command: z.enum(['ALL', 'SELECT', 'INSERT', 'UPDATE', 'DELETE']).optional().describe('Command the policy applies to (for create_policy)'), role: z.string().optional().describe('Role the policy applies to (for create_policy)'), replace: z.boolean().optional().describe('Whether to replace policy if exists (for create_policy)'), // Edit policy parameters roles: z.array(z.string()).optional().describe('List of roles for policy (for edit_policy)'), // Drop policy parameters ifExists: z.boolean().optional().describe('Include IF EXISTS clause (for drop_policy)') }),
  • src/index.ts:225-257 (registration)
    Registration of pg_manage_rls (imported as manageRLSTool) in the central allTools array passed to PostgreSQLServer constructor for MCP tool discovery and handling.
    const allTools: PostgresTool[] = [ // Core Analysis & Debugging analyzeDatabaseTool, debugDatabaseTool, // Schema & Structure Management (Meta-Tools) manageSchemaTools, manageFunctionsTool, manageTriggersTools, manageIndexesTool, manageConstraintsTool, manageRLSTool, // User & Security Management manageUsersTool, // Query & Performance Management manageQueryTool, // Data Operations (Enhancement Tools) executeQueryTool, executeMutationTool, executeSqlTool, // Documentation & Metadata manageCommentsTool, // Data Migration & Monitoring exportTableDataTool, importTableDataTool, copyBetweenDatabasesTool, monitorDatabaseTool ];
  • Helper function _enableRLS called by pg_manage_rls handler for enabling RLS on a table.
    async function _enableRLS( connectionString: string, tableName: string, schema = 'public' ): Promise<FunctionResult> { const db = DatabaseConnection.getInstance(); try { await db.connect(connectionString); await db.query(`ALTER TABLE ${schema}.${tableName} ENABLE ROW LEVEL SECURITY`); return { success: true, message: `Row-Level Security enabled on ${schema}.${tableName}`, details: { table: tableName, schema } }; } catch (error) { return { success: false, message: `Failed to enable RLS: ${error instanceof Error ? error.message : String(error)}`, details: null }; } finally { await db.disconnect(); } }
  • Helper function _createRLSPolicy for creating RLS policies.
    async function _createRLSPolicy( connectionString: string, tableName: string, policyName: string, using: string, check?: string, options: { schema?: string; command?: 'ALL' | 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE'; role?: string; replace?: boolean; } = {} ): Promise<FunctionResult> { const db = DatabaseConnection.getInstance(); try { await db.connect(connectionString); const schema = options.schema || 'public'; const command = options.command || 'ALL'; const createOrReplace = options.replace ? 'CREATE OR REPLACE' : 'CREATE'; // Build policy creation SQL let sql = ` ${createOrReplace} POLICY ${policyName} ON ${schema}.${tableName} FOR ${command} `; // Add role if specified if (options.role) { sql += ` TO ${options.role}`; } // Add USING expression sql += ` USING (${using})`; // Add WITH CHECK expression if provided if (check) { sql += ` WITH CHECK (${check})`; } await db.query(sql); return { success: true, message: `Policy ${policyName} created successfully on ${schema}.${tableName}`, details: { table: tableName, schema, policy: policyName, command } }; } catch (error) { return { success: false, message: `Failed to create policy: ${error instanceof Error ? error.message : String(error)}`, details: null }; } finally { await db.disconnect(); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/HenkDz/postgresql-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server