Schemabrain
About
A read-only trust + intelligence layer between AI agents and your database — the agent never writes SQL, PII is refused before the query runs, and every call lands in a tamper-evident audit log. Postgres today.
Details
- Author
- Arun-kc
- Downloads
- 361
- Categories
- Database, Other, Security, AI
Jump to
- Read-only architecture — 12 MCP tools, none can write.
- PII-aware refusal — blocked-category queries are rejected before hitting the database.
- Tamper-evident audit — SHA-256‑chained append‑only log of every call, refusal, and recovery.
- Postgres support today; Apache‑2.0 licensed.
- Simple installation via uvx.
Setting up with Highlight
This MCP is not yet compatible with Highlight’s one-click setup. However, you can still use it with Highlight by following these steps:
- Download and install Highlight from highlightai.com/download
- Navigate to the plugins tab and select "Add Custom Plugin"
-
Configure the plugin with the settings below
Plugin Name
SchemabrainCommand (node, npx, python, etc.)Please refer to the README for specific instructions on how to obtain API keys or other required environment variables.
- Enable "Start Automatically" if you want the plugin to start when Highlight launches
From the repository
Install Schemabrain using the uvx package manager. It sits between an AI agent and a Postgres database. Twelve read-only MCP tools are available; the agent never writes SQL directly.
Claude Desktop / Cursor
Paste into your MCP client config file to install this server.
{
"mcpServers": {
"schemabrain": {
"schemabrain": {
"command": "uvx",
"args": [
"schemabrain",
"serve",
"--url-env",
"DATABASE_URL"
],
"env": {
"DATABASE_URL": "postgresql://user:password@localhost:5432/dbname"
}
}
}
}
}
McpServers
{
"schemabrain": {
"command": "uvx",
"args": [
"schemabrain",
"serve",
"--url-env",
"DATABASE_URL"
],
"env": {
"DATABASE_URL": "postgresql://user:password@localhost:5432/dbname"
}
}
}
Give them SchemaBrain instead — a read-only trust and intelligence layer where the agent never writes SQL, PII is refused before the query runs, and every call lands in a tamper-evident audit log.
Works with Claude Desktop · Claude Code · Cursor · Windsurf · any MCP host
SchemaBrain compiles every query from definitions you control — no path from a prompt to raw SQL at your database.
Three guarantees that close the trust gap between AI agents and your database:
- Read-only by architecture— twelve MCP tools, none of which can write. Noexecute()tool, noquery()tool, no path from agent prompt to a write at your database.
- PII-aware refusal at retrieval— PII tags propagate from the physical schema through joins and metrics. If a query touches a blocked category, SchemaBrain refuses before the database is queried.
- Cryptographic audit chain— every call, refusal, and recovery is recorded in a SHA256-hashed append-only log (best-effort: a disk-full or no-writer configuration logs a warning and continues rather than failing the query).audit verifyexits non-zero if any past row was rewritten.
See it in action— ask for something the schema can't answer, and it refuses instead of fabricating a join:
SchemaBrain → agent:{ "kind": "unreachable_entity", "recovery": { "suggested_tool": "resolve_join" } }— there's noplan_idon usage events, so it won't invent one.
Claude:I can't fake that join — here'scontracted revenue by plan tierinstead, which actually resolves. ✓
→Full session, with the SQL and results
Watch it run— a live Postgres schema becomes a governed knowledge graph, the firewall computes the safe metric and refuses the leaks, and every call lands in a tamper-evident audit log. No agent, no API key:
uvx schemabrain init # then: Cmd+Q Claude Desktop, relaunch, and ask: "list the entities SchemaBrain knows about" # prefer a persistent install? pipx install schemabrain (or) pip install schemabrain
Cost:$0to run the bundled demo (pre-curated pack, no API key) · ~$0.03 to LLM-index a fresh 84-column schema ·$0to re-index unchanged schemas. Detail inSample session.
Status: 0.6.0 (beta).Postgres supported today (the local store itself is SQLite). SQLite / Snowflake / BigQuery / MySQL source connectors on the roadmap.
Just want to see what it does?uvx schemabrain demo— one command, zero prompts. Builds the sample SaaS layer, then lets you open the dashboard or run a terminal firewall showcase.No API key, and no Dockerfor the dashboard / showcase paths. The steps below are for wiring SchemaBrain into your own agent against your own database.
Three steps fromuvx schemabrain initto a working Claude Desktop integration. If you paste your own Postgres URL — no Docker needed, ~30s. Press Enter for the bundled demo andinitinvokes Docker + downloads a ~67 MB embedding model first time; ~45s once cached.
uvx schemabrain init # zero-install: runs the wizard in one shot # or install persistently first: pipx install schemabrain # (or) pip install schemabrain schemabrain --version
Source install (git clone+uvsync --extra dev) is documented indocs/setup.md.
initis a seven-stage wizard that takes you from "I have a Postgres database" to "Claude Desktop can answer questions about it" in one command. On first run it prompts for what it needs:
- A Postgres URL— paste your own connection string, or pressEnterto spin up a local demo Postgres container with the bundled SaaS fixture (Docker is invoked automatically; idempotent on re-runs).
- AnANTHROPIC_API_KEY— optional. Skip and the wizard still wires Claude Desktop. On thedemo path, entities + metrics + joins are pre-curated from a bundled YAML pack — the semantic layer works zero-config. Onyour own database, entity curation can run later viaschemabrain entities suggest --applyonce you have a key.
SchemaBrain init — activation wizard [1/7] Source check ✓ source reachable + read-only [2/7] Index schema ✓ 12 tables, 84 columns indexed [3/7] Curate entities ✓ 12 entities applied (bundled demo pack) [4/7] Curate metrics ✓ 5 metrics applied (bundled demo pack) [5/7] Curate joins ✓ 11 canonical joins applied (bundled demo pack) [6/7] Wire host ✓ wrote schemabrain entry to claude_desktop_config.json (default; switch with --host claude-code|cursor|windsurf|manual) [7/7] Next ✓ restart your MCP host, then ask: "list the entities SchemaBrain knows about"
Full wizard reference (stages explained, flags, dbt auto-detection,--print-onlyfor non-Claude-Desktop hosts,--no-entities/--no-metrics/--no-joinsopt-outs, cost-cap pauses):docs/setup.md.
-
Quit Claude Desktop fully —Cmd+Q, not just close the window. The MCP config is only read on cold start.
list the entities SchemaBrain knows about
If Claude callslist_entitiesand reportsuser,order, etc., you're done. If not, seeTroubleshooting.
After the wizard,schemabrain inspectshows what the agent has andschemabrain tailstreams every tool call live — seedocs/operations.md.
initwrites just./schemabrain.db(the local store — gitignore it) plus your host config. To tune thePII policyandsemantic layeras editable YAML, re-run with--emit-yaml-dir:
schemabrain init --url-env DATABASE_URL --emit-yaml-dir ./schemabrain # → ./schemabrain/pii_policy.yaml + entities/ + metrics/ + joins/
Edit a file,schemabrain apply ./schemabrain,schemabrain checkto validate, restartserve. There is noschemabrain.yaml— config is CLI flags +SCHEMABRAIN_env vars (auto-loaded from.env) + that YAML tree. Full map:Your project.
Six properties SchemaBrain enforces at the SQL boundary today:
1. Read-only by architecture, not configuration
The MCP surface exposes twelve tools —none of which can write. Noexecute(), noquery(), no path from agent prompt to a write at your database, regardless of session state — the guarantee is structural, not a flag the agent can flip.schemabrain servealso pinsdefault_transaction_read_only=onas belt-and-suspenders.Read-only by architecture →
2. PII-aware refusal at theget_metrictool boundary
Anyget_metrictouching a blocked PII category returns arefusedenvelope — the compiled SQL never runs and the refusal lands inmcp_audit.describe_entityenforces the same at the column level (blocked columns shipredacted=True).initblocks the catastrophic-leak set by default (credential,payment_card,government_id);--pii-blockreplacesthe set, so widen by listing the full target. Detection is column-name pattern matching across twelve GDPR / CCPA / HIPAA / PCI categories; content-aware classification is on the roadmap.PII taxonomy & propagation →
Every tool call writes one row to an append-onlymcp_audittable — PII categories, content-addressable fingerprints, sha256 hash chain.audit verifyre-walks the chain and exits non-zero if any past row was rewritten.
schemabrain audit verify # exit 0 = chain clean
Every non-success call — refused, error, or degraded — returns a structuredrecovery.suggested_argsblock, not a message to parse. PII blocks (status: "refused") ship the entity to retry; ambiguous dimensions and unreachable entities (status: "error") ship the candidate to pick or the next tool to call. Only policy refusals arerefused; "I won't guess" iserrorwith a recovery payload.
{ "status": "error", "kind": "ambiguous_time_dimension", "recovery": { "suggested_tool": "get_metric", "suggested_args": {"time_dimension": "order.placed_at"} } }
5. Compile path: definitions → parameterized SQL
Entities, metrics, and canonical joins compile to parameterized SQL SchemaBrain runs on its side. The agent sees rows + the SQL that ran — never arbitrary statements at your database. LLM-suggested definitions duringinitare reviewed and applied explicitly.Build your semantic layer →
The same MCP stdio surface Claude Desktop sees is exposed to any MCP host — your own Anthropic, OpenAI, or LangGraph loop included.examples/anthropic_demo.pyis a ~260-LOC drop-in that wires Claude Haiku 4.5 toschemabrain serveand prints exactly which tools the agent chose.Anthropic SDK walkthrough →
SchemaBrain ships an opt-in, read-only dashboard over the same audit + PII + refusal data the MCP server is already writing.schemabrain dashboardboots a local FastAPI sidecar serving a pre-built static UI — no Node runtime, no network exposure, no write paths.
pip install "schemabrain[ui]" schemabrain dashboard # → http://127.0.0.1:7878
It's a viewer, not a console — no settings, no SQL pad, no write path.Nine read-only surfaces, each answering an operator question the MCP envelope alone never surfaces visually. The signature surface is theKnowledge Graph— your schema rendered as the same entity-relationship projection the semantic layer compiles joins against:
- Knowledge Graph(/graph) —how does my schema actually connect?Entities as nodes, canonical joins as edges (solid for declared FKs, dashed for log-mined), PII-bearing entities flagged, and refusal hotspots highlighted, with declared-FK cardinality shown on the highlighted join path — the schema as a graph, not a table list.
- Overview(/overview) — the home surface: entity / metric / join / catastrophic-PII counts at a glance.
- Entities(/entities) — a sortable index; drill into any entity's columns, PII, metrics, and canonical joins.
- Data Dictionary(/dict) — every table, column, type, PII class, join, and metric, with one-click Markdown export (the same artifactschemabrain docswrites).
- PII matrix(/pii) —which columns carry sensitive data?A heatmap with one row per classified column and one cell per PII category, each column tagged block / redact / allow by its advisory band. Columns in a catastrophic-leak category (credential,payment_card,government_id) are hard-blocked regardless of policy and pinned to the top — so you catch apayment_cardcolumn hiding insideusersbefore you point an agent at a new schema, and see at a glance what trips the default--pii-blockpolicy. Select any row to drill into its entity's columns, metrics, and joins.
- Refusals(/refusals) —what did SchemaBrain block, and what did the agent see?A chronological feed of held calls; expand any row to reveal the full envelope inline — the reason that fired (pii_blocked,allowlist_violation,fragment_unsafe,cost_cap_exceeded,ambiguous_resolution,schema_drift), the exact category set that intersected the policy, and the structurederror.recovery(suggested tool + args) the agent got back to recover. Use it to triage "the agent says it can't access that" and to review whether those hints actually helped.
- Audit Viewer(/audit) —is the audit chain still intact?The visual face of the tamper-evident log: every tool call writes exactly one row — whatever the outcome — anchored bychain_hash = sha256(prev_hash || canonical(row)). An integrity strip readsnot verified this sessionuntil you run a pass, thenverified · n/N intact(or flagsN rows edited after write); theVerifybutton re-walks the chain server-sideandrecomputes each visible row's RFC-6962 Merkle inclusion proof in your browser. Selecting a row opens the full body (tool, status, cost class, PII categories, fingerprint,chain_hash, and the proof ladder up to the root). Reload to pick up new calls.
- Policy(/policy) — the block / redact / allow grid the firewall enforces, with the always-on catastrophic-leak floor disclosed (it can't be removed). Changes are made via copy-the-CLI actions — the dashboard never writes.
- Drift(/drift) — config and enrichment drift the store can detect, each with a copy-the-CLI fix.
Knowledge Graph — your schema as the entity-relationship projection the semantic layer compiles joins against; catastrophic-PII entities flagged, the canonical join path traced.
Overview — the whole boundary on one screen: what's bound, what's protected, what's drifted.
PII matrix — which columns carry sensitive data, and what the default policy blocks.
Refusals — every blocked call, the reason that fired, and the recovery hint the agent received.
Audit Viewer — the tamper-evident chain, verified server-side down to each row's hash linkage.
Entities — every business entity bound out of the raw schema, with PII exposure and join counts.
Data Dictionary — every table, column, type, and join, exportable to Markdown for your repo or wiki.
Policy — the block / redact / allow grid the firewall enforces, with the always-on floor disclosed.
Drift — config and enrichment drift the store can detect, each with a copy-the-CLI fix.
The dashboard binds127.0.0.1only— there is no--hostflag, by design. It's read-only and reads the same SQLite storeservewrites to. No agent talks to it.
Dashboard guide →·PII matrix →·Refusals →·Audit Viewer →
schemabrain init --host <X>writes the MCP entry directly into the host's config file.
schemabrain init --host manualprints the JSON entry to stdout — paste it into whatever host config you're using. Any client that launches a subprocess and speaks MCP stdio should work in principle; we have not exhaustively tested each. Common targets:
- Zed— full walkthrough atdocs/setup/zed.md
- Codex CLI(working path for ChatGPT users) — full walkthrough atdocs/setup/codex.md
- Cline(VS Code extension) —schemabrain init --host manualprints themcpServersblock; paste it into Cline's settings viaMCP Servers → Configure MCP Servers. Full walkthrough atdocs/setup/cline.md
- Continue— paste into~/.continue/config.json
- Your own agent loop— seeexamples/anthropic_demo.pyfor a ~250-LOC Anthropic-SDK reference
The 12-tool surface, PII-aware refusal, audit chain, and recovery contracts are transport-agnostic — any compliant stdio MCP client gets the same guarantees.
The same stdio MCP surface is reachable from any framework that can spawn an MCP server. The Anthropic SDK path is first-party-tested; the others work in principle if the framework's MCP integration speaks stdio.
- Anthropic SDK— first-party walkthrough atdocs/setup/manual.md; reference loop atexamples/anthropic_demo.py
- LangChain / LangGraph— vialangchain-mcp-adapters
- Pydantic AI— via itsbuilt-in MCP support
- CrewAI / AutoGen / Agno / custom loops— any framework with a stdio MCP client works in principle; we have not tested each
We don't ship per-framework adapters; the framework's standard MCP client is sufficient.
SchemaBrain v0.6 ships stdio only — no HTTPS / SSE transport. Clients that require a cloud HTTPS endpoint donotwork today:
- ChatGPT Connectors— see thehonest gap pagefor workarounds and the v0.5+ roadmap
- Hosted MCP gateways— by design (local-first wedge; seevs Querybear)
If you need ChatGPT support today, a community stdio→HTTPS bridge (mcp-remote,mcp-proxy, etc.) may work; we have not validated any specific bridge against the PII / audit / recovery semantics.
Security posture for procurement / review →
Real Claude Desktop session against the bundled SaaS fixture (12 tables, 84 columns, 12 entities). Condensed for length — a real agent exploreslist_metrics/suggest_joinsfirst, then concludes the path is unreachable:
You:Using SchemaBrain, compute our usage volume broken down by plan tier.
Claude:(callsget_metric(name="usage_volume", group_by=["plan.title"]). The metric anchors onusage_event; reachingplanwould need a join that isn't in the schema, so it refuses:)
{ "status": "error", "error": { "kind": "unreachable_entity", "message": "entity 'plan' is not reachable from metric anchor 'usage_event'; no canonical join exists. Run schemabrain joins suggest to surface candidate joins.", "recovery": { "suggested_tool": "resolve_join", "suggested_args": { "entity_a": "usage_event", "entity_b": "plan" } } } }
(Claude confirms at the join layer —resolve_join("usage_event", "plan")returnskind: no_canonical_join.usage_eventscarries onlyworkspace_id, never aplan_id, and no table bridges the two.)
Verdict up front: I can't compute usage-by-plan, and you shouldn't want me to fake it — there is no modeled relationship between usage events and plans in this schema.usage_eventsrecords aworkspace_id, not a plan, and nothing joins the two. "Usage volume by plan tier" is unanswerable until that link exists — and I'm not going to invent it.
What Icangive you — contracted revenue by plan tier (this path fully resolves:subscription_item → subscription → plan, bothfk_constraintjoins,confidence: HIGH):
SELECT p.title AS plan_tier, SUM(si.unit_price_cents si.seats) / 100.0 AS revenue -- prices stored in integer cents FROM public.subscription_items si JOIN public.subscriptions s ON si.subscription_id = s.id JOIN public.plans p ON s.plan_id = p.id GROUP BY p.title ORDER BY revenue DESC;
- Contracted, not collected.This is subscription line-item revenue (seats × unit_price_cents), not paid invoices. For billed totals, thetotal_revenuemetric anchors oninvoicesinstead.
- Integer cents.unit_price_centsis stored as an integer; the/ 100.0converts to currency.
The differentiator is whatdidn'thappen: most LLM-over-database tools, asked for usage-by-plan, would confidently emitJOIN plans p ON usage_events.plan_id = p.idagainst aplan_idcolumn that doesn't exist. SchemaBrain refused —get_metricreturnedkind: unreachable_entitywithrecovery.suggested_tool: resolve_join, not prose. The agentacted on the structured recovery contract programmaticallyinstead of fabricating a join. Refusal-not-fabrication is the safety mechanism, demonstrated live.
Cost.~$0.0004/column with Claude Haiku 4.5 (cryptic-name columns can opt into Sonnet 4.6 via--enable-sonnet). The bundled 12-table fixture (84 columns, 12 entities + 5 metrics + 11 joins) ships pre-curated, so the demo path applies it for$0— no API key. Indexing those 84 columns with LLM column descriptions comes to about$0.03. The Pagila DVD-rental sample (87 columns after partition deduplication) is the directly measured reference —$0.0299 in 105s. Re-indexing an unchanged schema is$0— content-addressable fingerprinting skips the LLM call entirely.
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.





