Skip to main content
Glama
abushadab

Self-Hosted Supabase MCP Server

by abushadab

get_auth_user

Retrieve user details, such as authentication data, from a self-hosted Supabase instance by specifying a user’s UUID. Simplify user management directly from MCP-compatible environments for efficient Supabase integration.

Instructions

Retrieves details for a specific user from auth.users by their ID.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
user_idYesThe UUID of the user to retrieve.

Implementation Reference

  • The execute handler function for the get_auth_user tool. It performs a parameterized SQL query on auth.users to fetch user details by ID using a direct PG transaction, validates the single row result with AuthUserZodSchema, handles errors, logs progress, and returns the AuthUser object.
    execute: async (input: GetAuthUserInput, context: ToolContext): Promise<GetAuthUserOutput> => { // Use GetAuthUserOutput
        const client = context.selfhostedClient;
        const { user_id } = input;
    
        if (!client.isPgAvailable()) {
            context.log('Direct database connection (DATABASE_URL) is required to get auth user details.', 'error');
            throw new Error('Direct database connection (DATABASE_URL) is required to get auth user details.');
        }
    
        const sql = `
            SELECT
                id,
                email,
                role,
                raw_app_meta_data,
                raw_user_meta_data,
                created_at::text,
                last_sign_in_at::text
            FROM auth.users
            WHERE id = $1
        `;
        const params = [user_id];
    
        console.error(`Attempting to get auth user ${user_id} using direct DB connection...`);
    
        // Use transaction for parameterized query
        const user = await client.executeTransactionWithPg(async (pgClient: PoolClient) => {
            const result = await pgClient.query(sql, params);
    
            if (result.rows.length === 0) {
                throw new Error(`User with ID ${user_id} not found.`);
            }
    
            // handleSqlResponse expects SqlExecutionResult (SuccessResponse | ErrorResponse)
            // We pass the single row which structurally matches SqlSuccessResponse[0]
            // but handleSqlResponse expects the array wrapper or error.
            // So, we validate the single object directly.
            try {
                const singleUser = AuthUserZodSchema.parse(result.rows[0]);
                return singleUser;
            } catch (validationError) {
                 if (validationError instanceof z.ZodError) {
                    console.error("Zod validation failed:", validationError.errors);
                    throw new Error(`Output validation failed: ${validationError.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ')}`);
                } 
                throw validationError; // Rethrow other errors
            }
        });
    
        console.error(`Found user ${user_id}.`);
        context.log(`Found user ${user_id}.`);
        // The return type is already AuthUser (via GetAuthUserOutput)
        return user;
    },
  • Zod input schema requiring user_id (UUID), output schema matching AuthUser fields, TypeScript type aliases, and static MCP JSON input schema.
    const GetAuthUserInputSchema = z.object({
        user_id: z.string().uuid().describe('The UUID of the user to retrieve.'),
    });
    type GetAuthUserInput = z.infer<typeof GetAuthUserInputSchema>;
    
    // Output schema - Zod for validation (single user)
    const AuthUserZodSchema = z.object({
        id: z.string().uuid(),
        email: z.string().email().nullable(),
        role: z.string().nullable(),
        created_at: z.string().nullable(),
        last_sign_in_at: z.string().nullable(),
        raw_app_meta_data: z.record(z.unknown()).nullable(),
        raw_user_meta_data: z.record(z.unknown()).nullable(),
        // Add more fields as needed
    });
    // Use AuthUser for the output type hint
    type GetAuthUserOutput = AuthUser;
    
    // Static JSON Schema for MCP
    const mcpInputSchema = {
        type: 'object',
        properties: {
            user_id: {
                type: 'string',
                description: 'The UUID of the user to retrieve.',
                format: 'uuid', // Hint format if possible
            },
        },
        required: ['user_id'],
    };
  • src/index.ts:114-114 (registration)
    Registers the imported getAuthUserTool in the availableTools object, which is used to populate the MCP server's tools capabilities.
    [getAuthUserTool.name]: getAuthUserTool as AppTool,
  • TypeScript interface defining the AuthUser type, used for output typing and Zod schema basis in get_auth_user tool.
     * Represents a user object from the auth.users table.
     * Based on fields selected in listAuthUsersTool, getAuthUserTool etc.
     */
    export interface AuthUser {
        id: string; // uuid
        email: string | null;
        role: string | null;
        created_at: string | null; // Timestamps returned as text from DB
        last_sign_in_at: string | null;
        raw_app_meta_data: Record<string, unknown> | null;
        raw_user_meta_data: Record<string, unknown> | null;
        // Add other relevant fields if needed, e.g., email_confirmed_at
    }

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observedv1.0.0

TDQS

B3.3/5.0
Behavior2/5

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

No annotations are provided, so the description carries full burden. It only states 'retrieves', which is a read operation, but does not disclose potential side effects, error cases, or permission requirements.

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?

Single sentence with no unnecessary words. It is front-loaded and efficient.

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

Completeness3/5

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

For a simple single-parameter read tool without output schema, the description is minimally adequate. It could benefit from mentioning what 'details' are returned or handling of non-existent users.

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?

Schema coverage is 100%, so the description adds little beyond 'by their ID'. The parameter is already fully described in the schema. No additional semantic value is provided.

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

Purpose5/5

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

The description clearly states the verb 'retrieves', the resource 'details for a specific user', and the method 'by their ID'. It distinctly separates from siblings like list_auth_users or create_auth_user.

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?

No guidance on when to use this tool versus alternatives like list_auth_users or other user-related tools. The description does not mention context, prerequisites, or exclusions.

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

Deploy Server

Other Tools

Related Tools