Return the structure of one table: columns with types, defaults, storage and compression, primary key, indexes with their definition and whether each is valid, constraints, foreign keys, inbound foreign keys (referenced_by), triggers with their enabled state, rules, row-level…
read-onlyany connectionsweeps instancesweeps groupcan return data values
tableDetails(schema, table)
Return the structure of one table: columns with types, defaults, storage and compression, primary key, indexes with their definition and whether each is valid, constraints, foreign keys, inbound foreign keys (referenced_by), triggers with their enabled state, rules, row-level security, policies and privileges. Two of those say when an object is not doing what its definition suggests: an index with valid false is what a failed CREATE INDEX CONCURRENTLY leaves behind -- it occupies disk and is maintained on every write while the planner never uses it -- and a trigger with enabled 'disabled' still has its full definition, since ALTER TABLE ...
DISABLE TRIGGER changes no text. 'replica' and 'always' are the session_replication_role states. Structure only -- it changes when someone issues DDL and not otherwise, and it returns no sample column values. For row counts, scan counters, dead tuples, vacuum times and the pg_stats column histograms call tableStats; for measured on-disk sizes call tableSize.
Also accepts connection, instance, group, described once under arguments every tool takes.
One table's structure. An absent extension or a missing grant is reported as {error, hint} instead.
| Field | Type |
|---|---|
| columns | object | null |
| constraints | object | null |
| description | string | null |
| foreign_keys | object | null |
| indexes | object | null |
| kind | string | null |
| policies | object | null |
| primary_key | array | null |
| referenced_by | object | null |
| roles | object | null |
| row_level_security | object | null |
| rules | object | null |
| table | string | null |
| triggers | object | null |
A physical replica is byte-identical here, so asking each member of a replication group adds nothing.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "tableDetails",
"arguments": {
"schema": "shop",
"table": "orders"
}
}
}
{
"table": "shop.orders",
"kind": "table",
"description": "Customer purchase orders.",
"columns": {
"id": {
"type": "bigint",
"nullable": false,
"default": "generated always as identity"
},
"customer_id": {
"type": "bigint",
"nullable": false,
"default": null
},
"status": {
"type": "text",
"nullable": false,
"default": "'pending'::text"
},
"created_at": {
"type": "timestamp with time zone",
"nullable": false,
"default": "now()"
}
},
"primary_key": [
"id"
],
"indexes": {
"orders_pkey": {
"definition": "CREATE UNIQUE INDEX orders_pkey ON shop.orders USING btree (id)"
},
"orders_customer_id_idx": {
"definition": "CREATE INDEX orders_customer_id_idx ON shop.orders USING btree (customer_id)"
}
},
"constraints": {
"orders_status_check": {
"type": "check",
"definition": "CHECK (status = ANY (ARRAY['pending'::text, 'paid'::text, 'shipped'::text]))"
}
},
"foreign_keys": {
"orders_customer_id_fkey": {
"columns": [
"customer_id"
],
"references": "shop.customers(id)",
"on_delete": "restrict"
}
},
"referenced_by": {
"order_items_order_id_fkey": {
"table": "shop.order_items",
"columns": [
"order_id"
]
}
},
"triggers": {},
"rules": {},
"row_level_security": {
"enabled": false,
"forced": false
},
"policies": {},
"roles": {
"app_rw": [
"SELECT",
"INSERT",
"UPDATE"
],
"reporting": [
"SELECT"
]
}
}
Invented values on a fictional shop database, shaped by and checked against this tool's output schema. Real output is returned as structuredContent to clients that negotiate MCP 2025-06-18 or later.
listSchemas, listTables, tableStats, largeObjects, listPartitions, partitionDetails, listTableStats, tableSize, listTableSizes, listFunctions, functionDetails, listEnums, enumDetails, listTypes, typeDetails, columnHistogram, listExtendedStatistics, listSequences