Skip to main content
Glama

describe_table

Analyze PostgreSQL table structure to view columns, data types, primary keys, and foreign keys for database schema understanding.

Instructions

Describe the structure of a table including columns, types, and constraints.

Args:
    table_name: Name of the table to describe
    schema: Schema name (default: public)
    
Returns:
    Table structure with columns, primary keys, and foreign keys

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
table_nameYes
schemaNopublic

Implementation Reference

  • The primary MCP tool handler for 'describe_table', registered via @mcp.tool() decorator. It invokes the PostgresClient method and formats the response using ColumnInfo models.
    @mcp.tool()
    @handle_db_error
    def describe_table(table_name: str, schema: str = "public") -> dict:
        """Describe the structure of a table including columns, types, and constraints.
        
        Args:
            table_name: Name of the table to describe
            schema: Schema name (default: public)
            
        Returns:
            Table structure with columns, primary keys, and foreign keys
        """
        client = get_client()
        result = client.describe_table(table_name, schema)
        
        if not result["columns"]:
            return not_found_response("Table", f"{schema}.{table_name}")
        
        # Transform columns
        columns = [
            ColumnInfo.from_row(col, result["primary_keys"]).model_dump()
            for col in result["columns"]
        ]
        
        return {
            "schema": schema,
            "table_name": table_name,
            "columns": columns,
            "primary_keys": result["primary_keys"],
            "foreign_keys": result["foreign_keys"],
        }
  • Core implementation in PostgresClient class that executes SQL queries against information_schema to retrieve table structure details: columns, PKs, and FKs.
    def describe_table(self, table_name: str, schema: str = "public") -> dict[str, Any]:
        """Get detailed table information.
        
        Args:
            table_name: Table name
            schema: Schema name (default: public)
            
        Returns:
            Dict with columns, primary keys, foreign keys
        """
        result = {
            "schema": schema,
            "name": table_name,
            "columns": [],
            "primary_keys": [],
            "foreign_keys": [],
        }
        
        with self.get_cursor() as cursor:
            # Get columns
            cursor.execute("""
                SELECT 
                    column_name,
                    data_type,
                    is_nullable,
                    column_default,
                    character_maximum_length,
                    numeric_precision,
                    numeric_scale
                FROM information_schema.columns 
                WHERE table_schema = %s AND table_name = %s
                ORDER BY ordinal_position
            """, (schema, table_name))
            result["columns"] = [dict(row) for row in cursor.fetchall()]
            
            # Get primary keys
            cursor.execute("""
                SELECT column_name
                FROM information_schema.table_constraints tc
                JOIN information_schema.key_column_usage kcu
                    ON tc.constraint_name = kcu.constraint_name
                    AND tc.table_schema = kcu.table_schema
                WHERE tc.table_schema = %s 
                    AND tc.table_name = %s
                    AND tc.constraint_type = 'PRIMARY KEY'
            """, (schema, table_name))
            result["primary_keys"] = [row["column_name"] for row in cursor.fetchall()]
            
            # Get foreign keys
            cursor.execute("""
                SELECT 
                    kcu.column_name,
                    ccu.table_name AS foreign_table_name,
                    ccu.column_name AS foreign_column_name
                FROM information_schema.table_constraints tc
                JOIN information_schema.key_column_usage kcu
                    ON tc.constraint_name = kcu.constraint_name
                    AND tc.table_schema = kcu.table_schema
                JOIN information_schema.constraint_column_usage ccu
                    ON ccu.constraint_name = tc.constraint_name
                    AND ccu.table_schema = tc.table_schema
                WHERE tc.table_schema = %s 
                    AND tc.table_name = %s
                    AND tc.constraint_type = 'FOREIGN KEY'
            """, (schema, table_name))
            result["foreign_keys"] = [
                {
                    "column": row["column_name"],
                    "references": f"{row['foreign_table_name']}.{row['foreign_column_name']}"
                }
                for row in cursor.fetchall()
            ]
        
        return result
  • Pydantic model ColumnInfo used in the handler to validate and structure the list of table columns in the tool response.
    class ColumnInfo(BaseModel):
        """Column information."""
        
        name: str
        type: str
        nullable: bool = True
        default: Optional[str] = None
        is_primary_key: bool = False
        max_length: Optional[int] = None
        precision: Optional[int] = None
        scale: Optional[int] = None
        
        @classmethod
        def from_row(cls, row: dict, primary_keys: list[str] = None) -> "ColumnInfo":
            primary_keys = primary_keys or []
            return cls(
                name=row.get("column_name", ""),
                type=row.get("data_type", ""),
                nullable=row.get("is_nullable", "YES") == "YES",
                default=row.get("column_default"),
                is_primary_key=row.get("column_name", "") in primary_keys,
                max_length=row.get("character_maximum_length"),
                precision=row.get("numeric_precision"),
                scale=row.get("numeric_scale"),
            )
Behavior3/5

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

With no annotations provided, the description carries the full burden. It discloses the tool's read-only behavior (describing structure implies no mutation) and specifies what information is returned (columns, types, constraints, primary/foreign keys). However, it doesn't mention potential errors (e.g., if table doesn't exist), performance characteristics, or authentication needs.

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 efficiently structured with a clear purpose statement followed by Args and Returns sections. Every sentence earns its place: the first sentence states what it does, and the bullet points provide essential parameter and return value details without redundancy.

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

Completeness4/5

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

Given the tool's moderate complexity (2 parameters, no output schema, no annotations), the description is reasonably complete. It covers purpose, parameters, and return values. However, without an output schema, it could benefit from more detail on the return format (e.g., structure of the output).

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

Parameters5/5

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

The schema description coverage is 0%, so the description must compensate fully. It successfully adds meaning beyond the bare schema by explaining both parameters: 'table_name' as 'Name of the table to describe' and 'schema' as 'Schema name (default: public)'. This clarifies their purpose and the default value.

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 specific action ('Describe the structure of a table') and resource ('table'), distinguishing it from siblings like list_tables (which lists names) or query (which executes queries). It explicitly mentions what gets described: 'columns, types, and constraints'.

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

Usage Guidelines4/5

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

The description provides clear context for when to use it (to get table structure details), but doesn't explicitly state when not to use it or name alternatives. For example, it doesn't contrast with describe_view for views or list_constraints for constraint-only listings, though the tool name implies table-specific use.

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

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