describe_table
Examine table structure with column types and descriptions using a Hasura GraphQL MCP Server. Input table name and optional schema to retrieve details.
Instructions
Shows the structure of a table including all columns with their types and descriptions
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| schemaName | No | Optional. The database schema name, defaults to 'public' | public |
| tableName | Yes | The exact name of the table to describe |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"schemaName": {
"default": "public",
"description": "Optional. The database schema name, defaults to 'public'",
"type": "string"
},
"tableName": {
"description": "The exact name of the table to describe",
"type": "string"
}
},
"required": [
"tableName"
],
"type": "object"
}
Implementation Reference
- src/index.ts:474-584 (handler)The handler function for 'describe_table' tool. It performs GraphQL introspection to fetch the table type, handles case variations for type name, parses field types (including lists and non-nulls), and returns structured column information.async ({ tableName, schemaName }) => { console.log(`[INFO] Executing tool 'describe_table' for table: ${tableName} in schema: ${schemaName}`); try { const schema = await getIntrospectionSchema(); const tableTypeQuery = gql` query GetTableType($typeName: String!) { __type(name: $typeName) { name kind description fields { name description type { kind name ofType { kind name ofType { kind name ofType { kind name } } } } args { name description type { kind name ofType { kind name } } } } } } `; const tableTypeResult = await makeGqlRequest(tableTypeQuery, { typeName: tableName }); if (!tableTypeResult.__type) { console.log(`[INFO] No direct match for table type: ${tableName}, trying case variations`); const pascalCaseName = tableName.charAt(0).toUpperCase() + tableName.slice(1); const alternativeResult = await makeGqlRequest(tableTypeQuery, { typeName: pascalCaseName }); if (!alternativeResult.__type) { throw new Error(`Table '${tableName}' not found in schema. Check the table name and schema.`); } tableTypeResult.__type = alternativeResult.__type; } const columnsInfo = tableTypeResult.__type.fields.map((field: any) => { let typeInfo = field.type; let typeString = ''; let isNonNull = false; let isList = false; while (typeInfo) { if (typeInfo.kind === 'NON_NULL') { isNonNull = true; typeInfo = typeInfo.ofType; } else if (typeInfo.kind === 'LIST') { isList = true; typeInfo = typeInfo.ofType; } else { typeString = typeInfo.name || 'unknown'; break; } } let fullTypeString = ''; if (isList) { fullTypeString = `[${typeString}]`; } else { fullTypeString = typeString; } if (isNonNull) { fullTypeString += '!'; } return { name: field.name, type: fullTypeString, description: field.description || null, args: field.args?.length ? field.args : null }; }); const result = { table: { name: tableName, schema: schemaName, description: tableTypeResult.__type.description || null, columns: columnsInfo.sort((a: any, b: any) => a.name.localeCompare(b.name)) } }; return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } catch (error: any) { console.error(`[ERROR] Tool 'describe_table' failed: ${error.message}`); throw error; } }
- src/index.ts:470-473 (schema)Input schema using Zod: requires 'tableName' (string), optional 'schemaName' (string, defaults to 'public').{ tableName: z.string().describe("The exact name of the table to describe"), schemaName: z.string().optional().default('public').describe("Optional. The database schema name, defaults to 'public'") },
- src/index.ts:468-585 (registration)Registration of the 'describe_table' tool via server.tool(), including name, description, input schema, and handler reference."describe_table", "Shows the structure of a table including all columns with their types and descriptions", { tableName: z.string().describe("The exact name of the table to describe"), schemaName: z.string().optional().default('public').describe("Optional. The database schema name, defaults to 'public'") }, async ({ tableName, schemaName }) => { console.log(`[INFO] Executing tool 'describe_table' for table: ${tableName} in schema: ${schemaName}`); try { const schema = await getIntrospectionSchema(); const tableTypeQuery = gql` query GetTableType($typeName: String!) { __type(name: $typeName) { name kind description fields { name description type { kind name ofType { kind name ofType { kind name ofType { kind name } } } } args { name description type { kind name ofType { kind name } } } } } } `; const tableTypeResult = await makeGqlRequest(tableTypeQuery, { typeName: tableName }); if (!tableTypeResult.__type) { console.log(`[INFO] No direct match for table type: ${tableName}, trying case variations`); const pascalCaseName = tableName.charAt(0).toUpperCase() + tableName.slice(1); const alternativeResult = await makeGqlRequest(tableTypeQuery, { typeName: pascalCaseName }); if (!alternativeResult.__type) { throw new Error(`Table '${tableName}' not found in schema. Check the table name and schema.`); } tableTypeResult.__type = alternativeResult.__type; } const columnsInfo = tableTypeResult.__type.fields.map((field: any) => { let typeInfo = field.type; let typeString = ''; let isNonNull = false; let isList = false; while (typeInfo) { if (typeInfo.kind === 'NON_NULL') { isNonNull = true; typeInfo = typeInfo.ofType; } else if (typeInfo.kind === 'LIST') { isList = true; typeInfo = typeInfo.ofType; } else { typeString = typeInfo.name || 'unknown'; break; } } let fullTypeString = ''; if (isList) { fullTypeString = `[${typeString}]`; } else { fullTypeString = typeString; } if (isNonNull) { fullTypeString += '!'; } return { name: field.name, type: fullTypeString, description: field.description || null, args: field.args?.length ? field.args : null }; }); const result = { table: { name: tableName, schema: schemaName, description: tableTypeResult.__type.description || null, columns: columnsInfo.sort((a: any, b: any) => a.name.localeCompare(b.name)) } }; return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } catch (error: any) { console.error(`[ERROR] Tool 'describe_table' failed: ${error.message}`); throw error; } } );