PostgREST
Official
import {
createMcpServer,
jsonResource,
jsonResourceResponse,
resources,
tool,
} from '@supabase/mcp-utils';
import { processSql, renderHttp } from '@supabase/sql-to-rest';
import { z } from 'zod';
import { version } from '../package.json';
import { ensureNoTrailingSlash, ensureTrailingSlash } from './util.js';
export type PostgrestMcpServerOptions = {
apiUrl: string;
apiKey?: string;
schema: string;
};
/**
* Creates an MCP server for interacting with a PostgREST API.
*/
export function createPostgrestMcpServer(options: PostgrestMcpServerOptions) {
const apiUrl = ensureNoTrailingSlash(options.apiUrl);
const apiKey = options.apiKey;
const schema = options.schema;
function getHeaders(
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' = 'GET'
) {
const schemaHeader =
method === 'GET' ? 'accept-profile' : 'content-profile';
const headers: HeadersInit = {
'content-type': 'application/json',
prefer: 'return=representation',
[schemaHeader]: schema,
};
if (apiKey) {
headers.apikey = apiKey;
headers.authorization = `Bearer ${apiKey}`;
}
return headers;
}
return createMcpServer({
name: 'supabase/postgrest',
version,
resources: resources('postgrest', [
jsonResource('/spec', {
name: 'OpenAPI spec',
description: 'OpenAPI spec for the PostgREST API',
async read(uri) {
const response = await fetch(ensureTrailingSlash(apiUrl), {
headers: getHeaders(),
});
const result = await response.json();
return jsonResourceResponse(uri, result);
},
}),
]),
tools: {
postgrestRequest: tool({
description: 'Performs an HTTP request against the PostgREST API',
parameters: z.object({
method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']),
path: z.string(),
body: z.record(z.unknown()).optional(),
}),
async execute({ method, path, body }) {
const url = new URL(`${apiUrl}${path}`);
const headers = getHeaders(method);
if (method !== 'GET') {
headers['content-type'] = 'application/json';
}
const response = await fetch(url, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
});
return await response.json();
},
}),
sqlToRest: tool({
description:
'Converts SQL query to a PostgREST API request (method, path)',
parameters: z.object({
sql: z.string(),
}),
execute: async ({ sql }) => {
const statement = await processSql(sql);
const request = await renderHttp(statement);
return {
method: request.method,
path: request.fullPath,
};
},
}),
},
});
}