Beta · active development · Postgres & SQLite

Turn Postgres into MCP tools, a REST API & OpenAPI — from one Rust engine

Point pgvis at your Postgres database. It introspects the schema, reloads it live on NOTIFY pgrst, and serves it three ways from a single pipeline: typed Model Context Protocol tools for LLM agents, a PostgREST-compatible REST API, and an OpenAPI 3.0 document. One parser, one planner, one SQL builder — behavior stays consistent by design.

License Apache-2.0
Language Rust · Edition 2024
Protocol MCP · REST · OpenAPI
Postgres SQLite pgvis engine parse → plan → SQL MCP REST OpenAPI
Postgres SQLite pgvis engine parse → plan → SQL MCP REST OpenAPI
Features

One pipeline. Three surfaces. Zero glue.

MCP for AI agents

Every table and function becomes a typed Model Context Protocol tool — list_*, create_*, update_*, delete_*, call_* — with discovery resources like pgvis://schemas. No glue code. Works with Claude Desktop and any MCP client.

PostgREST-compatible

Same query DSL, the same Prefer header semantics, the same PGRST* error codes. A flat routing mode lets existing PostgREST clients keep working unchanged.

OpenAPI 3.0

Generated from the same introspected schema as REST and MCP — always in sync by construction. Print it with pgvis openapi, or fetch it from the API root with Accept: application/openapi+json.

Rust & embeddable

pgvis-core is I/O-free and depends on no driver. Backends implement a single Backend trait. Add a database API to any Rust app with the pgvis-lib Builder.

Safe by construction

Parameterized SQL only. JWT verification (HS256/384/512, RS256, EdDSA) with exp, nbf and optional audience checks, role switching, and Row-Level Security. Secure defaults: binds to loopback, refuses to start without auth unless you pass --insecure-no-auth, and a token without a role is a 401.

Fast on the hot path

BEGIN, role and claims, pre-request hook and query go out as one pipelined round trip. Table reads forward Postgres's JSON text without re-parsing. Optional in-memory response cache and health-checked, lag-aware read replicas; pool exhaustion returns 503.

Live schema & pub/sub

The schema cache reloads on NOTIFY pgrst, 'reload schema' or SIGUSR1 — REST, OpenAPI and MCP pick up DDL without a restart. Opt-in pub/sub on Postgres LISTEN/NOTIFY: subscribe over SSE, publish over REST or MCP, with optional per-caller channel authorization by a SQL function.

Backend-agnostic

Postgres (including PostgreSQL 18 virtual generated columns and temporal keys) and SQLite today. Dialect capability flags drive feature gating — no core rewrite needed for a new backend.

Get started

Up and running in three commands

REST API
# build the CLI
cargo build --release --bin pgvis

# point it at your database (binds 127.0.0.1:3000)
export PGVIS_DSN="postgres://user@localhost/mydb"
# local dev only: no JWT, every request runs as the DSN's role.
# In production set PGVIS_JWT_SECRET and/or PGVIS_ANON_ROLE instead.
./target/release/pgvis serve --insecure-no-auth

# query
curl "http://localhost:3000/api/public/users?select=id,name&active=eq.true"
MCP for Claude Desktop
// claude_desktop_config.json
{
  "mcpServers": {
    "pgvis": {
      "command": "pgvis",
      "args": [
        "--dsn", "postgres://localhost/mydb",
        "mcp"
      ],
      "env": { "PGVIS_ANON_ROLE": "web_anon" }
    }
  }
}
Embed in Rust
use pgvis_lib::Builder;

// REST + MCP-over-HTTP router for axum::serve
let router = Builder::new("postgres://localhost/mydb")
    .schemas(vec!["public"])
    .with_mcp_http()
    .build()
    .await?;
Why pgvis

How it differs from PostgREST

I/O-free, backend-agnostic core

pgvis-core does no I/O. Backends implement a single Backend trait — Postgres and SQLite today — without touching the engine.

First-class MCP surface

MCP is not a bolt-on. Tables and functions lower into typed MCP tools through the same plan → SQL path REST uses, so the two surfaces can never disagree.

A library, not just a server

The CLI is one consumer of pgvis-lib. Embed the same stack in any Rust app with the Builder facade.

Schema-in-URL routing

Routes default to /{prefix}/{schema}/{table} with a flat PostgREST-compatible mode available via routing config for drop-in replacement.

Open source. Apache-2.0.

Contributions welcome — issues, PRs, and design feedback all land on GitHub.