Documentation · PostgreSQL
MCPDBWizard for Postgres
MCPDBWizard for Postgres is the same product pointed at PostgreSQL. You select the tables, views, functions, procedures, sequences and SQL statements an agent may use, and it generates an MCP server for exactly those. An object you did not select has no tool, no method and no class, and every call binds its values rather than passing SQL text. The console, the proxy, accounts, tokens, the access grid, audit and Context Pinning all work as they do on Oracle.
It is a separate image, because a Postgres image carries no Oracle driver at all:
docker pull ghcr.io/srmadscience/mcpdbwizard-postgres:2.0.33
docker pull docker.io/srmadscience/mcpdbwizard-postgres:2.0.33
Both registries hold the same multi-arch image (linux/amd64, linux/arm64). One licence
covers both products: an MCPDBWizard licence unlocks the Oracle image and the Postgres image
alike. See Commercials.
To get it running, follow Quickstart: Postgres.
Supported versions
PostgreSQL 16, 17 and 18. Each release is tested against all three. 15 and older are not
supported: describing a SQL statement’s result columns relies on pg_prepared_statements.result_types,
which arrived in 16.
What becomes a tool
| Object | Tools | Notes |
|---|---|---|
| Table, view, materialized view, foreign table, partitioned table | get_by_pk, insert, update, delete, plus a lookup per unique key, index and foreign key | Needs a primary key, as on Oracle. A partition is reached through its parent, not on its own. |
Expression index (upper(name), date_trunc(...)) | A lookup tool per index | Arguments are named for the index’s columns and typed by the expression, and the query is written so the index serves it. |
| Function or procedure | One tool per routine | Overloads get one tool each; the description names the signature (Call PostgreSQL function app.price(numeric)) so the agent can tell them apart. |
Function returning refcursor or SETOF | One tool returning rows | A refcursor returns at most 10,000 rows by default, as on Oracle. |
| Sequence | nextval | |
| Your own SQL statement | One tool per statement | The statement is described with PREPARE when the server is generated, so a bad statement is caught then, not on its first call. |
Tool names carry the schema — sales_orders_get_by_pk for sales.orders — because a
Postgres database commonly holds several schemas with tables of the same name. A name longer than
64 characters keeps its first 23 and last 31 characters with a hash between them, so the operation
stays at the end.
How the types cross
| Postgres | Over MCP |
|---|---|
integer, bigint, numeric, real, double precision | number |
text, varchar, char, uuid, xml, enum | string |
boolean | boolean |
date, timestamp | string, at full microsecond precision |
timestamptz | string, with its offset |
time, timetz, interval, money, inet, cidr, macaddr, bit, range and multirange types | string, in Postgres’s own text form (1 year 2 mons 3 days, [1,5)) |
bytea | base64 string |
| Composite type | JSON object, keyed by attribute name |
| Array, or a domain over one | JSON array, keeping a lower bound other than 1 |
json, jsonb | JSON text — a string holding the document, not an object |
PostGIS geometry, geography | EWKT string: SRID=4326;POINT(1 2) |
pgvector vector, halfvec | array of numbers |
pgvector sparsevec | {length, indices, values}, indices counting from 0 |
A domain crosses as its base type. A timestamp parameter accepts ISO (2026-11-03T10:55:00) and
the JDBC form (2026-11-03 10:55:00.123456).
Not mapped yet: the geometric types (point, polygon, …), the text-search types
(tsvector, tsquery), pg_lsn, and extension types other than PostGIS’s and pgvector’s
(citext, hstore, …). Each needs a decision about how it crosses JSON, so none is guessed at:
a routine with such a parameter is left out when the server is generated, and the log says why.
What is different from Oracle
- Packages are schemas. Where an Oracle config lists
PACKAGE.PROCEDURE, a Postgres config listsschema.routine. There is no package state. - Context Pinning uses a custom setting, not
SYS_CONTEXT. A URL parameter such asCUSTOMER_IDis set for the length of each call asmcp.customer_id. Your SQL reads it withcurrent_setting('mcp.customer_id', true)— and withnullif(..., '')where unset must mean NULL, because Postgres reports a setting it has seen before as''rather than NULL. Nothing needs installing in the database. See Context Pinning. - Pooling is always on. A generated Postgres server always runs pooled, and each tool call commits or rolls back on its own. The console’s pooling switch is fixed on, because an unpooled Postgres connection that hits one error refuses every later statement until it is rolled back. See Connection pooling.
- Errors name the SQLSTATE, ending
(SQLSTATE 23505), where Oracle’s nameORA-00001. - No
CREATE TYPEgrant is needed. Composites and arrays bind directly, so the generator never creates shadow types in your database, and a config has noEXTRA_SQL. - Names keep their case. Postgres folds unquoted names to lower case, and nothing is upper-cased on the way in. A quoted mixed-case name keeps its case.
- The session is named in
pg_stat_activity.application_name, the counterpart of Oracle’sDBMS_APPLICATION_INFO.
Not supported
- Routines: a refcursor as an input (no MCP client can supply one), polymorphic routines
(
anyelement,anyarray), and arrays of vectors. A multi-dimensional array fails when called, because Postgres array types do not record their dimensions. - Tables: a table without a primary key gets row classes but no MCP tools, as on Oracle. Composite and array columns are left out of a table tool’s schema.
- SQL statements: a
?inside a string literal, or thejsonb?operator, is taken for a parameter placeholder. Usejsonb_exists(...)in place of the operator. - Duality views and the SOAP layer are Oracle features with no Postgres counterpart.
See also Known issues on Postgres.