rest_query
Query or mutate database data through a PostgREST REST API using GET, POST, PATCH, or DELETE methods with configurable parameters.
Instructions
Query or mutate data via the PostgREST REST API. Supports GET/POST/PATCH/DELETE with query params.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | Yes | The project ID | |
| table | Yes | Table name to query | |
| method | No | HTTP method | GET |
| params | No | PostgREST query params (e.g. {select: 'id,name', order: 'id.asc', limit: '10'}) | |
| body | No | Request body for POST/PATCH (JSON object or array) | |
| key_type | No | Which key to use: anon (default, respects RLS) or service (bypasses RLS) | anon |
Implementation Reference
- src/tools/rest-query.ts:27-81 (handler)The handleRestQuery function executes the REST API query logic. It validates the project, builds the query string from params, makes an authenticated API request to the PostgREST endpoint with appropriate headers (including API key and authorization), and returns the formatted response.
export async function handleRestQuery(args: { project_id: string; table: string; method?: string; params?: Record<string, string>; body?: unknown; key_type?: string; }): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> { const project = getProject(args.project_id); if (!project) return projectNotFound(args.project_id); const method = args.method || "GET"; const keyType = args.key_type || "anon"; const key = keyType === "service" ? project.service_key : project.anon_key; // Build query string from params let queryStr = ""; if (args.params && Object.keys(args.params).length > 0) { const sp = new URLSearchParams(args.params); queryStr = `?${sp.toString()}`; } const path = `/rest/v1/${args.table}${queryStr}`; const headers: Record<string, string> = { apikey: key, Authorization: `Bearer ${key}`, }; // For mutating requests, ask PostgREST to return the result if (method !== "GET") { headers["Prefer"] = "return=representation"; } const res = await apiRequest(path, { method, headers, body: args.body, }); if (!res.ok) return formatApiError(res, "querying REST API"); const text = typeof res.body === "string" ? res.body : JSON.stringify(res.body, null, 2); return { content: [ { type: "text", text: `**${method} /rest/v1/${args.table}** → ${res.status}\n\n\`\`\`json\n${text}\n\`\`\``, }, ], }; } - src/tools/rest-query.ts:6-25 (schema)The restQuerySchema defines the input validation schema using Zod. It validates project_id (string), table name (string), HTTP method (enum: GET/POST/PATCH/DELETE, default GET), PostgREST query params (optional record of strings), request body (optional unknown for POST/PATCH), and key_type (enum: anon/service, default anon for RLS control).
export const restQuerySchema = { project_id: z.string().describe("The project ID"), table: z.string().describe("Table name to query"), method: z .enum(["GET", "POST", "PATCH", "DELETE"]) .default("GET") .describe("HTTP method"), params: z .record(z.string()) .optional() .describe("PostgREST query params (e.g. {select: 'id,name', order: 'id.asc', limit: '10'})"), body: z .unknown() .optional() .describe("Request body for POST/PATCH (JSON object or array)"), key_type: z .enum(["anon", "service"]) .default("anon") .describe("Which key to use: anon (default, respects RLS) or service (bypasses RLS)"), }; - src/index.ts:79-84 (registration)The rest_query tool is registered with the MCP server. It provides a description indicating it queries or mutates data via the PostgREST REST API supporting GET/POST/PATCH/DELETE with query params, and maps to the handleRestQuery handler function.
server.tool( "rest_query", "Query or mutate data via the PostgREST REST API. Supports GET/POST/PATCH/DELETE with query params.", restQuerySchema, async (args) => handleRestQuery(args), );