discoverLABSCO SUMMARY
Masking that the generated SQL cannot get around.
Plenty of database servers promise read-only and enforce it with a prompt or a keyword check; validating against the parsed statement is a materially stronger claim. The column masking is the part worth adopting even if you already have a Postgres server: rules live in a YAML policy, apply to query results and sample rows both, and are applied server-side, so no clever SELECT recovers the raw value. Start with --dry-run, then narrow SCHEMAS before pointing anything at a production database.
What it is
A single Go binary that gives a model read access to a PostgreSQL database. The tool surface is deliberately small — map the database, analyse a table, run a query — and the safety model is enforced server-side: read-only transactions, statements validated by parsing rather than string matching, row caps, query timeouts and schema filtering.
What you get
discoverreturns the whole landscape in one call — schemas with their tables, sizes, row counts and columnsdescribe_tablegives a full analysis of one table: columns, types, keys, statistics, sample rows and index usagequeryruns a read-only statement, optionally returning an EXPLAIN plan instead of, or alongside, the rows- Only SELECT and EXPLAIN are allowed, and that is checked by parsing the statement's syntax tree rather than matching text
- Column masking defined in a policy file — mark a column as redacted, hashed, partially hidden or nulled and it is masked in query results and in
describe_tablesample rows alike, with no way for generated SQL to route around it - A policy engine that adds business context to what tables and columns actually mean
- Operational extras — an NDJSON audit log of queries, OpenTelemetry tracing and metrics, and an HTTP transport with bearer-token auth for clients that cannot spawn a binary
Requirements
A PostgreSQL database, version 12 or newer, reachable from the machine. Install the prebuilt binary with the vendor's install script, or go install with Go 1.25+, or build from source; a Docker image exists but is aimed at testing since most clients expect a local binary. DATABASE_URL is the only required setting. The defaults worth knowing are MAX_ROWS at 100 and QUERY_TIMEOUT at 10s, with SCHEMAS limiting what is exposed and POLICY_FILE pointing at the masking and context rules. --dry-run validates the config and pings the database, which is the fastest way to confirm the wiring.
Setup effort
One command plus credentials — curl -fsSL https://isthmus.dev/install.sh | sh, then supply credentials
USE CASES
Letting a model explore a database it has never seen
Start with the landscape, drill into the tables that matter, then write SQL against real column names.
Answering a data question without write risk
Statements are validated as read-only before they run, so a misread instruction cannot change a row.
Keeping customer data out of the conversation
Mark the sensitive columns in the policy file and they arrive redacted in results and sample rows alike.
Working out why a query is slow
Ask for the EXPLAIN plan instead of the rows.
Limiting what is reachable at all
Expose only the schemas you name, and cap rows and query time at the server.
3 tools
Listed in project docs. Your client may show a different list.
describe_tablequeryBEFORE YOU INSTALL
What to know first
Tools you get
3 tools named in the project's documentation.
Requires
- isthmus on PATH
- DATABASE_URL in your environment
INSTALLATION
Connect your client
Server setup
curl -fsSL https://isthmus.dev/install.sh | shMCP Clients
Claude Desktop
{
"mcpServers": {
"isthmus": {
"command": "isthmus",
"env": {
"DATABASE_URL": "postgres://<YOUR_DB_USER>:<YOUR_DB_PASSWORD>@localhost:5432/<YOUR_DB_NAME>"
}
}
}
}Claude Desktop — Docker
{
"mcpServers": {
"isthmus": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e",
"DATABASE_URL=postgres://<YOUR_DB_USER>:<YOUR_DB_PASSWORD>@host.docker.internal:5432/<YOUR_DB_NAME>",
"guillermosasso/isthmus"
]
}
}
}Cursor
{
"mcpServers": {
"isthmus": {
"command": "isthmus",
"args": [
"--audit-log",
"/tmp/isthmus-audit.ndjson"
],
"env": {
"DATABASE_URL": "postgres://<YOUR_DB_USER>:<YOUR_DB_PASSWORD>@localhost:5432/<YOUR_DB_NAME>",
"SCHEMAS": "public,analytics",
"POLICY_FILE": "<YOUR_POLICY_FILE>",
"MAX_ROWS": "500"
}
}
}
}Any MCP client — HTTP
Start Isthmus in HTTP mode with a bearer token of your own (generate one with openssl rand -hex 32). It listens on port 8080 and refuses to start without the token:
TRANSPORT=http HTTP_BEARER_TOKEN=<YOUR_HTTP_BEARER_TOKEN> DATABASE_URL=postgres://user:pass@localhost:5432/mydb isthmusThen point your client at the endpoint, sending the same token:
{
"mcpServers": {
"isthmus": {
"url": "http://localhost:8080/mcp",
"headers": {
"Authorization": "Bearer <YOUR_HTTP_BEARER_TOKEN>"
}
}
}
}