For the complete documentation index, see llms.txt. This page is also available as Markdown.

MCP over HTTP

pREST MCP over HTTP β€” Model Context Protocol (MCP) read-only tools at /_mcp for AI agents to discover schemas and query SQL tables on the same server as REST.

pREST v2.1.0+ exposes a read-only Model Context Protocol (MCP) endpoint at /_mcp on the same server that already serves CRUD, catalog, and custom script routes. MCP clients can discover schema and read table data through JSON-RPC tools β€” without a separate process or transport.

Today MCP runs on the Native PostgreSQL adapter and Postgres-compatible engines you connect with that adapter. Other SQL families are on the roadmap.

Introduced in v2.1.0 (#977).


What is MCP?

MCP (Model Context Protocol) is an open standard for connecting AI applications and agents to external tools and data sources. Instead of each product inventing a private plugin format, MCP defines how clients discover tools and call them (for example over JSON-RPC).

AI agents, IDEs, and other MCP-capable clients use that protocol to list available tools and run them with structured arguments. pREST implements a read-only MCP surface at /_mcp so those clients can:

  • Discover databases, schemas, and tables

  • Describe columns

  • Select rows (with limits)

through the same prestd process, auth, ACL, and database routing as the REST API.

MCP in pREST is not a separate database, a second port, or a write/DDL interface. In v2.1.0 it does not insert, update, delete, or run arbitrary admin SQL β€” use REST or curated /_QUERIES scripts for writes when your deployment allows them.


What is AI (in these docs)?

Artificial intelligence (AI) here means applications and agents that use models to reason and act on tools and data. pREST connects them to your SQL catalog through read-only MCP at /_mcp and the same auth/ACL as the REST API.

Typical clients are AI agents, IDEs, and other tools that speak MCP. For client setup (adapters, IDE config), see docs.prestd.com/ai. pREST is the API layer those clients call β€” it is not itself an LLM or AI model.


How it fits in pREST

The MCP endpoint reuses the existing pREST request pipeline:

That means MCP inherits the same deployment model, authentication, access control, and database routing as the REST API. There is no second port to configure: MCP runs in-process on the same prestd HTTP server.

Many AI clients (Cursor, Claude Desktop, and others) expect a stdio MCP process rather than HTTP. For those, use the official pREST MCP Adapter (prest-mcp) β€” a tiny stdio ↔ HTTP bridge. The adapter does not implement tools; pREST still owns schema discovery and queries. See AI and MCP for install and client tutorials.

Concern
Behavior

Server process

Same prestd instance as REST

Authentication

HTTP auth stack β€” /_mcp is protected when auth is enabled

Permissions

access.tables and per-user rules apply to tool discovery and execution

Multi-database

Database aliases from the registry are used in tool names and arguments

Writes

Not supported in v2.1.0 β€” read-only by design


Endpoint shape

Method
Path
Purpose

GET

/_mcp

Discovery payload with server metadata and available tools

POST

/_mcp

JSON-RPC 2.0 requests for MCP operations

Supported JSON-RPC methods:

Method
Description

initialize

Returns server info, capabilities, and usage instructions

tools/list

Returns the full tool catalog with inputSchema per tool

tools/call

Executes a named tool with optional arguments

Unsupported methods return 400 Bad Request with unsupported method.


Discovery (GET /_mcp)

A GET request returns a JSON document describing the server and all tools visible to the current caller (after auth and ACL filtering):

Use discovery to inspect available tools and their typed inputSchema before calling them.


Tools reference

Since v2.4.1 (#1016), the three prest.list_* tools honour the [expose] settings. A denied listing is dropped from discovery and its tools/call returns 400 with unauthorized listing. See Safety and limits.

prest.list_databases

List database aliases accessible to the current caller.

Requires: expose.databases (v2.4.1+).

Arguments: none.

Returns: array of database objects. In registry multi-database mode, each entry includes:

Field
Description

name

Registered alias (used in URLs and tool names)

datname

Same as name

physical_name

Physical Postgres database name on the target cluster

In legacy single-host mode, returns databases from the catalog query.


prest.list_schemas

List readable schemas for a database alias.

Requires: expose.schemas (v2.4.1+).

Arguments:

Field
Required
Description

database

No

Database alias; defaults to pg.database when omitted

Returns: array of schema objects (filtered by access.tables permissions).


prest.list_tables

List readable tables for a database alias and optional schema.

Requires: expose.tables (v2.4.1+).

Arguments:

Field
Required
Description

database

No

Database alias; defaults to pg.database when omitted

schema

No

Filter to a single schema; omit to list across accessible schemas

Returns: array of table objects with name, schema, and related metadata.


prest.describe_table

Return column metadata for a table.

Arguments:

Field
Required
Description

database

No

Database alias; defaults to pg.database when omitted

schema

Yes

Schema name

table

Yes

Table name

Returns:

Column objects may also include max_length, generated, updatable, and default_value when available from the catalog.


prest.select_table

Read rows from a table using a generic tool name.

Arguments:

Field
Required
Description

database

No

Database alias; defaults to pg.database when omitted

schema

Yes

Schema name

table

Yes

Table name

columns

No

Project specific columns; omit to select all permitted columns

filters

No

Column-aware equality filters (see below)

order_by

No

Sort fields β€” use field for ascending, -field for descending

limit

No

Row limit (1–100); defaults to 100 when omitted or out of range

offset

No

Row offset; defaults to 0

Returns:


prest.select.{database}.{schema}.{table}

Schema-aware tools generated from the catalog at startup. Each readable table gets its own tool with a typed inputSchema derived from column metadata.

Tool name pattern:

Example: prest.select.prest-test.public.Reply

Arguments: same as prest.select_table, except database, schema, and table are encoded in the tool name and cannot be overridden.

The generated inputSchema exposes:

  • allowed columns (enum of permitted column names)

  • allowed order_by values (field and -field for each column)

  • column-aware filters with types matching each column's data type

  • limit (integer, 1–100) and offset (integer, minimum 0)

In multi-database mode, tools are generated for every registered alias. Tables the caller cannot read are omitted from the tool list.


Examples

Initialize

Response includes serverInfo, capabilities, and instructions:

List tools

Describe a table

Schema-aware select

List databases


Authentication and permissions

When auth is enabled, /_mcp requires the same credentials as other protected routes. Send the appropriate Authorization header (or basic auth, depending on your configuration) with every GET and POST request.

Permissions apply to MCP the same way they apply to REST:

  • Tool discovery only lists tables and columns the caller can read.

  • tools/call on a table without read permission returns an error.

  • Per-user [[access.users]] rules are respected.

If a tool list appears empty or a select returns a permission error, check your access.tables configuration.


Multi-database

MCP tools use database aliases β€” the same identifiers used in REST URLs (/{database}/{schema}/{table}). When the database argument is omitted, pREST uses the default database (pg.database).

Mode

database in tools

See also

Legacy multi-DB

Postgres database name

Registry multi-cluster

Registered alias

prest.list_databases returns both the alias (name) and physical_name in registry mode, so MCP clients can distinguish routing aliases from cluster database names.

When pg.single = true and a registry is active, only the default database alias is accepted.


Safety and limits

Rule
Detail

Read-only

No insert, update, delete, or DDL tools in v2.1.0

Row cap

Maximum 100 rows per select (limit defaults to 100)

Identifier validation

Database, schema, table, column, and filter names are validated

Unsupported tools

Return 400 Bad Request with unsupported tool

Catalog discovery (v2.4.1+)

[expose] applies to /_mcp, not just the REST listing routes β€” see below

Custom queries

/_QUERIES scripts are not exposed through MCP

Separate process

MCP runs in-process on prestd; optional stdio adapter for clients that cannot call HTTP

Calling a write tool (for example prest.drop_table) returns:

Catalog discovery and [expose] (v2.4.1)

Before v2.4.1, /_mcp never passed through the exposure middleware β€” a deployment that disabled the /databases, /schemas, or /tables REST routes still served its entire catalog to any MCP client. Since #1016, the MCP handler consults the same settings.

Setting

Effect on /_mcp

expose.enabled = false (default)

Everything is listable β€” no change from v2.4.0

expose.databases = false (with enabled = true)

prest.list_databases dropped from discovery; tools/call returns 400

expose.schemas = false (with enabled = true)

prest.list_schemas dropped from discovery; tools/call returns 400

expose.tables = false (with enabled = true)

prest.list_tables dropped from discovery; tools/call returns 400

Any of the three denied

All prest.select.{database}.{schema}.{table} tools withheld

A denied listing returns a JSON-RPC error rather than a bare HTTP body:

The REST routes return 401 for the same message β€” same rule, different surface.

[expose] governs discovery; [access] governs reads. prest.describe_table and prest.select_table are always advertised, so a client that already knows a table name can still read it subject to permissions. Configuration: Configuring pREST β€” Expose Data.


Troubleshooting

Symptom
Likely cause

401 / 403 on /_mcp

Auth enabled but credentials missing or invalid β€” see Auth

400 unsupported tool

Tool name not in the catalog or write operation attempted

400 unsupported method

JSON-RPC method other than initialize, tools/list, or tools/call

400 unsupported column

columns, filters, or order_by references a column not permitted or not on the table

Empty tool list

ACL hides all tables, or catalog is unreachable for registered aliases

400 unauthorized listing

The listing is denied by [expose] (v2.4.1+) β€” see Catalog discovery and [expose]

Per-table prest.select.* tools missing

[expose] is active with at least one listing denied (v2.4.1+); use prest.select_table

Permission error on select

Caller lacks read access to the table or specific columns β€” see Permissions

invalid identifier in path

Schema or table name failed identifier validation

For integration test examples, see integration/controllers/mcp_test.go in the prest repository.


Client tutorials

Last updated