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