Skip to main content
Glama
itsalfredakku

Postgres MCP Server

permissions

Manage PostgreSQL database permissions by creating users and roles, granting privileges, and controlling access to databases, schemas, and tables.

Instructions

Database permissions management: users, roles, grants, privileges

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
operationYesPermission operation to perform
usernameNoUsername for user operations
rolenameNoRole name for role operations
passwordNoPassword for user creation/modification
databaseNoDatabase name for grants
schemaNoSchema name for grants
tableNoTable name for grants
privilegesNoPrivileges to grant/revoke
attributesNoUser/role attributes
grantOptionNoGrant with GRANT OPTION

Implementation Reference

  • Tool definition and input schema for the 'permissions' MCP tool, defining all supported operations and parameters
    {
      name: 'permissions',
      description: 'Database permissions management: users, roles, grants, privileges',
      inputSchema: {
        type: 'object',
        properties: {
          operation: {
            type: 'string',
            enum: [
              'list_users', 'list_roles', 'list_grants', 'list_privileges',
              'create_user', 'create_role', 'drop_user', 'drop_role',
              'grant_role', 'revoke_role', 'grant_privilege', 'revoke_privilege',
              'alter_user', 'alter_role', 'check_permissions', 'grant_all_privileges'
            ],
            description: 'Permission operation to perform'
          },
          username: {
            type: 'string',
            description: 'Username for user operations'
          },
          rolename: {
            type: 'string',
            description: 'Role name for role operations'
          },
          password: {
            type: 'string',
            description: 'Password for user creation/modification'
          },
          database: {
            type: 'string',
            description: 'Database name for grants'
          },
          schema: {
            type: 'string',
            description: 'Schema name for grants'
          },
          table: {
            type: 'string',
            description: 'Table name for grants'
          },
          privileges: {
            type: 'array',
            items: {
              type: 'string',
              enum: ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER', 'CREATE', 'CONNECT', 'TEMPORARY', 'EXECUTE', 'USAGE', 'ALL']
            },
            description: 'Privileges to grant/revoke'
          },
          attributes: {
            type: 'object',
            properties: {
              superuser: { type: 'boolean', description: 'Superuser privilege' },
              createdb: { type: 'boolean', description: 'Create database privilege' },
              createrole: { type: 'boolean', description: 'Create role privilege' },
              replication: { type: 'boolean', description: 'Replication privilege' },
              login: { type: 'boolean', description: 'Login privilege' },
              inherit: { type: 'boolean', description: 'Inherit privileges' },
              bypassrls: { type: 'boolean', description: 'Bypass row level security' }
            },
            description: 'User/role attributes'
          },
          grantOption: {
            type: 'boolean',
            description: 'Grant with GRANT OPTION',
            default: false
          }
        },
        required: ['operation']
      }
    },
  • src/index.ts:670-672 (registration)
    Registration and dispatch for the 'permissions' tool in the CallToolRequestSchema handler switch statement
    case 'permissions':
      return await this.handlePermissions(args);
  • Core handler implementation for the 'permissions' tool. Handles all operations (list_users, create_user, grant_privilege, etc.) by executing specific PostgreSQL queries via queryClient.
    private async handlePermissions(args: any) {
      const { operation, username, rolename, password, database, schema, table, privileges, attributes, grantOption } = args;
    
      switch (operation) {
        case 'list_users':
          const users = await this.queryClient.executeQuery(`
            SELECT 
              r.rolname as username,
              r.oid as user_id,
              r.rolcreatedb as can_create_db,
              r.rolsuper as is_superuser,
              r.rolreplication as can_replicate,
              r.rolbypassrls as bypass_rls,
              r.rolvaliduntil as password_expires,
              ARRAY(
                SELECT m.rolname 
                FROM pg_roles m 
                JOIN pg_auth_members am ON m.oid = am.roleid 
                WHERE am.member = r.oid
              ) as member_of
            FROM pg_roles r
            WHERE r.rolcanlogin = true
            ORDER BY r.rolname
          `);
          return {
            content: [{
              type: 'text',
              text: JSON.stringify(users.rows, null, 2)
            }]
          };
    
        case 'list_roles':
          const roles = await this.queryClient.executeQuery(`
            SELECT 
              rolname as role_name,
              rolsuper as is_superuser,
              rolinherit as inherits,
              rolcreaterole as can_create_role,
              rolcreatedb as can_create_db,
              rolcanlogin as can_login,
              rolreplication as can_replicate,
              rolconnlimit as connection_limit,
              rolvaliduntil as valid_until,
              rolbypassrls as bypass_rls
            FROM pg_roles
            ORDER BY rolname
          `);
          return {
            content: [{
              type: 'text',
              text: JSON.stringify(roles.rows, null, 2)
            }]
          };
    
        case 'create_user':
          if (!username || !password) {
            throw new Error('Username and password are required for user creation');
          }
          const createUserSQL = `CREATE USER ${username} WITH PASSWORD '${password}'`;
          if (attributes) {
            const attrSQL = Object.entries(attributes)
              .filter(([, value]) => value === true)
              .map(([key]) => key.toUpperCase())
              .join(' ');
            if (attrSQL) {
              await this.queryClient.executeQuery(`${createUserSQL} ${attrSQL}`);
            } else {
              await this.queryClient.executeQuery(createUserSQL);
            }
          } else {
            await this.queryClient.executeQuery(createUserSQL);
          }
          return {
            content: [{
              type: 'text',
              text: `User '${username}' created successfully`
            }]
          };
    
        case 'grant_all_privileges':
          if (!username || !database) {
            throw new Error('Username and database are required for granting all privileges');
          }
          const grantAllSQL = [
            `GRANT ALL PRIVILEGES ON DATABASE ${database} TO ${username}`,
            `GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ${username}`,
            `GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO ${username}`,
            `GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO ${username}`
          ];
          
          for (const sql of grantAllSQL) {
            await this.queryClient.executeQuery(sql);
          }
          
          return {
            content: [{
              type: 'text',
              text: `All privileges granted to '${username}' on database '${database}'`
            }]
          };
    
        case 'grant_privilege':
          if (!username || !privileges || privileges.length === 0) {
            throw new Error('Username and privileges are required');
          }
          const target = table ? `TABLE ${schema ? schema + '.' : ''}${table}` : 
                        schema ? `SCHEMA ${schema}` : 
                        database ? `DATABASE ${database}` : 'ALL TABLES IN SCHEMA public';
          
          const grantSQL = `GRANT ${privileges.join(', ')} ON ${target} TO ${username}${grantOption ? ' WITH GRANT OPTION' : ''}`;
          await this.queryClient.executeQuery(grantSQL);
          
          return {
            content: [{
              type: 'text',
              text: `Privileges ${privileges.join(', ')} granted to '${username}' on ${target}`
            }]
          };
    
        case 'check_permissions':
          if (!username) {
            throw new Error('Username is required for permission check');
          }
          const permissionsQuery = `
            SELECT 
              t.schemaname,
              t.tablename,
              p.privilege_type
            FROM information_schema.table_privileges p
            JOIN information_schema.tables t ON p.table_name = t.table_name AND p.table_schema = t.table_schema
            WHERE p.grantee = $1
            ORDER BY t.schemaname, t.tablename, p.privilege_type
          `;
          const permissions = await this.queryClient.executeQuery(permissionsQuery, [username]);
          
          return {
            content: [{
              type: 'text',
              text: JSON.stringify(permissions.rows, null, 2)
            }]
          };
    
        default:
          throw new Error(`Unknown permissions operation: ${operation}`);
      }
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure but offers minimal information. It mentions 'management' which implies mutations, but doesn't specify required permissions, whether operations are reversible, potential side effects, or error conditions. For a tool with 16 diverse operations including destructive ones like 'drop_user', this is inadequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise - a single phrase that efficiently communicates the tool's domain and scope. Every word earns its place, with no redundant or unnecessary information. The structure is front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex permissions management tool with 10 parameters, 16 operations including destructive ones, no annotations, and no output schema, the description is insufficient. It doesn't address behavioral aspects, return values, error handling, or the relationship between different operations. The agent would struggle to use this tool correctly without significant trial and error.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 100% description coverage, so parameters are well-documented in the schema itself. The description adds minimal value by listing resource types (users, roles, grants, privileges) which helps contextualize the operation parameter, but doesn't provide additional syntax, format, or constraint details beyond what the schema already specifies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose as 'Database permissions management' and lists the key resources involved (users, roles, grants, privileges). It provides a specific domain and scope, though it doesn't explicitly differentiate from sibling tools like 'security' or 'admin' which might have overlapping functionality.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites, when to choose specific operations, or how it relates to sibling tools like 'security' or 'admin' that might handle related tasks. The agent must infer usage from the operation enum alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/itsalfredakku/postgres-mcp'

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